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

字节跳动面试官SpringBoot统一接口返回和全局异常处理怎么玩?

  现在大多数公司项目框架,基本都是属于前后端分离模式,这种模式会涉及到一个前后端对接问题,无论是对前端或者是后台服务,维护一套完善且规范的接口是非常有必要的,这样不仅能够提高对接效率,也可以让我的代码看起来更加简洁优雅。
  修改前后最大的区别是我们不用在每个接口单独捕获异常,也不用在每个接口都要组装一遍返回参数,可以参考下面这张对比图:
  一、SpringBoot不使用统一返回格式
  默认情况下,SpringBoot会有如下三种返回情况。1.1 字符串@GetMapping("/getUserName") public String getUserName(){     return "HuaGe"; }
  调用接口返回结果:HuaGe1.2 实体类@GetMapping("/getUserName") public User getUserName(){     return new User("HuaGe",18,"男"); }
  调用接口返回结果:{   "name": "HuaGe",   "age": "18",   "性别": "男",  }1.3异常返回@GetMapping("/getUserName") public static String getUserName(){     HashMap hashMap = Maps.newHashMap();     return hashMap.get(0).toString(); }
  模拟一个空指针异常,在不做任何异常处理的情况下,可以看下SpringBoot的默认返回结果:{     "timestamp": "2021-08-09T06:56:41.524+00:00",     "status": 500,     "error": "Internal Server Error",     "path": "/sysUser/getUserName" }
  对于上面这几种情况,如果整个项目没有定义统一的返回格式,五个后台开发人员定义五种返回格式,这样不仅代码臃肿,前后端对接效率低,而且还会有一些意向不到的情况发生,比如前端直接显示异常详情等,这给用户的体验是非常差的。二、基础玩法
  项目中最常见到的是封装一个工具类,类中定义需要返回的字段信息,把需要返回前端的接口信息,通过该类进行封装,这样就可以解决返回格式不统一的现象了。2.1 参数说明code: 状态码,后台可以维护一套统一的状态码;message: 描述信息,接口调用成功/失败的提示信息;data: 返回数据。2.2 流程说明新建Result类public class Result {          private int code;          private String message;          private T data;      public Result() {}     public Result(int code, String message) {         this.code = code;         this.message = message;     }          /**      * 成功      */     public static  Result success(T data) {         Result result = new Result();         result.setCode(ResultMsgEnum.SUCCESS.getCode());         result.setMessage(ResultMsgEnum.SUCCESS.getMessage());         result.setData(data);         return result;     }      /**      * 失败      */     public static  Result error(int code, String message) {         return new Result(code, message);     } }定义返回状态码public enum ResultMsgEnum {     SUCCESS(0, "成功"),     FAIL(-1, "失败"),     AUTH_ERROR(502, "授权失败!"),     SERVER_BUSY(503, "服务器正忙,请稍后再试!"),     DATABASE_OPERATION_FAILED(504, "数据库操作失败");     private int code;     private String message;       ResultMsgEnum(int code, String message) {         this.code = code;         this.message = message;     }     public int getCode() {         return this.code;     }          public String getMessage() {         return this.message;     } }使用方式
  上面两步定义了数据返回格式和状态码,接下来就要看下在接口中如何使用了。@GetMapping("/getUserName") public Result getUserName(){     return Result.success("huage"); }
  调用结果如下,可以看到是我们在Result中定义的参数类型。{     "code": 0,     "message": "成功",     "data": "huage" }
  这样写虽然能够满足日常需求,而且我相信很多小伙伴也是这么用的,但是如果我们有大量的接口,然后在每一个接口中都使用Result.success来包装返回信息,会新增很多重复代码,显得不够优雅,甚至都不好意思拿出去显摆。 肯定会有一种方式能够再一次提高代码逼格,实现最优解。
  三、进阶用法
  基本用法学会后,接下来看点究极版本,主要用到如下两个知识点,用法简单,无论是拿出来教学妹,还是指点小姐姐,都是必备技能。3.1 类介绍3.1类介绍3.1 类介绍ResponseBodyAdvice: 该接口是SpringMVC 4.1提供的,它允许在 执行 @ResponseBody后自定义返回数据,用来封装统一数据格式返回;@RestControllerAdvice: 该注解是对Controller进行增强的,可以全局捕获抛出的异常。3.2 用法说明新建ResponseAdvice类;实现ResponseBodyAdvice接口,实现supports、beforeBodyWrite方法;该类用于统一封装controller中接口的返回结果。@RestControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice {     @Autowired     private ObjectMapper objectMapper;       /**      * 是否开启功能 true:是       */     @Override     public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {         return true;     }       /**      * 处理返回结果      */     @Override     public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {         //处理字符串类型数据         if(o instanceof String){             try {                 return objectMapper.writeValueAsString(Result.success(o));             } catch (JsonProcessingException e) {                 e.printStackTrace();             }         }         return Result.success(o);     } }
  我们可以通过getUserName接口测试一下,会发现和直接使用Result返回的结果是一致的。
  不过,细心的小伙伴们肯定注意到了,在ResponseAdvice我们全部使用了Result.success(o)来处理结果,对于error类型的结果未做处理。我们来看下,发生异常情况时,返回结果是什么样呢?继续使用上面HashMap空指针异常的代码,测试结果如下:{     "code": 0,     "message": "成功",     "data": {         "timestamp": "2021-08-09T09:33:26.805+00:00",         "status": 405,         "error": "Method Not Allowed",         "path": "/sysUser/getUserName"     } }
  虽然格式上没有毛病,但是在code、data字段的具体数据上是不友好或不正确的。不处理好这些事情,会严重影响自己在前端妹妹心中的高大形象的,这是决不能容忍的。3.3 全局异常处理器
  以前我们遇到异常时,第一时间想到的应该是try..catch..finnal吧,不过这种方式会导致大量代码重复,维护困难,逻辑臃肿等问题,这不是我们想要的结果。
  今天我们要用的全局异常处理方式,用起来是比较简单的。首先新增一个类,增加@RestControllerAdvice注解,该注解的作用花哥上面已经介绍过,就不再唠叨了。@RestControllerAdvice public class CustomerExceptionHandler {      }
  如果我们有想要拦截的异常类型,就新增一个方法,使用@ExceptionHandler注解修饰,注解参数为目标异常类型。
  例如:controller中接口发生Exception异常时,就会进入到Execption方法中进行捕获,将杂乱的异常信息,转换成指定格式后交给ResponseAdvice方法进行统一格式封装并返回给前端小伙伴。@RestControllerAdvice @Slf4j public class CustomerExceptionHandler {       @ExceptionHandler(AuthException.class)     public String ErrorHandler(AuthorizationException e) {         log.error("没有通过权限验证!", e);         return "没有通过权限验证!";     }       @ExceptionHandler(Exception.class)     public Result Execption(Exception e) {         log.error("未知异常!", e);         return Result.error(ResultMsgEnum.SERVER_BUSY.getCode(),ResultMsgEnum.SERVER_BUSY.getMessage());     } }
  再次调用接口getUserName查看返回结果,会发现还是有一些问题,因为我们在CustomerExceptionHandler中已经将接口返回结果封装成Result类型,而代码执行到统一结果返回类ResponseAdvice时,又会结果再次封装,就出现了如下问题。{     "code": 0,     "message": "成功",     "data": {         "code": 503,         "message": "服务器正忙,请稍后再试!",         "data": null     } }3.4 统一返回结果处理类最终版
  解决上述问题非常简单,只要在beforeBodyWrite中增加一条判断即可。@RestControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice {     @Autowired     private ObjectMapper objectMapper;       /**      * 是否开启功能 true:开启      */     @Override     public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {         return true;     }       /**      * 处理返回结果      */     @Override     public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {         //处理字符串类型数据         if(o instanceof String){             try {                 return objectMapper.writeValueAsString(Result.success(o));             } catch (JsonProcessingException e) {                 e.printStackTrace();             }         }         //返回类型是否已经封装         if(o instanceof Result){             return o;         }         return Result.success(o);     } }
  至此,本章的任务就全部讲完,上述代码可以直接引用,不需要其他的配置项,非常推荐引用到自己的项目中。四、总结
  本章讲解的内容不是很多,主要就两个类的配置,即处理统一返回结果的类ResponseAdvice和异常处理类CustomerExceptionHandler。全文围绕RestControllerAdvice、ResponseBodyAdvice的使用,通过一步步的迭代,最终构建一套通用的代码代码返回格式。本文属于实用知识分享,不知道小伙伴们还有其他好用的统一处理方案嘛,如果有更好的方案,可以分享出来大家一块学习。
  作者:JavaGieGie
  链接:https://juejin.cn/post/6994629906424397837
犹豫中我还是没选中满意的电纸书产品我算是个重度阅读爱好者,特别是晚上睡觉一定要看会书,才能睡着。从最早的Kindle,到早期的ireader,后面用过博阅,2020年5月买了文石的nova2,一直用到现在,积累了几微信可以同时实名几个账号,明明白白告诉你要说大家最常用的即时通信服务软件,微信处于垄断地位,而且很多人会有两个微信号,一般是一个工作号,一个私人号。在使用微信过程中,很多功能需要实名认证之后才能使用,比如支付功能。有一两充电桩安装费用多少钱?私人安装充电桩,一般就安装慢充就可以了,一是价格便宜,一两千元(不含安装费),二是慢充充电有利于保护电池,三是可以利用夜间低谷电价。但问题的关键是小区物业能否允许你安装充电桩,因为明确!手机这个费用,将取消近日有网友在人民网领导留言板中提问来电显示费用何时能够取消如今进入了5G时代,现在的套餐基本上都是减免来电显示费用,但还是有少部分前期套餐附加的来电显示费用,希望工信部能够在提速降都说阿里巴巴福利好,为什么有人拿到offer却不愿意去阿里?没有都说的福利好,所以没去为什么地球百分之8人类之,熟悉自己国家语言哈哈哈哈呼呼呼呼就目前来说拿到阿里的offer还是比较优秀的,有大厂的背景很可以的,毕竟牌子带在身边看看好的装备常用的消息队列一redis消息队列和kafka消息队列的比较1Redis作为消息队列Redis的pubsub模式非常像西式快餐一样,快产快消,全都是因为Redis是使用内存来做存取,所有你生产的在华为工作是怎样一番体验?你好,我结合我身边的一个案例来说一说吧,我自己并没有在华为工作,是我自己家里面一个哥,他在华为工作,他的工作主要是手机开发。他是计算机硕士专业毕业的,然后当时应聘到了华为做手机开发新机型,华为Mate50Pro逆袭,华为P50Pro升级版自开年以来,国内各大手机厂商迅速发力,大量骁龙8Gen1机型快速发布,因为有这颗4纳米芯片加持,这些新机的性能都相当优秀。每一款都有超百万的跑分,流畅度相当高。部分机型仍然拥有极高iPhone14再曝光,苹果为了赚钱太无底线?曾几何时,苹果iPhone那绝对是工业设计和配置创新的双巅峰,再加上独有的iOS系统,让其面对整个安卓阵营也丝毫不虚,销量和热度没有哪一家厂商能够单独对抗。但不知道从什么时候开始,Python机器学习(五十六)SciPyfftpack(傅里叶变换)SciPy提供了fftpack模块,包含了傅里叶变换的算法实现。傅里叶变换把信号从时域变换到频域,以便对信号进行处理。傅里叶变换在信号与噪声处理图像处理音频信号处理等领域得到了广泛人是怎么来的之进化与创造和史前文明的想象进化论主张宇宙中最原始的存在,并不是具有精神的事物灵或神,而是具有生能的物质。这生能以进化方式,演进成生元,即细胞这细胞便是万物中一切生命的开始。在西方思想史上,力持进化论观点的是
顺联动力上线拼团新玩法,凭什么能够逆势成长?2021年,社交电商依然话题颇多。数据显示,今年中国社交电商市场规模预计达5。8万亿元,同比增长45,成为中国网络零售市场重要增长极。日前,有消息传拼团江湖再迎潜力选手,社交电商顺X战警强势来袭,刷了复4又要刷黑凤凰这款装备杠得住X战警黑凤凰劫后浴火重生,宇宙至强女英雄诞生了在刚刚过去的这些天用笔记本重复刷了个瘾复联4,心情还没平复下来新的英雄又诞生了,6月6日看完国内首映之后肯定是不过瘾的呀,看来又是重复天猫618什么值得买?官方来划重点了这些硬核爆款错不了近几天,相信大家都被天猫618刷屏了,眼花缭乱的折扣看得人蠢蠢欲动。为助力剁手党冲刺618,天猫官方重磅推出天猫618购买清单,从数码家电美妆服饰等9大品类上万好货中,精选出115JNNX33录音笔体验,正是你想要的课程录音笔有两种常见的场景需要使用录音笔,一是会议录音,做笔记时害怕记漏一些重要信息录音便是最好的保障。另一个是课堂录音,社会竞争压力大,很多小伙伴都努力增值自己报读各种提升职能的课堂,课堂大气宴席是怎样养成的,红牌窖藏1998功不可没中国白酒文化历史悠久,是国人生活中不可或缺的一个生活必需品,所有传统节日里都以白酒来祭拜祖先和神灵。另外在日常大大小小的宴席中也都以白酒来宴请宾客,白酒的档次也体现出主人的阔气和实玩坏AI音箱的方法有很多种,可惜你一个都想不到AI智能正在多元化发展,越来越多的传统数码产品因为有了AI智能的附身变成更加强大,更有意义。就像传统的便携音箱,没有AI智能之前只能够启用蓝牙连接手机或插入储存卡插放音频。当AI智iQOOPro5G版销量爆红,性能实力强,性价比更高最近有点烦恼,刚出的5G手机虽然不多,但想要在今天这种节骨眼上挑一款各方面都适合自己的也确实不容易。还好功夫不负有心人,经过艰难对比,小编终于选出了vivo旗下的iQOOPro5G机甲式机身,X天线,游戏专属通道,荣耀猎人游戏路由体验笔者有时也很庆幸自已是手游大军团中的一员,这种社交游戏有时候真的就是你能和别人尬聊的资本。不过近来却常常受打击,因为网速老是不稳定而且还不时断连,游戏时不是卡顿就是丢包,简直是气炸勇夺贵州十大名酒之首,酱酒窖藏1988问君能有几多愁中国白酒是闻名世界的六大蒸馏酒之一,与金酒,白兰地,伏特加,朗姆酒,威士忌齐名,但是在酿造工艺上,中国白酒要更加复杂的多。很多朋友品尝过很多中国名优白酒,但对白酒的酿制工艺你有没有成长风格指数基金之痛前言上篇关于医药指数基金的文章发了之后,很多人在后台留言,医药到底该买指数基金还是主动型基金?今天从成长类指数出发,再次探讨主动基金和被动基金的区别。从标题就可以看出来,我个人是不你的持仓收益跑得过沪深300吗?这是一个粉丝问我的问题。沪深300从3月10号的4971点到今天的5271点,涨幅约5。7。我的非公开组合涨幅10。74公开组合涨幅8。52不仅仅是他,大家去天天基金蛋卷之类的AP