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

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

(1)环境准备

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

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

(2)Action约定

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

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd"> <struts order="20">
<bean type="com.opensymphony.xwork2.UnknownHandler" name="convention" class="org.apache.struts2.convention.ConventionUnknownHandler"/> <bean type="org.apache.struts2.convention.ActionConfigBuilder" name="convention" class="org.apache.struts2.convention.PackageBasedActionConfigBuilder"/>
<bean type="org.apache.struts2.convention.ActionNameBuilder" name="convention" class="org.apache.struts2.convention.SEOActionNameBuilder"/>
<bean type="org.apache.struts2.convention.ResultMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultResultMapBuilder"/>
<bean type="org.apache.struts2.convention.InterceptorMapBuilder" name="convention" class="org.apache.struts2.convention.DefaultInterceptorMapBuilder"/>
<bean type="org.apache.struts2.convention.ConventionsService" name="convention" class="org.apache.struts2.convention.ConventionsServiceImpl"/> <bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.packageProvider" class="org.apache.struts2.convention.ClasspathPackageProvider"/>
<bean type="com.opensymphony.xwork2.config.PackageProvider" name="convention.containerProvider" class="org.apache.struts2.convention.ClasspathConfigurationProvider"/> <constant name="struts.convention.actionConfigBuilder" value="convention"/>
<constant name="struts.convention.actionNameBuilder" value="convention"/>
<constant name="struts.convention.resultMapBuilder" value="convention"/>
<constant name="struts.convention.interceptorMapBuilder" value="convention"/>
<constant name="struts.convention.conventionsService" value="convention"/> <constant name="struts.convention.result.path" value="/WEB-INF/content/"/>
<constant name="struts.convention.result.flatLayout" value="true"/>
<constant name="struts.convention.action.suffix" value="Action"/>
<constant name="struts.convention.action.disableScanning" value="false"/>
<constant name="struts.convention.action.mapAllMatches" value="false"/>
<constant name="struts.convention.action.checkImplementsAction" value="true"/>
<constant name="struts.convention.default.parent.package" value="convention-default"/>
<constant name="struts.convention.action.name.lowercase" value="true"/>
<constant name="struts.convention.action.name.separator" value="-"/>
<constant name="struts.convention.package.locators" value="action,actions,struts,struts2"/>
<constant name="struts.convention.package.locators.disable" value="false"/>
<constant name="struts.convention.package.locators.basePackage" value=""/>
<constant name="struts.convention.exclude.packages" value="org.apache.struts.*,org.apache.struts2.*,org.springframework.web.struts.*,org.springframework.web.struts2.*,org.hibernate.*"/>
<constant name="struts.convention.relative.result.types" value="dispatcher,velocity,freemarker"/>
<constant name="struts.convention.redirect.to.slash" value="true"/>
<constant name="struts.convention.action.alwaysMapExecute" value="true"/>
<constant name="struts.mapper.alwaysSelectFullNamespace" value="true"/>
<!-- <constant name="struts.convention.action.includeJars" /> -->
<constant name="struts.convention.action.fileProtocols" value="jar" /> <constant name="struts.convention.classes.reload" value="false" /> <constant name="struts.convention.exclude.parentClassLoader" value="true" /> <package name="convention-default" extends="struts-default">
</package>
</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处理:

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

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

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

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

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

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

 package yaolin.core.action;
/**
* /out.action
* @author yaolin
*/
public class OutAction { // 对应第一种规则
public String execute() {
return "success";
}
}
 package yaolin.core.action.ns;
/**
* ns子包名作为命名空间
* /ns/in.action
* @author yaolin
*/
public class InAction { // 对应第二种规则 public String execute() {
return "input";
} // /ns/in!play.action
public String play() {
return "play";
}
}
 package yaolin.core.action.ns;
/**
* ns子包名作为命名空间
* /ns/nil-oay.action
* @author yaolin
*/
public class NilOayAction { // 对应第三种规则 public String execute() {
return "input";
}
}

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

 <!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
</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源码,如下:

 org.apache.struts2.convention.ConventionUnknownHandler#handleUnknownResult
public Result handleUnknownResult(ActionContext actionContext, String actionName,ActionConfig actionConfig, String resultCode) throws XWorkException { PackageConfig pkg = configuration.getPackageConfig(actionConfig.getPackageName());
String ns = pkg.getNamespace();
String pathPrefix = determinePath(actionConfig, ns); Result result = scanResultsByExtension(ns, actionName, pathPrefix, resultCode, actionContext); if (result == null) {
// Try /idx/action/index.jsp
Map<String, ResultTypeConfig> resultsByExtension = conventionsService.getResultTypesByExtension(pkg);
for (String ext : resultsByExtension.keySet()) {
if (LOG.isTraceEnabled()) {
String fqan = ns + "/" + actionName;
LOG.trace("Checking for [#0/index.#1]", fqan, ext);
}
String path = string(pathPrefix, actionName, "/index", nameSeparator, resultCode, ".", ext);
result = findResult(path, resultCode, ext, actionContext, resultsByExtension);
if (result != null) {
break;
}
path = string(pathPrefix, actionName, "/index.", ext);
result = findResult(path, resultCode, ext, actionContext, resultsByExtension);
if (result != null) {
break;
}
}
} if (result == null && resultCode != null) {
//try to find an action to chain to. If the source action is "foo" and
//the result is "bar", we will try to find an action called "foo-bar"
//in the same package
String chainedTo = actionName + nameSeparator + resultCode;
ActionConfig chainedToConfig = pkg.getActionConfigs().get(chainedTo);
if (chainedToConfig != null) {
if (LOG.isTraceEnabled()) {
LOG.trace("Action [#0] used as chain result for [#1] and result [#2]", chainedTo, actionName, resultCode);
}
ResultTypeConfig chainResultType = pkg.getAllResultTypeConfigs().get("chain");
result = buildResult(chainedTo, resultCode, chainResultType, actionContext);
}
}
return result;
}

(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中的方法("!"后面的),看一下下面的例子:

 package yaolin.core.action.ns;

 import org.apache.struts2.convention.annotation.Action;

 /**
* ns子包名作为命名空间
* /ns/nil-oay.action
* @author yaolin
*/
public class NilOayAction { public String foo() {
return "bar";
} // chain to
@Action("nil-oay-bar")
public String bar() {
return "foo-bar";
}
}

这里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. .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验

    不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了.虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来.今天就给大家 ...

  2. 创建 OVS Local Network - 每天5分钟玩转 OpenStack(129)

    上一节我们完成了 OVS 的准备工作,本节从最基础的 local network 开始学习.local network 不会与宿主机的任何物理网卡连接,流量只被限制在宿主机内,同时也不关联任何的 VL ...

  3. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  4. ASP.NET Core 中文文档 第四章 MVC(4.6)Areas(区域)

    原文:Areas 作者:Dhananjay Kumar 和 Rick Anderson 翻译:耿晓亮(Blue) 校对:许登洋(Seay) Areas 是 ASP.NET MVC 用来将相关功能组织成 ...

  5. c#比较两个数组的差异

    将DataTable中某一列数据直接转换成数组进行比较,使用的Linq,要引用命名空间using System.Linq; string[] arrRate = dtRate.AsEnumerable ...

  6. 如何开发一个Jquery插件

    Jquery有两种开发插件的方法: 1.jquery.fn.extend(object); 2.jquery.extend(object); 第一种方法是给Jquery对象添加方法,jquery.fn ...

  7. 基于注解的Spring多数据源配置和使用

    前一段时间研究了一下spring多数据源的配置和使用,为了后期从多个数据源拉取数据定时进行数据分析和报表统计做准备.由于之前做过的项目都是单数据源的,没有遇到这种场景,所以也一直没有去了解过如何配置多 ...

  8. 【腾讯Bugly干货分享】程序员们也该知道的事——“期权和股票”

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/pfj9NLLuKYAfJJF84R9WAw 作者:B ...

  9. ASP.NET Web API 控制器执行过程(一)

    ASP.NET Web API 控制器执行过程(一) 前言 前面两篇讲解了控制器的创建过程,只是从框架源码的角度去简单的了解,在控制器创建过后所执行的过程也是尤为重要的,本篇就来简单的说明一下控制器在 ...

  10. How ASP.NET Web API 2.0 Works?[持续更新中…]

    一.概述 RESTful Web API [Web标准篇]RESTful Web API [设计篇] 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用 二.路由 ...