前言
?? 在Java項(xiàng)目中祖屏,在控制器、業(yè)務(wù)層效斑、數(shù)據(jù)庫(kù)操作的過(guò)程中非春,總是會(huì)遇到各種可控和不可控的異常需要處理,如果我們?cè)诿恳粋€(gè)異郴和溃可能出現(xiàn)的地方都手動(dòng)使用try{}catch{}單獨(dú)處理異常的話奇昙,會(huì)產(chǎn)生的最大的問(wèn)題就是:異常處理過(guò)程中的返回錯(cuò)誤信息、日志打印都可能不統(tǒng)一敌完,導(dǎo)致代碼冗余和不可維護(hù)敬矩。因此我們使用統(tǒng)一的方式處理異常:
本文內(nèi)容
一、SpringMVC處理異常方式:
- 使用@ExceptionHandler注解:弊端:進(jìn)行異常處理的方法必須與出錯(cuò)的方法在同一個(gè)Controller里面蠢挡;
- 實(shí)現(xiàn)HandlerExceptionResolver接口:可以進(jìn)行全局的異郴≡溃控制。
- 使用@ControllerAdvice注解:使用了該注解之后业踏,需要進(jìn)行異常處理的方法與出錯(cuò)的方法就不必須在同一個(gè)Controller中了禽炬。@ControllerAdvice + @ExceptionHandler也可以實(shí)現(xiàn)全局的異常捕捉。
二勤家、為控制器添加通知
如果要在多個(gè)控制器中處理異常腹尖,使用@ExceptionHandler注解是很有用的,但是如果多個(gè)控制器類(lèi)中都會(huì)拋出異常伐脖,那么所有的控制器中都有重復(fù)相同的@ExceptionHandler方法热幔。因此乐设,需要?jiǎng)?chuàng)建一個(gè)基礎(chǔ)的控制器類(lèi),所有的控制器要擴(kuò)展這個(gè)類(lèi)绎巨,從而繼承通用的@ExceptionHandler方法近尚。
?? Spring3.2引入了一個(gè)新的解決方案:控制器通知〕∏冢控制器通知是所有帶有@ControllerAdvice注解的類(lèi)戈锻,這個(gè)類(lèi)會(huì)包含一個(gè)或多個(gè)如下類(lèi)型的方法:
- @ExceptionHandler注解標(biāo)注的方法;
- @InitBinder注解標(biāo)注的方法和媳;
- @ModelAttribute注解標(biāo)注的方法格遭;
?? @ControllerAdvice可以將所有的@ExceptionHandler方法收集到一個(gè)類(lèi)中,把所有的控制器異常進(jìn)行一致的處理留瞳。
添加ControllerAdviceHandler.java
代碼并添加掃描:
package com.weyoung.framework.config;
import com.weyoung.framework.exception.BusinessException;
import com.weyoung.framework.web.Message;
import com.weyoung.platform.pojo.UserInfo;
import org.apache.log4j.Logger;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import static com.weyoung.framework.common.Constants.SESSION_DEFAULT;
import static com.weyoung.framework.common.ErrorConstants.EXCEPTION_SYSTEM_MSG;
/**
* @作者 weyoung
* @功能描述 給控制器請(qǐng)求添加默認(rèn)常用參數(shù)拒迅,統(tǒng)一處理異常
* @日期 2019/3/4
*/
@ControllerAdvice
public class ControllerAdviceHandler {
private static final Logger logger = Logger.getLogger(ControllerAdviceHandler.class);
/**
* @Description // 添加用戶(hù)信息,可以在Controller中獲取
**/
@ModelAttribute("BasUser")
public UserInfo basUser(HttpServletRequest request) {
HttpSession session = request.getSession(true);
UserInfo user = (UserInfo) session.getAttribute(SESSION_DEFAULT);
return user;
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Message exceptionHandler(Exception ex) {
// 處理業(yè)務(wù)異常
if (ex instanceof BusinessException) {
logger.error("BusinessException", ex);
// 返回業(yè)務(wù)異常code和message;
return Message.failed(((BusinessException) ex).getCode(), ex.getMessage());
} else {
logger.error("Exception", ex);
return Message.failed(Message.FAILED_CODE, EXCEPTION_SYSTEM_MSG);
}
}
}
三她倘、處理業(yè)務(wù)異常
BusinessException.java
package com.weyoung.framework.exception;
import com.weyoung.framework.web.Message;
/**
* @作者 weyoung
* @功能描述 業(yè)務(wù)異常處理
* @日期 2019/3/4
*/
public class BusinessException extends RuntimeException {
private int code;
public BusinessException(String message) {
super(message);
this.code = Message.FAILED_CODE;
}
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
測(cè)試璧微,在Controller中throw一個(gè)Exception,發(fā)現(xiàn)可以進(jìn)入該通知了帝牡,配置成功往毡。
在業(yè)務(wù)處理類(lèi)中遇到可預(yù)知或不可預(yù)知的錯(cuò)誤蒙揣,直接由程序攔截處理靶溜,我們開(kāi)發(fā)時(shí)只管throw Exception即可,控制器通知可以幫助我們處理和返回異常信息懒震。
個(gè)人認(rèn)為使用消息實(shí)體比如本文的Message類(lèi)來(lái)統(tǒng)一規(guī)范地處理異常罩息,不同的業(yè)務(wù)異常最好定義單獨(dú)的error code,產(chǎn)生異常的信息和具體原因整理成文檔个扰,這樣可以在上線之后不至于把敏感的錯(cuò)誤信息返回到前端瓷炮,又便于運(yùn)維、實(shí)施同事能夠快速地定位異常递宅。
相關(guān)文章推薦
源碼下載
?? 該項(xiàng)目持續(xù)更新中,會(huì)在代碼以及該文檔里面詳細(xì)注釋和介紹办龄。項(xiàng)目托管在<code>碼云</code>開(kāi)源平臺(tái)上烘绽,持續(xù)更新項(xiàng)目源碼鏈接:
https://gitee.com/nelucifer/ssm-note,點(diǎn)擊<code>克隆/下載</code>獲取該項(xiàng)目俐填。