又是周末,继续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.

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

未完,待续。

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

  1. Struts2 Convention Plugin ( struts2 零配置 )

    Struts2 Convention Plugin ( struts2 零配置 ) convention-plugin 可以用来实现 struts2 的零配置.零配置的意思并不是说没有配置,而是通过约 ...

  2. 菜鸟学Struts2——Interceptors

    昨天学习Struts2的Convention plugin,今天利用Convention plugin进行Interceptor学习,虽然是使用Convention plugin进行零配置开发,这只是 ...

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

    从struts2.1开始,struts2 引入了Convention插件来支持零配置,使用约定无需struts.xml或者Annotation配置 需要 如下四个JAR包 插件会自动搜索如下类 act ...

  4. struts2 零配置

    一.新建一个web项目,命名为:struts2 二.导入strut2所需的jar包 所需jar下载:http://pan.baidu.com/s/1dDxP4Z3 三.配置struts2的启动文件,在 ...

  5. spring+hibernate+struts2零配置整合

    说句实话,很久都没使用SSH开发项目了,但是出于各种原因,再次记录一下整合方式,纯注解零配置. 一.前期准备工作 gradle配置文件: group 'com.bdqn.lyrk.ssh.study' ...

  6. 注解实现struts2零配置

    零配置指的是不经过配置文件struts.xml配置Action 首先:导入jar   struts2-convention-plugin-2.3.24.1.jar package com.action ...

  7. struts2零配置參考演示样例

    <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2 ...

  8. 菜鸟学Struts2——Results

    在对Struts2的Action学习之后,对Struts2的Result进行学习.主要对Struts2文档Guides中的Results分支进行学习,如下图: 1.Result Types(Resul ...

  9. 菜鸟学Struts2——Actions

    在对Struts2的工作原理学习之后,对Struts2的Action进行学习.主要对Struts2文档Guides中的Action分支进行学习,如下图: 1.Model Driven(模型驱动) St ...

随机推荐

  1. C语言 · 薪水计算

    问题描述 编写一个程序,计算员工的周薪.薪水的计算是以小时为单位,如果在一周的时间内,员工工作的时间不超过40 个小时,那么他/她的总收入等于工作时间乘以每小时的薪水.如果员工工作的时间在40 到50 ...

  2. 使用CSS3实现一个3D相册

    CSS3系列我已经写过两篇文章,感兴趣的同学可以先看一下CSS3初体验之奇技淫巧,CSS3 3D立方体效果-transform也不过如此 第一篇主要列出了一些常用或经典的CSS3技巧和方法:第二篇是一 ...

  3. nginx源码分析之模块初始化

    在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...

  4. 在开启DRS的集群中修复VMware虚拟主机启动问题

    通过iSCSI方式连接到ESXi主机上的外挂存储意外失联了一段时间,导致部分虚拟主机在集群中呈现出孤立的状态,单独登陆到每台ESXi上可以看到这些虚拟主机都变成了unknow状态.因为有过上一次(VM ...

  5. Velocity笔记--使用Velocity获取动态Web项目名的问题

    以前使用jsp开发的时候,可以通过request很轻松的获取到根项目名,现在换到使用velocity渲染视图,因为已经不依赖servlet,request等一些类的环境,而Web项目的根项目名又不是写 ...

  6. obj.style.z-index的正确写法

    obj.style.z-index的正确写法 今天发现obj.style.z-index在js里面报错,后来才知道在js里应该把含"-"的字符写成驼峰式,例如obj.style.z ...

  7. php 基础代码大全(不断完善中)

    下面是基础的PHP的代码,不断完善中~ //语法错误(syntax error)在语法分析阶段,源代码并未被执行,故不会有任何输出. /* [命名规则] */ 常量名 类常量建议全大写,单词间用下划线 ...

  8. RMS去除在线认证

    在微软 OS 平台创建打开 RMS 文档如何避免时延 相信我们在企业内部的环境中已经部署了微软最新的OS平台,Windows 7和Windows 2008 R2,在这些OS平台上使用IRM功能时,您有 ...

  9. 深入理解 Android 之 View 的绘制流程

    概述 本篇文章会从源码(基于Android 6.0)角度分析Android中View的绘制流程,侧重于对整体流程的分析,对一些难以理解的点加以重点阐述,目的是把View绘制的整个流程把握好,而对于特定 ...

  10. Centos6.x 下安装Jexus独立版

    操作步骤: #cd /tmp #wget linuxdot.net/down/jexus-5.8.1-x64.tar.gz 注:如果有新版本,则修改为相应版本号即可. #tar -zxvf jexus ...