許多企業應用直接拋出 RemoteException、NamingException 等系統級異常到 Web 層,導致前端無法理解業務語義,也難以優雅處理。正確做法是:系統層拋系統異常,業務層拋業務異常,兩者透過異常鏈關聯。
自訂 ApplicationException 作為基礎業務異常,內部攜帶 cause 欄位保存原始低層異常:
public class ApplicationException extends Exception {
private Throwable cause;
public ApplicationException(String msg, Throwable cause) {
super(msg);
this.cause = cause;
}
// 重寫 getMessage/printStackTrace 遞歸輸出完整鏈路
@Override public String getMessage() {
String msg = super.getMessage();
Throwable child = cause;
while (child != null) {
if (child.getMessage() != null) msg += ": " + child.getMessage();
if (child instanceof ApplicationException) break;
child = getNestedException(child);
}
return msg;
}
}
建立「通用 → 業務領域 → 具體場景」三層結構:
ApplicationException (基礎)
├── BusinessException (業務通用)
│ ├── InsufficientFundsException (具體:餘額不足)
│ └── NoSuchBookException (具體:書籍不存在)
│ └── BackorderedException (更細粒度:缺貨訂購)
└── SystemUnavailableException (系統級:服務不可用)
每個具體異常只需提供語義化建構子:
public class NoSuchBookException extends BusinessException {
public NoSuchBookException(String book, String library) {
super("書籍《" + book + "》在「" + library + "」館藏中不存在");
}
}
SQLException 等,包裝為 SystemUnavailableException 拋出InsufficientFundsException 等業務異常投資一套深思熟慮的異常模型,能為專案長期維護節省無數除錯工時。