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

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

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

  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
相关资源
最近更新 更多