SpringBoot优雅的全局异常处理(二)@RestControllerAdvice注解方式

前言

SpringBoot版本:2.1.9.RELEASE
Mybatis Plus版本:3.3.0

上篇文章主要是讲的SpringBoot非web项目的全局异常处理方式,现在来讲一下web注解的方式。

一、新建自定义异常处理类GlobalExceptionHandler。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.junya.util.exception;

import com.junya.util.result.ResponseMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
* @program sweet-dream
* @description: 自定义全局异常处理类
* @author: zhangchao
* @date: 2020/02/26 22:05
* @since: 1.0.0
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

/**
* 全局异常拦截处理
* @param request
* @param e
* @return
*/
@ExceptionHandler
public ResponseMessage exceptionHandler(HttpServletRequest request, Exception e){
String requestUrl = request.getRequestURL().toString();//得到请求的URL地址
String queryString = request.getQueryString();//得到请求的URL地址中附带的参数
String remoteAddr = request.getRemoteAddr();//得到来访者的IP地址
String method = request.getMethod();//得到请求URL地址时使用的方法
//异常堆栈信息放入日志中
String api = requestUrl.replaceFirst("[\\s\\S]*\\d(.+)","$1");
ExceptionUtil.getFullStackTrace(e,api);
ResponseMessage responseMessage = new ResponseMessage();
String eStr = e.toString();
for (GlobalErrorCodeEnum global : GlobalErrorCodeEnum.values()){
if (eStr.toUpperCase().contains(global.toString().replaceAll("_",""))){
responseMessage.setCode(global.getCode());
responseMessage.setMsg(global.getMsg());
break;
}
}
if (eStr.contains("GlobalException")){
for (GlobalErrorCodeEnum statusCodeEnum : GlobalErrorCodeEnum.values()){
if (eStr.contains(statusCodeEnum.getMsg())){
if (eStr.contains("Data too long for column")){
String field = eStr.replaceAll("[\\s\\S]+Data too long for column '(.+)' at[\\s\\S]+","$1");
responseMessage.setCode(statusCodeEnum.getCode());
responseMessage.setMsg(statusCodeEnum.getMsg()+",字段长度超过限制:"+field);
break;
}
if (eStr.contains("Unknown column")){
String field = eStr.replaceAll("[\\s\\S]+Unknown column '(.+)' in[\\s\\S]+","$1");
responseMessage.setCode(statusCodeEnum.getCode());
responseMessage.setMsg(statusCodeEnum.getMsg()+",未知的字段:"+field);
break;
}
if (eStr.contains("doesn't have a default value")){
String field = eStr.replaceAll("[\\s\\S]+Field '(.+)' doesn't have a default value[\\s\\S]+","$1");
responseMessage.setCode(statusCodeEnum.getCode());
responseMessage.setMsg(statusCodeEnum.getMsg()+",此字段必须有值:"+field);
break;
}
responseMessage.setCode(statusCodeEnum.getCode());
responseMessage.setMsg(statusCodeEnum.getMsg());
break;
}
}
}
if ("".equals(responseMessage.getCode()) || "".equals(responseMessage.getMsg())){
responseMessage.setCode(GlobalErrorCodeEnum.UNKNOWN_EXCEPTION.getCode());
responseMessage.setMsg(GlobalErrorCodeEnum.UNKNOWN_EXCEPTION.getMsg());
}
responseMessage.setData("{请求PATH:"+api+",请求参数:"+queryString+",来访者IP:"+remoteAddr+",请求方法类型:"+method+"}");
return responseMessage;
}

}

二、 自定义异常类,继承RuntimeException。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.junya.util.exception;

/**
* 自定义全局异常类
*
* @author ZhangChao
* @date 2019/10/18 13:23
* @since 1.0.0
*/
public class GlobalException extends RuntimeException {
private static final long serialVersionUID = 6958499252468627021L;

/**
* 错误码
*/
private String code;

public GlobalException(String code, String msg) {
super(msg);
this.code = code;
}

public GlobalException(GlobalErrorCodeEnum errorCode) {
super(errorCode.getMsg());
this.code = errorCode.getCode();
}

public GlobalException(GlobalErrorCodeEnum errorCode, String msg){
super(errorCode.getMsg()+msg);
this.code = errorCode.getCode();
}

public GlobalException(String code, String msg, Throwable throwable){
super(msg,throwable);
this.code = code;
}
public GlobalException(GlobalErrorCodeEnum errorCode, Throwable throwable){
super(errorCode.getMsg(),throwable);
this.code = errorCode.getCode();
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}
}

三、异常枚举类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.junya.util.exception;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* 自定义全局异常枚举
*
* @author ZhangChao
* @date 2019/10/18 13:15
* @since 1.0.0
*/
public enum GlobalErrorCodeEnum {

/** 未知异常 */
UNKNOWN_EXCEPTION("CSEP001","未知异常,请联系管理员"),
/** 系统错误 */
SYSTEM_ERROR("CSEP002","系统错误"),
/** 类转换异常 */
CLASS_CAST_EXCEPTION("CSEP003","类型强制转换异常"),
/** 算术条件异常 */
ARITHMETIC_EXCEPTION("CSEP004","算术条件异常"),
/** 空指针异常 */
NULL_POINTER_EXCEPTION("CSEP005","空指针异常"),
/** 字符串转换为数字异常 */
NUMBER_FORMAT_EXCEPTION("CSEP006","字符串转换为数字异常"),
/** 数组下标越界异常 */
ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION("CSEP007","数组下标越界异常"),
/** 方法未找到异常 */
NO_SUCH_METHOD_EXCEPTION("CSEP008","方法未找到异常"),
/** 未找到类定义错误 */
NO_CLASS_DEF_FOUND_ERROR("CSEP009","未找到类定义错误"),
/** 未找到类定义错误 */
CLASS_NOT_FOUND_EXCEPTION("CSEP010","找不到类异常"),
/** 索引越界异常 */
INDEX_OUT_OF_BOUNDS_EXCEPTION("CSEP011","索引越界异常"),
/** 数据库异常 */
DB_ERROR("CSEP012","数据库异常")
;

private String code;
private String msg;

GlobalErrorCodeEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}

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;
}

}

四、异常工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.junya.util.exception;

import com.junya.util.result.ResponseMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
* 保存异常堆栈信息
* -- 两种方式 Throwable和Exception
*
* @author ZhangChao
* @date 2019/9/6 9:56
* @since 1.0.0
*/
public class ExceptionUtil {

private static final Logger logger = LoggerFactory.getLogger(ExceptionUtil.class);

/**
* 异常堆栈信息保存到日志中
* @param ex
*/
public static void getFullStackTrace(Exception ex) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream pout = new PrintStream(out);
ex.printStackTrace(pout);
String ret = new String(out.toByteArray());
pout.close();
try {
out.close();
} catch (Exception e) {
}
ex.printStackTrace();
logger.error(ret);
}

/**
* 异常堆栈信息保存到日志中,并保存消息记录
* @param ex
* @param msg
*/
public static void getFullStackTrace(Exception ex, String msg) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream pout = new PrintStream(out);
ex.printStackTrace(pout);
String ret = new String(out.toByteArray());
pout.close();
try {
out.close();
} catch (Exception e) {
}
ex.printStackTrace();
logger.error("出现异常==>: "+msg+" ==> \n"+ret);
// logger.error(ret);
}

/**
* 参数是Throwable
* @param e
* @return
*/
public static void getFullStackTrace(Throwable e){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
try {
e.printStackTrace(pw);
pw.flush();
sw.flush();
logger.error(sw.toString());
} finally {
pw.close();
}
}

}

五、测试
在这里插入图片描述

总结

通过@RestControllerAdvice@ExceptionHandler方式还是很简单的。

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2020 yak33
  • Powered by Hexo Theme Ayer
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信