参考:https://www.cnblogs.com/xuwujing/p/10933082.html
1、首先,需要引入maven依赖包,如下所示:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6 <parent>
7 <groupId>org.springframework.boot</groupId>
8 <artifactId>spring-boot-starter-parent</artifactId>
9 <version>2.3.12.RELEASE</version>
10 <relativePath /> <!-- lookup parent from repository -->
11 </parent>
12 <groupId>com.bie</groupId>
13 <artifactId>SpringbootException</artifactId>
14 <version>0.0.1-SNAPSHOT</version>
15 <name>SpringbootException</name>
16 <description>Demo project for Spring Boot</description>
17
18 <properties>
19 <java.version>1.8</java.version>
20 </properties>
21
22 <dependencies>
23 <!-- 引入springboot web模块 -->
24 <dependency>
25 <groupId>org.springframework.boot</groupId>
26 <artifactId>spring-boot-starter-web</artifactId>
27 </dependency>
28 <!-- 引入fastjson的依赖 -->
29 <dependency>
30 <groupId>com.alibaba</groupId>
31 <artifactId>fastjson</artifactId>
32 <version>1.2.41</version>
33 </dependency>
34
35 <dependency>
36 <groupId>org.springframework.boot</groupId>
37 <artifactId>spring-boot-starter-test</artifactId>
38 <scope>test</scope>
39 <exclusions>
40 <exclusion>
41 <groupId>org.junit.vintage</groupId>
42 <artifactId>junit-vintage-engine</artifactId>
43 </exclusion>
44 </exclusions>
45 </dependency>
46 </dependencies>
47
48 <build>
49 <plugins>
50 <plugin>
51 <groupId>org.springframework.boot</groupId>
52 <artifactId>spring-boot-maven-plugin</artifactId>
53 </plugin>
54 </plugins>
55 </build>
56
57 </project>
SpringBoot中有一个ControllerAdvice的注解,使用该注解表示开启了全局异常的捕获,我们只需再自定义一个方法,然后使用ExceptionHandler注解,在该注解的value属性里面,定义捕获异常的类型,即可对这些捕获的异常进行统一的处理。
2、自定义基础接口类。
首先定义一个基础的接口类,自定义的错误描述枚举类需实现该接口。
1 package com.bie.enums;
2
3 public interface BaseErrorInfoInterface {
4
5 // 错误码
6 public String getResultCode();
7
8 // 错误描述
9 public String getResultMsg();
10
11 }
3、自定义枚举类。
然后我们这里在自定义一个枚举类,并实现该接口。而使用枚举类的好处是处理异常的时候,可以通过枚举类直接获取到错误码、错误描述,方便调用。
1 package com.bie.enums;
2
3 public enum CommonEnum implements BaseErrorInfoInterface {
4
5 // 数据操作错误定义
6 SUCCESS("200", "接口调用成功!"),
7
8 BODY_NOT_MATCH("400", "请求的数据格式不符!"),
9
10 SIGNATURE_NOT_MATCH("401", "请求的数字签名不匹配!"),
11
12 NOT_FOUND("404", "未找到该资源!"),
13
14 INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
15
16 SERVER_BUSY("503", "服务器正忙,请稍后再试!");
17
18 // 错误码
19 private String resultCode;
20
21 // 错误描述
22 private String resultMsg;
23
24 CommonEnum(String resultCode, String resultMsg) {
25 this.resultCode = resultCode;
26 this.resultMsg = resultMsg;
27 }
28
29 @Override
30 public String getResultCode() {
31 return resultCode;
32 }
33
34 @Override
35 public String getResultMsg() {
36 return resultMsg;
37 }
38
39 }
4、自定义异常类。
然后我们在来自定义一个异常类,用于处理我们发生的业务异常。
1 package com.bie.exception;
2
3 import com.bie.enums.BaseErrorInfoInterface;
4
5 public class BizException extends RuntimeException {
6
7 /**
8 *
9 */
10 private static final long serialVersionUID = -6329783845738305585L;
11
12 // 错误码
13 protected String errorCode;
14 // 错误信息
15 protected String errorMsg;
16
17 public BizException() {
18 super();
19 }
20
21 public BizException(BaseErrorInfoInterface errorInfoInterface) {
22 super(errorInfoInterface.getResultCode());
23 this.errorCode = errorInfoInterface.getResultCode();
24 this.errorMsg = errorInfoInterface.getResultMsg();
25 }
26
27 public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
28 super(errorInfoInterface.getResultCode(), cause);
29 this.errorCode = errorInfoInterface.getResultCode();
30 this.errorMsg = errorInfoInterface.getResultMsg();
31 }
32
33 public BizException(String errorMsg) {
34 super(errorMsg);
35 this.errorMsg = errorMsg;
36 }
37
38 public BizException(String errorCode, String errorMsg) {
39 super(errorCode);
40 this.errorCode = errorCode;
41 this.errorMsg = errorMsg;
42 }
43
44 public BizException(String errorCode, String errorMsg, Throwable cause) {
45 super(errorCode, cause);
46 this.errorCode = errorCode;
47 this.errorMsg = errorMsg;
48 }
49
50 public String getErrorCode() {
51 return errorCode;
52 }
53
54 public void setErrorCode(String errorCode) {
55 this.errorCode = errorCode;
56 }
57
58 public String getErrorMsg() {
59 return errorMsg;
60 }
61
62 public void setErrorMsg(String errorMsg) {
63 this.errorMsg = errorMsg;
64 }
65
66 public String getMessage() {
67 return errorMsg;
68 }
69
70 @Override
71 public Throwable fillInStackTrace() {
72 return this;
73 }
74
75 }
5、自定义数据格式。
顺便这里我们定义一下数据的传输格式,作用主要用于返回给前端的数据格式。
1 package com.bie.utils;
2
3 import com.alibaba.fastjson.JSONObject;
4 import com.bie.enums.BaseErrorInfoInterface;
5 import com.bie.enums.CommonEnum;
6
7 public class ResultBody {
8
9 // 响应代码
10 private String code;
11
12 // 响应消息
13 private String message;
14
15 // 响应结果
16 private Object result;
17
18 public ResultBody() {
19 }
20
21 public ResultBody(BaseErrorInfoInterface errorInfo) {
22 this.code = errorInfo.getResultCode();
23 this.message = errorInfo.getResultMsg();
24 }
25
26 public String getCode() {
27 return code;
28 }
29
30 public void setCode(String code) {
31 this.code = code;
32 }
33
34 public String getMessage() {
35 return message;
36 }
37
38 public void setMessage(String message) {
39 this.message = message;
40 }
41
42 public Object getResult() {
43 return result;
44 }
45
46 public void setResult(Object result) {
47 this.result = result;
48 }
49
50 /**
51 * 成功
52 *
53 * @return
54 */
55 public static ResultBody success() {
56 return success(null);
57 }
58
59 /**
60 * 成功
61 *
62 * @param data
63 * @return
64 */
65 public static ResultBody success(Object data) {
66 ResultBody rb = new ResultBody();
67 rb.setCode(CommonEnum.SUCCESS.getResultCode());
68 rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
69 rb.setResult(data);
70 return rb;
71 }
72
73 /**
74 * 失败
75 */
76 public static ResultBody error(BaseErrorInfoInterface errorInfo) {
77 ResultBody rb = new ResultBody();
78 rb.setCode(errorInfo.getResultCode());
79 rb.setMessage(errorInfo.getResultMsg());
80 rb.setResult(null);
81 return rb;
82 }
83
84 /**
85 * 失败
86 */
87 public static ResultBody error(String code, String message) {
88 ResultBody rb = new ResultBody();
89 rb.setCode(code);
90 rb.setMessage(message);
91 rb.setResult(null);
92 return rb;
93 }
94
95 /**
96 * 失败
97 */
98 public static ResultBody error(String message) {
99 ResultBody rb = new ResultBody();
100 rb.setCode("-1");
101 rb.setMessage(message);
102 rb.setResult(null);
103 return rb;
104 }
105
106 @Override
107 public String toString() {
108 return JSONObject.toJSONString(this);
109 }
110
111 }
6、自定义全局异常处理类。
最后我们再来编写一个自定义全局异常处理的类,可以用于处理各类异常。
1 package com.bie.exception;
2
3 import javax.servlet.http.HttpServletRequest;
4
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7 import org.springframework.web.bind.annotation.ControllerAdvice;
8 import org.springframework.web.bind.annotation.ExceptionHandler;
9 import org.springframework.web.bind.annotation.ResponseBody;
10
11 import com.bie.enums.CommonEnum;
12 import com.bie.utils.ResultBody;
13
14 @ControllerAdvice
15 public class GlobalExceptionHandler {
16
17 private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
18
19 /**
20 * 处理自定义的业务异常
21 *
22 * @param req
23 * @param e
24 * @return
25 */
26 @ExceptionHandler(value = BizException.class)
27 @ResponseBody
28 public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e) {
29 logger.error("发生业务异常!原因是:{}", e.getErrorMsg());
30 return ResultBody.error(e.getErrorCode(), e.getErrorMsg());
31 }
32
33 /**
34 * 处理空指针的异常
35 *
36 * @param req
37 * @param e
38 * @return
39 */
40 @ExceptionHandler(value = NullPointerException.class)
41 @ResponseBody
42 public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
43 logger.error("发生空指针异常!原因是:", e);
44 return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
45 }
46
47 /**
48 * 处理其他异常
49 *
50 * @param req
51 * @param e
52 * @return
53 */
54 @ExceptionHandler(value = Exception.class)
55 @ResponseBody
56 public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {
57 logger.error("未知异常!原因是:", e);
58 return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
59 }
60
61 }
7、创建一个用户的实体类,如下所示:
1 package com.bie.po;
2
3 import java.io.Serializable;
4
5 import com.alibaba.fastjson.JSONObject;
6
7 public class User implements Serializable {
8
9 /**
10 *
11 */
12 private static final long serialVersionUID = 1360679426784375558L;
13
14 // 编号
15 private int id;
16 // 姓名
17 private String name;
18 // 年龄
19 private int age;
20
21 public User() {
22 }
23
24 public int getId() {
25 return id;
26 }
27
28 public void setId(int id) {
29 this.id = id;
30 }
31
32 public String getName() {
33 return name;
34 }
35
36 public void setName(String name) {
37 this.name = name;
38 }
39
40 public int getAge() {
41 return age;
42 }
43
44 public void setAge(int age) {
45 this.age = age;
46 }
47
48 public String toString() {
49 return JSONObject.toJSONString(this);
50 }
51
52 }
8、Controller 控制层。
控制层这边也比较简单,使用Restful风格实现的CRUD功能,主要是Restful风格的,根据请求方式get、post、put、delete,而请求路径是一个,主要根据请求方式来做区分操作。
1 package com.bie.controller;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import org.springframework.web.bind.annotation.DeleteMapping;
7 import org.springframework.web.bind.annotation.GetMapping;
8 import org.springframework.web.bind.annotation.PostMapping;
9 import org.springframework.web.bind.annotation.PutMapping;
10 import org.springframework.web.bind.annotation.RequestBody;
11 import org.springframework.web.bind.annotation.RequestMapping;
12 import org.springframework.web.bind.annotation.RestController;
13
14 import com.bie.exception.BizException;
15 import com.bie.po.User;
16
17 @RestController
18 @RequestMapping(value = "/api")
19 public class UserRestController {
20
21 @PostMapping("/user")
22 public boolean insert(@RequestBody User user) {
23 System.out.println("开始新增...");
24 // 如果姓名为空就手动抛出一个自定义的异常!
25 if (user.getName() == null) {
26 throw new BizException("-1", "用户姓名不能为空!");
27 }
28 return true;
29 }
30
31 @PutMapping("/user")
32 public boolean update(@RequestBody User user) {
33 System.out.println("开始更新...");
34 // 这里故意造成一个空指针的异常,并且不进行处理
35 String str = null;
36 str.equals("111");
37 return true;
38 }
39
40 @DeleteMapping("/user")
41 public boolean delete(@RequestBody User user) {
42 System.out.println("开始删除...");
43 // 这里故意造成一个异常,并且不进行处理
44 Integer.parseInt("abc123");
45 return true;
46 }
47
48 @GetMapping("/user")
49 public List<User> findByUser(User user) {
50 System.out.println("开始查询...");
51 List<User> userList = new ArrayList<>();
52 User user2 = new User();
53 user2.setId(1);
54 user2.setName("xuwujing");
55 user2.setAge(18);
56 userList.add(user2);
57 return userList;
58 }
59
60 }
9、接口功能测试,使用postman进行测试,如下所示:
9.1、首先进行查询,查看程序是否正常运行,使用GET 方式进行请求,如下所示:
9.2、进行插入操作,使用POST方式进行请求,如下所示:
9.3、进行修改操作,使用PUT方式进行请求,如下所示:
9.4、进行删除操作,使用DELETE方式进行请求,如下所示:
10、整体思路解析,按照步骤操作,按道理来说,这个思路是很优秀的,那么下面来分析一下这个设计思路。
10.1、在自己的方法中抛出自定义异常,而抛出的自定义异常是被全局异常类进行捕获处理的。
对抛出的自定义异常,在全局异常处理类中进行处理,然后返回的信息,是封装到自定义数据格式类中的,这样返回给前端的数据格式,就可以根据自己的需求进行设计。
10.2、而对于全局异常类中,可以定义捕获其他类型的异常。而在捕获其他异常之后,返回的数据封装到自定义数据格式里面,而对于其他异常而已直接使用定义的枚举类中来选择异常内容。
虽然,这种设计不能说100%完美,但是设计的已经很优秀了,基本可以满足日常需求,赞一个。