struts-convention-plugin
struts-convention-plugin作用约定大于配置
减少了开发时间,但维护的时间并不会少;
注:使用struts2.3.24
struts需要导入的JAR就不多说了
Convention插件需要加入
asm.jar
asm.commons.jar
struts-convention-plugin.jar
<!-- 设置在class被修改时是否热加载,发布时要设置为false --> <constant name="struts.convention.classes.reload" value="true"/> <!-- 用于配置包名后缀。默认为action、actions、struts;value="action"为搜索action文件夹下的所有类--> <constant name="struts.convention.package.locators" value="action" /> <!-- 用于配置类名后缀,默认为Action,设置后,Struts2只会去找这种后缀名的类做映射 --> <constant name="struts.convention.action.suffix" value="Action"/> <!-- 指定jsp文件所在的目录地址,默认为value="/WEB-INF/conent/"-->
<constant name="struts.convention.result.path" value="/WEB-INF/page/" />
<!-- 自定义jsp文件命名的分隔符 -->
<constant name="struts.convention.action.name.separator" value="-" />
<!-- 设置即使没有@Action注释,依然创建Action映射。默认值是false。因为Convention-Plugin是约定优于配置的风格, 可以不通过注解根据预先的定义就能访问相应Action中的方法 -->
<!-- <constant name="struts.convention.action.mapAllMatches" value="true"/> -->
<!--以下几个配置项就没测试过了--> <!-- 该常量指定包作为根包来搜索Action类。 Convention插件除了扫描默认的action,actions,struts,struts2, 还会扫描该常量指定的一个或多个包, Convention会试图从指定包中发现Action类。 -->
<!-- <constant name="struts.convention.action.packages" value="com.ackon.xxx" /> -->
<!-- 设置即使没有@Action注释,依然创建Action映射。默认值是false。因为Convention-Plugin是约定优于配置的风格, 可以不通过注解根据预先的定义就能访问相应Action中的方法 -->
<!-- <constant name="struts.convention.action.mapAllMatches" value="true"/> -->
<!-- 设置Convention插件是否从jar包中搜索Action类 [可选] 默认值为true -->
<constant name="struts.convention.action.disableJarScanning" value="true" />
<!-- 设置Convention插件文件协议类型 --><constant name="struts.convention.action.fileProtocols" value="jar,wsjar" />
<!-- 设置Convention插件需要搜索的jar包 -->
<constant name="struts.convention.action.includeJars" value=".*?/ackonOA*.*?jar(!/)?" />
com.ackon.oa.test.action.aa.TestaAction.java
访问方法: ip:prot/projectName/aa/testa!method1.do访问
例如此method1 return的string为”ta",则跳转的页面为/WEB-INF/page/aa/testa-ta.jsp
<constant name="struts.action.extension" value="do" /> struts访问action的扩展名
<constant name="struts.convention.result.path" value="/WEB-INF/page/" />决定页面目录
<constant name="struts.convention.action.suffix" value="Action"/>决定对应扫描注入的类为xxxAction.java
<constant name="struts.convention.package.locators" value="action" />和action.suffix决定了xxxAction.java的namespace,TestaAction.java的namespace为aa访问的模板页面在/WEB-INF/page/aa/下,具体页面testa-ta.jsp;
如com.ackon.oa.test.action,com.ackon.oa.action下的所有类都会被注入;com.ackon.oa.test.action下的目录aa下xxxAction的命名空间为aa
<constant name="struts.convention.action.name.separator" value="-" />设置页面间隔符,前一部分为actionName, separator后的部分为具体页面。
http://localhost/ackonOA/aa/test-one.do访问com.ackon.oa.test.action.aa.TestOneAction的execute方法return SUCCESS,跳转至/WEB-INF/page/aa/test-one.jsp;t6() return "td";跳转至/WEB-INF/page/aa/test-one-td.jsp;
曾separator设置value="_",testa_ta.jsp和testa-ta.jsp同时存在时会去访问testa-ta.jsp,同一目录下只有testa_ta.jsp一个文件时才会去访问它;所以为了避免麻烦value="-"还是好一些;
<constant name="struts.convention.action.mapAllMatches" value="true"/>不起作用,设置为false,不用注解的方式仍可正常访问。
参照自己项目中的具体配置进行文件定位,所以在项目建立初期就最好引入struts-convention-plugin;
补充:引入struts-convention-plugin插件之前在struts.xml中进行配置的action访问方法仍可正常访问;
package com.ackon.oa.test.action; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Actions; import com.opensymphony.xwork2.ActionSupport; public class TestaAction extends ActionSupport{ public String execute(){ System.out.println("---> TestaAction.execute(). SUCCESS"); return SUCCESS; } @Action("a") public String t1(){ System.out.println("---> TestaAction.t1(). SUCCESS"); return SUCCESS; } @Action("/aa/a") public String t2(){ System.out.println("--> TestaAction.t2(). ERROR"); return ERROR; } @Action("aa/b") public String t3(){ System.out.println("--> TestaAction.t3(). INPUT"); return INPUT; } @Actions({ @Action("b"), @Action("aa/test-one-td") }) public String t4(){ System.out.println("--> TestaAction.t4(). LOGIN"); return LOGIN; } @Action("testa-ta") public String t5(){ System.out.println("--> TestaAction.t5(). NONE"); return NONE; } public String t6(){ System.out.println("---> TestaAction.t6()"); return "ta"; }
@Action("test-tb") public String t7(){ System.out.println("---> TestaAction.t7()"); return "tb"; } }
注释掉@Action,即未加@Action注释前
localhost/ackonOA/testa.do 访问 execute() , 跳转至/WEB-INF/page/testa.jsp
localhost/ackonOA/testa!t1.do的形式访问自定义的方法,此为访问t1()
returnString为ACTION的五个常量时,SUCCESS,ERROR,INPUT,LOGIN跳转至/WEB-INF/page/testa.jsp; NONE跳转至空白页面;
t6()跳转至/WEB-INF/page/testa-ta.jsp
t7()跳转至/WEB-INF/page/testa-tb.jsp
@Action注解改变Convention plug约定的action与url之间的映射关系
相当于多了一种调用方法的方式,只是会根据条用方式的不同,返回不同的结果页面
http://localhost/ackonOA/testa!t1.do访问t1()跳转至/WEB-INF/page/testa.jsp
http://localhost/ackonOA/a.do访问t1()跳转至/WEB-INF/page/a.jsp
http://localhost/ackonOA/aa/a.do跳转至/WEB-INF/page/aa/a.jsp
http://localhost/ackonOA/aa/b.do跳转至/WEB-INF/page/aa/b.jsp
此处注意@Action("/aa/a")和@Action("aa/b")在@Namespace中就有区别了,前面有"/"的为全限定名,@Namespace无法正确访问,此种方式不要用;
http://localhost/ackonOA/testa-ta.do访问t5(),因为返回NONE,跳转至空白页面,不响应;
http://localhost/ackonOA/test-tb.do访问t7(),跳转至/WEB-INF/page/test-tb.jsp
@Namespace命名空间注释允许操作类名称空间改变而不是使用Convention Plugin约定的Java包的名称
package com.ackon.oa.test.action; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Actions; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.Result; import com.opensymphony.xwork2.ActionSupport; @Namespace("/aa") public class TestbAction extends ActionSupport{ public String execute(){ System.out.println("---> TesteAction.execute()"); return SUCCESS; } @Action("/testc") public String t1(){ System.out.println("---> TesteAction.t1()"); return "ta"; } @Action("c") public String tb(){ System.out.println("---> TesteAction.t2()"); return "ta"; } }
正确格式@Namespace("/aa"),@Namespace("aa")是错误的,否则会造成访问页面与实际不符;
http://localhost/ackonOA/aa/testb.do访问execute,跳转至/WEB-INF/page/aa/testb.jsp
http://localhost/ackonOA/aa/testc.do访问t1(),无对应返回页面,可实际/WEB-INF/page/aa/testc.jsp存在
http://localhost/ackonOA/aa/c.do访问t2(),返回/WEB-INF/page/aa/c.jsp
t1()不能正常返回页面因为@Action("/testb")对action的命名空间进行了完全限定,而@Namespace注释的效果只能对该类未完全限定的Action URLs起作用,改为@Action("testb")即可
@Results和@Result改变Conventiono plugin这种约定
package com.ackon.oa.test.action; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Actions; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import com.opensymphony.xwork2.ActionSupport; @Namespace("/b") @Results({ @Result(name = "ta", location = "testa.jsp")}) public class TestcAction extends ActionSupport { public String execute(){ System.out.println("---> TestcAction.execute()"); return "tc"; } public String t0(){ System.out.println("---> TestcAction.t0()"); return "tb"; } @Action("d") public String t1(){ System.out.println("---> TestcAction.t1()"); return "tb"; } @Action("teste") public String t2(){ System.out.println("---> TestcAction.t2()"); return "ta"; } @Actions({ @Action("a"), @Action("b") }) public String t3(){ System.out.println("---> TestcAction.t3()"); return "ta"; } @Action(value = "c", results = {@Result(name = SUCCESS, location = "/WEB-INF/page/a.jsp")}) public String t4(){ System.out.println("---> TestcAction.t4()"); return SUCCESS; } @Action(value = "/e", results = {@Result(name = "ta", location = "/WEB-INF/page/a.jsp")}) public String t5(){ System.out.println("---> TestcAction.t5()"); return "ta"; } }
http://localhost/ackonOA/b/teste.do访问t2(),本应该返回/WEB-INF/page/b/teste.jsp,实际却返回/WEB-INF/page/b/testa.jsp
因为类定义了@Results({ @Result(name = "ta", location = "testa.jsp")})
http://localhost/ackonOA/b/d.do和http://localhost/ackonOA/b/b.do都是访问t3()返回/WEB-INF/page/b/testa.jsp
t4()指定了@Action(value = "c", results = {@Result(name = SUCCESS, location = "/WEB-INF/page/a.jsp")})
returnString为SUCCESS返回location页面
http://localhost/ackonOA/b/c.do返回/WEB-INF/page/a.jsp
http://localhost/ackonOA/b/e.do访问t5();类和方法的返回值,方法的优先级高于类的,相当于覆盖了;
返回/WEB-INF/page/a.jsp,而不是/WEB-INF/page/b/testa.jsp
@Action(value = "c", results = {@Result(name = SUCCESS, location = "/WEB-INF/page/a.jsp")})可添加多个@Result
Caused by: The action class [class com.ackon.oa.test.action.TestaAction] contains two methods with an action name annotation whose value is the same (they both might be empty as well). - [unknown location]
启动时报错,类中的两个方法调用方式相同,出现混乱;