【问题标题】:How override InputStream in SpringBoot before controller?如何在控制器之前覆盖 SpringBoot 中的 InputStream?
【发布时间】:2020-04-19 22:20:35
【问题描述】:

如何在 Spring Boot 中覆盖 @RequestBody 内容,然后才能到达控制器?

  1. 我知道有 WebMvcConfigurer 和 HandlerInterceptorAdapter 类可以在控制器之前处理请求。

  2. 我也搜索了 RequestBodyAdviceAdapter。

有几个链接不适用于 Spring Boot。

How to read request.getInputStream() multiple times

How to modify request body before reaching controller in spring boot

现在我可以将输入流读入字符串,进行一些修改并设置回控制器的输入流吗?

【问题讨论】:

  • 任何提示都会有所帮助
  • 尝试使用 AOP。创建一个将被称为before 控制器的方法非常容易。以下是关键字:Aspect、@Before。我无法提供更多细节,也许在当天晚些时候,向我们展示你对 Aspect 的尝试
  • 我认为最好的办法是添加一个@ControllerAdvice/@RestControllerAdvice 类并实现RequestBodyAdvice。如果您知道@RequestBody 对象,那么在“afterBodyRead”中强制转换并设置特定属性。
  • @RUAROThibault 我的目标是在 json 字符串中更改对象名称(大写),然后再到达 spring boot 控制器,这样 spring 将按名称正确映射对象。我之前尝试过 AOP,这对我来说没有意义,因为我在 aop(proceedingJoinPoint.getArgs()) 中获取了映射对象,并且该值已经设置为 null。我想我需要在 Aop 之前。
  • @Lipu 感谢您的回复。我尝试了 ControllerAdvice 和 RequestBody 但我也需要访问请求正文(json字符串)的方法。我的控制器接收 json 对象(java 类)并且属性名称使用小写字母。我想在 spring boot 之前访问该 json 将尝试将其映射到对象并修改属性名称作为 java 和 spring boot 期望

标签: spring-boot inputstream


【解决方案1】:

这看起来是一个很好的 Servlet 过滤器用例。过滤器将在控制器之前接收请求,允许您修改请求,然后您可以将请求传递到过滤器链以供您的控制器处理。

示例: https://www.baeldung.com/spring-boot-add-filter

您需要编写一个自定义的 HttpServletRequestWrapper。在这个包装类构造函数中会接收到请求。将 InputStream 读入一个变量(此时可以修改流)。还要重写 getInputStream() 和 getReader() 方法以返回修改后的流(不是原始流)。

在您的过滤器中,创建包装器的新实例并将传入请求传递给构造函数。完成修改后,将包装好的请求传递给 chain.doFilter(myWrappedRequest, response) 以允许下游控制器处理它。

这是一个如何创建包装器并在过滤器中使用它的示例:https://howtodoinjava.com/servlets/httpservletrequestwrapper-example-read-request-body/

【讨论】:

  • 感谢您的回答。我查看了过滤器,但看不到如何读取输入流、修改和设置它的机会。你有例子吗?
  • 我修改了我的回复,向您展示如何使用自定义 HttpServletRequestWrapper 来允许您修改输入流,然后将其传递到链中。
  • 我想我试过这个例子但没有得到想要的结果。
【解决方案2】:

解决方案1:(我认为更好的解决方案) 正如评论中所建议的,请尝试为对象使用 @JsonProperty 或自定义 De-/Serializer。

解决方案 2: 添加 @ControllerAdvice 并实现 RequestBodyAdvice 并将 beforeBodyRead 覆盖为

@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
    InputStream body = inputMessage.getBody();
    String bodyStr = IOUtils.toString(body, Charset.forName("UTF-8"));
    /*
    Update bodyStr as you wish
    */
    HttpInputMessage ret = new MappingJacksonInputMessage(new ByteArrayInputStream(bodyStr.getBytes()), inputMessage.getHeaders()); //set the updated bodyStr
    return ret;
}

【讨论】:

  • 谢谢伙计。解决方案 2 正是我想要做的。解决方案 1 是完美的,我知道。但是我有基于 xsd 的类(从 xsd 模式生成),我不想手动更改它们并应用自定义注释。
  • 谢谢!在 OncePerRequestFilter 和 HandlerInterceptor 实现多次失败后找到了这个答案。这非常适合我的用例:检查内容签名是否与 Signature 标头值匹配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 1970-01-01
  • 2019-10-09
  • 1970-01-01
相关资源
最近更新 更多