前言
在 Controller 里提供接口,通常需要捕捉異常心赶,進(jìn)行異常處理缨叫。最簡單的方法使用try/catch進(jìn)行異常捕捉荔燎。
當(dāng)方法很多,每個(gè)都需要 try catch琐簇,代碼會(huì)顯得臃腫座享,寫起來也比較麻煩征讲。
這時(shí)就需要進(jìn)行統(tǒng)一的異常處理。
1.使用方法
通過 Spring 的 AOP 特性就可以很方便的實(shí)現(xiàn)異常的統(tǒng)一處理:使用@ControllerAdvice癣籽、@RestControllerAdvice捕獲運(yùn)行時(shí)異常滤祖。
代碼結(jié)構(gòu)
新建異常枚舉類
package com.local.dev.root.devroot.common.enums;
/**
* 異常枚舉類
*/
public enum ExceptionEnum {
// 400
BAD_REQUEST("400", "請(qǐng)求數(shù)據(jù)格式不正確!"),
UNAUTHORIZED("401", "登錄憑證過期!"),
FORBIDDEN("403", "沒有訪問權(quán)限!"),
NOT_FOUND("404", "請(qǐng)求的資源找不到!"),
// 500
INTERNAL_SERVER_ERROR("500", "服務(wù)器內(nèi)部錯(cuò)誤!"),
SERVICE_UNAVAILABLE("503", "服務(wù)器正忙匠童,請(qǐng)稍后再試!"),
// 未知異常
UNKNOWN("10000", "未知異常!"),
// 自定義
IS_NOT_NULL("10001","%s不能為空");
/**
* 錯(cuò)誤碼
*/
private String code;
/**
* 錯(cuò)誤描述
*/
private String msg;
ExceptionEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
自定義異常類
package com.local.dev.root.devroot.common.exception;
import com.local.dev.root.devroot.common.enums.ExceptionEnum;
/**
* 自定義業(yè)務(wù)異常類
*/
public class BusinessException extends RuntimeException {
private ExceptionEnum exceptionEnum;
private String code;
private String errorMsg;
public BusinessException() {
super();
}
public BusinessException(ExceptionEnum exceptionEnum) {
super("{code:" + exceptionEnum.getCode() + ",errorMsg:" + exceptionEnum.getMsg() + "}");
this.exceptionEnum = exceptionEnum;
this.code = exceptionEnum.getCode();
this.errorMsg = exceptionEnum.getMsg();
}
public BusinessException(String code, String errorMsg) {
super("{code:" + code + ",errorMsg:" + errorMsg + "}");
this.code = code;
this.errorMsg = errorMsg;
}
public BusinessException(String code, String errorMsg, Object... args) {
super("{code:" + code + ",errorMsg:" + String.format(errorMsg, args) + "}");
this.code = code;
this.errorMsg = String.format(errorMsg, args);
}
public ExceptionEnum getExceptionEnum() {
return exceptionEnum;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
ExceptionHandlerConfig.java
@RestControllerAdvice俏险,統(tǒng)一異常處理
package com.local.dev.root.devroot.common.config.exception;
import com.local.dev.root.devroot.common.enums.ExceptionEnum;
import com.local.dev.root.devroot.common.exception.BusinessException;
import com.local.dev.root.devroot.common.exception.ErrorPageException;
import com.local.dev.root.devroot.common.pojo.ApiResponse;
import com.local.dev.root.devroot.common.util.ErrorUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* RestControllerAdvice竖独,統(tǒng)一異常處理
*/
@Slf4j
@RestControllerAdvice
public class ExceptionHandlerConfig {
/**
* 業(yè)務(wù)異常處理
*
* @param e 業(yè)務(wù)異常
* @return
*/
@ExceptionHandler(value = BusinessException.class)
@ResponseBody
public ApiResponse exceptionHandler(BusinessException e) {
log.error(ErrorUtil.errorInfoToString(e));
return ApiResponse.error(e.getCode(), e.getErrorMsg());
}
/**
* 未知異常處理
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ApiResponse exceptionHandler(Exception e) {
// 把錯(cuò)誤信息輸入到日志中
log.error(ErrorUtil.errorInfoToString(e));
return ApiResponse.error(ExceptionEnum.UNKNOWN.getCode(),
ExceptionEnum.UNKNOWN.getMsg());
}
/**
* 錯(cuò)誤頁面異常
*/
@ExceptionHandler(value = ErrorPageException.class)
@ResponseBody
public ApiResponse exceptionHandler(ErrorPageException e) {
log.error(ErrorUtil.errorInfoToString(e));
return ApiResponse.error(e.getCode(), e.getErrorMsg());
}
/**
* 空指針異常
*/
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public ApiResponse exceptionHandler(NullPointerException e) {
log.error(ErrorUtil.errorInfoToString(e));
return ApiResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR.getCode(),
ExceptionEnum.INTERNAL_SERVER_ERROR.getMsg());
}
}
測試類
package com.local.dev.root.devroot.controller;
import com.local.dev.root.devroot.common.pojo.ApiResponse;
import com.local.dev.root.devroot.service.dev.TestServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloWorld {
@Autowired
private TestServiceImpl testServiceImpl;
@RequestMapping("world")
public String HelloWorld() {
return "Hello World!";
}
@RequestMapping("error1")
public ApiResponse Error1() {
return ApiResponse.ok();
}
@RequestMapping("error2")
public ApiResponse Error2() {
String msg = null;
msg.equals("xx");
return ApiResponse.ok("訪問成功");
}
@RequestMapping("error3")
public ApiResponse Error3() {
testServiceImpl.getBusinessException();
return ApiResponse.ok("訪問成功");
}
}
testServiceImpl 拋出自定義異常
package com.local.dev.root.devroot.service.dev;
import com.local.dev.root.devroot.common.enums.ExceptionEnum;
import com.local.dev.root.devroot.common.exception.BusinessException;
import org.springframework.stereotype.Service;
@Service
public class TestServiceImpl {
public Object getBusinessException() {
throw new BusinessException(ExceptionEnum.IS_NOT_NULL.getCode(),
ExceptionEnum.IS_NOT_NULL.getMsg(), "參數(shù)");
}
}
ErrorUtil工具類
package com.local.springboot.springbootcommon.utils;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 捕獲報(bào)錯(cuò)日志處理工具類
*/
public class ErrorUtil {
/**
* Exception出錯(cuò)的棧信息轉(zhuǎn)成字符串
* 用于打印到日志中
*/
public static String errorInfoToString(Throwable e) {
//try-with-resource語法糖 處理機(jī)制
try(StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)){
e.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.toString();
}catch (Exception ignored){
throw new RuntimeException(ignored.getMessage(),ignored);
}
}
}
ApiResponse
package com.local.springboot.springbootcommon.reponse;
import java.util.HashMap;
/**
* @author: MaoDeShu
* @date: 2021-09-17 11:29
* @Description: API請(qǐng)求返回類
**/
public class ApiResponse extends HashMap<String, Object> {
public ApiResponse() {
put("code", 200);
put("msg", "success");
}
public ApiResponse(String code, String msg) {
super(2);
put("code", code);
put("msg", msg);
}
public static ApiResponse ok() {
ApiResponse r = new ApiResponse();
r.put("msg", "操作成功");
return r;
}
public static ApiResponse msg(String msg) {
ApiResponse r = new ApiResponse();
r.put("msg", msg);
return r;
}
public static ApiResponse ok(Object obj) {
ApiResponse r = new ApiResponse();
r.put("code", 200);
r.put("results", obj);
return r;
}
public static ApiResponse error() {
return error("500", "未知異常,請(qǐng)聯(lián)系管理員");
}
public static ApiResponse error(String msg) {
return error("500", msg);
}
public static ApiResponse error(String code, String msg) {
ApiResponse r = new ApiResponse();
r.put("code", code);
r.put("msg", msg);
return r;
}
@Override
public ApiResponse put(String key, Object value) {
super.put(key, value);
return this;
}
/**
* 分頁
*
* @param page
* @return
*/
public ApiResponse page(Object page) {
return put("page", page);
}
public ApiResponse result(Object obj) {
super.put("result", obj);
return this;
}
}
2.測試
正常
http://localhost:8080/hello/error1
空指針異常
http://localhost:8080/hello/error2
業(yè)務(wù)異常
http://localhost:8080/hello/error3
3.查看日志
打開error日志
? 上一章:SpringBoot —— 多線程定時(shí)任務(wù)的實(shí)現(xiàn)(注解配置刊侯、task:annotation-driven配置)
? 下一章:SpringBoot —— 簡單整合Redis實(shí)例及StringRedisTemplate與RedisTemplate對(duì)比和選擇
創(chuàng)作不易长窄,關(guān)注纲菌、點(diǎn)贊就是對(duì)作者最大的鼓勵(lì)翰舌,歡迎在下方評(píng)論留言
求關(guān)注,定期分享Java知識(shí)椅贱,一起學(xué)習(xí)庇麦,共同成長。