Action 方法拋出異常可用 ActionListener 捕獲,但 Managed Bean 建構子異常 發生在建構階段,Filter 僅能捕獲包裝後的 ServletException,無法還原原始異常。
JSF 透過 VariableResolver 解析並實例化 Managed Bean。繼承實作類並覆寫 resolveVariable 即可攔截建構異常。
public class VariableResolverImpl extends org.apache.myfaces.el.VariableResolverImpl {
private static final String ERROR_FLAG = "error";
private static final String EXCEPTION_TYPE = "exception";
@Override
public Object resolveVariable(FacesContext facesContext, String name) {
try {
return super.resolveVariable(facesContext, name);
} catch (Throwable e) {
HttpServletRequest request = (HttpServletRequest)
facesContext.getExternalContext().getRequest();
request.setAttribute(ERROR_FLAG, Boolean.TRUE);
request.setAttribute(EXCEPTION_TYPE, e);
throw new RuntimeException(e); // 保持原始堆疊
}
}
}
<faces-config>
<application>
<variable-resolver>mypackage.VariableResolverImpl</variable-resolver>
</application>
</faces-config>
public class AppFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(req, resp);
} catch (ServletException e) {
Boolean error = (Boolean) req.getAttribute("error");
if (Boolean.TRUE.equals(error)) {
Throwable te = (Throwable) req.getAttribute("exception");
if (te instanceof AppException) {
// 業務異常處理
} else {
// 系統異常處理
}
} else {
// 其他 ServletException
}
}
}
}
VariableResolver.resolveVariable() —— Bean 實例化瞬間Throwable