一、Struts配置文件
Struts2默认会加载类加载路径下的struts.xml、struts-default.xml、struts-plugin.xml三类文件,其中struts.xml是开发者定义的默认配置文件,struts-default.xml是Struts2框架自带的配置文件,而struts-plugin.xml则是Struts2插件的默认配置文件。
struts.xml配置文件最大的作用是配置Action和请求之间的对应关系,并配置逻辑试图名和物理视图资源之间的对应关系。除此之外,struts.xml文件还有一些额外的功能,例如Bean配置、常量配置、导入其他配置文件等。
Struts2的常量相当于对于Struts2应用整体起作用的属性,因此Struts2常量常常也被称为Struts2属性。
虽然Struts2配置常量有三种方式:通过struts.properties文件;通过struts.xml配置文件;通过web应用的web.xml文件。通常推荐在struts.xml文件中定义Struts2属性,而不是在struts.properties文件中定义Struts2属性。
可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件,示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache SoftwareFoundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<!--指定Struts 2配置文件的根元素 -->
<struts>
<!-- 通过include元素导入其他配置文件-->
<includefile="struts-part1.xml"/>
<includefile="struts-part2.xml"/>
...
</struts>
被包含的struts-part1.xml文件是标准的Struts2配置文件,一样包含了DTD信息、Struts2配置文件的根元素等信息。通常,将Struts2的所有配置文件都放在web应用的WEB-INF/classes路径下,struts.xml文件包含了其他的配置文件,struts.xml文件由Struts2框架负责加载,从而可以将所有配置信息都加载进来。
二、实现Action
1.Action介绍
Action是应用的核心,开发者需要提供大量的Action类,并在struts.xml文件中配置Action。Action类里包含了对用户请求的处理逻辑,Action类也被称为业务控制器。
Action类是一个POJO,包含setter和getter方法,默认处理用户请求的方法:execute()方法。
ActionSupport是一个默认的Action实现类。如果我们配置的Action没有指定class属性(即没有用户提供Action类),系统自动使用ActionSupport类作为Action处理类。
2.Action访问Servlet API
由于Action类不在于ServletAPI耦合,从而能更轻松地测试该Action。Web应用中通常要访问的Servlet API就是HttpServletRequest、HttpSession和ServletContext,这三个接口分别代表JSP内置对象中的request、session和application。
方法一:Struts2提供了一个ActionContext类,Struts2的Action可以通过该类来访问Servlet API。类中常用方法如下:
Object get(Object key):相当于HttpServletRequest的getAttribute(Stringname)方法。
Map getApplication():返回一个Map对象,该对象模拟了该应用的ServletContext实例。
static ActionContext getContext():静态方法,获取系统的ActionContext实例。
Map getParameters():获取所有请求参数。类似于HttpServletRequest的getParameterMap().
Map getSession():返回一个Map对象,该Map对象模拟了HttpSession实例。
void setApplication(Map application):传入一个Map的key-value,转换成application的属性名、属性值。
void setSession(Map session):传入一个Map的key-value,转换成session的属性名、属性值。
方法二:Struts2提供如下几个接口(需要implements并实现方法):
ServletContextAware:实现该接口的Action可以直接访问Web应用的ServletContext实例。
ServletRequestAware:实现该接口的Action可以直接访问用户请求的HttpServletRequest实例。
ServletResponseAware:实现该接口的Action可以直接访问服务器响应的HttpServletResponse实例。
方法三:使用ServletActionContext(工具类)访问Servlet API:
static PageContext getPageContext():取得Web应用的PageContext对象。
Static HttpServletRequest getRequest():取得Web应用的HttpServletRequest对象。
Static HttpServletResponse getResponse ():取得Web应用的HttpServletResponse对象。
Static ServletContext getServletContext():取得Web应用的ServletContext对象。
3.配置action
实现了Action处理类之后,就可以在struts.xml文件中配置该Action了。配置Action就是让Struts2知道哪个Action处理哪个请求,也就是完成用户请求和Action之间的对应关系。我们可以认为,Action是Struts2的基本“程序单位”;
3.1包和命名空间
Struts2使用包来组织Action,因此,将Action定义放在包定义下完成,定义Action通过使用<package…/>下的<action…>子元素来完成,而每个package元素配置一个包。
Struts2框架中的核心组件就是Action、拦截器等,Struts框架使用包来管理Action、拦截器。
几个属性:
name:这是一个必须属性,该属性指定该包的名字,改名字是该包被其他包引用的key。
extends:该属性是一个可选属性,指定该包继承其他包(从而继承Action、拦截器)。
namespace:该属性是一个可选属性,该属性定义该包的命名空间。
abstract:该属性是一个可选属性,它指定该包是否是一个抽象包(不包含Action定义)。
Strut2-core.jar定义了struts-default抽象包,包含了大量结果类型定义、拦截器定义、拦截器引用定义等,这些都是配置普通Action的基础,所以开发者定义的package通常应该继承struts-default包。
如果配置<package…/>时没有指定namespace属性,则该包的Action处于默认的包空间下。
当某个包指定命名空间后,该包下所有的Action处理的URL应该是命名空间+Action名。
Namespace=”/”为根命名空间。
找Action顺序:先找命名空(包括根命名空间)间下的,再找默认命名空间下的。
3.2Action的基本配置
Struts2的Action名字就是它所处理的URL。
通常需要为action元素指定一个class属性,其中class属性指定了该Action的实现类。
配置Action时应该配置逻辑试图和物理视图资源之间的对应关系,一次一个<result…/>。
Name中开启斜线支持:将struts.enable.SlashesInActionNames值设置为true。
配置模版如下:
<actionname="login" class="org.crazyit.app.action.LoginAction">
<!--定义三个逻辑视图和物理资源之间的映射 -->
<resultname="input">/login.jsp</result>
<resultname="error">/error.jsp</result>
<resultname="success">/welcome.jsp</result>
</action>
3.3分配多个Action的处理逻辑
方法一:使用DMI(Dynamic Method Invocation)
动态方法调用是指表单元素的action并不是直接等于某个Action的名字,而是以如下形式来指定表单的action属性:
action=”ActionName!methodName”(放在javascript中)
例子:
网页中<inputtype=”submit” value=”注册” οnclick=”regist();”>//点注册按钮调用regist函数
functionregist(){
targetForm = document.forms[0];
targetForm.action= “login!regist”;
}
当用户点击注册,系统交给loginAction的regist方法处理。
通过这种方式,我们可以在一个Action中包含多个处理逻辑,并通过为表单元素指定不同action属性来提交给Action的不同方法,默认是execute方法。
开启系统的动态方法调用是通过设置strut.enable. DynamicMethodInvocation为true。
方法二:指定method属性及使用通配符
示例代码:
<?xml version="1.0"encoding="GBK"?>
<!DOCTYPE struts PUBLIC
"-//ApacheSoftware Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<packagename="lee" extends="struts-default">
<!--使用模式字符串定义Action的name,指定所有以Action结尾的请求,
都可用LoginRegistAction来处理,method属性使用{1},
这个{1}代表进行模式匹配时第一个*所代替的字符串-->
<actionname="*Action"class="org.crazyit.app.action.LoginRegistAction"
method="{1}">
<!--定义逻辑视图和物理视图之间的映射关系 -->
<resultname="input">/login.jsp</result>
<resultname="error">/error.jsp</result>
<resultname="success">/welcome.jsp</result>
</action>
</package>
</struts>
上面的<actionname=”*Action”…/>元素不是定义了一个普通Action,而是定义了一系列的Action,只要用户请求的URL是*Action.action的模式,都可以用该Action来处理。该method属性使用了一个表达式{1},该表达式的值就是name属性值中第一个*的值。
例如:
用户请求的URL为loginAction.action,则调用lee.LoginRegistAction类的login方法;如果请求的URL为registAction.action,则调用lee.LoginRegistAction类的regist方法;
也可以使用两个通配符:
<actionname=”*_*” method=”{2}” class=”actions.{1}”>
Action处理的优先级:
如果有URL为abcAction.action的请求,如果struts.xml文件中有abcAction.action则先有它处理,如果没有,则找*Action或*,*Action并不比*更优先匹配abcAction的请求,而是先找到哪个Action就会由哪个Action来处理用户的请求。