菜鸟学Struts2——零配置(Convention )

  又是周末,继续Struts2的学习,之前学习了,Struts的原理,Actions以及Results,今天对对Struts的Convention Plugin进行学习,如下图:

Struts Convention支持零配置进行开发,也就是约定约定优于配置的方式。

(1)环境准备

使用Convention Plugin进行开发,需要引入struts2-convention-plugin,完整的pom.xml依赖如下:

 1 <dependency>
 2     <groupId>org.apache.struts</groupId>
 3     <artifactId>struts2-core</artifactId>
 4     <version>2.3.31</version>
 5 </dependency>
 6 <dependency>
 7     <groupId>org.apache.struts</groupId>
 8     <artifactId>struts2-convention-plugin</artifactId>
 9     <version>2.3.31</version>
10 </dependency>

(2)Action约定

convention有自己定义的struts-plugin.xml如下:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5
 6 <struts order="20">
 7   <bean type="com.opensymphony.xwork2.UnknownHandler" name="convention" class="org.apache.struts2.convention.ConventionUnknownHandler"/>
 8
 9   <bean type="org.apache.struts2.convention.ActionConfigBuilder" name="convention" class="org.apache.struts2.convention.PackageBasedActionConfigBuilder"/>
10   <bean type="org.apache.struts2.convention.ActionNameBuilder" name="convention" class="org.apache.struts2.convention.SEOActionNameBuilder"/>
11   <bean type="org.apache.struts2.convention.ResultMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultResultMapBuilder"/>
12   <bean type="org.apache.struts2.convention.InterceptorMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultInterceptorMapBuilder"/>
13   <bean type="org.apache.struts2.convention.ConventionsService" name="convention" class="org.apache.struts2.convention.ConventionsServiceImpl"/>
14
15   <bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.packageProvider" class="org.apache.struts2.convention.ClasspathPackageProvider"/>
16   <bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.containerProvider" class="org.apache.struts2.convention.ClasspathConfigurationProvider"/>
17
18   <constant name="struts.convention.actionConfigBuilder" value="convention"/>
19   <constant name="struts.convention.actionNameBuilder" value="convention"/>
20   <constant name="struts.convention.resultMapBuilder" value="convention"/>
21   <constant name="struts.convention.interceptorMapBuilder" value="convention"/>
22   <constant name="struts.convention.conventionsService" value="convention"/>
23
24   <constant name="struts.convention.result.path" value="/WEB-INF/content/"/>
25   <constant name="struts.convention.result.flatLayout" value="true"/>
26   <constant name="struts.convention.action.suffix" value="Action"/>
27   <constant name="struts.convention.action.disableScanning" value="false"/>
28   <constant name="struts.convention.action.mapAllMatches" value="false"/>
29   <constant name="struts.convention.action.checkImplementsAction" value="true"/>
30   <constant name="struts.convention.default.parent.package" value="convention-default"/>
31   <constant name="struts.convention.action.name.lowercase" value="true"/>
32   <constant name="struts.convention.action.name.separator" value="-"/>
33   <constant name="struts.convention.package.locators" value="action,actions,struts,struts2"/>
34   <constant name="struts.convention.package.locators.disable" value="false"/>
35   <constant name="struts.convention.package.locators.basePackage" value=""/>
36   <constant name="struts.convention.exclude.packages" value="org.apache.struts.*,org.apache.struts2.*,org.springframework.web.struts.*,org.springframework.web.struts2.*,org.hibernate.*"/>
37   <constant name="struts.convention.relative.result.types" value="dispatcher,velocity,freemarker"/>
38   <constant name="struts.convention.redirect.to.slash" value="true"/>
39   <constant name="struts.convention.action.alwaysMapExecute" value="true"/>
40   <constant name="struts.mapper.alwaysSelectFullNamespace" value="true"/>
41   <!-- <constant name="struts.convention.action.includeJars"  /> -->
42   <constant name="struts.convention.action.fileProtocols" value="jar" />
43
44   <constant name="struts.convention.classes.reload" value="false" />
45
46   <constant name="struts.convention.exclude.parentClassLoader" value="true" />
47
48   <package name="convention-default" extends="struts-default">
49   </package>
50 </struts>

struts-plugin.xml是会被struts加载的,struts默认回加载"struts-default.xml,struts-plugin.xml,struts.xml";这些XML。这里需要关注的是上面的24行-36行。

Convention默认扫描的包含strutsstruts2action 或 actions的包,在这些包中实现了com.opensymphony.xwork2.Action或者是名字以Action结尾(上面struts-plugin.xml第26行的配置)的类型会被当作Action处理。下面这些类都会被当作Action处理:

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

strutsstruts2action 或 actions下面的子包会被当作命名空间(namespace)

1 com.example.actions.MainAction -> /
2 com.example.actions.products.Display -> /products
3 com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details

Action类的驼峰命名规则将被“-”分隔(上面struts-plugin.xml第32行配置)如下:

1 com.example.actions.MainAction -> /main
2 com.example.actions.products.Display -> /products/display
3 com.example.struts.company.details.ShowCompanyDetailsAction -> /company/details/show-company-details

下面是一个Action约定的例子(创建3个Action分别对应上面3种规则):

 1 package yaolin.core.action;
 2 /**
 3  * /out.action
 4  * @author yaolin
 5  */
 6 public class OutAction { // 对应第一种规则
 7     public String execute() {
 8         return "success";
 9     }
10 }
 1 package yaolin.core.action.ns;
 2 /**
 3  * ns子包名作为命名空间
 4  * /ns/in.action
 5  * @author yaolin
 6  */
 7 public class InAction { // 对应第二种规则
 8
 9     public String execute() {
10         return "input";
11     }
12
13     // /ns/in!play.action
14     public String play() {
15         return "play";
16     }
17 }
 1 package yaolin.core.action.ns;
 2 /**
 3  * ns子包名作为命名空间
 4  * /ns/nil-oay.action
 5  * @author yaolin
 6  */
 7 public class NilOayAction { // 对应第三种规则
 8
 9     public String execute() {
10         return "input";
11     }
12 }

创建struts.xml 开启“!”方法匹配(这里非必要,用于匹配play方法)

1 <!DOCTYPE struts PUBLIC
2     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
3     "http://struts.apache.org/dtds/struts-2.3.dtd">
4 <struts>
5     <constant name="struts.enable.DynamicMethodInvocation" value="true" />
6 </struts>

创建对应result的jsp页面(上面struts-plugin.xml第24行指定了jsp文件的根路径问“/WEB-INF/content”)

(2)Result约定

Result约定是在action名字之后加上“-result”,即如果InAction方法返回的是"input",那么jsp的名称为"in-input"(“in-input.jsp”),如果方法放回的是“success”则既可以匹配“in.jsp”也可以匹配“in-success.jsp”,如下表:


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

详见Struts源码,如下:

 1 org.apache.struts2.convention.ConventionUnknownHandler#handleUnknownResult
 2 public Result handleUnknownResult(ActionContext actionContext, String actionName,ActionConfig actionConfig, String resultCode) throws XWorkException {
 3
 4     PackageConfig pkg = configuration.getPackageConfig(actionConfig.getPackageName());
 5     String ns = pkg.getNamespace();
 6     String pathPrefix = determinePath(actionConfig, ns);
 7
 8     Result result = scanResultsByExtension(ns, actionName, pathPrefix, resultCode, actionContext);
 9
10     if (result == null) {
11         // Try /idx/action/index.jsp
12         Map<String, ResultTypeConfig> resultsByExtension = conventionsService.getResultTypesByExtension(pkg);
13         for (String ext : resultsByExtension.keySet()) {
14             if (LOG.isTraceEnabled()) {
15                 String fqan = ns + "/" + actionName;
16                 LOG.trace("Checking for [#0/index.#1]", fqan, ext);
17             }
18             String path = string(pathPrefix, actionName, "/index", nameSeparator, resultCode, ".", ext);
19             result = findResult(path, resultCode, ext, actionContext, resultsByExtension);
20             if (result != null) {
21                 break;
22             }
23             path = string(pathPrefix, actionName, "/index.", ext);
24             result = findResult(path, resultCode, ext, actionContext, resultsByExtension);
25             if (result != null) {
26                 break;
27             }
28         }
29     }
30
31     if (result == null && resultCode != null) {
32         //try to find an action to chain to. If the source action is "foo" and
33         //the result is "bar", we will try to find an action called "foo-bar"
34         //in the same package
35         String chainedTo = actionName + nameSeparator + resultCode;
36         ActionConfig chainedToConfig = pkg.getActionConfigs().get(chainedTo);
37         if (chainedToConfig != null) {
38             if (LOG.isTraceEnabled()) {
39                 LOG.trace("Action [#0] used as chain result for [#1] and result [#2]", chainedTo, actionName, resultCode);
40             }
41             ResultTypeConfig chainResultType = pkg.getAllResultTypeConfigs().get("chain");
42             result = buildResult(chainedTo, resultCode, chainResultType, actionContext);
43         }
44     }
45     return result;
46 }

(3)chain约定

如果Action的方法中返回的result中没有对应的物理视图且这个result跟这个Action类中的某个方法名一致,那么Struts,会自动转化成chain类型,规则是当前action+"-"+result(这里的"-"是上面struts-plugin.xml第32行配置)。

从上面org.apache.struts2.convention.ConventionUnknownHandler#handleUnknownResult的源码中可以看出如果result没有匹配到且“index”和默认拓展etx都没有匹配到result,那么struts会进行chain处理,如果原action是“foo”、result是“bar“,则chain为”foo-bar“,注意这里action是"action",不是Action中的方法("!"后面的),看一下下面的例子:

 1 package yaolin.core.action.ns;
 2
 3 import org.apache.struts2.convention.annotation.Action;
 4
 5 /**
 6  * ns子包名作为命名空间
 7  * /ns/nil-oay.action
 8  * @author yaolin
 9  */
10 public class NilOayAction {
11
12     public String foo() {
13         return "bar";
14     }
15
16     // chain to
17     @Action("nil-oay-bar")
18     public String bar() {
19         return "foo-bar";
20     }
21 }

这里foo是NilOayAction的一个方法(非execute),则访问规则为/ns/nil-oay!foo.action,但是没有为其指定"nil-oay-bar.jsp"物理视图,而NilOayAction类中有跟result一样名字的bar函数。那么Struts会将其转化为Chain,上一个action名称,即"nil-oay"(这里不是foo,foo是方法名,不是action),再加入result,即"bar",组成"nil-oay-bar",这样会访问上面的bar()方法,bar()方法@Action("nil-oay-bar"),这时返回result="foo-bar",对应的物理视图为"/WEB-INF/content/nil-oay-bar-foo-bar.jsp",如果找不到,则会直接找"/WEB-INF/content/foo-bar.jsp"。

(4)注解

(a)Action 注解:


Annotation


Description


Actions Annotation


Group of @Action annotations, maps multiple URLs to the same action


Action Annotation


Defines the URL of an action


InterceptorRefs Annotation


Gropup of @InterceptorRef annotations


InterceptorRef Annotation


Interceptor, or interceptor stack to be applied to at action


Results Annotation


Group of @Result annotations


Result Annotation


Defines a result for an action


Namespace Annotation


Set the path of the action URL (used to overwrite the default)


ResultPath Annotation


Set where the results are located (used to overwrite the default)


ParentPackage Annotation


Set the parent package of the actions (used to overwrite the default)


ExceptionMappings


Group of @ExceptionMapping annotations


ExceptionMapping


Defines an exception mapping

(b)Workflow  注解


Annotation


Description


InputConfig Annotation


Defines what method to execute, or result to be returned if there are validation errors

(c) Interceptor 注解


Annotation


Description


After Annotation


Marks a action method that needs to be executed after the result.


Before Annotation


Marks a action method that needs to be executed before the main action method.


BeforeResult Annotation


Marks a action method that needs to be executed before the result.

(d) Validation 注解


Annotation


Description


ConversionErrorFieldValidator Annotation


Checks if there are any conversion errors for a field.


DateRangeFieldValidator Annotation


Checks that a date field has a value within a specified range.


DoubleRangeFieldValidator Annotation


Checks that a double field has a value within a specified range.


EmailValidator Annotation


Checks that a field is a valid e-mail address.


ExpressionValidator Annotation


Validates an expression.


FieldExpressionValidator Annotation


Uses an OGNL expression to perform its validator.


IntRangeFieldValidator Annotation


Checks that a numeric field has a value within a specified range.


RegexFieldValidator Annotation


Validates a regular expression for a field.


RequiredFieldValidator Annotation


Checks that a field is non-null.


RequiredStringValidator Annotation


Checks that a String field is not empty.


StringLengthFieldValidator Annotation


Checks that a String field is of the right length.


UrlValidator Annotation


Checks that a field is a valid URL.


Validation Annotation


Marker annotation for validation at Type level.


Validations Annotation


Used to group validation annotations.


VisitorFieldValidator Annotation


Invokes the validation for a property‘s object type.


CustomValidator Annotation


Use this annotation for your custom validator types.

(e)Type Convention 注解


Annotation


Description


Conversion Annotation


Marker annotation for type conversions at Type level.


CreateIfNull Annotation


For Collection and Map types: Create the types within the Collection or Map, if null.


Element Annotation


For Generic types: Specify the element type for Collection types and Map values.


Key Annotation


For Generic types: Specify the key type for Map keys.


KeyProperty Annotation


For Generic types: Specify the key property name value.


TypeConversion Annotation


Used for class and application wide conversion rules.

接下来将用注解进行开发。

未完,待续。

时间: 2025-01-02 16:41:32

菜鸟学Struts2——零配置(Convention )的相关文章

Struts2 Convention Plugin ( struts2 零配置 )

Struts2 Convention Plugin ( struts2 零配置 ) convention-plugin 可以用来实现 struts2 的零配置.零配置的意思并不是说没有配置,而是通过约定大于配置的方式,大量通过约定来调度页面的跳转而使得配置大大减少.考虑到某种因素,这里采用 myeclipse 作为示例 IDE,环境 : JDK 1.6 myeclipse 8.6.1 struts 2.1.8 web.xml <filter>       <filter-name>

Struts2零配置介绍(约定访问)

从struts2.1开始,struts2 引入了Convention插件来支持零配置,使用约定无需struts.xml或者Annotation配置 需要 如下四个JAR包 插件会自动搜索如下类 action.actions.struts.struts2包下所有Java类 所有实现了com.opensymphony.xwork2.Action的Java类 所有类名以Action结尾的Java类 下面类名都符合Convention插件 cn.yzu.struts2.HelloAction cn.yz

菜鸟学Struts2——Interceptors

昨天学习Struts2的Convention plugin,今天利用Convention plugin进行Interceptor学习,虽然是使用Convention plugin进行零配置开发,这只是在Interceptor的使用上,定义Interceptor还是使用strutx.xml配置形式.Interceptors模块如下图: (1)编写Interceptor 自定义Interceptor可以实现com.opensymphony.xwork2.interceptor.Interceptor

struts2零配置参考示例

<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name&

菜鸟学Struts2——Struts工作原理

在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中需要用户实现的部分只有三个,那就是struts.xml,Action,Template(JSP),如下图: 2.3.31中的org.apache.struts2.dispatcher.ActionContextCleanUp已经被标记为@Deprecated Since Struts 2.1.3,2

菜鸟学Struts2——Actions

在对Struts2的工作原理学习之后,对Struts2的Action进行学习.主要对Struts2文档Guides中的Action分支进行学习,如下图: 1.Model Driven(模型驱动) Struts2可以让开发者不必在需要接收很多参数的时候,在Action定义一系列的属性,或者定义一个类属性传参的时候使用className.fieldName的形式传值.使用Struts2的Model Driven需要打开Model Driven拦截器,不过这个拦截器(scopedModelDriven

struts2 Convention插件零配置,使用注解开发

从struts21开始,struts2不再推荐使用codebehind作为零配置插件,而是改用Convention插件来支持零配置.与以前相比较,Convention插件更彻底. 使用Convention插件,需要将struts2-convention-plugin-2.3.1.2.jar文件复制到lib目录中即可 这个插件是自动搜索action的功能: 规则如下:它会自动搜索位于action,actions,struts.struts2包下的java类.   Convention插件会把如下两

菜鸟学SSH(十六)——Struts2内部是如何工作的

前面说完了Spring.Hibernate,很自然今天轮到struts了.struts的核心原理就是通过拦截器来处理客户端的请求,经过拦截器一系列的处理后,再交给Action.下面先看看struts官方的工作原理图: 图1 struts原理图 简单分析一下:首先客户端发来HttpServletRequest请求,传递给FilerDispatcher(ActionMapper是访问静态资源(struts的jar文件等)时用的,平时很少用),然后FilerDispatcher会为我们创建一个Acti

JAVAWEB开发之Struts2详解(二)——Action接受请求参数、类型转换器、使用Struts2的输入校验、以及遵守约定规则实现Struts2的零配置

Action接受请求参数 作为MVC框架,必须要负责解析HTTP请求参数,并将其封装到Model对象中 Struts2提供了非常强大的类型转换机制用于请求数据 到 model对象的封装 Struts2和MVC定义关系 StrutsPrepareAndExecuteFilter:控制器 在Struts2中action是什么?(Struts2是一个MVC框架) V:jsp M:action C:action StrutsPrepareAndExecuteFilter Struts2提供了三种数据封装