龙空技术网

从源码看struts异常处理过程,教你自定义异常

芒格果子 161

前言:

如今看官们对“apachejsp显示源码”大体比较关注,大家都需要学习一些“apachejsp显示源码”的相关资讯。那么小编同时在网摘上汇集了一些关于“apachejsp显示源码””的相关内容,希望各位老铁们能喜欢,咱们一起来了解一下吧!

编程式异常

• 概念:在Action中调用业务逻辑层对象的方法时,用 try-catch 的方式来截获异常之后,手工对异常进行处理

• 处理:使用 struts 的消息处理机制 -- 创建消息对象并传递最后处理

• 处理过程:

○ 截获异常

○ 针对异常创建消息文本对象

○ 将消息文本对象进行传递

§ 将 ActionMessage 放到 ActionMessages 中

§ 将 ActionMessages 放到内置对象中

○ 处理异常

§ <html:messages/> 标签

§ <html:error/> 标签

• 实例:动态信息国际化 -- 编程式异常

声明式异常

• 概念:进行相应的配置后,由 struts 来处理异常,不需要手工在 Action 中进行捕获异常并处理

• 配置:

○ 在 struts-config.xml 中进行 <exception> 标签的配置

○ 在与请求对应的 <action> 标签中进行 input 属性的配置

• 缺点:

○ 代码量大,配置量大

○ 只能添加一个动态填充

• 优点:

○ 不需要手工写异常代码

声明式异常实例

• Tomcat 一启动就将 web.xml 文件读取到内存,读取 <servlet> 标签创建出中央控制器 ActionServlet ,再将主配文件 struts-config.xml 读取到内存实际是读取到内存的一个文件对象 ModuleConfigImpl [ 实现 ModuleConfig 接口 ] 中进行管理 -- 将主配文件封装到 ModuleConfigImpl 文件对象中

• ModuleConfigImpl() // 此对象继续封装配置信息

public ModuleConfigImpl( String prefix) { this.exceptions = new HashMap(); }

ModuleConfigImpl 对象创建一个 Map 集合 exceptions :

□ exceptions:存放 ExceptionConfig 对象 -- key 为 type,value 为 ExceptionConfig 对象

□ ExceptionConfig 对象 -- 封装对应的 <exception> 标签中的各个属性

® ExceptionConfig 由 exceptions 来管理,数据结构为 Bean

□ <exception> 标签中有五个属性:

® key:国际化资源文件中的 key

® type:异常的类型

® path:处理完异常后到哪个页面显示异常信息

® scope:默认为 request

® handle:默认为 ExceptionHandle

• 进入首页:

------------------------- ExceptionConfig.java

public class ExceptionConfig implements Serializable {protected String handler = "org.apache.struts.action.ExceptionHandler"; protected String key = null;protected String path = null; protected String scope = "request"; protected String type = null; }

• 进入登录页面:

<form action="login.do" method="post"><bean:message key="user.username"/>:<input type="text" name="username"><br><bean:message key="user.password"/>:<input type="password" name="password"><br><input type="submit" value="<bean:message key="user.button.login"/>"></form>

• 用户输入用户名和密码,提交请求,请求字符串:

• Tomcat 处理国际化信息:

○ 创建 request 接收协议头中的 locale 信息

○ 取得用户对应的 session

○ 将从 request 中取得的 locale 信息设置到 session 中,属性名为 Globals.LOCALE_KEY

• Tomcat 将 .do 请求提交给 struts

• struts 截取到 path="/login"

• struts 处理 locale 信息 -- processLocale():

○ 拿到当前用户对应的 session

○ 看 session 中是否有属性名为 Globals.LOCALE_KEY 的属性值

□ 如果有值就使用原值

□ 如果没有,从 request 中拿到 locale 信息并将取得的 locale 信息设置到 session 中,属性名为 Globals.LOCALE_KEY

• 在 struts-config.xml 中寻找 path="/login" 的 <action> 标签:

<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"/></action>

• 通过 name 找 ActionForm -- 创建出 ActionForm 对象后将表单数据收集到 LoginActionForm: private String username; -- "tom"

private String password; -- "123"

• 通过 type 创建出 Action 对象,并执行 Action 中的 execute() 方法:

------------------------- LoginAction.java LoginActionForm laf = (LoginActionForm)form; String username = laf.getUsername();String password = laf.getPassword(); UserManager.getInstance().login(username, password); return mapping.findForward("success");

• 调用业务层 login() 方法:

if (!"admin".equals(username)) { throw new UserNotFoundException(username); } if (!"admin".equals(password)) { throw new PasswordErrorException(); }• 此时用户名不正确,抛出 UserNotFoundException 异常给 Action 的 execute() 方法:public class UserNotFoundException extends RuntimeException {public UserNotFoundException(String msg) { super(msg); } // super 调用父类方法}

• Action 声明了抛出异常,不处理业务对象跑出来的异常,故再往前抛异常到processException() 方法中处理异常:

---------------------------------- processActionPerform(request, response, action, form, mapping) try { return (action.execute(mapping, form, request, response));

}catch (Exception e) { // 抛给 struts 一个异常

return ( processException(request, response, e, form, mapping)); } } // e -- 抛出的异常对象的地址

○ 返回给 struts 一个 ActionForward 对象 [ 封装 name / path 跳转路径 / redirect 跳转方式]

---------------------------------- processException(request, response, e, form, mapping)

protected ActionForward processException( HttpServletRequest request, HttpServletResponse response, Exception exception,ActionForm form,ActionMapping mapping) throws IOException, ServletException { 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); }}

---------------------------------- findException(exception.getClass()) public ExceptionConfig findException(Class type) {

ExceptionConfig config = null; // ExceptionConfig 对象中封装了 <exception> 标签中的所有属性String name = type.getName(); // 将异常对象的类名赋给name 变量

config = findExceptionConfig(name); if (config != null) { return (config); }

// 如果与请求对应的<action> 标签中没有对应 type 的 <exception> 标签,struts 会去整个配置文件中找<exception> 标签config = getModuleConfig().findExceptionConfig(name);

}

---------------------------------- findExceptionConfig(name) ExceptionConfig findExceptionConfig(String type) {

return ((ExceptionConfig) exceptions.get(type));

}

® exception.getClass().getName() -- 如果不写 getName() 也显示反射类的类名 -- 取得异常对象的类型

® 通过异常对象类型,从该请求配置文件中对应的 <action> 中按照 type 来找和异常对应的 <exception> 标签

◊ 如果没有对应type 的<exception> 标签,struts 会去整个配置文件中找 <exception> 标签

□ config:封装 <exception> 标签的 ExceptionConfig

□ 取得 ExceptionHandler 类后,通过反射方法创建出 ExceptionHandler 对象

□ 调用 ExceptionHandler 的 execute() 方法,最后返回一个ActionForward 对象

---------------------------------- execute(exception, config, mapping, form, request, response)

public ActionForward execute( Exception ex, ExceptionConfig ae, ActionMapping mapping, ActionForm formInstance, HttpServletRequest request, HttpServletResponse response) throws ServletException { ex:封装的异常对象 / ae:封装了 <exception> 标签中的各个属性

ActionForward forward = null; ActionMessage error = null; String property = null;

if (ae.getPath() != null) { forward = new ActionForward(ae.getPath());

} else { forward = mapping.getInputForward(); }

} 从 <exception> 标签中取得 path 属性值 -- 作为ActionForward 对象中的 forward 转向信息

} 如果 <exception> 标签中没有配置 path 属性,就去与请求对应的 <action> 中获取 input 属性的值作为forward 转向信息

if (ex instanceof ModuleException) {

error = ((ModuleException) ex).getActionMessage(); property = ((ModuleException) ex).getProperty();} else {error = new ActionMessage(ae.getKey(), ex.getMessage()); property = error.getKey();}

} 创建国际化消息文本对象:

– key 为 <exception> 标签中的 key -- 即国际化资源文件中的 key

– value 为异常对象的 message -- 作为动态填充符

} 将国际化消息文本对象中的 key 作为 ActionMessages 中messages 集合的 key

request.setAttribute(Globals.EXCEPTION_KEY, ex); this.storeException(request, property, error, forward, ae.getScope()); return forward;

}

---------------------------------- storeException(request, property, error, forward, ae.getScope()) protected void storeException( HttpServletRequest request, String property,

ActionMessage error, ActionForward forward, String scope) {

ActionMessages errors = new ActionMessages(); errors.add(property, error);

– 创建 ActionMessages 对象

– 将国际化文本对象作为 value 放入 ActionMessages 对象中的 Map 集合中,key 为国际化资源文件中的 key

if ("request".equals(scope)) { request.setAttribute(Globals.ERROR_KEY, errors);

} else {

request.getSession().setAttribute(Globals.ERROR_KEY, errors);

}

}

• 异常流程完成后返回给 struts 一个 ActionForward 对象,struts 解析后跳转到 jsp 页面 -- login_error.jsp:

<html:errors/> -- 直接进行异常信息的输出

复写 ExceptionHandler 类

• ExceptionHandler 类 - 语法:

○ 继承 ExceptionHandler 类

○ 要有 execute() 方法

• 优点:

○ 用一个异常类处理多个异常对象

○ 可以有多个动态填充符

○ 只需要配置一个 <exception> 标签,且该标签可以使用为 <global-exceptions> 全局标签

• 缺点:

○ 要复写 ExceptionHandler 类 -- 比较规范

--------------------------------------------------------------------------------------------------------------------------------------

• 写一个自定义异常类 -- 可以处理所有的异常对象,有多个构造方法: public class ErrorCodeException extends RuntimeException {

private String errorCode; // 国际化资源文件中的 key

private Object[] args; // 动态填充信息,类型为数组对象类型-- 可以填充多个

public ErrorCodeException(String errorCode) { this(errorCode, null); }public ErrorCodeException(String errorCode, Object args0) { this(errorCode, new Object[]{args0}); }public ErrorCodeException(String errorCode, Object[] args) { this.errorCode = errorCode; this.args = args; }}• struts-config.xml:<global-exceptions><exception key="error.exception" type="com.bjsxt.struts.ErrorCodeException" handler="com.bjsxt.struts.ErrorCodeExceptionHandler"/></global-exceptions>○ 此时使用的 handler 是自己复写的,不能使用 ExceptionHandler<action path="/login" type="com.bjsxt.struts.LoginAction" name="loginForm" scope="request"validate="false" input="/login.jsp"><forward name="success" path="/login_success.jsp"/></action>• 调用业务层 login() 方法:if (!"admin".equals(username)) { throw new ErrorCodeException("user.not.found", username); } if (!"admin".equals(password)) { throw new ErrorCodeException("user.password.error"); }

○ 通过有参的构造方法,向异常类中设值 -- 国际化资源文件中的 key,如果需要填充符则设置动态填充符errorCode = "user.not.found";

Object[] args = { tom };

--------------------------------------

errorCode = "user.password.error"; Object[] args = null;

○ 抛出异常的对象不一样,但是类型都是同一个异常类 -- 一定要调用有参的构造方法

• Action 声明了抛出异常,不处理业务对象跑出来的异常,故再往前抛异常到processException() 方法中处理异常:

---------------------------------- processActionPerform(request, response, action, form, mapping)

---------------------------------- processException(request, response, e, form, mapping)) ExceptionConfig config = mapping.findException(exception.getClass());

try {

此时获取到的是<global-exceptions> 中的<exception> 标签中的属性

ExceptionHandler handler = (ExceptionHandler)RequestUtils.applicationInstance(config.getHandler()); return (handler.execute(exception, config, mapping, form, request, response));

®

取得 ExceptionHandler 类,此时为自己复写的类 -- 通过反射创建出 ErrorCodeExceptionHandler 对象

® 调用复写类 ErrorCodeExceptionHandler 类的 execute() 方法,最后返回一个ActionForward 对象

} catch (Exception e) { throw new ServletException(e); }

---------------------------------- execute(exception, config, mapping, form, request, response)

public class ErrorCodeExceptionHandler extends ExceptionHandler {public ActionForward execute( Exception ex, ExceptionConfig ae, ActionMapping mapping, ActionForm formInstance, HttpServletRequest request, HttpServletResponse response) throws ServletException {// 如果异常类型不是 ErrorCodeException,就调用父类的 execute() 方法,最后返回一个 ActionForward 对象给 strutsif ( !(ex instanceof ErrorCodeException) ) { return super.execute(ex, ae, mapping, formInstance, request, response); } ActionForward forward = null; ActionMessage error = null; String property = null; if (ae.getPath() != null) { forward = new ActionForward(ae.getPath());} else { forward = mapping.getInputForward(); }} 从 <exception> 标签中取得 path 属性值 -- 作为ActionForward 对象中的 forward 转向信息

} 如果 <exception> 标签中没有配置 path 属性,就去与请求对应的 <action> 中获取 input 属性的值作为forward 转向信息

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();

– 将 Exception 异常对象造型为 ErrorCodeException 自定义异常对象类型

标签: #apachejsp显示源码