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

时间:2010-11-04 13:13:43

标签: json spring http spring-mvc jackson

我使用Spring的@RequestBody注释和MappingJacksonHttpMessageConverter将我的请求的JSON POST数据映射到一个对象。然而,之后我想以String形式阅读数据以进行一些额外的身份验证。但是当编组发生时,InputStream中的HttpServletRequest为空。从方法中删除@RequestBody参数后,将POST数据读取到String按预期工作。

我是否必须通过放弃@RequestBody并以某种方式手动执行绑定或是否有更优雅的解决方案来妥协?

3 个答案:

答案 0 :(得分:2)

所以,基本上你需要计算请求体的哈希值。优雅的方法是将装饰器应用于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。在这种情况下,装饰器可以将计算的散列作为请求属性传递给处理程序方法。但是,您需要仔细映射此过滤器,以仅将其应用于对特定处理程序方法的请求。

答案 1 :(得分:0)

在你的urlMapping bean中,你可以声明其他拦截器的列表:

  <bean id="urlMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors">
      <list>
        <bean class="org.foo.MyAuthInterceptor"/>
      </list>
    </property>
  </bean>

这些拦截器可以访问HttpServletRequest,但是如果你从流中读取参数映射器将无法读取它。

public class AuthInterceptor extends HandlerInterceptorAdapter {

  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    ...
  }

  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) {
    ...
  }
}

答案 2 :(得分:0)

如果我理解正确的话,JAX-RS使用的一种常见方式(在绑定请求方面有点类似于Spring MVC)是首先“绑定”到某个中间原始类型(通常是byte [],但是String)也工作),并使用底层数据绑定器(杰克逊)手动绑定到对象。我经常这样做是为了能够完全自定义数据绑定的错误处理。