定义
捕获异常并定位到指定视图。
ps:从这给类的原型,可以帮助我们思考异常如何以日志形式记录,可以再此类的基础上进行扩展。这个待日后有慢慢琢磨。
使用
1.局部exception配置使用
Action源码:
public class SourceCoreAction {
public String error() throws ClassNotFoundException {
System.out.println("do the error!");
Class.forName("xxx");
return "success";
}
}
struts-xxx.xml配置:
<action name="error" class="com.company.strutstudy.web.action.core.SourceCoreAction"
method="error">
<interceptor-ref name="exception"></interceptor-ref><!--只有一个默认拦截器起作用,好debug-->
<result name="input">/core/exception.jsp</result>
<result name="success">/core/ok.jsp</result>
<exception-mapping result="input" exception="java.lang.Exception"></exception-mapping>
</action>
2.全局exception配置使用
Action源码不变,参考局部exception
struts-xxx.xml配置:
<struts>
<package name="exception" extends="struts-default" abstract="true">
<global-results>
<result name="input">/core/exception.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="input" exception="java.lang.Exception"></exception-mapping>
</global-exception-mappings>
</package>
<package name="core" extends="exception">
<action name="error"class="com.company.strutstudy.web.action.core.SourceCoreAction" method="error">
<interceptor-ref name="exception"></interceptor-ref>
<result name="success">/core/ok.jsp</result>
</action>
</package>
</struts>
源码阅读
public class ExceptionMappingInterceptor extends AbstractInterceptor {
protected static final Log log = LogFactory.getLog(ExceptionMappingInterceptor.class);
protected Log categoryLogger;
protected boolean logEnabled = false;
protected String logCategory;
protected String logLevel;
....getset省略
public String intercept(ActionInvocation invocation) throws Exception {
String result;
/*
* 处理action或拦截器执行的异常
*/
try {
result = invocation.invoke();
} catch (Exception e) {
//默认为false
if (logEnabled) {
handleLogging(e);
}
//获取全局或局部与该action相关的exception映射信息
List exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings();
//获取异常发生以后的逻辑视图(resultcode)
String mappedResult = this.findResultFromExceptions(exceptionMappings, e);
if (mappedResult != null) {
result = mappedResult;
//将异常信息压入栈顶,异常信息可在页面通过ognl进行获取。
publishException(invocation, new ExceptionHolder(e));
} else {
throw e;
}
}
return result;
}
/**
* Handles the logging of the exception.
*
* @param e the exception to log.
*/
protected void handleLogging(Exception e) {
if (logCategory != null) {
if (categoryLogger == null) {
// init category logger
categoryLogger = LogFactory.getLog(logCategory);
}
doLog(categoryLogger, e);
} else {
doLog(log, e);
}
}
/**
* Performs the actual logging.
*
* @param logger the provided logger to use.
* @param e the exception to log.
*/
protected void doLog(Log logger, Exception e) {
if (logLevel == null) {
logger.debug(e.getMessage(), e);
return;
}
if ("trace".equalsIgnoreCase(logLevel)) {
logger.trace(e.getMessage(), e);
} else if ("debug".equalsIgnoreCase(logLevel)) {
logger.debug(e.getMessage(), e);
} else if ("info".equalsIgnoreCase(logLevel)) {
logger.info(e.getMessage(), e);
} else if ("warn".equalsIgnoreCase(logLevel)) {
logger.warn(e.getMessage(), e);
} else if ("error".equalsIgnoreCase(logLevel)) {
logger.error(e.getMessage(), e);
} else if ("fatal".equalsIgnoreCase(logLevel)) {
logger.fatal(e.getMessage(), e);
} else {
throw new IllegalArgumentException("LogLevel [" + logLevel + "] is not supported");
}
}
private String findResultFromExceptions(List exceptionMappings, Throwable t) {
String result = null;
// Check for specific exception mappings.
if (exceptionMappings != null) {
int deepest = Integer.MAX_VALUE;
for (Iterator iter = exceptionMappings.iterator(); iter.hasNext();) {
ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) iter.next();
int depth = getDepth(exceptionMappingConfig.getExceptionClassName(), t);
if (depth >= 0 && depth < deepest) {
deepest = depth;
result = exceptionMappingConfig.getResult();
}
}
}
return result;
}
/**
* Return the depth to the superclass matching. 0 means ex matches exactly. Returns -1 if there's no match.
* Otherwise, returns depth. Lowest depth wins.
*
* @param exceptionMapping the mapping classname
* @param t the cause
* @return the depth, if not found -1 is returned.
*/
public int getDepth(String exceptionMapping, Throwable t) {
return getDepth(exceptionMapping, t.getClass(), 0);
}
private int getDepth(String exceptionMapping, Class exceptionClass, int depth) {
if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
if (exceptionClass.equals(Throwable.class)) {
return -1;
}
return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
}
/**
* Default implementation to handle ExceptionHolder publishing. Pushes given ExceptionHolder on the stack.
* Subclasses may override this to customize publishing.
*
* @param invocation The invocation to publish Exception for.
* @param exceptionHolder The exceptionHolder wrapping the Exception to publish.
*/
protected void publishException(ActionInvocation invocation, ExceptionHolder exceptionHolder) {
invocation.getStack().push(exceptionHolder);
}
}