范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

SpringbootAPI接口统一输出消息格式保持原接口返回值不变

  环境:Springboot2.4.11
  很多时候我们对接口的返回值都会做统一的处理,返回{code, message,data}等信息标识本次请求的处理结果,这统一的处理也都是在各自的Controller上做自行的处理。本篇内容告诉你如何通过ResponseBodyAdvice对象来实现对结果的统一处理,也就是说在Controller上我们不再对返回结果进行处理了,而是由统一的一个ControllerAdice Bean对象进行处理。这对我们的Controller接口来说可读性更强,也业务无关的东西一概不出现,同时代码也更加简洁。ResponseBodyAdvice是什么
  ResponseBodyAdvice类型的Bean对象允许在执行@ResponseBody或ResponseEntity控制器方法之后但在使用HttpMessageConverter写入正文之前自定义响应。实现可以直接向RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver注册,或者更可能使用@ControllerAdvice进行注释,在这种情况下,它们都将被自动检测到。定义统一返回对象public class R { 	   public R() {   }    private int code ; 	   private String message ; 	   private Object result ; 	   private String errorDetails ;    public R(int code, String message, Object result) {     super();     this.code = code;     this.message = message;     this.result = result;   } 	   public R(int code, String message, Object result, String errorDetails) {     super();     this.code = code;     this.message = message;     this.result = result;     this.errorDetails = errorDetails ;   }    public R(int code, String message, String errorDetails) {     super();     this.code = code;     this.message = message;     this.errorDetails = errorDetails ;   } 	   public R(int code, String message) {     super();     this.code = code;     this.message = message;   }   public static R success() {     return success(null) ;   } 	   public static R success(Object data) {     return success("成功", data) ;   } 	   public static R success(String message, Object data) {     return new R(ResultCode.SUCCESS, message, data) ;   } 	   public static R failure() {     return failure("失败") ;   } 	   public static R failure(Object data) {     return failure("失败", data) ;   } 	   public static R failure(String message) {     return failure(message, null) ;   }   public static R failure(int code, String message) {     return new R(code, message) ;   }      public static R failure(String message, Object data) {     return new R(ResultCode.FAILURE, message, data) ;   }   public static R failure(String message, String errorDetails) {     return new R(ResultCode.FAILURE, message, errorDetails) ;   } 	   public static R error(String message, String errorDetails) {     return new R(ResultCode.ERROR, message, errorDetails) ;   }   public static interface ResultCode {     int SUCCESS = 0 ;     int FAILURE = -1 ;     int ERROR = 500 ;   } }定义ResponseBodyAdvice@RestControllerAdvice public class ResponseResultControllerAdvice implements ResponseBodyAdvice {    @Override   public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {     return returnType.getParameterType() != Void.TYPE          && (!returnType.hasMethodAnnotation(NoPack.class)          && !returnType.getMethod().getDeclaringClass().isAnnotationPresent(NoPack.class)) ; 	}    @Override   public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,     Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {     if (body instanceof R) {       return body ;     }     return R.success(body) ;   }  }
  上面的类非常简单
  supports 方法判断当前的请求接口是否支持,在这里对于void,或是有@NoPack注解的都不进行处理。
  beforeBodyWrite 该方法判断如果返回值类型本身就是R类型就之间进行输出了,否则就进行包装处理。测试接口@GetMapping("/get1") public Users get1() {   Users users = new Users() ;   users.setAge(100) ;   return users ; }
  包装成功!!!
  修改测试接口
  在接口中抛出一个异常@GetMapping("/get1") public Users get1() {   Users users = new Users() ;   users.setAge(100) ;   System.out.println( 1 / 0 ) ;   return users ; }
  当有异常的时候并不能被处理,这里我们需要结合统一异常处理的机制。异常处理@RestControllerAdvice public class ExceptionControllerAdvice {    private static final Logger logger = LoggerFactory.getLogger(ExceptionControllerAdvice.class) ; 	   @ExceptionHandler(Exception.class)   public R jsonErrorHandler(HttpServletRequest req, Exception e){     String fullThrowMessage = getStackTrace(e);     if (e instanceof ServletRequestBindingException) {       return R.error("参数绑定异常,请检查接口入参: " + e.getMessage(), fullThrowMessage) ;     }     if (e instanceof ClassCastException) {       return R.error("请检查入参是否正确", fullThrowMessage) ;     }     if (e instanceof MethodArgumentNotValidException) {       return R.failure(((MethodArgumentNotValidException)e).getBindingResult().getAllErrors().stream().map(err -> err.getDefaultMessage()).collect(Collectors.toList())) ;     }     Throwable cause = e.getCause() ;     if (cause != null) {       if (cause instanceof SQLDataException) {         return R.error("数据格式错误,请检查入参是否正确", fullThrowMessage) ;       }       if (cause instanceof NumberFormatException) {         return R.error("数据格式错误,请检查!" + cause.getMessage(), fullThrowMessage) ;       }     }     logger.error("未捕获的异常:{}", e) ;     return R.error(e.getMessage(), fullThrowMessage) ;   }        private static String getStackTrace(final Throwable throwable) {     final StringWriter sw = new StringWriter();     final PrintWriter pw = new PrintWriter(sw, true);     throwable.printStackTrace(pw);     return sw.getBuffer().toString() ;   } }
  在Springboot中可以通过@RestControllerAdvice注解标识一个类,让其可以统一处理未捕获的异常。查看这篇文章《Spring MVC 异常处理方式》该篇文章详细的讲解了异常的处理。
  在进行测试
  对于异常也统一的处理了。实现原理
  在Spring MVC中返回值的处理都是由HandlerMethodReturnValueHandler对象进行处理的public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver implements HandlerMethodReturnValueHandler {     protected  void writeWithMessageConverters(@Nullable T value, ...) {         // 根据当前的请求获取客户端能产生的响应类型         List producibleTypes = getProducibleMediaTypes(request, valueType, targetType);         // 遍历所有的HttpMessageConverter对象         for (HttpMessageConverter<?> converter : this.messageConverters) {             GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?                                                             (GenericHttpMessageConverter<?>) converter : null);             if (genericConverter != null ?                 ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :                 converter.canWrite(valueType, selectedMediaType)) {                 // 在输出内容前先通过ResponseBodyAdvice处理内容信息                 body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,                                                    (Class<? extends HttpMessageConverter<?>>) converter.getClass(),                                                    inputMessage, outputMessage);                 if (body != null) {                     Object theBody = body;                     addContentDispositionHeader(inputMessage, outputMessage);                     if (genericConverter != null) {                         // ResponseBodyAdvice处理完后,最后通过GenericHttpMessageConverter输出内容到客户端了。                         // 后续就是处理其它的比如拦截器的afterCompletion方法等操作了。                         genericConverter.write(body, targetType, selectedMediaType, outputMessage);                     } else {                         ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);                     }                 } else {                 }                 return;             }         }     } }
  完毕!!!
  求关注+转发
  公众:Springboot实战案例锦集
  SpringCloud Nacos 服务消费者
  SpringCloud Hystrix实现资源隔离应用
  SpringCloud zuul 动态网关配置
  SpringCloud Nacos 整合feign
  SpringCloud整合Seata实现分布式事务通过nacos实现注册和配置
  SpringCloud Zookeeper配置中心详解
  SpringCloud Zookeeper服务发现及负载均衡
  Springboot Security 基础应用 (1)
  SpringBoot中使用Cache及JSR107的使用
  Springboot项目使用docker部署
  sharding-jdbc oracle分表避坑
ROG游戏手机5sPro官方开箱抢先看,信仰灯效拉满,你给几分?最近,全新升级的ROG游戏手机5sPro正式发布了,吸引了许多玩家的目光。和此前一样,ROG游戏手机5sPro在延续和腾讯游戏合作的同时,本身也迎来了全面的升级,不仅仅搭载了骁龙8如何打造理想的家庭影音室体验猫客M5智能影音伴侣就懂了后疫情时代,人们逐渐减少外出的机会,待在家中的时间变多,于是对于宅家的舒适度要求也逐渐提高。cc身边也有不少朋友在装修时,就开始各种张罗各种家居好物的布置,爱听音乐看电影的朋友也一这个千亿电商新市场,一年干出700个新品牌,有何秘诀?halo,我是新猫网小编,定期分享电商行业资讯,欢迎关注公众号有人的地方就有生意,如今电商行业火速发展,紧接着直播电商带动着短视频电商,随着而来的就是越来越多的品牌蜂拥而入,而这个美媒泄密苹果发布会,除了iPhone13系列,还有4款新品近段时间,有关iPhone13系列以及苹果秋季新品发布会的消息越来越多。结合多方爆料可知,今年苹果公司会在9月份如期举行一年一度的秋季发布会。虽然苹果官方并没有透露出任何相关信息,为什么苹果公司没有苹果研究院苹果曾经是有研究院的。乔布斯回到苹果后,第一时间砍掉了研究院。当时研究院的负责人是心理学家诺曼博士,是的,就是在Usability用户体验领域非常有名的诺曼,写过日常物品的设计情感轻薄自拍手机推荐,华为vivo实力机型任你选随着vivoS10Pro的出现,网络上关于自拍手机的讨论又变得多了起来,相信有不少人已经被这款手机的自然美颜拍照打动了。其实,除了vivoS10Pro之外,市面上还有不少主打自拍的新款苹果iPhone系列渲染图曝光日落金配色亮眼近日,外媒LetsGoDigital联合平面设计师Technizo绘制了一系列关于iPhone12sPro5G的渲染图以及视频,从各个方面展示了新款iPhone手机。苹果秋季发布会预算50元真能买到好耳机?是的我真没忽悠你首先我们要明确的是,只想花50元买耳机的消费者,他们的需求是什么?可以肯定的是,这一定不是他她的主力耳机,以我的观察来看,平时工作地点在办公室从事视频拍摄剪辑工作经常用笔记本电脑开各种视频信号格式及VGADVIHDMI区别视频信号是我们接触最多的显格式及示信号,但您并不一定对各种视频信号有所了解。因为国内用到的视频信号格式和端子非常有限,一般就是复合视频和S端子,稍高级一些的就是色差及VGA。对于那一个大老爷们买了一个小米的化妆镜一个大老爷们买了一个化妆镜,这是想干啥?可能仅仅就是因为他是小米出的吧我作为一个大老爷们是不喜欢逛街的,但是我喜欢逛小米商城,经常就是看到东西然后去匹配需求,不知女生逛街是不是这个联想个人云存储T2VS海康威视MAGE20谁是更好的家庭数据中心?信息的爆炸增长相信每个人都深有感触。在每一次换手机换电脑,每一次设备提示你磁盘空间不足时,你都会意识到,身为普通人的你居然有这么多的数据。整理个人数据都是相当痛苦的事情,这些年相信
SSD逃不过掉速?这类SSD最好不要买SSD寿命不太行容易掉速应该每个人都有所耳闻。电脑卡顿经常蓝屏开机速度游戏加载速度变慢,硬盘跑分也确实慢了不少,难道真是SSD固态硬盘掉速了?不行了?其实只要不是特别拉胯的SSD,何伟文阴谋论挡不住外企对华用脚投票来源环球时报路透社近日引述知情人士消息称,美国电商巨头亚马逊约两年前应中方要求,对中国平台上的书评做了限制。路透社称,亚马逊这样做是为了讨好中国。路透社是在为亚马逊抱打不平,还是在高频面试题请聊一下JVM中堆和栈的区别上一回我们说完了JVM的内存结构,将JVM中有哪些元素已经搞清了。今天就再根据之前的主题接着延伸出一个更容易被面试官问到的题目。堆和栈的区别!这次我们就从以下几个方面说一说有什么不马上评车企门店偷脸43万张,出门真的要戴头盔了?澎湃特约评论员任然你能想象,逛逛街看看车,脸就被偷了吗?据报道,日前,上海小鹏汽车销售服务有限公司被徐汇区市场监督管理局罚款10万元。处罚事由为,当事人购买具有人脸识别功能的摄像设golang面试题1。golang中make和new的区别make和new是两个内置函数,主要用来创建并分配内存。make只用于分配或初始化mapslicechannel的数据类型,返回不是指针类型Python入门精华eval()eval()函数1。函数原型eval(expression,globals,locals)expression表达式globals变量作用域,全局命名空间,如果被提供,则必须是一个Python入门精华OOP创建可管理的属性(property)为类创建可管理的属性概述我们可以在实例属性的获取和设定上增加一些额外的功能,比如在设定时增加类型的检查解决方案要自定义对属性的访问,一种简单的方式是将其定义为property,增加柳传志整人手段究竟有多狠?被插刀的任正非还得帮他洗白在司马南的穷追不舍之下,最近联想集团终于发出了官方的回应。搞出了一个内网声明,关上门在家里,自说自话,自证清白,说大家放心,自己没有问题。既当选手又当裁判,这份粗糙的声名,又能有多苹果上线数字遗产网络世界留下的足迹能继承?来源北京日报苹果上线数字遗产功能网络世界留下的足迹能继承吗?本报记者赵莹莹12月15日起,苹果用户陆续接收到iOS15。2的更新推送,其中一项新变化是数字遗产功能正式上线,被指定的10001500元手机选购攻略,5G网络大内存大电池1亿像素相机热门手机数码资讯早知道,快来关注作者。编辑孙凤新审核文峥对于大多数手机用户来说,千元档5G手机不仅价格实惠,性能也能够满足日常使用需求。今天为大家介绍几款10001500元的热门手人民日报批虚假广告滥用极限词规范网络电商广告用语全网仅一家史上最低价销量总冠军行业领导者打开互联网平台的商品页直播间,广告极限词并不鲜见。一些消费者被类似广告吸引,购买商品或服务后却发现名不副实,既影响体验也面临维权难题。滥用广