天天看点

JavaEE struts2的convention插件

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