在開發階段,遇到bug是常事,爲了給了用戶良好的體驗,我們肯定得處理異常,比如跳轉到一個錯誤頁面打印對應的信息,而不是直接出現異常頁面或者沒有任何反應,所以說統一一個全局的異常處理是很必要的。
對於SpringBoot項目或SSM項目可借鑑的異常處理思路:
系統遇到異常時,在程序中手動拋出,dao拋給service,service再拋給Controller,最後Controller拋給前端控制器,前端控制器調用全局異常處理器
如下圖:
代碼如下:
聲明一個全局的異常類(可選可不選)
/**
* @program: flea
* @classname: BadArgumentsException
* @description: 錯誤參數異常
* @author: 南街
* @create: 2019-11-09 08:46
**/
public class BizException extends RuntimeException {
/**
* 默認關閉棧追蹤信息和掛起參數 優化性能
* https://blog.csdn.net/neosmith/article/details/82626960
* @param message
* @return
* @date 2019/11/9 9:55
*/
public BizException(String message) {
super(message, null, false, false);
}
public BizException(String message, Throwable cause) {
super(message, cause, false, false);
}
protected BizException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
聲明全局異常處理器(返回json數據,因爲我的項目是通過json來交互的)
@ExceptionHandler 需要進行異常處理的方法必須與出錯的方法在同一個Controller裏面。那麼當代碼加入了 @ControllerAdvice,則不需要必須在同一個 controller 中了。這也是 Spring 3.2 帶來的新特性。從名字上可以看出大體意思是控制器增強。 也就是說,@controlleradvice + @ ExceptionHandler 也可以實現全局的異常捕捉。
package com.changda.flea.management.config;
import com.changda.flea.common.constants.HttpStatusEnum;
import com.changda.flea.common.exception.BizException;
import com.changda.flea.common.util.Result;
import com.changda.flea.common.util.ResultGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @description: 全局異常統一處理類
* @author: 南街
* @create: 2019-01-17 10:24
**/
@RestControllerAdvice
public class ApplicationControllerExceptionHandler {
/**
* 方法參數效驗 針對validation
*
* @param ex
* @return com.zhulin.ascentweb.dto.Result
* @date 2019/9/8 9:58
*/
@ExceptionHandler(value = BindException.class)
@ResponseBody
public Result<String> bindException(BindException ex) {
StringBuilder message = new StringBuilder();
ex.getBindingResult().getAllErrors()
.forEach(error -> message.append(error.getDefaultMessage()).append(","));
return ResultGenerator.getResultByHttp(HttpStatusEnum.BAD_REQUEST,
message.substring(0,message.length()-1));
}
/**
* 方法參數效驗 針對validation
*
* @param ex
* @return com.zhulin.ascentweb.dto.Result
* @date 2019/9/8 9:58
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseBody
public Result<String> handlerMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
StringBuilder message = new StringBuilder();
ex.getBindingResult().getAllErrors()
.forEach(error -> message.append(error.getDefaultMessage()).append(","));
return ResultGenerator.getResultByHttp(HttpStatusEnum.BAD_REQUEST,
message.substring(0,message.length()-1));
}
/**
* @RequestParam 註解請求參數有誤
* @date 2019/11/8 20:09
*/
@ExceptionHandler(value = MissingServletRequestParameterException.class)
@ResponseBody
public Result<String> missingServletRequestParameterException(MissingServletRequestParameterException e) {
return ResultGenerator.getResultByHttp(HttpStatusEnum.BAD_REQUEST);
}
/**
* @RequestParam 業務異常
* @date 2019/11/8 20:09
*/
@ExceptionHandler(value = BizException.class)
@ResponseBody
public Result<String> bizException(BizException e) {
return ResultGenerator.getResultByHttp(HttpStatusEnum.BAD_REQUEST, e.getMessage());
}
}
我這裏意思就是如果出現異常,統一都返回錯誤提示給用戶,告訴用戶,系統碰到了一些預期之外的錯誤
也許有些小夥伴可能需要在一個方法中區分是系統異常還是自定義異常,然後返回對應的異常的信息,那就參考如下:
@ControllerAdvice
public class ApplicationControllerExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public MessageBean handlerError(HttpServletRequest req, Exception e) {
// MessageBean一個前後臺交互的Json實體類,包括success,msg,data屬性
if (e instanceof 自定義異常){
return new MessageBean(false,e.msg());
}
return new MessageBean(false, Constants.ERROR_MSG);
}
}
如上都是提供思路,代碼僅供參考,直接複製可能報錯哦。
這裏的MessageBean和Result其實就是統一返回結果集,下面粘貼我平常使用的結果集。
/**
* 返回結果集
* @author: 南街
*/
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int resultCode;
private String message;
private T data;
public Result() {
}
public Result(int resultCode, String message) {
this.resultCode = resultCode;
this.message = message;
}
public int getResultCode() {
return resultCode;
}
public void setResultCode(int resultCode) {
this.resultCode = resultCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
return "Result{" +
"resultCode=" + resultCode +
", message='" + message + '\'' +
", data=" + data +
'}';
}
}