前言
SpringBoot版本:2.1.9.RELEASE
Mybatis Plus版本:3.3.0
上篇文章主要是讲的SpringBoot非web项目的全局异常处理方式,现在来讲一下web注解的方式。
一、新建自定义异常处理类GlobalExceptionHandler。
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。
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;
}
}
三、异常枚举类
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;
}
}
四、异常工具类
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方式还是很简单的。
PS: 更多技术干货,欢迎大家来我的个人博客 yak33的技术人生