编程式异常:
1、概念:在Action中调用业务逻辑层对象的方法时,用try{ }catch的方式来截获异常之后,手工对异常进行处理
2、在哪里处理?
在Action里的excute里处理
3、处理过程:
1、截获异常
2、创建消息文本对象
3、把消息文本对象放到ActionMessages里
4、把ActionMessages放到request里,属性名为Globals.ERROR_KEY
声明式异常:
概念:在action中不处理异常,把异常交给struts处理
processActionPerform调用action的excute方法
我们需要在配置文件中指示struts如何处理这些被抛出的异常,使用元素来定义自动异常处理
在struts-config.xml文件中配置<exeception/>
标签
<action path="/login"
type="com.bjsxt.struts.LoginAction"
name="loginForm"
scope="request"
validate="false"
input="/login.jsp"
>
<!--
<exception key="user.not.found" type="com.bjsxt.struts.UserNotFoundException" path="/login_error.jsp"/>
<exception key="user.password.error" type="com.bjsxt.struts.PasswordErrorException" path="/login_error.jsp"/>
-->
<forward name="success" path="/login_success.jsp"/>
<forward name="error" path="/login.jsp"/>
</action>
<exception/>
元素的配置,指示了struts如何处理异常的方式
在通常的情况下,我们得到异常以后,需要将页面导航到一个错误提示的页面,提示错误信息
tomcat一启动为<exception />
标签创建了ExceptionConfig,
ExceptionConfig:封装配置信息里的exception标签,有5个属性,(path,scope,handle可以省略)
把ExceptionConfig封装到一个map里,这个map叫Exceptions,这个map的key是type(异常对象类型)
<exception/>
元素配置的关键属性是:
key – 即这个异常所对应的错误提示消息文本的key,这个key的值,需要在资源属性文件中进行定义(国际化资源文件的key)
type – 即定义需要处理哪种类型的Exception( 异常类型)
path – 定义一旦出现异常,需要转向哪个页面来进行提示,如果不定义path属性,默认情况下,将使用Action配置中的input属性的值来作为转向的页面(指定在哪个页面处理异常信息)
scope:可以取值request和session,默认为request
handler:异常的处理类,struts默认采用org.apache.struts.action.ExceptionHandler,如果做个性化的异常处理可以继承此类覆写相应的方法
登录的业务层
public void login(String username, String password) {
if (!"admin".equals(username)) {
throw new UserNotFoundException(username);
}
if (!"admin".equals(password)) {
throw new PasswordErrorException();
}
}
struts源码
protected ActionForward
processActionPerform(HttpServletRequest request,
HttpServletResponse response,
Action action,
ActionForm form,
ActionMapping mapping)
throws IOException, ServletException {
try {
return (action.execute(mapping, form, request, response));
} catch (Exception e) {
return (processException(request, response,
e, form, mapping));
}
}
------------------------------------------------------------------------------
protected ActionForward processException(HttpServletRequest request,
HttpServletResponse response,
Exception exception,
ActionForm form,
ActionMapping mapping)
throws IOException, ServletException {
// Is there a defined handler for this exception?
ExceptionConfig config = mapping.findException(exception.getClass());
---------------------------------------------------------------------
try {
ExceptionHandler handler = (ExceptionHandler)
RequestUtils.applicationInstance(config.getHandler());
return (handler.execute(exception, config, mapping, form,
request, response));
} catch (Exception e) {
throw new ServletException(e);
}
1、通过抛出的异常对象找到异常类(通过反射),然后到ActionMapping里找到exceptions这个map,然后通过key(异常对象的类型)找到ExceptionConfig
2、通过ExceptionConfig拿到handle属性,
public ActionForward execute(
Exception ex, //抛出的异常对象
ExceptionConfig ae, //配置信息里的Exception标签
ActionMapping mapping, //这个请求的配置信息
ActionForm formInstance,
HttpServletRequest request,
HttpServletResponse response)
throws ServletException {
ActionForward forward = null;
ActionMessage error = null;
String property = null;
// Build the forward from the exception mapping if it exists
// or from the form input
if (ae.getPath() != null) {
forward = new ActionForward(ae.getPath());
} else {
forward = mapping.getInputForward();
}
// Figure out the error
if (ex instanceof ModuleException) {
error = ((ModuleException) ex).getActionMessage();
property = ((ModuleException) ex).getProperty();
} else {
error = new ActionMessage(ae.getKey(), ex.getMessage());
property = error.getKey();
}
this.logException(ex);
// Store the exception
request.setAttribute(Globals.EXCEPTION_KEY, ex);
this.storeException(request, property, error, forward, ae.getScope());
return forward;
}
protected void storeException(
HttpServletRequest request,
String property,
ActionMessage error,
ActionForward forward,
String scope) {
ActionMessages errors = new ActionMessages();
errors.add(property, error);
if ("request".equals(scope)) {
request.setAttribute(Globals.ERROR_KEY, errors);
} else {
request.getSession().setAttribute(Globals.ERROR_KEY, errors);
}
}
1、先到exception标签里找到path属性,如果存在就创建ActionForward作为转向,如果不存在就在ActionMapping里找到input属性
2、创建国际化文本对象
3、storeException:把ActionMessage存放到ActionMessages,然后把ActionMessages设置到request里
4、返回到调用这个异常的方法ActionForward,在本例子中是/login_error.jsp
struts处理异常流程
1、用户名不匹配,就创建UserNotFoundException对象,并且通过有参的构造方法调用父类的super把异常信息设置给异常对象的message属性,然后通过throw把创建的异常对象抛出给action的excute方法,action的excute方法再抛给processActionPerform
2、在processActionPerform将异常拦截,然后调用processException方法
3、在processException方法到配置信息里找exceptionConfig,
4、通过ExceptionConfig拿到handle属性(通过反射创建出ExceptionHandler对象,然后执行excute方法)
5、在execute方法里通过ExceptionConfig找path,如果找到了,就用path创建ActionForward,如果没找到,就到ActionMapping里找input属性,都没找到就出错
6、创建国际化文本对象ActionMessage,第一个参数是Exception标签里的key,第二个参数填充符(异常对象信息)
7、把ActionMessage存放到ActionMessages,然后把ActionMessages设置到request里Globals.ERROR_KEY
8、把ActionForward回传给调用方法,struts通过调用processForwardConfig对forward解析,进入到错误页面
修饰标签,每一行用红色代表
errors.header=<UL>
errors.prefix=<LI><font color="red">
errors.suffix=</font></LI>
errors.footer=</UL>
二、用一个异常类,处理多个异常信息
全局exception配置
<global-exceptions>
<!--
<exception key="user.not.found" type="com.bjsxt.struts.UserNotFoundException" path="/login_error.jsp"/>
<exception key="user.password.error" type="com.bjsxt.struts.PasswordErrorException" path="/login_error.jsp"/>
-->
<!--
<exception key="user.not.found" type="com.bjsxt.struts.UserNotFoundException" handler="org.apache.struts.action.ExceptionHandler"/>
<exception key="user.password.error" type="com.bjsxt.struts.PasswordErrorException" handler="org.apache.struts.action.ExceptionHandler"/>
-->
<!--
<exception key="error.exception" type="com.bjsxt.struts.ErrorCodeException" handler="com.bjsxt.struts.ErrorCodeExceptionHandler"/>
-->
<!--
<exception key="error.exception" type="com.bjsxt.struts.AppException" handler="com.bjsxt.struts.AppExceptionHandler"/>
-->
<exception key="error.exception" type="com.bjsxt.struts.AppException"/>
</global-exceptions>
自定义一个异常类,继承RuntimeException
public class ErrorCodeException extends RuntimeException {
private String errorCode;
private Object[] args;
public ErrorCodeException(String errorCode) {
this(errorCode, null);
}
//两个属性,一个是国际化资源的key,一个是动态填充符
public ErrorCodeException(String errorCode, Object args0) {
this(errorCode, new Object[]{args0});
}
public ErrorCodeException(String errorCode, Object[] args) {
this.errorCode = errorCode;
this.args = args;
}
public String getErrorCode() {
return errorCode;
}
public Object[] getArgs() {
return args;
}
}
自定义ErrorCodeExceptionHandler 继承 ExceptionHandler
public class ErrorCodeExceptionHandler extends ExceptionHandler {
public ActionForward execute(
Exception ex,
ExceptionConfig ae,
ActionMapping mapping,
ActionForm formInstance,
HttpServletRequest request,
HttpServletResponse response)
throws ServletException {
//如果这个异常对象不是ErrorCodeException就调用父类
if (!(ex instanceof ErrorCodeException)) {
return super.execute(ex, ae, mapping, formInstance, request, response);
}
ActionForward forward = null;
ActionMessage error = null;
String property = null;
// Build the forward from the exception mapping if it exists
// or from the form input
if (ae.getPath() != null) {
forward = new ActionForward(ae.getPath());
} else {
forward = mapping.getInputForward();
}
// Figure out the error
if (ex instanceof ModuleException) {
error = ((ModuleException) ex).getActionMessage();
property = ((ModuleException) ex).getProperty();
} else {
ErrorCodeException ece = (ErrorCodeException)ex;
String errorCode = ece.getErrorCode();
Object[] args = ece.getArgs();
error = new ActionMessage(errorCode, args);
property = error.getKey();
//error = new ActionMessage(ae.getKey(), ex.getMessage());
//property = error.getKey();
}
this.logException(ex);
// Store the exception
request.setAttribute(Globals.EXCEPTION_KEY, ex);
this.storeException(request, property, error, forward, ae.getScope());
return forward;
}
}
先在请求对应的配置信息里找,没找到再到全局配置里找
public ExceptionConfig findException(Class type) {
// Check through the entire superclass hierarchy as needed
ExceptionConfig config = null;
while (true) {
// Check for a locally defined handler
String name = type.getName();
config = findExceptionConfig(name);
if (config != null) {
return (config);
}
// Check for a globally defined handler
config = getModuleConfig().findExceptionConfig(name);
if (config != null) {
return (config);
}
// Loop again for our superclass (if any)
type = type.getSuperclass();
if (type == null) {
break;
}
}
return (null); // No handler has been configured
}
登录的业务层
public void login(String username, String password) {
if (!"admin".equals(username)) {
throw new ErrorCodeException("user.not.found", username);
}
if (!"admin".equals(password)) {
throw new ErrorCodeException("user.password.error");
}
}
步骤:
1、自定义一个异常类,继承RuntimeException
2、创建异常对象,往ErrorCodeException里设置信息,国际化资源文件的key和动态填充符
3、全局配置,配置自定义的handle
4、覆写ErrorCodeExceptionHandler 继承 ExceptionHandler
优点:
1、用一个异常类处理多个异常对象
2、配置简单
缺点:自己覆写Exception
三、用一个类处理所有的异常,不用覆写 ErrorCodeExceptionHandler
第一种:
优点:
缺点:只能写一个动态填充
第二种:
优点:
缺点:需要覆写
第三种方案:
优点:用一个类处理多个异常对象
2、只配全局exception
3、没有覆写ExceptionHandle
4、可以显示多个动态填充
缺点:无法国际化