当前位置: 首页 > 知识库问答 >
问题:

如何在spring boot中到达控制器之前修改请求正文

裴欣荣
2023-03-14

我有一个spring boot应用程序。我更改每个post请求的请求正文。是否可以在请求到达控制器之前修改请求正文。请附上一个例子。

共有3个答案

司徒高丽
2023-03-14

我使用HTTP过滤器的答案。

请求Filter.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() {

    }

}

RequestWrapper。Java语言

 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()));
        }
}
陶博涉
2023-03-14

简短回答是的,但不容易。

详细信息
我知道有三个选项可以在请求“到达”控制器中的处理程序方法之前更改请求体;

  1. 在调用方法之前使用AOP更改请求。
  2. 创建一个HTTP过滤器。
  3. 创建自定义Spring HandlerInterceptor。

既然您已经在使用spring boot,选项3,定制spring HandlerInterceptor,似乎是您的最佳选择。

这里有一个链接到一篇关于spring HandlerInterceptors的Baeldung文章。

Baeldung文章并不是您问题的完整答案,因为您只能一次读取HttpServletRequest返回的InputStrem。

您需要创建一个扩展HttpServletRequest的包装类,并将包装类中的每个请求包装在自定义HandlerInterceptor或自定义过滤器中(这里可能是使用过滤器)。

包装器类

  1. 阅读包装类构造函数中的HttpServletRequest输入流

如何包装请求

  1. 在过滤器中,实例化包装器类并传入原始请求(这是doFilter方法的参数)
  2. 把包装纸递给链条。doFilter方法(不是原始请求)
金骞尧
2023-03-14

另一种选择是向HttpServletRequest对象添加一个属性。之后,您可以在Controller类中使用@Request estAtcm注释读取该属性。

在拦截器里

@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";
    }
}

这具有不修改请求正文的优点。

 类似资料:
  • 在到达spring控制器之前,如何从UI端修改请求体中发送的JSON对象? 我尝试添加过滤器,但是一旦我从请求(servletrequest.getReader())读取,然后将请求转发到过滤器链中的下一个过滤器,它就会失败(请求无法到达控制器)。 使用这个,我得到了字符串中的JSON,但我无法弄清楚如何将其放回请求中。

  • 在spring boot中@RequestBody内容到达控制器之前,我如何覆盖它? > 此外,我还搜索了Request estBodyAdviceAdapter。 有几个链接对spring boot不起作用。 如何多次读取request.getInputStream() 如何在Spring引导到达控制器之前修改请求正文 现在,我可以将输入流读入字符串中,进行一些修改并设置回控制器的输入流吗?

  • 我正在使用Java和Spring构建一个RESTAPI,我需要在我的控制器中处理一个POST请求,但我需要从该请求中提取主体,它是一个JSON,也是该请求的“来源”, 我有几个问题:首先是如何获取该请求的来源(我猜是在标题中移动的url?),是否有与@RequestBody类似的注释?。 我的第二个问题是,在这种post方法中,通常应该返回什么对象作为响应。

  • 我正在开发我的第一个基于spring的项目样本。下面是我的dispatcher-servlet.xml的摘录。 我尝试向以下url发布帖子,但它似乎从未到达相应的控制器类: 网址: post<code>{“testID”:“1”} 就是回应。 为什么我得到400错误,尽管一切似乎都在地方?

  • 我正在使用ApacheTiles构建一个带有SEO友好URL和多主题UI的小型Spring Boot应用程序。 我有两个类似的问题 例如map是 通过扩展什么类,我可以访问这个?以及如何阻止请求被Spring Security阻止? 更改controller后的视图名称