前言
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方式還是很簡單的。