Springの@RequestBodyを使用して、httpservletrequest.getInputStream()を読んでいます
-
28-09-2019 - |
質問
私は私のリクエストのJSONの投稿データをSpringを使用してオブジェクトにマッピングします @RequestBody
注釈と MappingJacksonHttpMessageConverter
. 。しかしその後、私はでデータを読みたいです String
追加の認証を行うためのフォーム。しかし、マーシャリングが起こったとき、 InputStream
の HttpServletRequest
空です。削除したら @RequestBody
メソッドからのパラメーターポストデータの読み取り値への読み取り 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
デコレーターを適用します。この場合、デコレーターは、計算されたハッシュをリクエスト属性としてハンドラーメソッドに渡すことができます。ただし、このフィルターを慎重にマッピングして、特定のハンドラーメソッドにリクエストにのみ適用する必要があります。
他のヒント
URLマッピング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) {
...
}
}
これを正しく理解している場合、JAX-RSで使用される1つの一般的な方法(これは、バインディングリクエストに関してスプリングMVCに多少似ています)は、最初に中間生タイプに「バインド」することです(通常はバイト[]が、文字列も機能します) 、そしてそれから手動でバインドし、基礎となるデータバインダー(Jackson)を使用します。データバインディングのエラー処理を完全にカスタマイズできるように、これを行うことがよくあります。