1.介绍
这里都是以spring4.0以上讲解
ActionConfig封装了一个Action配置,对应了struts.xml配置<action>标签,属性了这个实体类,我们才能更好的配置struts.xml,也能清楚的了解问什么要这么配置
2.ActionConifg
2.1关键属性
public static final String DEFAULT_METHOD = "execute";//action默认的执行方法
public static final String WILDCARD = "*";
protected List<InterceptorMapping> interceptors; //这个action的拦截器,只要是进入这个action,拦截器就会执行
protected Map<String,String> params;//需要保存的一些参数
protected Map<String, ResultConfig> results;//结果映射
protected List<ExceptionMappingConfig> exceptionMappings;//异常映射配置
protected String className;//action对应的class---对应<action class=""> class属性 这个class可以是真正的class属性,
也可以是一个名称,如果是一个名称,说明这个action交给了spring管理创建
protected String methodName;//这个action对应的方法--对应<action method="">method属性
protected String packageName;//所在包的名称--<package name="">对应name属性
protected String name;//action的名称---对应<action name=""> name 属性
protected Set<String> allowedMethods;//允许访问的方法--如果struts.xml中配置的一个method是一个通配符形式比如{1},
但是没有配置allowedMethod,那么即便匹配成功了,也是不能访问的 对应<allowed-methods>
2.2关键方法
boolean isAllowedMethod(String method) 判断方法是否允许访问
判断条件:
如果allowedMethods大小等于1,并且allowedMethods中的内容是*表示所有方法都允许,则直接返回true
否则,要么这个method等于execute,要么allowedMethods contains这个方法
2.3ActionConfig创建流程
项目的启动的时候,struts核心组件会解析struts.xml,然后解析出来<action>标签组成ActionConfig对象,一个action标签就对应一个ActionConfig对象
2.3.1没有通配符的配置
<package name="test" namespace="/test" extends="struts-default">
<!-- action配置 -->
<action name="test" class="cn.dhcc.action.TestAction" method="test">
<result name="index">/index.jsp</result>
<!-- <exception-mapping result="" exception=""></exception-mapping>
<interceptor-ref name=""></interceptor-ref>
<param name=""></param> -->
</action>
</package>
封装成ActionConfig对象后:
name:test
className:cn.dhcc.action.TestAction
methodName:test
allowedMethods:空的set,这个不用配置,这不是通配符匹配,所以直接用methodName对应的方法,因此这个属性此时是不起作用的
packageName:test
results:是一个map,里面非空
interceptors:空的map,当然可以配置
params:空的map,当然可以配置
exceptionMappings:空的map,当然可以配置
2.3.2 有通配符的配置
<package name="test1" extends="struts-default" namespace="/">
<!-- action配置 -->
<action name="*Action" class="loginAction" method="{1}">
<result name="index">/index.jsp</result>
<allowed-methods>login,logout</allowed-methods>
</action>
</package>
解析后,生成的ActionConfig对象
name:*Action
className:loginAction---由spring管理的bean
methodName:{1} ----通配符
allowedMethods:set集合 将login logout以逗号分隔后生成set集合
packageName:test1
results:是一个map,里面非空
interceptors:空的map,当然可以配置
params:空的map,当然可以配置
exceptionMappings:空的map,当然可以配置
2.4解析流程
这里先大概介绍一下Action解析:
一个请求发出来以后,比如http://xxxx:8080/web/test1/loginAction.action?age=10&name=lisi
1.首先从requet对象中得到请求的uri, /test1/loginAction.action
2.然后去掉后缀,根据struts配置的允许的后缀名来切割,留下/test1/loginAction
3.循环PackageConfig配置(下节介绍),根据namespace判断,最后解析出来namespace /test1,action的名称就是loginAction
4.解析action的名称,看看是不是有!,如果有也表示动态方法调用的,切割!前面的作为action名称,后面作为方法名称,当然对于这个例子,肯定不会执行这行代码
到这一步:已经得到了一个ActionMapping对象,其中name='loginAction', namespace='/', method='null', extension='action', params=null, result=null
5.接下来就是创建代理,创建代理是有一步就是解析action对应的方法,首先根据命名空间,还有action的名称找到对应的ActionConfig对象,这里查找ActionConfig时稍微有些复杂,首先根据命名空间,action名称进行精确查找,如果找不到,然后根据命名空间,找到满足条件的所有ActionConfig,然后循环,通过匹配查找,如果是动态匹配的话,比如这个例子中,就会解析出参数,0=loginAction 1=login ,然后再通过对应的ActionConfig(属性method={1}),解析出来对应的方法是login。解析出来login后,还要判断这个动态的方法是否允许访问,通过isAllowedMethod()方法判断。注意这里不仅仅会转换action方法,还包括result只要用到了动态匹配参数,都会进行转换。这样就通过配置的ActionConfig解析出来了一个真正运行时的ActionConfig,里面都是精确的属性值
这一步,也说明了,为什么配置了了精确的action时,allowedMethods就没作用了,那就是因为,精确查找的话,直接就能找到配置对应的action,不会再去验证方法是否允许被访问了
6.第5步,找到了action---loginAction(这其实是bean的名称),还有对应的方法名login。接下来就是通过反射创建action类,然后调用对应的方法
3.总结---struts中action的配置方式
struts2中action的配置请求有三种方式
1.精确配置,一个action对应一个请求方法
如:<action name="test" class="cn.dhcc.action.TestAction" method="test"></action>
这样一个action就仅仅对应一个处理方法
http://xxxxx:8080/web/test/test.action----对应就是TestAction的test()方法
这种方式比较麻烦,一个方法对应一个action配置
这种方式不用配置allowedMethods,因为,请求的方法test就等于了ActionConfig的methodName属性了
2.模糊匹配,一个action对应多个请求方法,通过占位符来实现
如:<action name="*Action" class="loginAction" method="{1}">
请求http://xxxxx:8080/web/test/loginAction.action----对应就是loginAction的login()方法
http://xxxxx:8080/web/test/logoutAction.action----对应就是loginAction的logout()方法
这种方式可以动态的指定请求方法,但可读性不好,因为占位符是name的一部分,这么以来就会出现loginAction logoutAction--无法准确的知道到底是哪个action类
这种方式一定要配置allowedMethods指明可以动态访问的方法,因为,动态方法不会等于ActionConfig的methodName属性又不等于默认的execute,只能通过是否配置了allowedMethods来判断可访问性
3.模糊匹配,一个action对应多个请求方法,通过!感叹号来实现
如:<action name="testAction" class="cn.dhcc.action.TestAction" ></action> 配置action的时候,不指明方法名。请求的时候指定
如:http://xxxxx:8080/web/test/testAction!test.action----对应就是TestAction的test()方法
http://xxxxx:8080/web/test/testAction!list.action----对应就是TestAction的list()方法
这种方式也可以动态的指定请求方法,并且可读性好,因为一看就知道test list都是同一个action类,这对于一个模块的多个方法(一个模块一个类来表示),可以准确的知道所在的是哪个模块,推荐使用
这种方式也一定要配置allowedMethods指明可以动态访问的方法,因为,动态方法不会等于ActionConfig的methodName属性又不等于默认的execute,只能通过是否配置了allowedMethods来判断可访问性