ResponseBodyAdvice和HttpMessageConverter应用浅析

目录

1 使用ResponseBodyAdvice

2 使用HttpMessageConverter

3 使用ResponseBodyAdvice和RequestBodyAdvice给controller做环绕日志

4 源码跟踪


此文的目的是想要对@ResponseBody修饰的方法的返回值,从大写下划线转成小写驼峰,而突然发现官方文档表示“HandlerInterceptor的postHandle() 不支持@ResponseBody、@ResponseEntity修饰方法输出结果的处理,应该使用@ResponseBodyAdvice”。

同时官方文档SpringWebMvc一章中1.10MvcConfig章节的1.10.7MessgeConverters小节也有类似功效。

所以写此文记录下对两者的使用。

本文提到的大写下划线转驼峰工具见 https://blog.csdn.net/qq_26950567/article/details/115102515?spm=1001.2014.3001.5501

1 使用ResponseBodyAdvice

需要用@ControllerAdvice注入

@ControllerAdvice // reponseBodyAdvice可以用@ControllerAdvice注入
public class CamelCaseResponseBodyAdvice implements ResponseBodyAdvice<BeeActionResponse> {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 需要满足:
     * 1. 需要转换的方法被@NeedConvert(converterName="camelCaseConverter")修饰
     * 2. 返回BeeActionResponse的组合类型
     * @param returnType
     * @param converterType
     * @return
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        NeedConvert methodAnnotation = returnType.getMethodAnnotation(NeedConvert.class);
        if (methodAnnotation == null)
            return false;
        else
            return "camelCaseConverter".equals(returnType.getMethodAnnotation(NeedConvert.class).converterName())
                            && BeeActionResponse.class.isAssignableFrom(returnType.getMethod().getReturnType());
    }

    @Override
    public BeeActionResponse beforeBodyWrite(BeeActionResponse body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        Object camelParse = CamelCaseUtils.underLineToCamelCase(body.getRespData());
        BeeActionResponse beeActionResponse = new BeeActionResponse();
        beeActionResponse.setRespCode(body.getRespCode());
        beeActionResponse.setRespMsg(body.getRespMsg());
        beeActionResponse.setTraceId(body.getTraceId());
        beeActionResponse.setRespData(camelParse);
        beeActionResponse.setPager(body.getPager());
         return beeActionResponse;
        //return body;
    }
}

2 使用HttpMessageConverter

  1. 可以用@Component直接注入
  2. CanWrite表示哪种返回类型的方法,可被我这个HttpMessageConverter改写输出结果
  3. GetSupportedMediaType写空集合就行
  4. 具体的改写输出逻辑,在write方法中进行

@Component
public class CamelCaseConverter implements HttpMessageConverter<BeeActionResponse> {
    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return false;
    }
    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return BeeActionResponse.class.isAssignableFrom(clazz);
    }
    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return Collections.unmodifiableList(Collections.emptyList());
    }
    @Override
    public BeeActionResponse read(Class<? extends BeeActionResponse> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }
    @Override
    public void write(BeeActionResponse response, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        Object camelParse = CamelCaseUtils.underLineToCamelCase(response.getRespData());
        outputMessage.getBody().write(JSONObject.toJSONString(camelParse).getBytes());
    }
}

3 使用ResponseBodyAdvice和RequestBodyAdvice给controller做环绕日志

/**
 *
 * @author onion.li
 */
@Slf4j
@ControllerAdvice
public class AroundAdvice implements RequestBodyAdvice,ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    /**
     * RequestBody读之前要做什么操作
     * 什么都不做
     */
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        return httpInputMessage;
    }

    /**
     * RequestBody读之后要做什么操作
     * 打印日志
     */
    @Override
    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        Method method=methodParameter.getMethod();
        String eventName = method.getDeclaringClass().getSimpleName() + "#" + method.getName();
        log.info("req" + JSONObject.toJSONString(o));
        return o;
    }

    /**
     * 若RequestBody为空怎么办
     * 打印日志
     */
    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        Method method=methodParameter.getMethod();
        String eventName = method.getDeclaringClass().getSimpleName() + "#" + method.getName();
        log.info("req" + null);
        return null;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    /**
     * reponseBody返回之前要做什么操作
     * 写日志
     */
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        Method method=methodParameter.getMethod();
        String eventName = method.getDeclaringClass().getSimpleName() + "#" + method.getName();
        log.info("resp" + JSONObject.toJSONString(o));
        return o;
    }
}

4 源码跟踪

可以看出ReponseBodyAdvice对输出的改写,同HttpMessageConverter对输出的改写,两者是挨着的,所以我觉得一般情况,使用ResponseBodyAdvice就足够了。

下图是HttpMessageConverter在springmvc的请求链路中的作用。

每个httpMessgeConverter能告诉我们

它支持什么样的协议 application/json、text/plain 还是其他。

它能够将httpMessge转为什么对象,是字符串、对象、还是别的什么。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RequestBodyAdviceResponseBodyAdvice是用于对请求和响应的消息进行处理的接口。它们可以在HttpMessageConverter转换消息之前和之后对消息进行定制化操作。 HttpMessageConverter是用于将请求和响应的消息与Java对象进行转换的组件。它负责将请求的消息转换为方法参数的对象,并将方法的返回值转换为响应的消息。 具体来说,在请求的处理过程中,HttpMessageConverter首先会将请求的消息转换为Java对象。在这个过程中,可以使用RequestBodyAdvice接口的beforeBodyRead方法在消息转换之前对请求的消息进行处理。然后,HttpMessageConverter会将转换后的Java对象作为参数传递给业务方法进行处理。在业务方法处理完毕后,HttpMessageConverter会将方法的返回值再次转换为响应的消息。在这个过程中,可以使用ResponseBodyAdvice接口的beforeBodyWrite方法在消息转换之后对响应的消息进行处理。 因此,RequestBodyAdviceResponseBodyAdvice可以在HttpMessageConverter转换消息的前后对消息进行修改、记录日志或添加额外的信息等操作。它们提供了更灵活的方式来对请求和响应的消息进行定制化处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Spring解密之RequestBodyAdviceResponseBodyAdviceHttpMessageConverter](https://blog.csdn.net/Sophisticated_/article/details/102614321)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [ResponseBodyAdviceHttpMessageConverter应用浅析](https://blog.csdn.net/qq_26950567/article/details/115263381)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值