struts在2.1版本时提供了convention插件来替代Codebehind插件来实现struts的零配置,零配置并不是没有配置,而是通过约定大于配置的方式,大量通过约定来调度页面的跳转而使得配置大大减少。
convention简介
convention插件有以下特性:
- 以包名(Java包不是struts的package)定位Action;
- 以Action名定位物理页面(JSP,FreeMarker等);
- Action类名映射URL地址;
- 包名(Java包)确定名空间(namespace);
- action可被注解配置;
- interceptor可被注解配置;
- namespace可被注解配置;
- XWork包可被注解配置。
使用convention插件
将struts-version/lib
目录中的asm-version.jar
、asm-commons-version.jar
、asm-tree-version.jar
和struts2-convention-plugin-version.jar
文件拷贝到WEB-INF/lib
目录下,即可使用convention插件。
小提示:
如果不导入asm-*.jar
等文件,可能出现Exception starting filter struts2 java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
错误。
convention约定
convention使用约定来取代对struts的配置,因此需要了解convention的相关约定。
- 结果目录:默认所有的物理页面(result)都放在WEB-INF/content
目录下,可以通过设置struts.convention.result.path
属性来改变到其他路径。如:
<constant name="struts.convention.result.path" value="/WEB-INF/jsp" />
- 识别根包:所有包路径包含action、actions、struts或struts2的包都会被struts作为含有Action类的路径来搜索。可以通过设置
struts.convention.package.locators
属性来修改这个配置,此属性指定的值都将作为Action类搜索的根包。如:
<constant name="struts.convention.package.locators" value="web,action" />
- 搜索Action:convention从根包及其子包中搜索实现了
com.opensymphony.xwork2.Action
接口的类以及以Action结尾的类,并将这些类识别为Action。如:
com.example.actions.MainAction
com.example.actions.products.Display (implements com.opensymphony.xwork2.Action)
com.example.struts.company.details.ShowCompanyDetailsAction
- 名空间:从根包开始到包结束的部分,将被识别为Action的名空间(namespace)。如:
com.example.actions.MainAction -> /
com.example.actions.products.Display -> /products
com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details
- URL资源:convention通过如下规则确定URL的资源部分:去掉类名的Action后缀(如果有的话),再将每个单词的首字母转为小写后用”-“分隔,最后再合并到名空间之后。可以设置
struts.convention.action.name.separator
属性修改分隔符。如:
<constant name="struts.convention.action.name.separator" value="-" />
com.example.actions.MainAction -> /main
com.example.actions.products.Display -> /products/display
com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details/show-company-details
- 定位物理页面:convention根据URL的资源部分和resultCode(即Action处理逻辑返回的字符串)寻找对应的物理页面:将URL的资源部分和resultCode用”-“连接后,再加上文件后缀(.jsp、.html等)。如:
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的主要约定,除此之外,还有一些其他约定:
- 搜索特定包:可以设置struts.convention.action.packages
属性来搜索某个特定的包。如:
<constant name="struts.convention.action.packages" value="com.example" />
- 排除某个包:可以设置
struts.convention.exclude.packages
属性让convention排除搜索某个包。如:
<constant name="struts.convention.exclude.packages" value="action" />
- Action链:如果一个Action的名字和其处理逻辑返回的字符串用”-“连接后为另一个Action的名字,且这两个Action在同一个包内,另外前一个Action没有对应的物理页面,则后一个Action将被执行,从而形成Action链。如:
package com.example.actions;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
public class HelloAction extends ActionSupport {
@Action("foo")
public String foo() { return "bar"; }
@Action("foo-bar")
public String bar() { return SUCCESS; }
}
- XWork包:XWork包相当于在struts.xml文件中的package元素,Action放在不同的包中以避免名冲突。XWork父包使用
struts.convention.default.parent.package
属性指定,默认为convention-default。Action的XWork包由Java包、名空间和XWork父包决定,如:
<java-package>#<namespace>#<parent-package>
com.example.actions#/#conventionDefault
convention注解
convention插件提供了大量的注解来覆盖默认的convention约定,比如Action和URL、物理页面的映射规则。
@Action和@Actions注解
@Action注解可以定义Action到URL的映射关系,此注解用于方法级别。如:
public class HelloWorld extends ActionSupport {
@Action("/different/url")
public String execute() {
return SUCCESS;
}
}
这个例子在execute()方法上使用了@Action注解,它改变了Action与URL间的映射关系,而这种改变并不是“OverWrite”,而是在原来约定的基础上增加了另外一种调用方式。
也可以利用@Actions注解将一个Action映射到多个URL。如:
public class HelloWorld extends ActionSupport {
@Actions({
@Action("/different/url"),
@Action("/another/url")
})
public String execute() {
return SUCCESS;
}
}
还可以使用@Action注解实现DMI。如:
public class HelloWorld extends ActionSupport {
@Action("/different/url")
public String execute() {
return SUCCESS;
}
@Action("url")
public String doSomething() {
return SUCCESS;
}
}
@Result注解
@Result注解定义Action到物理页面的映射关系,它分为全局方式和局部方式。全局方式将@Result注解用于类级别,它对类中的所有方法都有用;局部方式将@Result注解用于方法级别,它只对此方法有用。如:
@Results({
@Result(name="failure", location="fail.jsp")
})
public class HelloWorld extends ActionSupport {
@Action(value="/different/url",
results={@Result(name="success", location="http://struts.apache.org", type="redirect")}
)
public String execute() {
return SUCCESS;
}
@Action("/another/url")
public String doSomething() {
return SUCCESS;
}
}
@Result注解也可以将参数传递给物理页面,这些参数以键值对的方式包装成一个字符串数组(因此此数组的长度为偶数)。如:
public class HelloWorld extends ActionSupport {
@Action(value="/different/url",
results={@Result(name="success", type="httpheader", params={"status", "500", "errorMessage", "Internal Error"})}
)
public String execute() {
return SUCCESS;
}
@Action("/another/url")
public String doSomething() {
return SUCCESS;
}
}
@Namespace注解
@Namespace注解允许修改默认的名空间(以Java包产生),它可以用于类级别或包级别(package-info.java文件)。如果用于类,则对此类中的所有Action(用@Action注解配置的方法)都有用;如果用于package-info.java文件,则对此Java包中的所有Action都有用。如:
@Namespace("/custom")
public class HelloWorld extends ActionSupport {
@Action("/different/url")
public String execute() {
return SUCCESS;
}
@Action("url")
public String doSomething() {
return SUCCESS;
}
}
在这个例子中,Action将映射到/different/url
(execute方法使用默认的名空间)和/custom/url
(其他方法用@Namespace注解配置)。
// com/example/actions/package-info.java
@org.apache.struts2.convention.annotation.Namespace("/custom")
package com.example.actions;
在package-info.java文件中的@Namespace注解对此包中的所有Action都有用,但是@Namespace注解对(Java)子包不起作用。
@ResultPath注解
@ResultPath注解将设置物理页面的保存地址,它同样可以应用于类级别和包级别。如:
@ResultPath("/WEB-INF/jsps")
public class HelloWorld extends ActionSupport {
public String execute() {
return SUCCESS;
}
}
这个例子中的Action的物理页面放在WEB-INF/jsps
目录下而不是WEB-INF/content
目录。
@ParentPackage注解
@ParentPackage注解类似于在struts.xml文件中设置struts.convention.default.parent.package
属性,它同样可以用于类级别和包级别。如:
@ParentPackage("customXWorkPackage")
public class HelloWorld extends ActionSupport {
public String execute() {
return SUCCESS;
}
}
@ParentPackage注解用于package-info.java文件时,对(Java)子包也有用。
@ExceptionMapping注解
@ExceptionMapping注解可以定义Action的异常处理映射,它可以用于类级别和Action注解中。如:
@ExceptionMappings({
@ExceptionMapping(exception = "java.lang.NullPointerException", result = "success", params = {"param1", "val1"})
})
public class ExceptionsActionLevelAction {
public String execute() throws Exception {
return null;
}
}
public class ExceptionsMethodLevelAction {
@Action(value = "exception1", exceptionMappings = {
@ExceptionMapping(exception = "java.lang.NullPointerException", result = "success", params = {"param1", "val1"})
})
public String run1() throws Exception {
return null;
}
}
@InterceptorRef注解
@InterceptorRef注解类似于struts.xml文件中的interceptor-ref
元素,它可以配置异常的拦截器,它可以用于方法级别和类级别。如:
@InterceptorRefs({
@InterceptorRef("interceptor-1"),
@InterceptorRef("defaultStack")
})
public class HelloWorld extends ActionSupport {
@Action(value="action1", interceptorRefs=@InterceptorRef("validation"))
public String execute() {
return SUCCESS;
}
@Action(value="action2")
public String doSomething() {
return SUCCESS;
}
}
convention插件配置
Name | Default Value | Description |
---|---|---|
struts.convention.action.alwaysMapExecute | true | Set to false, to prevent Convention from creating a default mapping to “execute” when there are other methods annotated as actions in the class |
struts.convention.action.includeJars | Comma separated list of regular expressions of jar URLs to be scanned. eg. “.*myJar-0\.2.*,.*thirdparty-0\.1.*” | |
struts.convention.action.packages | An optional list of action packages that this should create configuration for (they don’t need to match a locator pattern) | |
struts.convention.result.path | /WEB-INF/content/ | Directory where templates are located |
struts.convention.result.flatLayout | true | If set to false, the result can be put in its own directory: resultsRoot/namespace/actionName/result.extension |
struts.convention.action.suffix | Action | Suffix used to find actions based on class names |
struts.convention.action.disableScanning | false | Scan packages for actions |
struts.convention.action.mapAllMatches | false | Create action mappings, even if no @Action is found |
struts.convention.action.checkImplementsAction | true | Check if an action implements com.opensymphony.xwork2.Action to create an action mapping |
struts.convention.default.parent.package | convention-default | Default parent package for action mappins |
struts.convention.action.name.lowercase | true | Convert action name to lowercase |
struts.convention.action.name.separator | - | Separator used to build the action name, MyAction -> my-action. This character is also used as the separator between the action name and the result in templates, like action-result.jsp |
struts.convention.package.locators | action,actions,struts,struts2 | Packages whose name end with one of these strings will be scanned for actions |
struts.convention.package.locators.disable | false | Disable the scanning of packages based on package locators |
struts.convention.exclude.packages | org.apache.struts.*, org.apache.struts2.*, org.springframework.web.struts.*, org.springframework.web.struts2.*, org.hibernate.* | Packages excluded from the action scanning |
struts.convention.package.locators.basePackage | If set, only packages that start with its value will be scanned for actions | |
struts.convention.relative.result.types | dispatcher,velocity,freemarker | The list of result types that can have locations that are relative and the result location (which is the resultPath plus the namespace) prepended to them |
struts.convention.redirect.to.slash | true | A boolean parameter that controls whether or not this will handle unknown actions in the same manner as Apache, Tomcat and other web servers. This handling will send back a redirect for URLs such as /foo to /foo/ if there doesn’t exist an action that responds to /foo |
struts.convention.classLoader.excludeParent | true | Exclude URLs found by the parent class loader from the list of URLs scanned to find actions (needs to be set to false for JBoss 5) |
struts.convention.action.eagerLoading | false | If set, found action classes will be instantiated by the ObjectFactory to accelerate future use, setting it up can clash with Spring managed beans |