1. 程式人生 > 其它 >Springboot全域性異常處理案例--@ControllerAdvice

Springboot全域性異常處理案例--@ControllerAdvice

1.新增依賴

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

2.自定義一個錯誤介面類,包含錯誤碼和錯誤資訊

package com.example.demo.util;

/**
 * @author lyd
 * @Description:
 * @date 16:15
 */
public interface BaseErrorInfoInterface {


	/**
	 * 得到錯誤碼
	 *
	 * @return {@link String}
	 */
	String getResultCode();

	/**
	 * 得到錯誤資訊
	 *
	 * @return {@link String}
	 */
	String getResultMsg();

}

3.自定義一個列舉類,實現錯誤介面類,在這個列舉裡面自定義一些錯誤型別

package com.example.demo.util;


/**
 * 常見的列舉
 *
 * @author lyd
 * @Description: 自定義列舉類
 * @date 16:16
 */
public enum CommonEnum implements BaseErrorInfoInterface {

	SUCCESS("200", "成功"),
	BODY_NOT_MATCH("400", "請求的資料格式不符"),
	SIGNATURE_NOT_MATCH("401", "請求的數字簽名不匹配!"),
	OT_FOUND("404", "未找到該資源!"),
	INTERNAL_SERVER_ERROR("500", "伺服器內部錯誤!"),
	SERVER_BUSY("503", "伺服器正忙,請稍後再試!");

	/**
	 * 錯誤碼
	 */
	private String resultCode;

	/**
	 * 錯誤描述
	 */
	private String resultMsg;

	CommonEnum(String resultCode, String resultMsg) {
		this.resultCode = resultCode;
		this.resultMsg = resultMsg;
	}

	@Override
	public String getResultCode() {
		return resultCode;
	}

	@Override
	public String getResultMsg() {
		return resultMsg;
	}
}

4.自定義一個異常類,等會處理業務異常的時候用

package com.example.demo.exception;

import com.example.demo.util.BaseErrorInfoInterface;

/**
 * @author lyd
 * @Description: 自定義異常類
 * @date 16:25
 */
public class BizException extends RuntimeException {


	/**
	 * 錯誤程式碼
	 */
	private String errorCode;
	/**
	 * 錯誤資訊
	 */
	private String errorMsg;

	public BizException() {
		super();
	}

	public BizException(String message, String errorMsg) {
		super(message);
		this.errorMsg = errorMsg;
	}

	public BizException(String message, String errorCode, String errorMsg) {
		super(message);
		this.errorCode = errorCode;
		this.errorMsg = errorMsg;
	}

	public BizException(BaseErrorInfoInterface baseErrorInfoInterface) {
		super(baseErrorInfoInterface.getResultCode());
		this.errorCode = baseErrorInfoInterface.getResultCode();
		this.errorMsg = baseErrorInfoInterface.getResultMsg();
	}

	public BizException(BaseErrorInfoInterface baseErrorInfoInterface, Throwable cause) {
		super(baseErrorInfoInterface.getResultCode(), cause);
		this.errorCode = baseErrorInfoInterface.getResultCode();
		this.errorMsg = baseErrorInfoInterface.getResultMsg();
	}

	public BizException(Throwable cause, String errorCode, String errorMsg) {
		super(errorCode, cause);
		this.errorCode = errorCode;
		this.errorMsg = errorMsg;
	}

	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getErrorMsg() {
		return errorMsg;
	}

	public void setErrorMsg(String errorMsg) {
		this.errorMsg = errorMsg;
	}

	@Override
	public synchronized Throwable fillInStackTrace() {
		return super.fillInStackTrace();
	}
}

5.再定義一個數據響應格式,便於資料互動

package com.example.demo.util;

import com.alibaba.fastjson.JSONObject;

/**
 * @author lyd
 * @Description: 自定義資料傳輸格式
 * @date 16:40
 */
public class ResultBody {

	/**
	 * 響應程式碼
	 */
	private String code;
	/**
	 * 響應訊息
	 */
	private String message;
	/**
	 * 響應結果
	 */
	private Object result;

	public ResultBody() {
	}

	public ResultBody(BaseErrorInfoInterface baseErrorInfoInterface) {
		this.code = baseErrorInfoInterface.getResultCode();
		this.message = baseErrorInfoInterface.getResultMsg();
	}

	/**
	 * 成功
	 *
	 * @param data 資料
	 * @return {@link ResultBody}
	 */
	public static ResultBody success(Object data) {
		ResultBody resultBody = new ResultBody();
		resultBody.setCode(CommonEnum.SUCCESS.getResultCode());
		resultBody.setMessage(CommonEnum.SUCCESS.getResultMsg());
		resultBody.setResult(data);
		return resultBody;
	}

	/**
	 * 錯誤
	 *
	 * @param errorInfo 錯誤資訊
	 * @return {@link ResultBody}
	 */
	public static ResultBody error(BaseErrorInfoInterface errorInfo) {
		ResultBody resultBody = new ResultBody();
		resultBody.setCode(errorInfo.getResultCode());
		resultBody.setMessage(errorInfo.getResultMsg());
		resultBody.setResult(null);
		return resultBody;
	}

	/**
	 * 錯誤
	 *
	 * @return {@link ResultBody}
	 */
	public static ResultBody error(String code, String message) {
		ResultBody resultBody = new ResultBody();
		resultBody.setCode(code);
		resultBody.setMessage(message);
		resultBody.setResult(null);
		return resultBody;
	}

	public String getCode() {
		return code;
	}

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

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getResult() {
		return result;
	}

	public void setResult(Object result) {
		this.result = result;
	}

	@Override
	public String toString() {
		return JSONObject.toJSONString(this);
	}
}

6.最關鍵的一步:自定義一個全域性異常處理類,用到兩個註解@ControllerAdvice @ExceptionHandler

package com.example.demo.exception;

import com.example.demo.util.ResultBody;
import com.example.demo.util.CommonEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * @author lyd
 * @Description:自定義全域性異常處理類
 * @date 16:12
 */
@ControllerAdvice
public class MyExceptionHandler {

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

	/**
	 * 自定義的業務異常處理程式
	 *
	 * @param httpServletRequest http servlet請求
	 * @param ex
	 * @return {@link ResultBody}
	 */
	@ExceptionHandler(value = BizException.class)
	@ResponseBody
	public ResultBody bizExceptionHandler(HttpServletRequest httpServletRequest, BizException ex) {
		logger.error("啦啦啦啦啦發生業務異常,原因是:" + ex.getErrorMsg());
		return ResultBody.error(ex.getErrorCode(), ex.getErrorMsg());
	}

	/**
	 * 空指標異常處理程式
	 *
	 * @param req 要求的事情
	 * @param e   e
	 * @return {@link ResultBody}
	 */
	@ExceptionHandler(value = NullPointerException.class)
	@ResponseBody
	public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
		logger.error("啦啦啦啦發生空指標異常!原因是:", e);
		return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
	}

	/**
	 * 其他異常處理程式
	 *
	 * @param req 要求的事情
	 * @param e   e
	 * @return {@link ResultBody}
	 */
	@ExceptionHandler(value = Exception.class)
	@ResponseBody
	public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {
		logger.error("啦啦啦啦發生未知異常!原因是:", e);
		return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
	}

}

7.定義一個實體類,等會掉介面測試使用

package com.example.demo.pojo;

import java.io.Serializable;

/**
 * @author lyd
 * @Description:
 * @date 17:19
 */
public class User implements Serializable {

	private int id;
	private String name;
	private int age;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

8.controller層定義幾個介面做測試

package com.example.demo.controller;

import com.example.demo.exception.BizException;
import com.example.demo.pojo.User;
import org.springframework.web.bind.annotation.*;

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

@RestController
public class UserRestController {


	@PostMapping("/user")
	public boolean insert(User user) {
		System.out.println("開始新增...");
		//如果姓名為空就手動丟擲一個自定義的異常!
		if (user.getName() == null) {
			throw new BizException("-1", "使用者姓名不能為空!");
		}
		return true;
	}

	@PutMapping("/user")
	public boolean update(User user) {
		System.out.println("開始更新...");
		//這裡故意造成一個空指標的異常,並且不進行處理
		String str = null;
		str.equals("111");
		return true;
	}

	@DeleteMapping("/user")
	public boolean delete(User user) {
		System.out.println("開始刪除...");
		//這裡故意造成一個字元轉換異常,並且不進行處理
		Integer.parseInt("abc123");
		System.out.println("發生異常後繼續執行");
		return true;
	}

	@GetMapping("/user")
	public List<User> findByUser(User user) {
		System.out.println("開始查詢...");
		List<User> userList = new ArrayList<>();
		User user2 = new User();
		user2.setId(1);
		user2.setName("liuliu");
		user2.setAge(18);
		userList.add(user2);
		return userList;
	}


}

最後使用postman測試

先使用Post請求測試

可以看到有手動異常丟擲

再測一下Delete請求的,看看自動的捕捉異常