web-dev-qa-db-ja.com

SpringMVCでのJson応答の後処理

次のように、@ ResponseBodyアノテーションが付いた同じ汎用Responseオブジェクトを返すコントローラーがいくつかあります。

@RequestMapping(value = "/status", method = RequestMethod.GET)
    @Transactional(readOnly = true)
    public @ResponseBody Response<StatusVM> status()

応答が返された後、すべてのコントローラーで操作を実行する必要があります。この操作により、Responseオブジェクトが新しいデータで強化されます。

コードを複製したくないので、単一の介入ポイントが必要です。ただし、ドキュメントによると、Interceptorsでこれを実行できると思いました http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping -interceptor これは@ResponseBodyではうまく機能しません:

HandlerInterceptorのpostHandleメソッドは、@ ResponseBodyメソッドおよびResponseEntityメソッドでの使用に必ずしも理想的に適しているとは限らないことに注意してください。このような場合、HttpMessageConverterは、postHandleが呼び出される前に応答を書き込んでコミットします。これにより、たとえばヘッダーを追加するなど、応答を変更できなくなります。代わりに、アプリケーションはResponseBodyAdviceを実装し、それを@ControllerAdvice Beanとして宣言するか、RequestMappingHandlerAdapterで直接構成できます。

私はこのテクニックの例を見つけることができませんでした、誰かが私を助けることができますか?

別の方法として、アスペクトを操作することもできますが、その場合はすべてのコントローラーに注釈を付ける必要があります。これは避けたいことです。

18
LittleSquinky

最終的に、私は次のようにResponseBodyAdviceを実装しました。

@ControllerAdvice
public class StatusAdvice implements ResponseBodyAdvice<Response<?>> {


    @Override
    public boolean supports(MethodParameter returnType,
            Class<? extends HttpMessageConverter<?>> converterType) {

        if (returnTypeIsReponseVM(returnType)&&responseConverterIsJackson2(converterType)){
            return true;
        }

        return false;
    }

....

    @Override
    public Response<?> beforeBodyWrite(Response<?> body, MethodParameter returnType,
            MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType,
            ServerHttpRequest request, ServerHttpResponse response) {

        ....

        return body;
    }

}

そのため、予想よりも簡単でした。

31
LittleSquinky