(1)、包和命名空间
Struts2用包来组织Action和拦截器等,每个包就是多个Action、拦截器、拦截器引用的集合;
<package.../>元素常用属性:
name:必须属性,指定该包的名字,让其他包引用的key
extends:指定该包继承其他包(另一个包的name属性:表示让该包继承另一包)(可继承其他包中的Action定义、拦截器定义等)
namespace:定义该包的命名空间
abstract:指定该包是否为一个抽象包(抽象包中不能包含Action定义)
父包应在子包前定义
struts.xml配置文件范例:
<struts> <package name="default" extends="struts-default"> <!-- 下面定义了拦截器部分 --> <interceptors> <!-- 定义拦截器栈 --> <interceptor-stack name="crudStack"> <interceptor-ref name="params" /> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <default-action-ref name="myAction" /> <!-- 定义一个Action,该Action直接映射到show.jsp页面 --> <action name="show"> <result>show.jsp</result> </action> <action name="Date" class="org.crazyit.app.action.DateAction"> <result name="success">/date.jsp</result> </action> </package> <!-- 继承default包 --> <package name="skill" extends="default" namespace="/skill"> <!-- 定义默认的拦截器引用 --> <default-interceptor-ref name="crudStack" /> <action name="Edit" class="lee.SkillAction"> <result>/empmanager/editSkill.jsp</result> <interceptor-ref name="params" /> <interceptor-ref name="basicStack" /> </action> <!-- 使用save方法作为处理方法 --> <action name="Save" class="lee.SkillAction" method="save"> <result name="input">/empmanager/editSkill.jsp</result> <result type="redirect">edit.action?skillName=${currentSkill.name}</result> </action> <!-- 使用delte方法作为处理方法 --> <action name="Delete" class="lee.SkillAction" method="delete"> <result name="error">/empmanager/editSkill.jsp</result> <result type="redirect">edit.action?skillName=${currentSkill.name}</result> </action> </package> </struts>
Struts2的命名空间主要是为了处理同一个Web应用中包含同名Action的情形。同一个命名空间里不能有同名Action,不同的命名空间里可有同名的Action
Struts2不支持为单独的Action设置命名空间,而是通过为包指定namespace属性来为包下面的所有Action指定共同的命名空间;如果配置包时没有指定namespace,则该包下的所有Action处于默认的包空间下
struts2命名空间的用法:
<struts> <constant name="struts.evMode" value="true" /> <!-- 继承struts-default(Struts2默认包),没有指定命名空间,将使用默认命名空间 --> <package name="lee" extends="struts-default"> <action name="login" class="org.crazyit.app.action.LoginAction"> <result name="error">/error.jsp</result> <result name="success">/welcome.jsp</result> </action> </package> <!-- 指定该包的命名空间为/book --> <package name="get" extends="struts-default" namespace="/book"> <action name="getBooks" class="org.crazyit.app.action.GetBooksAction"> <result name="login">/login.jsp</result> <result name="success">/showBook.jsp</result> </action> </package> </struts>
当某个包指定了命名空间后,该包下所有的Action处理的URL应该是:命名空间/Action名
Action=”命名空间/Action名”
http://localhost:8080/webDemo/book/getBooks.action
根命名空间:namespace=“/”
默认命名空间:没有指定namespace
若请求为/barsace/bar.action,系统首先查找/barspace命名空间里名为bar的Action,若在该命名空间里找到对应的Action,则使用该Action处理用户请求;否则系统将到默认命名空间中查找名为bar的Action,若找到对应的Action,则使用该Action处理用户请求;若两个命名空间里都找不到名为bar的Action,则系统出现错误
默认命名空间里的Action可处理任何命名空间下的Action请求(即如果存在URL为/barspace/bar.action的请求,并且/barspace的命名空间下没有名为bar的Action,则默认命名空间下名为bar的Action也会处理用户请求);但根命名空间下的Action只处理根命名空间下的Action请求,这是根命名空间和默认命名空间的区别
若请求为/login.action,系统会在根命名空间(“/”)中查找名为login的Action,若在根命名空间中找到名为login的Action,则由该Action处理用户请求;否则系统将转入默认空间中查找名为login的Action,,若默认的命名空间里有名为login的Action,则由该Action处理用户请求;如果两个命名空间里都找不到名为login的Action,则系统出现错误
命名空间只有一个级别;若请求的URL为/bookservice/search/get.action,系统将先在/bookservice/search的命名空间下查找名为get的Action,若在该命名空间内找到名为get的Action,则由该Action处理用户请求;若在该命名空间内没有找到名为get的Action,系统将直接进入默认命名空间中查找名为get的Action,而不会在/bookservice的命名空间下查找名为get的Action
(2)、Action的基本配置
配置Action至少需要指定name(Action的名字:指定了Action所处理请求的URL);通常还需指定class(指定Action的实现类)-----该属性可选,若无则使用系统的ActionSupport类
<package name="xxx"> <action name=”login”class=”lee.LoginAction”> <!—配置逻辑视图和物理视图之间的映射关系--> <result.../> <result.../> </action> </package>
Action的name屬性通常由字母和數字組成,如需在name屬性中使用(/),則需設置該常量(struts.enable.SlashesInActionNames=true)
不推荐在Action的name属性值中使用(.)(-)
(3)、Action的动态方法调用(实现一个Action包含多个控制处理逻辑)
如同一个表单,当用户通过不同的提交按钮(登陆、注册)来提交同一个表单时,系统需用Action的不同方法来处理用户请求
Struts2采用DMI(DynamicMethod Invocation动态方法调用)来处理这种请求(不推荐);
<!— ActionName指定提交到哪个Action,methodName指定提交到指定方法 -->
Action=”ActionName!methodName”
<input tyoe=”submit” value=”登陆” /> <input type=”submit” vlaue=”注册“ onclick=”regist();”/>
function regist(){ targetForm = document.forms[0]; // 获取页面的第一个表单 targetForm.action = “login!regist.action”; // 动态修改表单的action属性 }
LoginRegistAction.java: Public class LoginRegistAction extends ActionSupport{ private String username; prviate String password; private String tip; // 省略对应setter、getter方法 // Action包含的注册控制逻辑 public String regist() throws Exception{ ActionContext.getContext().getSession().put(“user”,getUsername()); setTip(“恭喜你,” + getUsername() + “,你已经注册成功!”); return SUCCESS; } // Action默认包含的控制逻辑 public String execute() throws Exception{ if(getUsername().equals(“lbd”) && getPassword().equals(“123”){ ActionContext.getContext().getSession().put(“user”,getUsername()); setTip(“欢迎,” + getUsername() + “,您已经登录成功!”); return SUCCESS; } else{ return ERROR; } } }
使用动态方法调用前需开启系统的动态方法调用:设置常量struts.enable.DynamicMethodInvocation为true
(4)、指定method属性
将一个Action处理类定义成多个逻辑Action(在配置Action时指定method属性,则可让Action调用指定方法、而不是execute方法来处理用户请求)
<action name=”login”class=”com.LoginAction” method=”login” />
......
</action>
Action类的每个处理方法都映射成一个逻辑Action
<package name=”lee” extends=”struts-default”> <!—默认使用execute方法处理请求 --> <action name=”login” class=”com.LoginAction”> <result name=”input”>/login.jsp</result> <result name=”error”>/error.jsp</result> <result name=”success”>/welcome.jsp</result> </action> <!— 指定使用regist方法处理请求 --> <action name=”regist” class=”com.LoginAction” method=”regist”> <result name=”input”>/login.jsp</result> <result name=”error”>/error.jsp</result> <result name=”success”>/welcome.jsp</result> </action> </package>
修改JSP页面的JavaScript代码 function regist(){ targetForm = document.forms[0]; targetForm.action = “regist.action”; }
使用通配符实现动态方法调用(实现一个Action包含多个控制处理逻辑):
<constantname="struts.enable.DynamicMethodInvocation" value="false"/>(官方推荐)
配置<action.../>时,在name属性使用模式字符串,然后在class、method属性及<result.../>中使用{N}的形式来代表前面第N个星号(*)所匹配的字串
<package name="data-default" namespace="/" extends="struts-default"> <default-action-ref name="login" /> <action name="*-*-*" class="com.dhec.iems.web.action.{1}.{2}Action" method="{3}"> <result name="dwz">common/dwzJson.jsp</result> <result name="input">input.jsp</result> <result name="error">error.jsp</result> <result name="index">index.jsp</result> <result name="download" type="stream"> <param name="contentType">${fileType}</param> <param name="inputName">inputStream</param> <param name="contentDisposition">attachment;filename="${realFileName}"</param> <param name="bufferSize">8192</param> </result> <result name="preview" type="stream"> <param name="contentType">${fileType}</param> <param name="inputName">inputStream</param> <param name="contentDisposition">inline;filename="${realFileName}"</param> <param name="bufferSize">8192</param> </result> <result name="success">pages/{1}/{2}-{3}.jsp</result> <result name="method">pages/{1}/{2}-{3}.jsp</result> <result name="pagedefined">${packageName}/${pageName}.jsp</result> <result name="pagesdefined">pages/${packageName}/${pageName}.jsp</result> </action> </package>
<action name=”*_*method=”{2}” class=”actions.{1}”>
该定义片段定义了一个模式为*_*的Action,即只要匹配该模式的请求,都可被该Action处理,如有URL为Book_save.action的请求,则调用actions.Book处理类的save方法来处理用户请求
后面将会介绍针对Action的输入校验,在对Action进行输入校验时,必须为该Action制定对应的校验文件
Struts2默认的校验文件命名遵守如下规则:ActionName-validation.xml
Struts2允许制定校验文件精确到处理方法,即制定如下形式的校验文件:ActionName-methodName-validation.xml
定义一个通用Action(该Action应放在最后定义)
<action name=”*”>
<result>/{1}.jsp</result>
</action>
通过这种方式,可避免让浏览者直接访问系统的JSP页面,而是让Struts2框架来管理所有用户请求
(5)、配置默认Action
为了让Struts2的Action可以接管用户请求,可配置name=“*”的Action、除此外Struts2还支持配置默认Action; 当用户请求找不到对应的Action时,系统默认的Action即将处理用户请求
<package name=”lee”extends=”action-default”> <default-action-refname=”simpleViewResultAction”/> <!—通过action元素配置默认的Action --> <action name=”simpleViewResultAction”class=”com.SimpleViewResultAction”> <result.../> ...... </action> </package>
将默认Action配置在默认命名空间里就可让Action处理所有请求,因为默认命名空间的Action可处理任何命名空间的请求
(6)、配置Action的默认处理类
当配置<action.../>没指定class属性时,系统默认使用ActionSupport作为Action处理类
<package name=“struts-default” abstract=”true”> <default-class-refclass=”com.opensymphony.xwork2.ActionSupport”/> </package>