现在的位置: 首页 > 综合 > 正文

Zero Config plugins零配置

2013年09月06日 ⁄ 综合 ⁄ 共 9373字 ⁄ 字号 评论关闭

Introduction

The Convention Plugin is bundled with Struts since 2.1 and replaces the Codebehind
Plugin
 and Zero Config plugins. It provides the following features:

  • Action location by package naming conventions
  • Result (JSP, FreeMarker, etc) location by naming conventions
  • Class name to URL naming convention
  • Package name to namespace convention
  • SEO compliant URLs (i.e. my-action rather than MyAction)
  • Action name overrides using annotations
  • Interceptor overrides using annotations
  • Namespace overrides using annotations
  • XWork package overrides using annotations
  • Default action and result handling (i.e. /products will try com.example.actions.Products as well as com.example.actions.products.Index)

The Convention Plugin should require no configuration to use. Many of the conventions can be controlled using configuration properties and many of the classes can be extended or overridden.

Setup

In order to use the Convention plugin, you first need to add the JAR file to the WEB-INF/lib directory of your application or include the dependency in your project's Maven POM file.

<dependency>
    <groupId>org.apache.struts</groupId>
    <artifactId>struts2-convention-plugin</artifactId>
    <version>2.1.6</version>
</dependency>

Converting a Codebehind based application to Convention

See this
page
 for the required changes and tips.

If you are using REST with the Convention plugin, make sure you set these constants in struts.xml:

<constant name="struts.convention.action.suffix" value="Controller"/>
<constant name="struts.convention.action.mapAllMatches" value="true"/>
<constant name="struts.convention.default.parent.package" value="rest-default"/>

Hello world

Now that the Convention plugin has been added to your application, let's start with a very simple example. This example will use an actionless result that is identified by the URL. By default, the Convention plugin assumes that
all of the results are stored in WEB-INF/content. This can be changed by setting the property struts.convention.result.path in the Struts properties file to the new location. Don't worry about trailing slashes, the Convention plugin
handles this for you. Here is our hello world JSP:

<html>
<body>
Hello world!
</body>
</html>

If you start Tomcat (or whichever J2EE container you are using) and type in http://localhost:8080/hello-world into
your browser you should get this result:

WEB-INF/content/hello-world.jsp
Hello world!

This illustrates that the Convention plugin will find results even when no action exists and it is all based on the URL passed to Struts.

Code behind hello world

Let's expand on this example and add a code behind class. In order to do this we need to ensure that the Convention plugin is able to find our action classes. By default, the Convention plugin will find all action classes that implement com.opensymphony.xwork2.Action or
whose name ends with the word Action in specific packages.

These packages are located by the Convention plugin using a search methodology. First the Convention plugin finds packages named strutsstruts2action or actions. Any packages that match those
names are considered the root packages for the Convention plugin. Next, the plugin looks at all of the classes in those packages as well as sub-packages and determines if the classes implement com.opensymphony.xwork2.Action or if their name ends with Action (i.e.
FooAction). Here's an example of a few classes that the Convention plugin will find:

Classes
com.example.actions.MainAction
com.example.actions.products.Display (implements com.opensymphony.xwork2.Action)
com.example.struts.company.details.ShowCompanyDetailsAction

Each of the action classes that the plugin finds will be configured to respond to specific URLs. The URL is based on the package name that the class is defined in and the class name itself. First the plugin determines the namespace
of the URL using the package names between the root package and the package the class is defined in. For our examples above, the namespaces would be:

Namespaces
com.example.actions.MainAction -> /
com.example.actions.products.Display -> /products
com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details

Next, the plugin determines the URL of the resource using the class name. It first removes the word Action from the end of the class name and then converts camel case names to dashes. In our example the full URLs
would be:

Full URLs
com.example.actions.MainAction -> /main
com.example.actions.products.Display -> /products/display
com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details/show-company-details

You can tell the Convention plugin to ignore certain packages using the property struts.convention.exclude.packages. You can also tell the plugin to use different strings to locate root packages using the propertystruts.convention.package.locators.
Finally, you can tell the plugin to search specific root packages using the property struts.convention.action.packages.

Here is our code behind action class:

com.example.actions.HelloWorld
package com.example.actions;

import com.opensymphony.xwork2.ActionSupport;

public class HelloWorld extends ActionSupport {
  private String message;

  public String getMessage() {
    return message;
  }

  public String execute() {
    message = "Hello World!";
    return SUCCESS;
  }
}

If you compile this class and place it into your application in the WEB-INF/classes, the Convention plugin will find the class and map the URL /hello-world to it. Next, we need to update our JSP to print out the
message we setup in the action class. Here is the new JSP:

WEB-INF/content/hello-world.jsp
<html>
<body>
The message is ${message}
</body>
</html>

If start up the application server and open up http://localhost:8080/hello-world in our browser, we should get this
result:

Result
The message is Hello World!

Results and result codes

The Convention Plugin will pre-configure all of you action classes when Struts is started. By default, this configuration will also contain results for any JSPs that it can find within the application. The JSPs have an additional
feature that allows different JSPs to be used based on the result code of the action. Since action methods return Strings and these Strings are traditionally used to locate results for the action, the Convention plugin allows you to define different results
based on the result code.

Building on our example from above, let's say we want to provide a different result if the result code from our action is the String zero rather than success. First, we update the action class to return different
result codes:

com.example.actions.HelloWorld
package com.example.actions;

import com.opensymphony.xwork2.ActionSupport;

public class HelloWorld extends ActionSupport {
  private String message;

  public String getMessage() {
    return message;
  }

  public String execute() {
    if (System.currentTimeMillis() % 2 == 0) {
      message = "It's 0";
      return "zero";
    }

    message = "It's 1";
    return SUCCESS;
  }
}

Next, we add a new JSP to the application named WEB-INF/content/hello-world-zero.jsp. Notice that the first part of the file name is the same as the URL of the action and the last part of the name is the result code. This
is the convention that the plugin uses to determine which results to render. Here is our new JSP:

WEB-INF/content/hello-world.jsp
<html>
<body>
The error message is ${message}
</body>
</html>

Now, if you compile the action and restart the application, based on the current time, you'll either see the result from WEB-INF/content/hello-world.jsp or WEB-INF/content/hello-world-zero.jsp.

The result type is based on the extension of the file. The supported extensions are: jsp,ftl,vm,html,html. Examples of Action and Result to Template mapping:

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

Chaining

If one action returns the name of another action in the same package, they will be chained together, if the first action doesn't have any result defined for that code. In the following example:

com.example.actions.HelloWorld
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;
    }
}

The "foo" action will be executed, because no result is found, the Convention plugin tries to find an action named "foo-bar" on the same package where "foo" is defined. If such an action is found, it will be invoked using the "chain"
result.

XWork packages

Actions are placed on a custom XWork package which prevents conflicts. The name of this package is based on the Java package the action is defined in, the namespace part of the URL for the action and the parent XWork package for
the action. The parent XWork package is determined based on the property named struts.convention.default.parent.package(defaults to convention-default), which is a custom XWork package that extends struts-default.

Therefore the naming for XWork packages used by the Convention plugin are in the form:

XWork package naming
<java-package>#<namespace>#<parent-package>

Using our example from above, the XWork package for our action would be:

XWork package naming
com.example.actions#/#conventionDefault

Annotation reference

The Convention plugin uses a number of different annotations to override the default conventions that are used to map actions to URLs and locate results. In addition, you can modify the parent XWork package that actions are configured
with.

Action annotation

The Convention plugin allows action classes to change the URL that they are mapped to using the Action annotation. This annotation can also be used inside the Actions annotation to allow multiple
URLs to map to a single action class. This annotation must be defined on action methods like this:

抱歉!评论已关闭.