Java充电社
专辑
博文
联系我
本人继续续收门徒,亲手指导
SpringMVC教程
-> 实战篇:通用返回值 & 异常处理设计
1、Helloword
2、@Controller、@RequestMapping
3、接口测试利器
4、如何接受请求中的参数?
5、@RequestBody接收Json格式数据
6、多文件上传
7、返回页面常见的5种方式
8、返回json格式数据 & 通用返回值设计
9、SpringMVC返回null是什么意思?
10、异步处理请求
11、如何集成静态资源?
12、拦截器怎么用?
13、统一异常处理
14、实战篇:通用返回值 & 异常处理设计
15、全注解的方式 & 原理解析
16、源码解析SpringMVC处理请求的流程
17、源码解析SpringMVC容器的启动过程
18、RequestBodyAdvice:对@ReuqestBody进行增强
19、ResponseBodyAdvice:对@ResponseBody进行增强
20、RESTful接口详解
21、接口调用利器RestTemplate
22、参数解析器HandlerMethodArgumentResolver解密
23、@RequestParam用法及原理详解
24、@RequestBody原理解密
25、@RequestHeader详解
26、@CookieValue详解
27、@RequestAttribute详解
28、@SessionAttribute详解
29、重定向和转向详解
30、Converter转换器详解
31、跨域问题详解
32、类容协商,颠覆你的认知
33、终章
34、CORS通信
35、浏览器安全策略 & CORS
36、Http中的Content-Type详解
上一篇:统一异常处理
下一篇:全注解的方式 & 原理解析
<div style="display:none"></div> 大家好,我是路人,这是SpringMVC系列第14篇。 ## 1、本文目的 目前多数系统都采用前后端分离的方式,后端只负责提供restfull接口,返回json格式的数据就可以了,前端负责渲染。 本文带大家主要解决2个问题,在springmvc提供json格式的接口的时候,需要解决2个问题 - 问题1:所有接口的返回值采用统一的格式 - 问题2:系统中异常处理设计的问题,采用一种非常好的方式来解决这个问题 下面咱们一起来解决这2个问题。 ## 2、解决问题1:实现统一的返回值 所有的接口均返回ResultDto类型的数据,ResultDto类的代码如下,主要有4个字段 - success:表示接口是成功还是失败 - code:错误码,当有异常的时候,可以返回具体的错误码 - msg:提示信息,比如:操作成功、用户名有误、密码有误等等 - data:类型是一个泛型,表示任意类型,这个用来存放接口中具体返回的数据,可以是任意类型的对象 - 还提供了几个静态方法,方便创建ResultDto对象 ```java /** * rest接口通用返回值数据结构 * * @param <T> */ public class ResultDto<T> { //接口状态(成功还是失败) private Boolean success; //错误码 private String code; //提示信息 private String msg; //数据 private T data; public Boolean getSuccess() { return success; } public void setSuccess(Boolean success) { this.success = success; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public static <T> ResultDto<T> success(T data) { return success(data, "操作成功!"); } public static <T> ResultDto<T> success(T data, String msg) { ResultDto<T> result = new ResultDto<>(); result.setSuccess(Boolean.TRUE); result.setMsg(msg); result.setData(data); return result; } public static <T> ResultDto<T> error(String msg) { return error(null,msg); } public static <T> ResultDto<T> error(String code,String msg) { return error(code,msg,null); } public static <T> ResultDto<T> error(String code, String msg, T data) { ResultDto<T> result = new ResultDto<>(); result.setSuccess(Boolean.FALSE); result.setCode(code); result.setMsg(msg); result.setData(data); return result; } } ``` ## 3、解决问题2:统一处理异常 ### 3.1、如何做? 异常处理这块,我们的设计主要有2点,通过这2点来解决异常处理的问题 - 第一点:定义一个基础的业务异常类(BusException),业务代码中手动抛出异常的时候,统一抛出这种类型的异常,异常类型中可以携带更详细的错误信息,比如错误码、提示信息、扩展数据等等 - 第2点:采用springmvc全局来处理异常,控制器中不要捕获异常,将一次交给springmvc框架来统一处理。 ### 3.2、具体代码 下面我们来看具体的代码片段,主要有2个类 #### 业务异常类:BusException > 代码比较简单,主要有2个属性和几个静态方法 > > - code:异常错误码,最终会丢给ResultDto的code属性输出到客户端 > - data:异常的时候,可以传递一些扩展信息,此时可以丢到data中,最终会丢给ResultDto的data属性输出到客户端 > - 提供了几个静态方法,便于抛出BusException异常 > - 当我们的业务代码中需要抛出异常的时候,要求均抛出BusException类型的异常 ```java /** * 业务异常 */ public class BusException extends RuntimeException { //异常错误码 private String code; //错误扩展信息 private Object data; public BusException(String msg) { this(null, msg); } public BusException(String code, String msg) { this(code, msg, null); } public BusException(String code, String msg, Object data) { super(msg); this.code = code; this.data = data; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static void throwBusException(String msg) { throwBusException(null, msg); } public static void throwBusException(String code, String msg) { throwBusException(code, msg, null); } public static void throwBusException(String code, String msg, Object data) { throw new BusException(code, msg, data); } } ``` #### 全局异常统一处理类:GlobalExceptionHandle > 如下代码,大家对springmvc统一异常处理不了解,建议先看一下上一篇文章。 > > 注意下面代码中的`@1`,这里使用到了@RestControllerAdvice,这个注解之前没有介绍过,他和@ControllerAdvice功能类似,只是这个注解内部定义的时候上面多了一个@ResponseBody注解,表示下面这个类中处理异常的方法返回值最终都会以json格式输出到客户端 ```java /** * 全局异常处理 */ @RestControllerAdvice // @1 public class GlobalExceptionHandle { /** * 统一处理业务异常 * * @param e * @param <T> * @return */ @ExceptionHandler(BusException.class) public <T> ResultDto<T> doBusException(BusException e) { //1、记录错误日志 //2、返回结果 return ResultDto.error(e.getCode(), e.getMessage(), (T) e.getData()); } /** * 处理其他异常 * * @param e * @param <T> * @return */ @ExceptionHandler public <T> ResultDto<T> doException(Exception e) { //1、记录错误日志 //2、返回结果 return ResultDto.error("系统异常,请联系管理员,错误详情:" + e.getMessage()); } } ``` 2个问题解决了,下面我们来看看controller中如何使用。 ## 4、Controller中代码如何写? ### 来个案例 如下代码,注意两点信息 - 内部提供了2个接口,接口的返回值都是ResultDto类型的 - 代码中,没有了try catch,而是将异常类型封装为BusException类型抛出,比如验证码有误,会抛出了BusException,顺便携带了错误码和错误提示信息,这些都会通过全局异常的处理,输出到客户端 ```java @RestController @RequestMapping("/user") public class UserController { /** * 获取用户id * * @param code * @return */ @RequestMapping("/getUserName") public ResultDto<String> getUserName(@RequestParam("code") Integer code) { if (!Integer.valueOf(6666).equals(code)) { //验证码有误的时候,返回4001错误码 BusException.throwBusException("4001", "验证码有误!"); } return ResultDto.success("路人"); } /** * 获取用户id * * @param code * @return */ @RequestMapping("/getUserId") public ResultDto<String> getUserId(@RequestParam("code") Integer code) { if (!Integer.valueOf(6666).equals(code)) { BusException.throwBusException("4001", "验证码有误!"); } return ResultDto.success("8888"); } } ``` ### 验证效果 > 下面我们通过idea提供的HTTP client工具搞三个测试用例,测试下接口的效果,如下图,大家可以分别运行一下3个案例。 ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/225/03082c00-80d9-4ef9-9353-65cac440ad0b.png) 用例1输出结果: ```json { "success": true, "code": null, "msg": "操作成功!", "data": "路人" } ``` 用例2输出结果: ```json { "success": false, "code": "4001", "msg": "验证码有误!", "data": null } ``` 用例3输出的结果: ```json { "success": false, "code": null, "msg": "系统异常,请联系管理员,错误详情:Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"abc\"", "data": null } ``` ## 5、总结 本文内容主要有2点:统一返回值、统一异常的处理,这2点大家要好好掌握,目前业界很少使用springmvc直接开发接口了,更多的是采用springboot来开发接口,本文的内容直接可以用到springboot中,来优化咱们的系统。 ## 6、案例代码 ```html git地址:https://gitee.com/javacode2018/springmvc-series ``` ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/225/41ff8e45-68f9-409b-a2a4-1b38ad090675.png) <a style="display:none" target="_blank" href="https://mp.weixin.qq.com/s/_S1DD2JADnXvpexxaBwLLg" style="color:red; font-size:20px; font-weight:bold">继续收门徒,亲手带,月薪 4W 以下的可以来找我</a> ## 最新资料 1. <a href="https://mp.weixin.qq.com/s?__biz=MzkzOTI3Nzc0Mg==&mid=2247484964&idx=2&sn=c81bce2f26015ee0f9632ddc6c67df03&scene=21#wechat_redirect" target="_blank">尚硅谷 Java 学科全套教程(总 207.77GB)</a> 2. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484192&idx=1&sn=505f2faaa4cc911f553850667749bcbb&scene=21#wechat_redirect" target="_blank">2021 最新版 Java 微服务学习线路图 + 视频</a> 3. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484573&idx=1&sn=7f3d83892186c16c57bc0b99f03f1ffd&scene=21#wechat_redirect" target="_blank">阿里技术大佬整理的《Spring 学习笔记.pdf》</a> 4. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484544&idx=2&sn=c1dfe907cfaa5b9ae8e66fc247ccbe84&scene=21#wechat_redirect" target="_blank">阿里大佬的《MySQL 学习笔记高清.pdf》</a> 5. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485167&idx=1&sn=48d75c8e93e748235a3547f34921dfb7&scene=21#wechat_redirect" target="_blank">2021 版 java 高并发常见面试题汇总.pdf</a> 6. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485664&idx=1&sn=435f9f515a8f881642820d7790ad20ce&scene=21#wechat_redirect" target="_blank">Idea 快捷键大全.pdf</a> ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/1/2883e86e-3eff-404a-8943-0066e5e2b454.png)
#custom-toc-container