三、Action及异常处理
一、Action介绍
在Struts2中,Action是最重要的,因为struts2是由多个Action组成的;比如要对业务进行分发都需要使用Action;
Struts2相比Struts1,采用低侵入式设计,即一个普通的Java类也可以作为一个Action,不一定要继承或实现Action接口;
而定义Action通常需要遵循几个规范:
1.可以选择继承ActionSupport;
2.重写public String execute()throws Exception 方法,此方法是访问Action默认调用的方法(当然可以自己设定调用任意方法,此配置需要在struts.xml进行);
3.Action类中的属性是用于封装HTTP请求、页面结果数据的;在访问Action时,如果带有请求参数,则会通过params拦截器对Action同名的属性进行赋值;
Action和ActionSupport:用于规范action类的处理;
二、配置Action
我们在struts.xml中配置Action;
模板:
<struts> <constant name="struts.devMode" value="true"></constant> <package name="" extends="struts-default" namespace="" > <action name="" class=""> <param name="name">xiazdong</param> <result>1.jsp</result> </action> </package> </struts>
配置Action规范:<action>元素必须在<package>中;
下面开始介绍配置action时的常用元素;
1.<package>
package能够用几个属性:
(1)name:表示包名称,通过随意指定即可;
(2)extends:继承哪个父包,如果继承了某个父包,则会继承父包的action;通常我们需要继承 struts-default ,此package定义了内建拦截器;
(3)namespace:定义命名空间,如果不指定,则为默认的命名空间;如果为"/",则表示根命名空间;
(4)abstract:不常用,如果为true,则不能定义action;
举例:
<package name="myPackage" namespace="/" extends="struts-default"> </package>
默认命名空间和根命名空间:
默认命名空间是一个很特殊的命名空间,如果要访问一个action,最后都会在默认命名空间中寻找;
比如/aaa/bbb.action,首先先去命名空间为"/aaa"中去找,如果找不到,则去默认命名空间中寻找bbb.action;
而根命名空间只是一个普通的命名空间;
访问某个action时的URL 通常为: http://localhost:8080/ApplicationName/Namespace/ActionName.action;
命名空间的查找规则:
比如 http://localhost:8080/StrutsProject/a/b/c/d/aa.action;
1.查找是否存在/a/b/c/d 命名空间
如果不存在,则跳到步骤2
如果存在则查找是否存在aa.action
如果不存在该action,则到默认命名空间中查找是否存在aa.action;
如果存在即可;
2.查找是否存在/a/b/c 命名空间
如果不存在,则跳到步骤3
如果存在则查找是否存在aa.action
如果不存在该action,则到默认命名空间中查找是否存在aa.action;
如果存在即可;
3.查找是否存在/a/b 命名空间
如果不存在,则跳到步骤4
如果存在则查找是否存在aa.action
如果不存在该action,则到默认命名空间中查找是否存在aa.action;
如果存在即可;
4.查找是否存在/a 命名空间
如果不存在,则跳到步骤5
如果存在则查找是否存在aa.action
如果不存在该action,则到默认命名空间中查找是否存在aa.action;
如果存在即可;
5.查找是否存在/ 命名空间
如果不存在,则跳到步骤6
如果存在则查找是否存在aa.action
如果不存在该action,则到默认命名空间中查找是否存在aa.action;
如果存在即可;
6.在默认命名空间中查找;
2.<action>
<action>的属性有:
(1)name:指定了Action的名字,也是对外的URL;
(2)class:访问此Action的处理类,不指定则默认为ActionSupport,ActionSupport的返回值为SUCCESS,注意:必须要写出类的全名;
(3)method:如果不指定,则默认调用execute方法,如果指定,则调用此方法;
3.<result>
定义了Action的返回结果所对应的JSP(当然可以是任意的视图页面);
<result>的常用属性为
(1)name:Action方法返回的字符串,默认为success;
(2)type:结果类型,默认为dispatcher,此问题在下面会详细讲解;
代码示例:
<package name="MyPackage" extends="struts-default" namespace="/" > <action name="loginAction" class="org.login.action.LoginAction" > <result name="success" type="redirect"> <param name="location">/result.jsp</param> </result> <result name="error" type="redirect">/result.jsp</result> </action> </package>
逻辑Action和物理Action的区别:
逻辑Action是在struts.xml中配置的action元素,物理Action是实际的Action类;
如果某个Action类存在fun1() 和fun2()方法,则可以定义两个逻辑Action,虽然处理类都是一样的;
局部结果和全局结果:
全局结果是在<global-results>元素中配置,此结果映射关系对于所有action都起作用;
局部结果是在<action>元素中配置,是指此结果映射关系只对特定的Action起作用;
当局部结果和全局结果同时满足要求,则局部结果优先;
全局结果放在<package>元素中,对于该package的所有Action都有效;
全局结果的语法:
<global-results>
<result>
</result>
</global-results>
4.<param>
如果是<action>的子元素,用于为action注入值;
比如
当HelloAction中有name属性,struts.xml中包含如下代码:
<action name="hello" class="org.xiazdong.HelloAction"> <param name="name">xiazdong</param> <result>/1</result> </action>
则执行此action时会自动为name属性赋值;
三、DMI
Dynamic Method Invocation,即动态决定调用Action的哪个方法,即不是提前配置决定,比如一个页面有登陆按钮和注册按钮,只有一个Action类,里面有login()方法和regist()方法,如果点击注册按钮,则调用regist方法,如果点击登录按钮,则调用login()方法,此时可以使用动态方法调用;
注意:在struts2.3 中动态方法调用默认开启,因此不需要配置,否则
<constant name="struts.enable.dynamicMethodInvocation" value="true"></constant>
默认配置文件:struts2-core-2.3.1.1.jar\org\apache\struts2\default.properties;
动态方法调用语法:ActionName!methodName
比如loginAction!login则调用loginAction类中的login方法;
示例代码:
LoginAction.java
package org.login.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport{ private String user; private String password; private String result; public String login()throws Exception{ if(user.equals("xiazdong")&&password.equals("12345")){ setResult("登陆成功"); return SUCCESS; } else{ setResult("登陆失败"); return ERROR; } } public String regist()throws Exception{ setResult("注册成功"); return SUCCESS; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void setResult(String result) { this.result = result; } public String getResult() { return result; } }
login.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>登录界面</title> <script type="text/javascript"> function regist(){ document.forms[0].action = "loginAction!regist"; } </script> </head> <body> <form action="loginAction!login"> 用户名:<input type="text" name="user"/><br /> 密码:<input type="password" name="password"/><br /> <input type="submit" value="登录"/> <input type="submit" value="注册" onClick="regist();"/> </form> </body> </html>
struts.xml
<?xml version="1.0" encoding="GBK" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.devMode" value="true"></constant> <package name="MyPackage" extends="struts-default" namespace="/" > <action name="loginAction" class="org.login.action.LoginAction" > <result name="success" type="redirect"> <param name="location">/result.jsp</param> </result> <result name="error" type="redirect">/result.jsp</result> </action> </package> </struts>
四、通配符使用
我们可能会遇到这种情况:需要配置很多个逻辑Action,但是名称上有许多相似的地方,比如:
<action name="loginAction" class="org.login.action.LoginAction" > <result name="success" type="dispatcher">/result.jsp</result> <result name="error" type="dispatcher">/result.jsp</result> </action> <action name="registAction" class="org.login.action.registAction" > <result name="success" type="dispatcher">/result.jsp</result> <result name="error" type="dispatcher">/result.jsp</result> </action>
则如果使用通配符则可以表示成:
<action name="*Action" class="org.login.action.{1}Action" > <result name="success" type="dispatcher">/result.jsp</result> <result name="error" type="dispatcher">/result.jsp</result> </action>
在name属性中使用“*”,而在class、method、result元素中都可以使用{1}、{2}表示第一个*的值、第二个*的值;
<action name="*">时可以匹配任意的action请求,因为他是位于默认命名空间;
注意:如果同时匹配多个action,则除非完全相同,否则按先后顺序决定;
{N}表达式可以用于class属性、method属性、result属性;
在result中还可以使用${attributeName} 通过OGNL表达式引用Action类的属性的值;
比如 <result>/${name}.jsp
五、默认Action和默认处理类
都配置在<package>元素下;
默认Action是指当全部的action不匹配时,执行此action;
默认处理类是指如果不指定class属性时的处理类,如果不指定,则是ActionSupport;
语法分别如下:
<default-action-ref name="actionName">
<default-class-ref class="Action"/>
六、<result>的type属性
逻辑视图和物理视图的定义:
逻辑视图是Action处理完后的返回值即String,而物理视图是JSP页面;
1.dispatcher
默认值,与JSP相关联;
2.redirect
重定向到JSP页面,与dispatcher的区别是:
dispatcher是服务器跳转;redirect是客户端跳转;
3.redirectAction
重定向到另一个Action类;
<result>子元素<param>可以填写如下两个属性指定Action:
<result type="redirectAction">
<param name="actionName">actionname</param>
<param name="namespace">namespace</param>
</result>
4. stream
一般用于文件下载,此处不细讲;
5.plainText
用于显示视图资源的源代码;
配置plainText的模板:
<result type="plainText">
<param name="location">/index.jsp</param>
<param name="charSet">UTF-8</param>
</result>
七、访问Servlet
ServletActionContext能够很方便的获得Servlet的常用对象;在execute()方法中通过:
HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); PageContext page = ServletActionContext.getPageContext(); ServletContext application = ServletActionContext.getServletContext(); HttpSession session = request.getSession();
获得;
补充:
PreResultListener的使用
PreResultListener触发于执行完Action代码之后、进入物理视图之前;
模板代码如下:
ActionInvocation invocation = ActionContext.getContext().getActionInvocation(); invocation.addPreResultListener(new PreResultListener(){ public void beforeResult(ActionInvocation invocation,String resultCode){ ..... } });
八、异常处理
根据Action的execute方法定义public String execute()throws Exception可知,此方法可以抛出任何异常;因此我们遇到任何异常,只需要抛出,交给struts2的框架即可,框架会通过拦截器exception进行捕捉;
我们在struts.xml中配置异常处理的方案,当execute抛出异常后,就会在struts.xml 中寻找解决方案;
异常分为全局异常和局部异常;
全局异常的语法:
<global-exception-mappings> <exception-mapping exception="" result=""/> </global-exception-mapping>
exception 指定异常所属类;
result是指逻辑视图名;
比如:
<exception-mapping exception="java.sql.SQLException" result="error"/>
局部异常语法:
<action> <exception-mapping exception="" result=""/> </action>
输出异常信息:通过<s:property value="exception.messaeg"/>输出;
代码:
ExceptionAction.java
package org.login.action; import com.opensymphony.xwork2.ActionSupport; public class ExceptionAction extends ActionSupport{ private String str; public String execute()throws Exception{ if("".equals(str) || str==null){ throw new NullPointerException(); } else{ throw new ArithmeticException(); } } }
struts.xml
<action name="exceptionAction" class="org.login.action.ExceptionAction"> <exception-mapping result="xxxx" exception="java.lang.NullPointerException"></exception-mapping> <exception-mapping result="yyyy" exception="java.lang.ArithmeticException"></exception-mapping> <result name="xxxx">/xxxx.jsp</result> <result name="yyyy">/yyyy.jsp</result> </action>