• 观点:在Action中调用业务逻辑层工具的方法时,用 try-catch 的办法来截获非常之后,手工对非常进行处理

• 处理:利用 struts 的处理机制 -- 创建工具并通报末了处理

• 处理过程:

struts无法跳转jsp页面从源码看struts异常处置进程教你自界说异常 AJAX

○ 截获非常

○ 针对非常创建文本工具

○ 将文本工具进行通报

§ 将 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 自定义非常工具类型