从 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