企業級應用需將異常處理從業務代碼中剝離,實現統一攔截、日誌記錄、友好提示。Spring MVC 提供 HandlerExceptionResolver 接口,支援全局異常解析器模式。
分層向上拋出:DAO → Service → Controller → DispatcherServlet → 全局異常解析器。
public class CustomException extends Exception {
private String message;
public CustomException(String message) {
super(message);
this.message = message;
}
@Override public String getMessage() { return message; }
}
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
CustomException customEx;
if (ex instanceof CustomException) {
customEx = (CustomException) ex; // 業務異常:直接使用自帶訊息
} else {
customEx = new CustomException("未知錯誤"); // 非業務異常:統一轉換
ex.printStackTrace(); // 記錄完整堆棧到日誌
}
ModelAndView mv = new ModelAndView();
mv.addObject("message", customEx.getMessage());
mv.setViewName("error"); // 統一錯誤頁
return mv;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><body>
<h2>系統提示</h2>
<p style="color:red">${message}</p>
</body></html>
<!-- 僅需將實現類註冊為 Bean,Spring MVC 自動識別 -->
<bean class="com.iot.learnssm.firstssm.exception.CustomExceptionResolver" />
注意:全局解析器全應用上下文只生效一個,多註冊無意義。
Service 層拋出(推薦用於業務邏輯相關異常):
public ItemsCustom findItemsById(Integer id) throws Exception {
Items items = itemsMapper.selectByPrimaryKey(id);
if (items == null) {
throw new CustomException("修改的商品信息不存在!");
}
// 複製屬性返回
return itemsCustom;
}
Controller 層拋出(用於參數校驗、權限等非核心業務異常):
@RequestMapping("/editItems")
public String editItems(Model model, @RequestParam("id") Integer itemsId) throws Exception {
ItemsCustom itemsCustom = itemsService.findItemsById(itemsId);
if (itemsCustom == null) {
throw new CustomException("修改的商品信息不存在!");
}
model.addAttribute("items", itemsCustom);
return "items/editItems";
}
原則:業務語義強的異常在 Service 拋出,保持 Service 純粹;表現層相關的在 Controller 處理。
CustomException → 頁面顯示自定義訊息。此機制實現了「用戶看友好提示,開發者查詳細日誌」的雙贏目標。