Java 如何在spring boot中到达控制器之前修改请求正文
我有一个spring启动应用程序。 我更改每个post请求的请求正文。 是否可以在请求到达控制器之前修改请求正文。Java 如何在spring boot中到达控制器之前修改请求正文,java,spring,spring-boot,Java,Spring,Spring Boot,我有一个spring启动应用程序。 我更改每个post请求的请求正文。 是否可以在请求到达控制器之前修改请求正文。 请提供一个例子。简短回答 是的,但不容易 详细信息 我知道更改请求正文的三个选项 “before”到达控制器中的handler方法 在调用方法之前,使用AOP更改请求 创建HTTP筛选器 创建自定义Spring HandlerInterceptor 由于您已经在使用spring boot, 选项3,定制弹簧手柄拦截器, 似乎是你最好的选择 这里是一个到覆盖弹簧手柄拦截器的链接 Ba
请提供一个例子。简短回答
是的,但不容易 详细信息
我知道更改请求正文的三个选项 “before”到达控制器中的handler方法
HttpServletRequest
返回的InputStrem
您需要创建一个扩展HttpServletRequest
并将包装类中的每个请求包装在自定义HandlerInterceptor中,或包装在自定义筛选器中(这里可能是使用筛选器)
包装类
HttpServletRequest
InputStream
toByteArray
从流中检索实际的字节[]
getInputStream
方法getInputStream
时,将字节[]
包装在ByteArrayInputStream中。返回此流另一种选择是向HttpServletRequest对象添加一个属性。之后,您可以使用@RequestAttribute注释在控制器类中读取该属性 在拦截器中
@Component
public class SimpleInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException, IOException {
String parameter = request.getParameter("parameter");
if (parameter == "somevalue") {
request.setAttribute("customAttribute", "value");
}
return true;
}
}
在控制器中
@RestController
@RequestMapping("")
public class SampleController {
@RequestMapping(value = "/sample",method = RequestMethod.POST)
public String work(@RequestBody SampleRequest sampleRequest, @RequestAttribute("customAttribute") String customAttribute) {
System.out.println(customAttribute);
return "This works";
}
}
这样做的优点是不修改请求主体 我的答案使用HTTP过滤器 RequestFilter.java
@Component
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
RequestWrapper wrappedRequest = new RequestWrapper((HttpServletRequest) request);
chain.doFilter(wrappedRequest, response);
}
@Override
public void destroy() {
}
}
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
private ObjectMapper objectMapper = new ObjectMapper();
public RequestWrapper(HttpServletRequest request) throws IOException {
// So that other request method behave just like before
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
// Store request body content in 'requestBody' variable
String requestBody = stringBuilder.toString();
JsonNode jsonNode = objectMapper.readTree(requestBody);
//TODO -- Update your request body here
//Sample
((ObjectNode) jsonNode).remove("key");
// Finally store updated request body content in 'body' variable
body = jsonNode.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
RequestWrapper.java
@Component
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
RequestWrapper wrappedRequest = new RequestWrapper((HttpServletRequest) request);
chain.doFilter(wrappedRequest, response);
}
@Override
public void destroy() {
}
}
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
private ObjectMapper objectMapper = new ObjectMapper();
public RequestWrapper(HttpServletRequest request) throws IOException {
// So that other request method behave just like before
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
// Store request body content in 'requestBody' variable
String requestBody = stringBuilder.toString();
JsonNode jsonNode = objectMapper.readTree(requestBody);
//TODO -- Update your request body here
//Sample
((ObjectNode) jsonNode).remove("key");
// Finally store updated request body content in 'body' variable
body = jsonNode.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
一种方法是通过反思。ProceedingJoinPoint包含传递给方法的args对象
@Aspect
@Component
public class AopInterceptor {
@Around(value = "@annotation(xyz.rpolnx.spring.web.poc.annotation.AopIntercepExample)")
public Object handler(final ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Object[] args = joinPoint.getArgs();
Class<?> someClass = args[0].getClass();
Field field = someClass.getDeclaredField("custom");
field.setAccessible(true);
field.set(args[0], "custom");
field.setAccessible(false);
return joinPoint.proceed();
}
}
@RestController
public class SimpleController {
@PostMapping("/aop")
@AopIntercepExample
public Person handleAopIntercept(@RequestBody Person nodes) {
return nodes;
}
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AopIntercepExample {
}
public class Person {
private String name;
private String id;
private String custom;
}
@方面
@组成部分
公共类AOP接收器{
@大约(value=“@annotation(xyz.rpolnx.spring.web.poc.annotation.AopIntercepExample)”)
公共对象处理程序(最终处理joinPoint joinPoint)抛出可丢弃的{
HttpServletRequest请求=((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
对象[]args=joinPoint.getArgs();
类someClass=args[0]。getClass();
Field=someClass.getDeclaredField(“自定义”);
字段。setAccessible(true);
field.set(参数[0],“自定义”);
字段.setAccessible(false);
返回joinPoint.procedure();
}
}
@RestController
公共类SimpleController{
@后映射(“/aop”)
@AopIntercepExample
公共人员handleaointercept(@RequestBody Person节点){
返回节点;
}
}
@目标({ElementType.METHOD})
@保留(RetentionPolicy.RUNTIME)
public@interface AopIntercepExample{
}
公共阶层人士{
私有字符串名称;
私有字符串id;
私人字符串自定义;
}
以下是我如何使用RequestBodyAdvice实现它的:
@ControllerAdvice
公共类CustomRequestBodyAdvice实现RequestBodyAdvice{
<!-- language: lang-js -->
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("In afterBodyRead() method of {}", getClass().getSimpleName());
if (body instanceof AuthorDTO) {
AuthorDTO authorDTO = (AuthorDTO) body;
authorDTO.setName("Test");
return authorDTO;
}
return body;
}
@覆盖
公共布尔支持(MethodParameter、类型、类>aClass){
info(“在{}的supports()方法中”,getClass().getSimpleName());
返回methodParameter.getContainingClass()==AuthorController.class&&type.getTypeName()==AuthorDTO.class.getTypeName();
}
b、 在身体准备好之前
<!-- language: lang-js -->
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
log.info("In beforeBodyRead() method of {}", getClass().getSimpleName());
return httpInputMessage;
}
@凌驾
公共HttpInputMessage beforeBodyRead(HttpInputMessage HttpInputMessage,MethodParameter MethodParameter,类型,类>aClass)引发IOException{
info(“在{}的beforeBodyRead()方法中,getClass().getSimpleName());
返回httpInputMessage;
}
c、 afterBodyRead:这里是您可以修改请求正文的地方
<!-- language: lang-js -->
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("In afterBodyRead() method of {}", getClass().getSimpleName());
if (body instanceof AuthorDTO) {
AuthorDTO authorDTO = (AuthorDTO) body;
authorDTO.setName("Test");
return authorDTO;
}
return body;
}
@凌驾
公共对象afterBodyRead(对象主体、HttpInputMessage HttpInputMessage、MethodParameter方法参数、类型、类>aClass){
info(“在{}的afterBodyRead()方法中,getClass().getSimpleName());
if(AuthorDTO的主体实例){
AuthorDTO AuthorDTO=(AuthorDTO)body;
authorDTO.setName(“测试”);
返回authordo;
}
返回体;
}
d、 手持式车身
<!-- language: lang-js -->
@Override
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("In handleEmptyBody() method of {}", getClass().getSimpleName());
return body;
}
@凌驾
公共对象handleEmptyBody(对象体,HttpInputMessage HttpInputMessage,MethodParameter MethodParameter,类型,类>aClass){
info(“在{}的handleEmptyBody()方法中”,getClass().getSimpleName());
返回体;
}
来源:看看这个:我认为只允许设置请求参数zombie。在我的例子中,修改请求正文。谢谢,我将工作并更新状态HI its TROWS无法读取HTTP消息:org.springframework.HTTP.converter.httpMessageNodeTableException:读取输入消息时发生I/O错误;嵌套异常为java.io.I