使用Spring的@RequestBody并随后读取HttpServletRequest.getInputStream()


问题内容

我正在使用Spring的@RequestBody注释和将请求的JSON
POST数据映射到一个对象中MappingJacksonHttpMessageConverter。但是之后,我想读取String表格中的数据以进行其他身份验证。但是,当编组已经发生了,InputStreamHttpServletRequest为空。一旦我@RequestBody从方法中删除了参数,POST数据的读取就可以String正常工作了。

我是否必须通过@RequestBody手动放弃绑定并以某种方式进行折衷来解决问题,还是有一个更优雅的解决方案?


问题答案:

因此,基本上,您需要计算请求正文的哈希值。做到这一点的优雅方法是将装饰器应用于InputStream

例如,在处理程序方法内部(在这种情况下,您不能使用@RequestBody并且需要HttpMessageConverter手动创建):

@RequestMapping(...)
public void handle(HttpServletRequest request) throws IOException {
    final HashingInputStreamDecorator d = 
        new HashingInputStreamDecorator(request.getInputStream(), secretKey);
    HttpServletRequest wrapper = new HttpServletRequestWrapper(request) {
        @Override
        public ServletInputStream getInputStream() throws IOException {
            return d;
        }
    };

    HttpMessageConverter conv = ...;
    Foo requestBody = (Foo) conv.read(Foo.class, new ServletServerHttpRequest(wrapper));
    String hash = d.getHash();

    ...
}

其中哈希值是在的重写read方法中递增计算的HashingInputStreamDecorator

@RequestBody如果您创建Filter要应用的装饰器,也可以使用。在这种情况下,装饰器可以将计算出的哈希值作为请求属性传递给处理程序方法。但是,您需要仔细映射此过滤器,以仅将其应用于对特定处理程序方法的请求。