21.2  约定大于配置

21.2.1约定大于配置的HelloWorld

先来做一个示例,让大家体会一下什么是约定大于配置。

1:Convention Plugin

从Struts2.1版本起,Struts2官方就推荐使用Convention Plugin替换Codebehind Plugin来实现零配置。相对Codebehind Plugin而言,Convention Plugin有如下一些特点:

  • 通过包的命名习惯来指定Action的位置

  • 通过命名习惯来约定Result(包括Jsp、FreeMarker等)的路径

  • 类名对应于URL的约定转换

  • 包名对应于命名空间的约定转换

  • 遵循SEO规范的链接地址,比如:使用test-action来替换TestAction

  • 基于注解的Action名称约定

  • 基于注解的拦截器约定

  • 基于注解的命名空间约定

  • 基于注解的XWork包

  • 默认action以及默认的Result

等等。总之,使用Convention Plugin来实现零配置,会更灵活、更彻底,基本上可以做到不需要struts.xml来进行配置,甚至不需要注解进行配置,完全由Struts2依靠约定进行自动配置即可。

2:设置环境

要使用Convention Plugin,需要把struts2-convention-plugin-2.1.8.1.jar包拷贝到web工程的WEB-INF\lib包里面。

3:最简单的HelloWorld

要示范零配置,当然首先去掉struts.xml文件,缺省情况下,Convention Plugin会约定所有的结果页面都存放在WEB-INF\content文件夹下。

在WEB-INF文件夹下新建一个content文件夹,然后在content文件夹下新建一个名称为helloworld.jsp的文件,内容示例如下:


java代码:
  1. <%@ page contentType="text/html; charset=gb2312" pageEncoding="gb2312"%>  

  2. <html>  

  3. <head>  

  4. <meta http-equiv="Content-Type" content="text/html; charset=gb2312">  

  5. <title>Insert title here</title>  

  6. </head>  

  7. <body>  

  8.    约定配置,Hell World  

  9. </body>  

  10. </html>  

访问的方式是:在web上下文后面直接访问这个页面,不用加后缀,直接用名字就可以了,也就是URL为:http://localhost:9080/helloworld/helloworld,运行结果如下:

《研磨struts2》第二十一章 零配置 之 21.2 约定大于配置 _JavaEE

图21.1  约定配置示例

4:说明

在这个HelloWorld里面,根本就没有写Action,当然也不存在struts.xml文件,完全是按照Convention Plugin的约定来运行,直接到WEB-INF/content文件夹下面,根据请求的url来找到对应的helloworld.jsp,然后直接运行这个页面就得到了如上的运行结果。

那么对于Convention Plugin来说,到底有哪些约定呢?

21.2.2常见的约定

1默认把所有的结果页面都存储在WEB-INF/content文件夹下,这个值可以通过在struts.xml或者struts.properties文件中设置struts.convention.result.path这个属性的值来改变到其他路径。示例如下:


java代码:
  1. <constant name="struts.convention.result.path" value="/WEB-INF/mypage" />  

      这样就将默认的result页面路径设置到了WEB-INF/mypage文件夹里面。

2在应用启动的时候,Convention插件会自动搜索位于action、actions、struts、struts2的包及其子包下的所有Java类,以搜索Action类。

      可以通过在struts.xml或者struts.properties文件中设置struts.convention.package.locators这个属性的值来改变搜索的文件夹。示例如下:


java代码:
  1. <constant name="struts.convention.package.locators" value="web,s2" />  

      上面的示例定义了:在项目中,包路径中包含web和s2的将被视为包含Action类的路径而被搜索。

3在应用启动的时候,Convention插件在上述包及其子包的路径下搜索满足如下条件的类来作为Action类:

(1)       实现com.opensymphony.xwork2.Action的类

(2)       类名以Action结尾的Java类

比如:在cn.javass.testproject.action包下面,有一个HelloAction的类,那么Convention插件会自动把这个HelloAction类当作Action来进行处理。

4在映射Action的名称的时候,通常遵循如下规则:

(1)       如果该Action类名以Action作为后缀,那么会将后缀的Action去掉,其他的不做处理。

(2)       如果该Action类名采用驼峰式的写法,也就是每个单词首字母大写的写法,那么需要把所有字母变成小写,单词与单词之间以中画线隔开。
   比如有一个Action的名称为HelloWorldAction,那么对应的映射资源的名称为hello-world。

(3)       如果是单个词的Action名称,那么把它的所有字母变成小写,作为对应的映射资源的名称。比如Action类名为HelloAction,它是以Action作为后缀的,那么对应的映射资源的名称为先去掉Action后缀,得到Hello,又是单个词的名称,变成小小,那么最终对应的映射资源的名称为hello。

5:命名空间

从定义的package.locators开始到包结束的部分,就是命名空间。比如有一个Action类位于如下包中:cn.javass.testproject.action.t1.t2,那么命名空间就是/t1/t2。

命名空间对应着访问的url中的path部分,位于web上下文之后,具体的资源名称之前的部分,比如访问的url为:http://localhost:9080/helloworld/t1/t2/hello-world,其中的helloworld就是web上下文,而后面的hello-world就是要访问的资源的名称,中间的/t1/t2就是url的path部分。

命名空间还对应着WEB-INF/content文件夹下的子文件夹路径,如果命名空间为/t1/t2,那就以为着对应的result页面,应该放在WEB-INF/content/t1/t2文件夹下。

6:对应resutl页面的约定

(1)       Result页面默认的都以WEB-INF/content作为定位的起点。

(2)       如果没有对应的Action存在,那么访问资源的名称就直接和页面的名称对应,要注意都是小写的

(3)       如果有对应的Action存在,那么对应的方式是:优先按照“Action的URL+Result的字符串+文件类型的后缀”的方式进行对应,如果没有对应的页面,那么也可以按照“Action的URL+文件类型的后缀”的方式进行对应。

7:Action链的约定

如果一个Action执行完成后,希望进入到另外一个Action,从而形成Action链,基本的约定如下:

(1)       第一个Action返回的result没有对应的页面存在。

(2)       第二个Action和第一个Action在同一个包中,而且第二个Action映射的URL为:第一个Action映射的URL+返回的result字符串,而且名称采用驼峰式的写法,也就是首字母大写。

21.2.3  示例常见的约定

看了上面的约定,感觉如何,很糟糕是不是,这些约定的规则太抽象了,具体怎么使用呢?接下来就通过示例来说明。

1:没有Action的时候,就如同前面约定大于配置的HelloWorld那样,访问的URL为:http://localhost:9080/helloworld/helloworld,由于没有对应的Action,因此直接到WEB-INF的content文件夹下面,寻找名称为“helloworld”,后缀可以为“.jsp”、“.htm”、“.html”等的页面,找到后就直接运行。

2:如果有如下的包结构和类的定义:

《研磨struts2》第二十一章 零配置 之 21.2 约定大于配置 _JavaEE_02

图21.2  示例的包结构

(1)如果要运行HelloWorldAction的话,对应的URL应该为:http://localhost:9080/helloworld/t1/t2/hello-world,而且在content文件夹下应该有t1文件夹,t1文件夹下应该有t2文件夹,t2文件夹下应该有相应的result页面,如下图:

《研磨struts2》第二十一章 零配置 之 21.2 约定大于配置 _Struts2_03

图21.3  t2文件夹示例

像这个示例中,同时存在hello-world-success.jsp和hello-world.jsp,那么会优先匹配到hello-world-success.jsp,如果不存在hello-world-success.jsp才匹配hello-world.jsp。

(2)先看看ConventionAction的实现,示例代码如下:


java代码:
  1. publicclass ConventionAction extends ActionSupport{  

  2. public String msg = "";  

  3. public String userId = "";    

  4. public String execute() throws Exception {  

  5.        System.out.println("now in ConventionAction");  

  6. if(userId==null || userId.trim().length()==0){  

  7.            msg = "用户编号不能为空";  

  8. return"toadd";  

  9.        }  

  10.        msg = "用户编号输入正确";  

  11. return SUCCESS;  

  12.    }  

  13. }  

此时在content文件夹下,有如下图所示的页面:

《研磨struts2》第二十一章 零配置 之 21.2 约定大于配置 _Struts2_04

图21.4 content文件夹

如果运行的URL为:http://localhost:9080/helloworld/convention?userId=22,那么会匹配到ConventionAction这个类,运行结束后,返回success。接下来到content文件夹下去优先匹配到convention-success.jsp,然后运行这个页面,展示给用户。

如果运行的URL为:http://localhost:9080/helloworld/convention,那么会匹配到ConventionAction这个类,运行结束后,返回toadd。接下来到content文件夹下去优先匹配到convention-toadd.jsp,然后运行这个页面,展示给用户。

如果此时把convention-toadd.jsp文件去掉,然后再次运行,运行的URL同样为:

http://localhost:9080/helloworld/convention,那么会匹配到ConventionAction这个类,运行结束后,返回toadd。接下来到content文件夹下去寻找匹配的页面,没有能匹配上的,那么就会到ConventionAction这个类的同包下,寻找是否有ConventionToaddAction这个类,有这个类,那么就会运行这个类,相当于是Action链了。



From : http://sishuok.com/forum/blogPost/list/0/4184.html