从struts2.1开始,struts2不再推荐使用Codebehind作为零配置插件,而是改为使用Convention插件来支持零配置,和Codebehind相比,Convention插件更彻底,该插件完全抛弃配置信息,不仅不需要是使用struts.xml文件进行配置,甚至不需要使用Annotation进行配置,而是由struts2根据约定自动配置。零配置并不是没有配置,而是通过约定大于配置的方式,大量通过约定来调度页面的跳转而使得配置大大减少。所以,首先应该了解下convention-plugin的约定:
- <span style="font-family:Microsoft YaHei;"> <!--设置Convention插件定位视图资源的根路径,默认为/WEB-INFO/content -->
- <constant name="struts.convention.result.path" value="/WEB-INF/content/"/>
- <!--如果设置为false,则可以将视图页面放置Action对应的目录(无需放入WEB-INFO/content) -->
- <constant name="struts.convention.result.flatLayout" value="true"/>
- <!--Convention搜索Action类的类名后缀,默认为Action -->
- <constant name="struts.convention.action.suffix" value="Action"/>
- <!--是否禁止通过包扫描Action,默认是false -->
- <constant name="struts.convention.action.disableScanning" value="false"/>
- <!--设置即使没有@Action注释,是否依然创建Action映射。默认值为false -->Create action mappings, even if no @Action is found
- <constant name="struts.convention.action.mapAllMatches" value="false"/>
- <!--设置是否所有实现com.opensymphony.xwork2.Action的Action都创建Action映射,默认是true -->
- <constant name="struts.convention.action.checkImplementsAction" value="true"/>
- <!--设置Convention映射的Action所在包的默认父包。默认值是convention-default -->
- <constant name="struts.convention.default.parent.package" value="convention-default"/>
- <!--设置映射Action时,是否将Action的name属性值转换为所有字母小写,默认值是true -->
- <constant name="struts.convention.action.name.lowercase" value="true"/>
- <!--设置映射Action时指定name属性值各单词之间的分隔符。默认值为中画线(“-”) -->
- <constant name="struts.convention.action.name.separator" value="-"/>
- <!--默认包路径包含action,actions,struts,struts2的所有包都会被struts作为含有Action类的路径来搜索 -->
- <constant name="struts.convention.package.locators" value="action,actions,struts,struts2"/>
- <!--指定禁止从Action的根包里搜索Action。默认值为false -->
- <constant name="struts.convention.package.locators.disable" value="false"/>
- <!--如果指定了该常量,Convention只会以该常量值开始的包中搜索Action类 -->
- <constant name="struts.convention.package.locators.basePackage" value=""/>
- <!--指定排除在搜索Action之外的包。默认值为org.hibernate.* ... -->
- <constant name="struts.convention.exclude.packages" value="org.apache.struts.*,org.apache.struts2.*,org.springframework.web.struts.*,org.springframework.web.struts2.*,org.hibernate.*"/>
- <!--指定Convention映射的Result时默认支持的结果类型。默认值为dispatcher,velocity,freemarker -->
- <constant name="struts.convention.relative.result.types" value="dispatcher,velocity,freemarker"/>
- <!--设置是否重定向到斜线(/)。例如用户请求/foo,但/foo不存在时,如果设置该常量为可重定向到/foo/。默认值是true -->
- <constant name="struts.convention.redirect.to.slash" value="true"/></span>
下面开始了解一下Convention如何使用
1.将struts-Convention-plugin-2.1.6.jar文件复制到WEB-INF/lib路径下
2. struts-Convention-plugin如何扫描我们的Action类的呢
1)对于Convention插件而言,它会自动搜索位于action,actions,struts,struts2包下的所有java类,对于所有实现了com.opensymphony.xwork2.Action的java类以及所有类名以Action结尾的java类都会当成Action类来处理。
- <span style="font-family:Microsoft YaHei;"><constant name="struts.convention.package.locators" value="action,actions,struts,struts2"/>
- 可以通过设置struts.convention.package.locators属性来修改这个配置。如:
- <constant name="struts.convention.package.locators" value="web,action" /> </span>
则定义了在项目中,包路径包含web和action的将被视为Action存在的路径来进行搜索。
Com.ustb.web.* 或者 com.ustb.action.*都将被视为含有Action的包路径而被搜索。
2)struts.Convention.exclude.packges::指定不扫描哪些包下的java类,位于这些包结构下的java类将不会自动映射成Action;
3) struts.convention.action.packages:Convention插件以该常量指定包作为根包来搜索Action类。Convention插件除了扫描action,actions,struts,struts2四个包的类以外,还会扫描该常量指定的一个或多个包,Convention会试图从中发现Action类。
4) struts.convention.package.locators.basePackag: 扫描的基包,也即是,只有这个包的子包才被Struts2 Convention Plugin扫描。
4. 映射Action的name时,遵循如下两步规则:
1) 如果该Action类名包含Action后缀,将该Action类名的Action后缀去掉。否则不做任何处理。2) 将Action类名的驼峰写法(每个单词首字母大写、其他字母小写的写法)转成中画线写法(所有字母小写,单词与单词之间以中画线隔开)
如:LoginAction映射的Acion的name属性为login,GetBooks映射的Action的name的属性为get-books,AddEmployeeAction映射的Action的name属性为add-employee
5. Convention如何确定URL的具体资源
1) 默认情况下,Convention总会到WEB应用的WEB-INF/content路径下定位物理资源,定位资源的约定是:actionRUL+resultCODE+suffix。当某个逻辑视图找不到对应的试图资源时,Convention会自动视图使用ActionURL+suffix作为物理视图资源。
如:actions.fore.LoginAction 返回success字符串时,Convention优先考虑使用WEB-INF/content/fore目录下的login-success.jsp作为视图资源。如果找不到该文件,login.jsp也可作为对应的试图资源。如果返回input字符串,Convention会将WEB-INF/content/fore里面查找login-input.jsp
2) 去掉类名的Action部分,然后将将每个分部的首字母转为小写,用’-’分割。
如:UserAction->user UserDetailAction ->user-detail。结合上面的。对于com.ustb.web.user.detail.UserDetailAction,映射的 url就是/WEB-INF/content/user/detail/user-detail.jsp
3)struts支持.jsp .html .htm .vm格式的文件。下面是actiong和结果模版的映射关系:
URL | Result | File that could match | Result Type |
/hello | success | /WEB-INF/content/hello.jsp | Dispatcher |
/hello | success | /WEB-INF/content/hello-success.htm | Dispatcher |
/hello | success | /WEB-INF/content/hello.ftl | FreeMarker |
/hello-world | input | /WEB-INF/content/hello-world-input.vm | Velocity |
/test1/test2/hello | error | /WEB-INF/content/test/test2/hello-error.html | Dispatcher |
当然,简单的通过默认的方式来进行配置不能完全满足实际项目的需要。所幸,convention的零配置是非常灵活的。
通过@Action注释
对如下例子:
- package com.example.web;
- import com.opensymphony.xwork2.Action;
- import com.opensymphony.xwork2.ActionSupport;
- public class HelloAction extends ActionSupport {
- @Action("action1")
- public String method1() {
- return SUCCESS;
- }
- @Action("/user/action2")
- public String method2() {
- return SUCCESS;
- }
- }
方法名 | 默认调用路径 | 默认映射路径 |
method1 | /hello!method1.action . | /WEB-INF/content/hello.jsp |
method2 | /hello!method2.action. | /WEB-INF/content/hello.jsp |
通过@Action注释后
方法名 | @Action注释后调用路径 | @Action注释 后映射路径 |
method1 | /action1!method1.action. | /WEB-INF/content/action1.jsp |
method1 | /user/action2!method2.action | /WEB-INF/content/user/action2.jsp |
通过@Actions注释
- package com.example.web;
- import com.opensymphony.xwork2.ActionSupport;
- import org.apache.struts2.convention.annotation.Action;
- import org.apache.struts2.convention.annotation.Actions;
- public class HelloAction extends ActionSupport {
- @Actions({
- @Action("/different/url"),
- @Action("/another/url")
- })
- public String method1() {
- return “error”;
- }
我们可以通过:/different/url!method1.action 或 /another/url!method1.action 来调用method1 方法。
对应的映射路径分别是/WEB-INF/content/different/url-error.jsp; /WEB-INF/content/another/url-error.jsp
可能误导了大家,一个方法被@Action注释后,只是多了一种调用方式,而不是说覆盖了原来的调用方式。比如对于如下例子:
- package com.example.web;
- import com.opensymphony.xwork2.ActionSupport;
- import org.apache.struts2.convention.annotation.Action;
- import org.apache.struts2.convention.annotation.Actions;
- public class HelloAction extends ActionSupport {
- @Action("/another/url")
- public String method1() {
- return “error”;
- }
我们调用method1方法可以通过两种方式:
1 /hello!method1.action 映射 url:/WEB-INF/content/hello-error.jsp
2 /another/url!method1.action 映射 url:/WEB-INF/content/another/url-error.jsp
可见,两种方式均可对method1方法进行调用,唯一的区别就是,两种调用的映射是不一样的,所以,想跳转到不同的界面,这是一个非常好的选择。
通过@Namespace 注释
- package com.example.web;
- import com.opensymphony.xwork2.ActionSupport;
- import org.apache.struts2.convention.annotation.Action;
- import org.apache.struts2.convention.annotation.Actions;
- @Namespace("/other")
- public class HelloWorld extends ActionSupport {
- public String method1() {
- return “error”;
- }
- @Action("url")
- public String method2() {
- return “error”;
- }
- @Action("/different/url")
- public String method3() {
- return “error”;
- }
- }
通过 /other/hello-world!method1.action 访问method1 方法。
通过 /other/url!method2.action 访问method2 方法
通过 /different /url!method3.action 访问method3 方法
与@Action 注释不同的是,该注释覆盖了默认的namespace(这里是’/’),此时再用hello!method1.action 已经不能访问method1 了.
@Results和@Result
1 全局的(global)。
全局results可以被action类中所有的action分享,这种results在action类上使用注解进行声明。
- package com.example.actions;
- import com.opensymphony.xwork2.ActionSupport;
- import org.apache.struts2.convention.annotation.Action;
- import org.apache.struts2.convention.annotation.Actions;
- import org.apache.struts2.convention.annotation.Result;
- import org.apache.struts2.convention.annotation.Results;
- @Results({
- @Result(name="failure", location="/WEB-INF/fail.jsp")
- })
- public class HelloWorld extends ActionSupport {
- public String method1() {
- return “failure”;
- }
- @Action("/different/url")
- public String method2() {
- return “failure”;
- }
- }
当我们访问 /hello -world !method1.action 时,返回 /WEB-INF/fail.jsp
当我们访问 /hello -world !method2.action 时,返回 /WEB-INF/fail.jsp
当我们访问 /different/url!method2.action 时,返回 /WEB-INF/fail.jsp
2 本地的(local)。
本地results只能在action方法上进行声明。
- package com.example.actions;
- import com.opensymphony.xwork2.ActionSupport;
- import org.apache.struts2.convention.annotation.Action;
- import org.apache.struts2.convention.annotation.Actions;
- import org.apache.struts2.convention.annotation.Result;
- import org.apache.struts2.convention.annotation.Results;
- public class HelloWorld extends ActionSupport {
- @Action(value="/other/bar",results={@Result(name = "error", location = "www.baidu.com",type="redirect")})
- public String method1() {
- return “error”;
- }
- }