企業級應用需統一處理控制層、服務層、資料層拋出的異常,避免重複 try-catch 污染業務代碼。Spring MVC 提供四種異常處理機制:SimpleMappingExceptionResolver(XML 配置)、繼承 SimpleMappingExceptionResolver 自定義、實作 HandlerExceptionResolver 介面、@ExceptionHandler 註解。本文以自定義業務異常體系為例,完整示範四種方案的配置與代碼。
// 基礎業務異常
public class UserException extends Exception { ... }
// 具體異常
public class NameException extends UserException { ... }
public class AgeException extends UserException { ... }
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="error.jsp" /> <!-- 預設錯誤頁 -->
<property name="exceptionAttribute" value="ex" /> <!-- 頁面取異常 ${ex.message} -->
<property name="exceptionMappings"> <!-- 指定異常對應頁面 -->
<props>
<prop key="cn.zhang.exception.AgeException">error/ageerrors.jsp</prop>
<prop key="cn.zhang.exception.NameException">error/nameerrors.jsp</prop>
</props>
</property>
</bean>
Controller 拋出異常即自動跳轉對應頁面。
若需在解析過程中記錄日誌、發送告警,可繼承並覆寫 doResolveException:
public class CustomExceptionResolver extends SimpleMappingExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) {
log.error("業務異常", ex);
// 可在此動態決定視圖
return super.doResolveException(req, resp, handler, ex);
}
}
XML 註冊:<bean class="cn.zhang.resolvers.CustomExceptionResolver" />
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/errors.jsp"); // 預設
if (ex instanceof NameException) mv.setViewName("/error/nameerrors.jsp");
if (ex instanceof AgeException) mv.setViewName("/error/ageerrors.jsp");
return mv;
}
}
XML 註冊:<bean class="cn.zhang.resolvers.MyHandlerExceptionResolver" />
@Controller
public class MyHandlerExceptionResolver {
@ExceptionHandler
public ModelAndView resolveException(Exception ex) {
ModelAndView mv = new ModelAndView();
mv.addObject("ex", ex);
mv.setViewName("/errors.jsp");
if (ex instanceof NameException) mv.setViewName("/error/nameerrors.jsp");
if (ex instanceof AgeException) mv.setViewName("/error/ageerrors.jsp");
return mv;
}
}
Controller 繼承該類或掃描到同包即可生效。優勢:可直接在 Controller 類內定義處理方法,支援多方法處理不同異常,程式碼內聚性高。
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| SimpleMappingExceptionResolver | 零代碼、集中配置 | 無法執行自定義邏輯(日誌、告警) | 簡單專案、快速原型 |
| 繼承 SimpleMappingExceptionResolver | 擴充點清晰、復用 XML 映射 | 仍受限於父類流程 | 需在解析前後加邏輯 |
| 實作 HandlerExceptionResolver | 完全控制解析流程 | 樣板代碼多、需手動判斷異常型別 | 複雜異常處理邏輯 |
| @ExceptionHandler | 程式碼內聚、支援多方法、可注入 Spring Bean | 分散在各 Controller/Advice 類 | 現代 Spring MVC 首選 |
@ControllerAdvice 定義全域異常處理類,集中管理所有 @ExceptionHandler 方法。{code, message, data},配合 @ResponseBody + ResponseEntity 控制 HTTP 狀態碼。