一、struts2的核心组件
1.全局配置文件struts.properties
2.映射文件struts.xml
3.过滤器FilterDispatcher
4.业务控制器Action
5.值栈ValueStack
二、struts.properties(属性文件的内容一般以键=值对的形式出现)
struts2的核心JAR包的org.apache.struts2目录下提供了默认的属性配置文件default.properties,如果要自定义属性的话,只需要在web-inf\classes目录下添加struts.properties来覆盖系统的默认文件属性.
该文件的一些常用的属性如下:
//设置默认的国际化地区信息和国际化信息内码
#struts.locale=en_US
struts.i18n.encoding=UTF-8
//指定URL扩展名,可以指定多个扩展名,用逗号分隔,如action,do
struts.action.extension=action
//Struts自动加载的配置文件列表
struts.configuration.files=struts-default.xml,struts-plugin.xml,struts.xml
三、struts.xml
Struts框架的核心配置文件,该文件主要负责管理struts2框架的业务控制器Action,默认情况下,struts2将自动加载放在web-inf\classes路径下的struts.xml.
该文件中定义的元素:
1.<struts>:根元素
2.<constant>:属性定义元素,用于定义一个属性,该属性与struts.properties中的属性重名,并覆盖struts.properties中该属性的值.这样做的好处是如果使用了多个映射文件,允许每一个文件都使用不同的属性.
//下面的配置将覆盖struts.properties文件中的struts.enable.DynamicMethodInvocation,表示允许使用动态方法调用
<constant name="struts.enable.DynamicMethodInvocation" value="true">
3.<include>:导入子文件元素,被导入的文件与struts.xml有同样的结构,使用相同的配置语法.通过这种方式提供了一种模块化的方式来管理struts.xml文件,简化了struts1中的模块化配置.
4.<package>:包定义元素,定义一组<action>和拦截器元素,name属性表示包的名字,extends="struts-default"表示继承自struts-default.xml(位于struts2的核心包的根目录)中所定义的包的名字,struts-default.xml中默认定义了struts-default的包名,继承包就相当于在该包内可以使用被继承包中的拦截器.(struts-default.xml中定义了一系列的result和拦截器及核心bean,如果不继承的话,我们将无法使用<result>等元素,且从请求参数到Action类属性的封装也要由自己开发实现)
<package name="main" extends="struts-default">
<action name="index">
<result>login.jsp</result>
</action>
</pcakage>
5.<action>:Action映射配置元素,Action Mappings是框架中的基本工作单元,框架通过对请求路径进行映射来决定由哪个Action来处理请求.Action Mappings能指定一系列的Result,异常处理和拦截器.该元素的name属性是必须的.
按照作用不同,可以配置5种类型的请求映射:
--只有name属性的直接转发请求的action:该action将不作任何处理直接将请求转发到result指定的资源.
<action name="index">
<result>login.jsp</result>
</action>
--指定处理的Action类:一个请求对应一个Action类,如果使用了struts2与spring的集成,class属性可以是spring配置文件中<bean>组件的名字.
<action name="login" class="xxx.xxx.LoginAction">
<result name="success">welcome.jsp</result>
<result name="input">login.jsp</result>
</action>
--指定Action类的处理方法:一个Action类可以对应多个请求如果不显式使用method属性,默认使用execute()方法来处理请求
<action name="login" class="xxx.xxx.LoginAction" method="login">
<result name="success">welcome.jsp</result>
<result name="input">login.jsp</result>
</action>
<action name="logout" class="xxx.xxx.LoginAction" method="logout">
<result name="success">welcome.jsp</result>
<result name="input">login.jsp</result>
</action>
--(动态方法调用)通过请求动态指定执行函数:上面的method属性存在一个问题,就是需要为每一个请求与处理方法之间配置一个<action>元素,会引起配置文件的内容膨胀.使用请求动态指定执行函数只需把struts.properties中的struts.enable.DynamicMethodInvocation设为true.
<action name="login" class="xxx.xxx.LoginAction">
<result name="success">welcome.jsp</result>
<result name="input">login.jsp</result>
</action>
表单元素的action不直接等于某个Action的名字,而是以"Action名!Action类的方法名.action".
<form action="login!logout.action" method="post">
</form>
--通配符映射:当我们使用通配符定义Action的name属性时,相当于用一个元素action定义了多个逻辑Action.
<action name="Login_*.action" class="xxx.xxx.LoginAction" method="{1}">
...
</action>
上面定义了一系列请求url为Login_*.action模式的逻辑Action.同时method属性的值为表达式{1},表示它的值是name属性值中的第一个*的值.
6.<result>:结果配置元素.Action类处理完一个请求后会返回一个字符串,这个字符串将被用来选择一个<result>元素.通常一个ActionMapping会有多个<result>,代表各个可能不同的结果.ActionSupport中定义了几个标准的ResultToken,这也就是为什么继承了ActionSupport的Action类就可以直接在处理方法中直接使用'return SUCCESS'的原因.如下所示:
String SUCCESS="success";
String NONE="none";
String ERROR="error";
String INPUT="input";
String LOGIN="login";
<result>元素有两个工作:
一是提供一个逻辑名,用于与Action类返回的字符串进行匹配;
二是提供一个返回类型(ResultType).我们可以为每个包设置默认的返回类型,如果一个包继承了另外一个包,它可以选择设置自己的默认返回类型或者直接使用父包的.struts-default.xml中设置的默认返回类型的方式如下:
<result-types>
<result-type name="dispatcher" default="true" class="ogr.apache.strut2.dispatcher.ServletDispatcherResult" />
<result-types>
这也就是为什么extends="struts-default"后不用设置<result>元素的type属性.关于struts-default.xml中定义的result-types,详见struts2 result视图渲染
<result>元素有name和type两个属性,都是可选,name属性默认为success.
动态result:即result在运行前是未知的,如一个result所跳转的页面取决于它所在Action类的运行结果或者客户端输入等,可以用表达式语言(EL)来表示,这个表达式的值是动态的,取决于Action的运行状况:
private String nextAction;
public String getNextAction
{
return nextAction;
}
<action name="fragment" class="FragmentAction">
<result name="next" type="redirect-action">${nextAction}</result>
</action>
上例result的值将是它所在Action的nextAction的属性值.
7.<global-results>:映射全局结果元素,框架首先寻找嵌套在<action>元素中的result,没有匹配项则在全局范围内寻找.
<global-results>
<result name="error">/err.jsp</result>
<result name="login" type="redirect-action">login!input</result>
</global-results>
8.<interceptors>:拦截器配置元素,该元素在<package>元素中定义使用拦截器可以在Action中的方法执行前后执行一些事先定义好的方法.拦截器有很多功能,如下所示:
校验(validation):检查输入是否正确,(如对表单输入域的数据检测可以放在拦截器中);
属性封装(property population):将输入传输和转化为对象的属性(从请求参数到Action的属性被填充也是因为拦截器的作用);
日志(logging):记录关于每个Action的详细信息;
切面(profiling):记录Action的吞吐量.
拦截器栈(interceptor stack):由多个拦截器链接在一起形成(比如有一个Action不仅要对客户端的资格进行审查,还要记录它自己的行为).<action>中可以定义自己的本地(局部)栈:
<action name="xxx" class="xxx.xxx.xxx">
<interceptor-ref name="被引用的拦截器的逻辑名">
</action>
<interceptors>--定义一组拦截器
<interceptor name="security" class="xxx.xxx.SecurityInterceptor" />--定义一个拦截器
<interceptor-stack name="secureStack">--定义拦截器栈
<interceptor-ref name="security" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
四、FilterDispatcher
详见FilterDispatcher处理流程
五、Action
1.Action可以是任意的POJO类
不一定继承某个类型的Action父类,不需要直接依赖于容器,易于测试,目的是能让Action和框架完全解耦.
2.任何声明为public String MethodName()的方法都可以作为Action的处理方法被调用.
3.继承ActionSupport类,理论上struts2.0的Action无须实现任何接口或继承任何类型,但为了方便实现Action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并重载此类的execute()方法.
4.Action类中需要提供属性的getter/setter方法,便于请求发生时,将请求参数自动注入该Action中.
5.在Action中访问上下文变量
如果要取得Servlet API中的一些对象,如request,response,session等,在struts2.0中有两种方式获得这些对象:
--非IoC(控制反转Inversion of Control)
使用com.opensymphony.xwork2.ActionContext类,可以通过它的getContext()获取当前Action的上下文对象;
HttpServletSession session=ActionContext.getContext().getSession();
使用org.apache.struts2.ServletActionContext辅助类快速获取这几个对象:
HttpServletRequest request=ServletActionContext.getRequeset();
HttpServletSession session=ServletActionContext.getSession();
--IoC(控制反转)
首先需要告诉IoC容器(Container)想取得某个对象的意愿,通过实现相应的接口做到这点.包括SessionAware、ServletRequestAware、ServletResponseAware,这样就可以在该类中定义对应的变量了如下所示:
public IoCAction extends ActoinSupport Implements SessionAware,ServletRequestAware,ServletResponseAware
{
private String message;
private Map att;
private HttpServletRequest request;
private HttpServletResponse response;
getter/setter....
public String execute()
{
att.put("msg","Hello World from Session!");
HttpSession session=request.getSession();
......
}
}