• 观点:在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>
• 用户输入用户名和密码,提交要求,要求字符串:http://127.0.0.1:8080/test/login.do
• 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 自定义非常工具类型