WEB开发中有这样的需求: 返回给前台的数据需要有统一格式。但是在controller的每个mapping中手写包装很是麻烦,所以可以自定义返回值处理器进行结果包装。

文章目录

  • 返回给前台的消息格式
  • 自定义的返回值处理器
  • RequestResponseBodyMethodProcessor的supportsReturnType代码
  • @RestController代码
  • 配置自定义返回值处理器
  • RequestResponseBodyMethodProcessor的handleReturnValue源码

返回给前台的消息格式

package net.mshome.twisted.tmall.common;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.mshome.twisted.tmall.enumeration.ErrorCode;/*** 返回给前台的消息包装类** @author tangjizhouchn@foxmail.com* @date 2019-08-18*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResultWrapper<T> {@Builder.Defaultprivate int code = ErrorCode.OK.getValue();@Builder.Defaultprivate String message = "操作成功";private T result;}

自定义的返回值处理器

package net.mshome.twisted.tmall.handler;import net.mshome.twisted.tmall.common.ResultWrapper;
import net.mshome.twisted.tmall.exception.TmallException;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;/*** 包装返回值,针对有mapping注解的方法返回的json数据包装** @author tangjizhouchn@foxmail.com* @date 2019/9/4*/
@Component
public class ReturnValueHandler extends RequestResponseBodyMethodProcessor implements HandlerMethodReturnValueHandler {// 要求构造函数需要一个和父类保持一致的,没有无参构造函数public ReturnValueHandler(List<HttpMessageConverter<?>> converters) {super(converters);}@Overridepublic boolean supportsReturnType(MethodParameter returnType) {Method method = returnType.getMethod();if (method == null || method.getReturnType().isAssignableFrom(ResultWrapper.class)|| method.getReturnType().isAssignableFrom(Exception.class)) {return false;}return super.supportsParameter(returnType);}@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {// 此处进行值的包装returnValue = ResultWrapper.builder().result(returnValue).build();// 使用父类去处理,然后返回super.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}}

1、返回ResponseBody类型的数据会由 RequestResponseBodyMethodProcessor 处理。
2、 此处继承了 RequestResponseBodyMethodProcessor ,直接调用 super.handleReturnValue(returnValue, returnType, mavContainer, webRequest) 去处理。

RequestResponseBodyMethodProcessor的supportsReturnType代码

@Override
public boolean supportsReturnType(MethodParameter returnType) {return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class));
}

从上可以看出,RequestResponseBodyMethodProcessor 这个类处理的就是有个@ResponseBody注解的类或者方法。

@RestController代码


package org.springframework.web.bind.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {@AliasFor(annotation = Controller.class)String value() default "";
}

@RestController注解也有@ResponseBody修饰

配置自定义返回值处理器

package net.mshome.twisted.tmall.configuration;import net.mshome.twisted.tmall.handler.ReturnValueHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;import javax.annotation.PostConstruct;
import java.util.LinkedList;
import java.util.List;/*** 配置类,配置自定义返回值处理器** @author tangjizhouchn@foxmail.com* @date 2019/9/4*/
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {@Autowiredprivate RequestMappingHandlerAdapter requestMappingHandlerAdapter;/*** 自定义的返回值处理器*/@Autowiredprivate ReturnValueHandler returnValueHandler;@PostConstructpublic void init() {final List<HandlerMethodReturnValueHandler> newHandlers = new LinkedList<>();final List<HandlerMethodReturnValueHandler> originalHandlers = requestMappingHandlerAdapter.getReturnValueHandlers();if (null != originalHandlers) {newHandlers.addAll(originalHandlers);// 获取处理器应处于的位置,需要在RequestResponseBodyMethodProcessor之前final int index = obtainValueHandlerPosition(originalHandlers, RequestResponseBodyMethodProcessor.class);newHandlers.add(index, returnValueHandler);} else {newHandlers.add(returnValueHandler);}requestMappingHandlerAdapter.setReturnValueHandlers(newHandlers);}/*** 获取让自定义处理器生效应处于的位置** @param originalHandlers 已经添加的返回值处理器* @param handlerClass     返回值处理器的类型* @return 自定义处理器需要的位置*/private int obtainValueHandlerPosition(final List<HandlerMethodReturnValueHandler> originalHandlers, Class<?> handlerClass) {for (int i = 0; i < originalHandlers.size(); i++) {final HandlerMethodReturnValueHandler valueHandler = originalHandlers.get(i);if (handlerClass.isAssignableFrom(valueHandler.getClass())) {return i;}}return -1;}}

1、Spring提供的返回值处理器条件是:如果supportsReturnType返回true,则返回值将交由此类进行处理。
2、RequestResponseBodyMethodProcessor这个类中的返回值处理函数handleReturnValue在处理之后将直接返回,不再交由下一处理器处理,源码如下。故我们的自定义处理器需要排在此处理器之前。

RequestResponseBodyMethodProcessor的handleReturnValue源码

@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {// 此处将请求设置为已经处理,将不会继续处理了mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);// Try even with null return value. ResponseBodyAdvice could get involved.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}

springboot 自定义返回值处理器HandlerMethodReturnValueHandler相关推荐

  1. springboot自定义参数处理器和返回值处理器

    参数处理器(ArgumentResolvers)和返回参数处理器(ReturnValueHandlers) 在我们调用controller层组件时,Springboot实际上是使用代理模式进行调用,s ...

  2. Spring MVC 执行过程原理(请求映射原理、参数处理原理、返回值处理器)

    Spring MVC 执行过程分析 文章目录 Spring MVC 执行过程分析 请求映射原理 适配器Adapter 执行目标方法 参数处理器解析器HandlerMethodArgumentResol ...

  3. SpringBoot 自定义全局异常处理器

    SpringBoot自定义全局异常处理器 一.maven依赖 二.GlobalExceptionHandler.java 三.ResponseStandard.java 四.logback.xml 五 ...

  4. Python 之return 自定义返回值

    return 自定义返回值 作用: 将函数内部的数据返回到函数的外部,返回到函数的调用处; 语法: return 定义在函数的内部,函数外部不能使用 1.return 可以接6大标准数据类型 , 还可 ...

  5. springboot切面返回值_SpringBoot实战15-Spring基础-AOP

    上篇我们学习了<SpringBoot实战14-Spring基础-Spring EL表达式>,本篇我们学习面向切面编程AOP. 7 AOP 面向切面编程(Aspect-Oriented Pr ...

  6. springboot切面返回值_SpringBoot之切面AOP

    SpringBoot提供了强大AOP支持,我们前面讲解过AOP面向切面,所以这里具体AOP原理就补具体介绍: AOP切面主要是切方法,我们一般搞一些日志分析和事务操作,要用到切面,类似拦截器: @As ...

  7. bat 存储过程返回值_使用Mybatis过程中遇到的坑

    常规SSM框架开发中,mybatis遇到的坑是最多的,把以下几点坑记录下来防止以后再遇到同样的情况. 1.mybatis 若果在mapper中返回值没有配置resultMap而是使用resultTyp ...

  8. JPA 自定义返回字段

    实体类:User.java @Data @Accessors(chain = true) @EqualsAndHashCode(callSuper = true) @Entity @Table(nam ...

  9. Nancy 返回值详解

    简介 Nancy 是一个轻量级的,简单粗暴的framework用来构建基于HTTP的各种服务,兼容.Net和Mono.它的返回值也是多种多样的,适应各种不同的情况.包括Response.AsFile( ...

最新文章

  1. DB2的一些精品文章地址
  2. 2018-03-02 Linux
  3. 微信系小程序 StorageSync
  4. controller怎么调用controller_SpringMVC五大核心组件及调用过程
  5. PCM接口详细介绍--TDM方式
  6. 有序数组原地删除重复出现的元素问题(js)
  7. 【资料】翘首期盼247天!《阿里巴巴Java开发手册》扫描插件详情介绍
  8. FMS飞行模拟器简介
  9. python爬虫教材推荐 豆瓣_学习python爬虫推荐书籍
  10. CSS学习03:CSS文本属性
  11. 前后端报文传输加密方案
  12. LeetCode/LintCode 题解丨一周爆刷双指针:K个空的位置
  13. NDK开发-Android下摄像头YUV数据获取与H264编码(FFmpeg、x264)总结
  14. dota游戏之我之见
  15. 嵌入式软件设计第7次实验报告-140201235-陈宇
  16. 互联网查询信用报告,为什么提示“无法进行注册”?
  17. 华为鸿蒙手机曝光,华为鸿蒙手机新特性曝光:充电期间系统将进行深度优化
  18. Windows截取gif动态图的软件 ScreenToGif 的安装、使用教程
  19. mos管栅极电阻的作用-电阻在MOS电路中注意事项及参考选择方法
  20. ExcelVBA 之Select Case

热门文章

  1. 图像混合模式 正片叠底、滤色、叠加
  2. Excel 排序时标题移动
  3. 硬盘IO的个人理解(机械硬盘)
  4. PTA(每日一题)7-45 小霸王
  5. 解决本地文件不显示SVN图标的问题
  6. PHP排序--冒泡排序
  7. 终于等到你,强大的百度云AI智能小助手可以预约申请内测了……!
  8. python urlopen函数_Python urlopen()函数 示例分享
  9. 对称加密算法之基于口令加密——PBE
  10. 真无线蓝牙耳机品牌排行榜,综合实力强的蓝牙耳机