从 struts2.1 版本开始, Convention Plugin 作为替换替换 Codebehind Plugin 来实现 Struts2 的零配置。 零配置并不是没有配置,而是通过约定大于配置的方式,大量通过约定来调度页面的跳转而使得配置大大减少 ,我们也可以在类中复写其中的方法来达到扩展的目的。
使用 Convention 插件,需要将其 JAR 文件放到你应用的 WEB-INF/lib 目录中,你也可以在你 maven 项目的 POM 文件中添加下面包依赖
<dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-convention-plugin</artifactId> <version>2.1.6</version> </dependency
convention-plugin的约定
1. 默认情况下,Convention会默认所有的结果页面都存储在WEB-INF/content下,你也可以在struts的配置文件中设定struts.convention.result.path的值到一个新的路径。如
<constant name="struts.convention.result.path" value="/WEB-INF/page" />
这样的话所有结果页面的会存储在 WEB-INF/page 下了,把 jsp 放在 WEB-INF 下有一个好处 ,别人就没有办法直接访问了,这样就可以简化 spring security 的配置工作。
2. 默认 情况下, 包 的 路径包含 action,actions,struts,struts2 的所有包都会被 struts 作为含有 Action 类的路径来搜索。你可以通过设置 struts.convention.package.locators 属性来修改这个配置,如 springside 的 struts.xml 中是这样配置的,
<constant name="struts.convention.package.locators" value="web" />
则在项目中,包 的 路径 含有 web的将被视为Action存在的路径来进行搜索。
3. 接着, Convention 从前一步找到的 package 以及其子 package 中寻找 com.opensymphony.xwork2.Action 的实现以及以 Action 结尾的类,如:
com.courseonline.test.web.account.UserAction 就会被扫描到。
4. 命名空间。从定义的 .package.locators 标示开始到包结束的部分,就是命名空间。举个例子 ,上面我们定义了
<constant name="struts.convention.package.locators" value="web" />
所以 com.courseonline.test.web.account.UserAction的命名空间是: “ / account ” 。
5. Convention 通过如下规则确定 URL 的具体资源部分 : 去掉类名的 Action 部分。然后将每个分部的首字母转为小写,用‘ - ’分割,你可以设置 struts.convention.action.name.separator 如
<constant name="struts.convention.action.name.separator" value="-" />
比如上面的例子 com.courseonline.test.web.account.UserAction 对应的 jsp 为 /WEB-INF/content/account/use.jsp
如果是 com.courseonline.test.web.account.User Detail Action 对应的 jsp 为 /WEB-INF/content/account/use-detail.jsp
下面是 convention 的一些常用注解
1.@Action 注解
public class UserAction extends ActionSupport { @Action("url1") public String method1() { return SUCCESS; } @Action("/account/url2") public String method2() { return SUCCESS; } }
未用 @Action 注解前
默认调用路径 |
访问方法 |
默认映射路径 |
/user!method1.action |
method1 |
/WEB-INF/content/user.jsp |
/user!method2.action |
method2 |
/WEB-INF/content/user.jsp |
|
|
|
使用 @Action 注解后
@Action 注解后调用的路径 |
访问方法 |
@Action 注解后映射的路径 |
/url1!method1.action |
method1 |
/WEB-INF/content/url1.jsp |
/account/url2!method2.action |
method2 |
/WEB-INF/content/account/url2.jsp |
2. @Namespace 注释
@Namespace("/account") public class UserDetailAction extends ActionSupport { public String method1() { return "error"; } @Action("url") public String method2() { return “error”; } @Action("/different/url2") public String method3() { return “error”; } }
调用路径 |
访问方法 |
映射路径 |
/account/user-detail!method1.acton |
method1 |
/WEN-INF/content/account/user-detail-error.jsp |
/account/url!method2.acton |
method2 |
/WEN-INF/content/account/url.jsp |
/different/url2!method3.action |
method3 |
/WEN-INF/content/different/url2.jsp |
与@Action 注释不同的是,该注释覆盖了默认的namespace( 默认的 是’/’),此时再用 user-detail !method1.action 已经不能 访问 method1 了 .
3. @Result
Convention 允许action类为每个action定义不同的results,results分为两类,全局的(global)和本地的(local),全局results可以被action类中所有的action分享,这种results在action类上使用注解进行声明。本地results只能在action方法上进行声明。下面是两种results注解的例子 .
1 )全局的 (global)。
@Results({@Result(name="failure", location="/WEB-INF/fail.jsp") }) public class UserAction extends ActionSupport { String method1() { return “failure”; } @Action("/different/url") public String method2() { return “failure”; } }
调用路径 |
访问方法 |
映射路径 |
/user!method1.action |
method1 |
/WEB-INF/fail.jsp |
/different/url!method2.action |
method2 |
/WEB-INF/fail.jsp |
2 本地的(local)。
public class UserAction extends ActionSupport { @Action(value="/other/ url ",results={@Result(name = "error", location = " /WEB-INF/fail",type="redirect")}) public String method1() { return “error”; } }
调用路径 |
访问方法 |
映射路径 |
/user!method1.action |
method1 |
/WEB-INF/content/user-error.jsp |
/other/url!method2.action |
method1 |
/WEB-INF/fail.jsp |
有了上面的知识,现在来看看 springside 3 的 mini-web 项目中部分用到的 convention 插件的地方,理解起来就不难了。
比较典型的是 UserAction.java 。
@Namespace("/account") @Results( { @Result(name = CrudActionSupport.RELOAD, location = "user.action", type = "redirect") }) public class UserAction extends CrudActionSupport<User> { ……………… @Override public String list() throws Exception { ………… return SUCCESS; } @Override public String input() throws Exception { ………… return INPUT; } @Override public String save() throws Exception { ………… return RELOAD; } ……………… }
这里我只选了三个返回结果分别为 SUCCESS 、 INPUT 、和 RELOAD 的方法来做例子。
调用路径 |
访问方法 |
映射路径 |
/account/user!list.action |
list |
/WEB-INF/content/account/user.jsp |
/account/user!input.action |
input |
/WEB-INF/content/account/user-input.jsp |
/account/user!save.action |
save |
/WEB-INF/content/account/user.jsp |
在调用 save 方法后,为什么会返回 /WEB-INF/content/account/user.jsp 这个页面 呢?因为在全局的 Result 定义名为reload的result重定向到user.action, 其他result则按照convention默认 ,所以当调用完 save 方法后,返回的是 RELOAD ,又被重定向到 user.action ,然后返回到 /WEB-INF/content/account/user.jsp 了;同理,访问 input 方法时,返回的是 INPUT ,所以会返回 /WEB-INF/content/account/user-input.jsp
@Namespace("/account") 表示 定义URL映射对应/account/user.action
@Results( { @Result(name = CrudActionSupport.RELOAD, location = "user.action", type = "redirect") })
定义名为reload的result重定向到user.action, 其他result则按照convention默认.
以上说的不一定都是正确的,如有错误请指正,谢谢。
参考资料: http://www.blogjava.net/libin2722/articles/256525.html