菜鸟学Struts2——零配置(Convention )
又是周末,继续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默认扫描的包含struts, struts2, action 或 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
而struts, struts2, action 或 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 |
|---|---|
|
Group of @Action annotations, maps multiple URLs to the same action |
|
|
Defines the URL of an action |
|
|
Gropup of @InterceptorRef annotations |
|
|
Interceptor, or interceptor stack to be applied to at action |
|
|
Group of @Result annotations |
|
|
Defines a result for an action |
|
|
Set the path of the action URL (used to overwrite the default) |
|
|
Set where the results are located (used to overwrite the default) |
|
|
Set the parent package of the actions (used to overwrite the default) |
|
|
Group of @ExceptionMapping annotations |
|
|
Defines an exception mapping |
(b)Workflow 注解
|
Annotation |
Description |
|---|---|
|
Defines what method to execute, or result to be returned if there are validation errors |
(c) Interceptor 注解
|
Annotation |
Description |
|---|---|
|
Marks a action method that needs to be executed after the result. |
|
|
Marks a action method that needs to be executed before the main action method. |
|
|
Marks a action method that needs to be executed before the result. |
(d) Validation 注解
|
Annotation |
Description |
|---|---|
|
Checks if there are any conversion errors for a field. |
|
|
Checks that a date field has a value within a specified range. |
|
|
Checks that a double field has a value within a specified range. |
|
|
Checks that a field is a valid e-mail address. |
|
|
Validates an expression. |
|
|
Uses an OGNL expression to perform its validator. |
|
|
Checks that a numeric field has a value within a specified range. |
|
|
Validates a regular expression for a field. |
|
|
Checks that a field is non-null. |
|
|
Checks that a String field is not empty. |
|
|
Checks that a String field is of the right length. |
|
|
Checks that a field is a valid URL. |
|
|
Marker annotation for validation at Type level. |
|
|
Used to group validation annotations. |
|
|
Invokes the validation for a property's object type. |
|
|
Use this annotation for your custom validator types. |
(e)Type Convention 注解
|
Annotation |
Description |
|---|---|
|
Marker annotation for type conversions at Type level. |
|
|
For Collection and Map types: Create the types within the Collection or Map, if null. |
|
|
For Generic types: Specify the element type for Collection types and Map values. |
|
|
For Generic types: Specify the key type for Map keys. |
|
|
For Generic types: Specify the key property name value. |
|
|
Used for class and application wide conversion rules. |
接下来将用注解进行开发。
未完,待续。
菜鸟学Struts2——零配置(Convention )的更多相关文章
- Struts2 Convention Plugin ( struts2 零配置 )
Struts2 Convention Plugin ( struts2 零配置 ) convention-plugin 可以用来实现 struts2 的零配置.零配置的意思并不是说没有配置,而是通过约 ...
- 菜鸟学Struts2——Interceptors
昨天学习Struts2的Convention plugin,今天利用Convention plugin进行Interceptor学习,虽然是使用Convention plugin进行零配置开发,这只是 ...
- Struts2零配置介绍(约定访问)
从struts2.1开始,struts2 引入了Convention插件来支持零配置,使用约定无需struts.xml或者Annotation配置 需要 如下四个JAR包 插件会自动搜索如下类 act ...
- struts2 零配置
一.新建一个web项目,命名为:struts2 二.导入strut2所需的jar包 所需jar下载:http://pan.baidu.com/s/1dDxP4Z3 三.配置struts2的启动文件,在 ...
- spring+hibernate+struts2零配置整合
说句实话,很久都没使用SSH开发项目了,但是出于各种原因,再次记录一下整合方式,纯注解零配置. 一.前期准备工作 gradle配置文件: group 'com.bdqn.lyrk.ssh.study' ...
- 注解实现struts2零配置
零配置指的是不经过配置文件struts.xml配置Action 首先:导入jar struts2-convention-plugin-2.3.24.1.jar package com.action ...
- struts2零配置參考演示样例
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2 ...
- 菜鸟学Struts2——Results
在对Struts2的Action学习之后,对Struts2的Result进行学习.主要对Struts2文档Guides中的Results分支进行学习,如下图: 1.Result Types(Resul ...
- 菜鸟学Struts2——Actions
在对Struts2的工作原理学习之后,对Struts2的Action进行学习.主要对Struts2文档Guides中的Action分支进行学习,如下图: 1.Model Driven(模型驱动) St ...
随机推荐
- Javascript 的执行环境(execution context)和作用域(scope)及垃圾回收
执行环境有全局执行环境和函数执行环境之分,每次进入一个新执行环境,都会创建一个搜索变量和函数的作用域链.函数的局部环境不仅有权访问函数作用于中的变量,而且可以访问其外部环境,直到全局环境.全局执行环境 ...
- nodejs进阶(4)—读取图片到页面
我们先实现从指定路径读取图片然后输出到页面的功能. 先准备一张图片imgs/dog.jpg. file.js里面继续添加readImg方法,在这里注意读写的时候都需要声明'binary'.(file. ...
- hadoop 2.7.3本地环境运行官方wordcount-基于HDFS
接上篇<hadoop 2.7.3本地环境运行官方wordcount>.继续在本地模式下测试,本次使用hdfs. 2 本地模式使用fs计数wodcount 上面是直接使用的是linux的文件 ...
- 我为NET狂官方面试题-数据库篇
求结果:select "1"? 查找包含"objs"的表?查找包含"o"的数据库? 求今天距离2002年有多少年,多少天? 请用一句SQL获 ...
- InnoDB体系结构学习笔记
后台线程 Master Thread 核心的后台线程,主要负责将缓冲池的数据异步刷新到磁盘,保证数据的一致性,包括(脏页的刷新).合并插入缓冲.(UNDO页的回收)等 IO Thread 4个writ ...
- MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示
上次创建了栏目模型,这次主要做栏目的前台显示.涉及到数据存储层.业务逻辑层和Web层.用到了迁移,更新数据库和注入的一些内容. 一.添加数据存储层 1.添加Ninesky.DataLibrary(与上 ...
- 卡片抽奖插件 CardShow
这个小项目(卡片秀)是一个卡片抽奖特效插件,用开源项目这样的词语让我多少有些羞愧,毕竟作为一个涉世未深的小伙子,用项目的标准衡量还有很大差距.不过该案例采用 jQuery 插件方式编写,提供配置参数并 ...
- javaScript中的小细节-script标签中的预解析
首先介绍预解析,虽然预解析字面意思很好理解,但是却是出坑出的最多的地方,也是bug经常会有的地方,利用好预解析的特性可以解决很多问题,并且提高代码的质量及数量,浏览器在解析代码前会把变量的声明和函数( ...
- git 命令总结
1 删除分支 git push origin :branch name(Task_******) //删除远程分支 git branch -D branch name(Task_******) ...
- Vim使用
模式 ESC\Ctrl+c:退出编辑模式 ZZ\wq:命令模式下保存退出 编辑 i:进入编辑模式 I:转到行首非空字符开始编辑 s:删除当前字符进入编辑模式 a:从当前字符后开始编辑 A:从当前行末非 ...