(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=”注册“ οnclick=”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>