Struts 2框架分析

时间:2019-05-13 15:49:52下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《Struts 2框架分析》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《Struts 2框架分析》。

第一篇:Struts 2框架分析

宁波工程学院学年论文

Struts2框架分析

汤禹鑫

宁波工程学院,(315016)

E-mail 372854786@qq.com

摘 要: 本文对基于MVC模式,延续了Struts1和WebWork优势的WEB框架——Struts2框架的各个层次的组成、功能进行了详细的介绍。关键词:Struts2;框架;J2EE;

1.引言

Apache Struts2是一个为企业级应用打造的优秀的、可扩展的Web框架。该框架旨在充分精简应用程序的开发周期,从而减少创建、发布、应用所花费的时间。而且对于Struts1有很多革命性的改进,但它并不是全新的框架,而是在WebWork框架的基础上发展起来的。所以也可以说Struts2是WebWork的升级,吸收了Struts1和WebWork的优势,稳定性、性能都有了很好的保证。

2.Struts2的起源和背景

2.1 Struts1

在过去,Struts1是所有MVC框架中不容辩驳的胜利者。其程序运行流程如图2-1所示。

图2-1 Struts 1的程序运行流程

但是对于Struts 1框架而言,因为它与JSP/Servlet耦合非常紧密,因而导致了许多不可避免的缺陷,还有支持的表现层技术单

一、代码严重依赖于Struts 1 API。随着Web应用的拙见扩大,这些缺陷逐渐变成制约Struts 1发展的的重要因素——这也是Struts 2出现的原因。

宁波工程学院学年论文

(1)客户端初始化一个指向Servlet容器(例如Tomcat)的请求;

(2)这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其它框架的集成很有帮助,例如:SiteMesh Plugin);

(3)接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action;

(4)如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy;

(5)ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类;

(6)ActionProxy创建一个ActionInvocation的实例;

(7)ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用;

(8)一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts 2 框架中继承的标签,在这个过程中需要涉及到ActionMapper。

3.2 Struts 2配置文件

Struts2 配置文件是用户请求(View)和业务逻辑模块(Model)Action 之间联系的桥梁。开发者可以通过修改Struts2的配置文件来快速适应业务需求,它是整个Struts2的精髓之一。当然,熟悉Struts1和WebWork的框架的人对配置文件一定不会陌生,同Struts1和WebWork框架一样,Struts2框架配置文件也分为XML文件和属性资源文件两种。struts.xml 文件中包含了Action 的定义以及Action 的返回值对应的视图资源、命名空间等信息。此外,用户也可以定义自己的XML文件,然后通过include指令将其包含到struts.xml文件中。另一类配置文件是属性资源文件。资源文件中一般采用固定的Key-Value形式,用于定义Struts2 全局或者局部的资源数据,例如定义国际化、开发模式等信息。

3.3 Struts 2控制器

Struts 2的控制器组建是Struts 2框架的核心,事实上所有MVC框架都是以控制器组件为核心的。正如前面提到的,Struts 2的控制器由两个部分组成:FilterDispatcher和业务控制器Action。前者由框架提供,负责拦截所有的用户请求,其过程如图3-3所示

宁波工程学院学年论文

图3-1 过滤器处理请求过程

对于业务控制器Action,Struts 2框架为用户提供了一个名为Action的接口,在接口中定义了SUCCESS、ERROR、INPUT、LOGIN、NONE五个静态的字符串和一个execute方法,用户在编写自己的Action时只要实现该接口并重写其中的execute方法,将所要实现的业务逻辑在该方法中处理就行了,当调用此Action时,Struts 2框架会自调用execute方法来完成所需的业务逻辑处理。实际上,在Struts2中起作用的业务逻辑并不是用户自定义的Action ,而是系统生成的Action代理,只不过Action代理以用户定义的Action为目标。

3.4 Struts 2标签库

于业Struts 2的标签库也是Struts 2的重要组成部分,Struts 2的标签库提供了非常丰富的功能,这些标签不仅提供了表现层数据处理,而且还提供了基本的流程控制功能,还提供了国际化、Ajax支持等功能。使用标签,开发者可以最大限度地减少页面代码的书写。

4.Struts 2框架应用举例

例如课本上的Struts2用作登陆的例子,添加Struts 2功能框架核心需要如下三个步骤:(1)修改web.xml文件,在web.xml中配置Struts 2的核心Filter。

struts2

org.apache.struts2.dispatcher.FilterDispatcher

(2)将Struts 2框架的类库复制到Web应用的WEB-INF/lib路径下(也可以自己手动进行添加)。

宁波工程学院学年论文

5.结论

Struts 2结合了Struts 1框架和WebWork框架的优点,其框架的各个组件都是可靠的松散耦合。Struts 2最大的特点就是简单性,引入了OGNL表达式和值栈的概念,可以用最单间的代码实现复杂的数据访问。总而言之,Struts 2是一个当今Web开发中一个很重要而且功能足够强大的框架,能让我们更好地设计和完成Web应用。

参考文献

[1]郑阿奇.J2EE应用实践教程.电子工业出版社,2011年7月.[2]李刚.Strut s2权威指南.电子工业出版社,2007年9月.[3]闫术卓.杨强.Strut s2技术详解.电子工业出版社,2008年6月.

第二篇:struts2代码分析

1.Struts2架构图和请求处理流程

请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。

ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里创建ActionProxy,ActionProxy创建ActionInvocation,然后ActionInvocation调用Interceptors,执行Action本身,创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。

2.Struts2部分类介绍

这部分从Struts2参考文档中翻译就可以了。

ActionMapper

ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等java Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docs¥actionmapper.html。

ActionProxy&ActionInvocation

Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。

ConfigurationProvider&Configuration

ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。

3.Struts2请求流程

1、客户端发送请求

2、请求先通过ActionContextCleanUp-->FilterDispatcher

3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action

4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行

5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类

6、ActionProxy创建一个ActionInvocation的实例

7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用

8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现。

首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.接下来就从Dispatcher开始看起,先看其构造函数:

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

我们再看在FilterDispatcher创建Dispatcher的:

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

创建Dispatcher之后,来看init()方法

init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.主要分七步走,看下面注释

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager

=

new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

}

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager

=

new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

throw

}

new ConfigurationException(“Could not find or error in org/apache/struts2/default.properties”, e);

loadSettings(props, defaultSettings);

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings =

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

settings.getImpl(name),// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

再来看第二步:init_TraditionalXmlConfigurations()

private void init_TraditionalXmlConfigurations(){

settings.getImpl(name), //首先读取web.xml中的config初始参数值

//如果

使

认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

private void init_TraditionalXmlConfigurations(){

//首先读取web.xml中的config初始参数值

//如果

使

认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

对于其它配置文件只用接口。

类XmlConfigurationProvider负责配置文件的读取和解析,首先通过init()中的loadDocuments(configFileName);利用DomHelper中的

public static Document parse(InputSource inputSource, Map dtdMappings)将configFileName配置文件通过SAX解析方式按照DtdMappings解析成Document对象.然后通过Provider的register()方法加载“bean”和“constant”属性,再通过loadPackages()加载package及package中的属性

addAction()方法负责读取标签,并将数据保存在ActionConfig中; addResultTypes()方法负责将标签转化为ResultTypeConfig对象; loadInterceptors()方法负责将标签转化为InterceptorConfi对象;

loadInterceptorStack()方法负责将标签转化为InterceptorStackConfig对象;

StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProviderloadInterceptorStacks()方法负责将标签转化成InterceptorStackConfig对象。

而上面的方法最终会被addPackage()方法调用,addPackage又会被Provider的loadPackages()调用,将所读取到的数据汇集到PackageConfig对象中。

protected PackageConfig

addPackage(Element

packageElement)

throws ConfigurationException {

PackageConfig.Builder newPackage = buildPackageContext(packageElement);

if(newPackage.isNeedsRefresh()){

return newPackage.build();

}

// add result types(and default result)to this package

addResultTypes(newPackage, packageElement);

// load the interceptors and interceptor stacks for this package

loadInterceptors(newPackage, packageElement);

// load the default interceptor reference for this package

loadDefaultInterceptorRef(newPackage, packageElement);

// load the default class ref for this package

loadDefaultClassRef(newPackage, packageElement);

// load the global result list for this package

loadGlobalResults(newPackage, packageElement);

// load the global exception handler list for this package

loadGobalExceptionMappings(newPackage, packageElement);

// get actions

NodeList actionList = packageElement.getElementsByTagName(“action”);

for(int i = 0;i < actionList.getLength();i++){

Element actionElement =(Element)actionList.item(i);

addAction(actionElement, newPackage);

}

// load the default action reference for this package

loadDefaultActionRef(newPackage, packageElement);

PackageConfig cfg = newPackage.build();

configuration.addPackageConfig(cfg.getName(), cfg);

return cfg;

}

loadConfigurationFiles解析读取xml中的内容

private List

loadConfigurationFiles(String

fileName,Element includeElement){

...//通过DomHelper调用SAX进行解析xml

doc = DomHelper.parse(in, dtdMappings);

...Element rootElement = doc.getDocumentElement();

NodeList children = rootElement.getChildNodes();

int childSize = children.getLength();

for(int i = 0;i < childSize;i++){

Node childNode = children.item(i);

if(childNode instanceof Element){

Element child =(Element)childNode;

final String nodeName = child.getNodeName();

if(“include”.equals(nodeName)){

String includeFileName = child.getAttribute(“file”);

//解析每个action配置是,对于include文件可以使用通配符*来进行配置

//如Struts.xml中可配置成

if(includeFileName.indexOf('*')!=-1){

ClassPathFinder wildcardFinder = new ClassPathFinder();

wildcardFinder.setPattern(includeFileName);

Vector wildcardMatches = wildcardFinder.findMatches();

for(String match : wildcardMatches){

//递归Load子file中的

docs.addAll(loadConfigurationFiles(match, child));

}

} else {

docs.addAll(loadConfigurationFiles(includeFileName, child));

}

}

}

}

docs.add(doc);

loadedFileUrls.add(url.toString());

...return docs;

}

首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.接下来就从Dispatcher开始看起,先看其构造函数:

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

我们再看在FilterDispatcher创建Dispatcher的:

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

创建Dispatcher之后,来看init()方法

init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.主要分七步走,看下面注释

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

new

}

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

new

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

settings.getImpl(name),if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

props.setProperty(name, settings.getLocationImpl(name));

}

}

再来看第二步:init_TraditionalXmlConfigurations()

private void init_TraditionalXmlConfigurations(){

//首先读取web.xml中的config初始参数值

//如果

使

settings.getImpl(name),用默认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

private void init_TraditionalXmlConfigurations(){

//首先读取web.xml中的config初始参数值

//如果

使

认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

对于其它配置文件只用接口。

类XmlConfigurationProvider负责配置文件的读取和解析,首先通过init()中的loadDocuments(configFileName);利用DomHelper中的

public static Document parse(InputSource inputSource, Map dtdMappings)将configFileName配置文件通过SAX解析方式按照DtdMappings解析成StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProviderDocument对象.然后通过Provider的register()方法加载“bean”和“constant”属性,再通过loadPackages()加载package及package中的属性

addAction()方法负责读取标签,并将数据保存在ActionConfig中; addResultTypes()方法负责将标签转化为ResultTypeConfig对象; loadInterceptors()方法负责将标签转化为InterceptorConfi对象;

loadInterceptorStack()方法负责将标签转化为InterceptorStackConfig对象;

loadInterceptorStacks()方法负责将标签转化成InterceptorStackConfig对象。

而上面的方法最终会被addPackage()方法调用,addPackage又会被Provider的loadPackages()调用,将所读取到的数据汇集到PackageConfig对象中。

protected PackageConfig

addPackage(Element

packageElement)

throws ConfigurationException {

PackageConfig.Builder newPackage = buildPackageContext(packageElement);

if(newPackage.isNeedsRefresh()){

return newPackage.build();

}

// add result types(and default result)to this package

addResultTypes(newPackage, packageElement);

// load the interceptors and interceptor stacks for this package

loadInterceptors(newPackage, packageElement);

// load the default interceptor reference for this package

loadDefaultInterceptorRef(newPackage, packageElement);

// load the default class ref for this package

loadDefaultClassRef(newPackage, packageElement);

// load the global result list for this package

loadGlobalResults(newPackage, packageElement);

// load the global exception handler list for this package

loadGobalExceptionMappings(newPackage, packageElement);

// get actions

NodeList actionList = packageElement.getElementsByTagName(“action”);

for(int i = 0;i < actionList.getLength();i++){

Element actionElement =(Element)actionList.item(i);

addAction(actionElement, newPackage);

}

// load the default action reference for this package

loadDefaultActionRef(newPackage, packageElement);

PackageConfig cfg = newPackage.build();

configuration.addPackageConfig(cfg.getName(), cfg);

return cfg;

}

loadConfigurationFiles解析读取xml中的内容

private List

loadConfigurationFiles(String

fileName, includeElement){

...//通过DomHelper调用SAX进行解析xml

doc = DomHelper.parse(in, dtdMappings);

...Element rootElement = doc.getDocumentElement();

NodeList children = rootElement.getChildNodes();

int childSize = children.getLength();

for(int i = 0;i < childSize;i++){

Node childNode = children.item(i);

if(childNode instanceof Element){

Element child =(Element)childNode;

final String nodeName = child.getNodeName();

if(“include”.equals(nodeName)){

String includeFileName = child.getAttribute(“file”);

//解析每个action配置是,对于include文件可以使用通配符*来进行配置

//如Struts.xml中可配置成

if(includeFileName.indexOf('*')!=-1){

ClassPathFinder wildcardFinder = new ClassPathFinder();

wildcardFinder.setPattern(includeFileName);

Element

Vector wildcardMatches = wildcardFinder.findMatches();

for(String match : wildcardMatches){

//递归Load子file中的

docs.addAll(loadConfigurationFiles(match, child));

}

} else {

docs.addAll(loadConfigurationFiles(includeFileName, child));

}

}

}

}

docs.add(doc);

loadedFileUrls.add(url.toString());

...return docs;

}

接下来第三步:init_LegacyStrutsProperties()调用的是调用的是LegacyPropertiesConfigurationProvider 通过比较前

DefaultPropertiesProvider

用的是LegacyPropertiesConfigurationProvider.发现DefaultPropertiesProvider继承自后者,但重写了register()方法,主要是生成PropertiesSetting的不同,前者是根据org/apache/struts2/default.properties 后者是根据struts.properties 我们展开register()中的Settings.getInstance(),最后是调用getDefaultInstance()

private static Settings getDefaultInstance(){

if(defaultImpl == null){

// Create bootstrap implementation

//不带参数的DefaultSettings(),区别与DefaultPropertiesProvider中直接带default.properties参数

//不带参数就是默认为struts.propertes,并且加载struts.custom.properties所定义的properties文件

defaultImpl = new DefaultSettings();

// Create default implementation

try {

//STRUTS_CONFIGURATION为:struts.configuration

//在struts.proterties中查找struts.configuration的值,这个值必须是org.apache.struts2.config.Configuration接口的实现类

//所以我有个困惑就是在下面的转换当中怎么将Configuration转换成Setting类型的...//这一点先放下了,有时间再研究

String className = get(StrutsConstants.STRUTS_CONFIGURATION);

if(!className.equals(defaultImpl.getClass().getName())){

try {

// singleton instances shouldn't be built accessing request or session-specific context data

defaultImpl oader().loadClass(className), null);

} catch(Exception e){

LOG.error(“Settings:

}

}

} catch(IllegalArgumentException ex){

// ignore

}

private static Settings getDefaultInstance(){

if(defaultImpl == null){

// Create bootstrap implementation

//不带参数的DefaultSettings(),区别与DefaultPropertiesProvider中直接带default.properties参数

//不带参数就是默认为struts.propertes,并且加载struts.custom.properties所定义的properties文件

defaultImpl = new DefaultSettings();

// Create default implementation

try {

//STRUTS_CONFIGURATION为:struts.configuration

//在struts.proterties中查找struts.configuration的值,这个值必须是

Could

not

instantiate

the struts.configuration object, substituting the default implementation.”, e);

=

(Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLorg.apache.struts2.config.Configuration接口的实现类

//所以我有个困惑就是在下面的转换当中怎么将Configuration转换成Setting类型的...//这一点先放下了,有时间再研究

String className = get(StrutsConstants.STRUTS_CONFIGURATION);

if(!className.equals(defaultImpl.getClass().getName())){

try {

// singleton instances shouldn't be built accessing request or session-specific context data

defaultImpl oader().loadClass(className), null);

} catch(Exception e){

LOG.error(“Settings:

}

}

} catch(IllegalArgumentException ex){

// ignore

}

在2.1.6中去掉了第四步:init_ZeroConfiguration();第五步是自定义的configProviders

private void init_CustomConfigurationProviders(){

//从这里可以看到可以将自定义的Provider定义在web.xml中FilterDispatcher的param中:configProviders

String configProvs = initParams.get(”configProviders“);

if(configProvs!= null){

String[] classes = configProvs.split(”¥¥s*[,]¥¥s*“);

for(String cname : classes){

try {

Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

ConfigurationProvider(ConfigurationProvider)cls.newInstance();

configurationManager.addConfigurationProvider(prov);

prov

=

Could

not

instantiate

the struts.configuration object, substituting the default implementation.”, e);

=

(Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassL

}

...}

}

}

private void init_CustomConfigurationProviders(){

//从这里可以看到可以将自定义的Provider定义在web.xml中FilterDispatcher的param中:configProviders

String configProvs = initParams.get(“configProviders”);

if(configProvs!= null){

String[] classes = configProvs.split(“¥¥s*[,]¥¥s*”);

for(String cname : classes){

try {

Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

ConfigurationProvider(ConfigurationProvider)cls.newInstance();

configurationManager.addConfigurationProvider(prov);

}

...}

}

}

第六步:init_FilterInitParameters

//从这里可以看出struts.properties中的属性不仅可以在struts.xml中以constant形式定义,而且可以在FilterDispatcher的param中定义

private void init_FilterInitParameters(){

configurationManager.addConfigurationProvider(new ConfigurationProvider(){

public void destroy(){}

public

void

init(Configuration

configuration)

throws ConfigurationException {}

public void loadPackages()throws ConfigurationException {}

public boolean needsReload(){ return false;}

prov

=

public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

props.putAll(initParams);//在这里实现滴~

}

});

}

//从这里可以看出struts.properties中的属性不仅可以在struts.xml中以constant形式定义,而且可以在FilterDispatcher的param中定义

private void init_FilterInitParameters(){

configurationManager.addConfigurationProvider(new ConfigurationProvider(){

public void destroy(){}

public

void

init(Configuration

configuration)

throws ConfigurationException {}

public void loadPackages()throws ConfigurationException {}

public boolean needsReload(){ return false;}

public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

props.putAll(initParams);//在这里实现滴~

}

});

}

第七步:init_AliasStandardObjects,使用BeanSelectionProvider 这是将配置文件中定义的与实际的类相映射,就是注入bean的依赖关系,这部分以后有时候再研究Container

接下来是看怎样调用这些ConfigurationProviders 展开init_PreloadConfiguration()

private Container init_PreloadConfiguration(){

Configuration config = configurationManager.getConfiguration();

Container container = config.getContainer();

boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

LocalizedTextUtil.setReloadBundles(reloadi18n);

return container;

}

//再看getConfiguration()

public synchronized Configuration getConfiguration(){

if(configuration == null){

setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

try {

//重点就是这个reloadContainer

configuration.reloadContainer(getContainerProviders());

} catch(ConfigurationException e){

setConfiguration(null);

throw new ConfigurationException(“Unable to load configuration.”, e);

}

} else {

conditionalReload();

}

return configuration;

}

private Container init_PreloadConfiguration(){

Configuration config = configurationManager.getConfiguration();

Container container = config.getContainer();

boolean reloadi18n

=

Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

LocalizedTextUtil.setReloadBundles(reloadi18n);

return container;

}

//再看getConfiguration()

public synchronized Configuration getConfiguration(){

if(configuration == null){

setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

try {

//重点就是这个reloadContainer

configuration.reloadContainer(getContainerProviders());

} catch(ConfigurationException e){

setConfiguration(null);

throw new ConfigurationException(“Unable to load configuration.”, e);

}

} else {

conditionalReload();

}

return configuration;

}

展开DefaultConfiguration中的reloadContainer

public synchronized List

reloadContainer(List providers)throws ConfigurationException {

packageContexts.clear();

loadedFileNames.clear();

List

packageProviders = new ArrayList

();

//Struts2(xwork2)用Container来完成依赖注入的功能

//首先初始化一个ContainerBuilder,再由builder来保存接口与实现类或工厂类的对应关系

//然后通过builder.create(boolean)方法产生container

//由container.getInstance(Class);就可以得到接口的实现实例了

//这一部分比较复杂,后面研究完成了,会单独拿出来讲,这里先弄清楚Xwork依赖注入的实现步骤就可以了

ContainerProperties props = new ContainerProperties();

ContainerBuilder builder = new ContainerBuilder();

for(final ContainerProvider containerProvider : providers)

{

//循环调用ConfigurationProvider的init和register方法,明白了吧,在这里统一循环调用

containerProvider.init(this);

containerProvider.register(builder, props);

}

props.setConstants(builder);

//注入依赖关系,在这里并不产生实例

builder.factory(Configuration.class, new Factory(){

public Configuration create(Context context)throws Exception {

return DefaultConfiguration.this;

}

});

ActionContext oldContext = ActionContext.getContext();

try {

// Set the bootstrap container for the purposes of factory creation

Container bootstrap = createBootstrapContainer();

setContext(bootstrap);

//create已经注入依赖关系的Container

container = builder.create(false);

setContext(container);

objectFactory = container.getInstance(ObjectFactory.class);

// Process the configuration providers first

for(final ContainerProvider containerProvider : providers)

{

if(containerProvider instanceof PackageProvider){

container.inject(containerProvider);

//调用PackageProvider的loadPackages()方法,这里主要是针对XmlConfigurationProvider和StrutsXmlConfigurationProvider

((PackageProvider)containerProvider).loadPackages();

packageProviders.add((PackageProvider)containerProvider);

}

}

// Then process any package providers from the plugins

Set

packageProviderNames

= container.getInstanceNames(PackageProvider.class);

if(packageProviderNames!= null){

for(String name : packageProviderNames){

PackageProvider

provider.init(this);

provider.loadPackages();

packageProviders.add(provider);

}

}

rebuildRuntimeConfiguration();

} finally {

if(oldContext == null){

ActionContext.setContext(null);

}

}

return packageProviders;

}

Dispatcher已经在之前讲过,这就好办了。FilterDispatcher是Struts2的核心控制器,首先看一下init()方法。

public void init(FilterConfig filterConfig)throws ServletException {

try {

this.filterConfig = filterConfig;

initLogging();

//创建dispatcher,前面都已经讲过啰

dispatcher = createDispatcher(filterConfig);

dispatcher.init();

//注入将FilterDispatcher中的变量通过container注入,如下面的staticResourceLoader

dispatcher.getContainer().inject(this);

//StaticContentLoader在BeanSelectionProvider中已经被注入了依赖关系:DefaultStaticContentLoader

//可以在struts-default.xml中的可以找到

staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

} finally {

provider

= container.getInstance(PackageProvider.class, name);

ActionContext.setContext(null);

}

}

public void init(FilterConfig filterConfig)throws ServletException {

try {

this.filterConfig = filterConfig;

initLogging();

//创建dispatcher,前面都已经讲过啰

dispatcher = createDispatcher(filterConfig);

dispatcher.init();

//注入将FilterDispatcher中的变量通过container注入,如下面的staticResourceLoader

dispatcher.getContainer().inject(this);

//StaticContentLoader在BeanSelectionProvider中已经被注入了依赖关系:DefaultStaticContentLoader

//可以在struts-default.xml中的可以找到

staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

} finally {

ActionContext.setContext(null);

}

}

//下面来看DefaultStaticContentLoader的setHostConfig

public void setHostConfig(HostConfig filterConfig){

//读取初始参数

pakages,调用

parse(),解析成类似/org/apache/struts2/static,/template的数组

String param = filterConfig.getInitParameter(“packages”);

//“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

String packages = getAdditionalPackages();

if(param!= null){

packages = param + “ ” + packages;

}

this.pathPrefixes = parse(packages);

initLogging(filterConfig);

}

template //下面来看DefaultStaticContentLoader的setHostConfig

public void setHostConfig(HostConfig filterConfig){

//读取初始参数

pakages,调用

parse(),解析成类似/org/apache/struts2/static,/template的数组

String param = filterConfig.getInitParameter(“packages”);

//“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

String packages = getAdditionalPackages();

if(param!= null){

packages = param + “ ” + packages;

}

this.pathPrefixes = parse(packages);

initLogging(filterConfig);

}

现在回去doFilter的方法,每当有一个Request,都会调用这些Filters的doFilter方法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

HttpServletRequest request =(HttpServletRequest)req;

HttpServletResponse response =(HttpServletResponse)res;

ServletContext servletContext = getServletContext();

String timerKey = “FilterDispatcher_doFilter: ”;

try {

// FIXME: this should be refactored better to not duplicate work with the action invocation

//先看看ValueStackFactory所注入的实现类OgnlValueStackFactory

//new OgnlValueStack

ValueStack

stack

= dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

ActionContext ctx = new ActionContext(stack.getContext());

ActionContext.setContext(ctx);

template

UtilTimerStack.push(timerKey);

//如果是multipart/form-data就用MultiPartRequestWrapper进行包装

//MultiPartRequestWrapper

StrutsRequestWrapper的子类,两者都是HttpServletRequest实现

//此时在MultiPartRequestWrapper中就会把Files给解析出来,用于文件上传

//所有request都会StrutsRequestWrapper进行包装,StrutsRequestWrapper是可以访问ValueStack

//下面是参见Dispatcher的wrapRequest

// String content_type = request.getContentType();

//if(content_type!= null&&content_type.indexOf(“multipart/form-data”)!=-1){

//MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

//request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

//} else {

//

request = new StrutsRequestWrapper(request);

// }

request = prepareDispatcherAndWrapRequest(request, response);

ActionMapping mapping;

try {

//根据url取得对应的Action的配置信息

//看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存储在 ActionMapping对象中

mapping

=

actionMapper.getMapping(request, dispatcher.getConfigurationManager());

} catch(Exception ex){

log.error(“error getting ActionMapping”, ex);

dispatcher.sendError(request,return;

}

//如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等

//这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到

response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

=new 404

if(mapping == null){

// there is no action in this request, should we look for a static resource?

String resourcePath = RequestUtils.getServletPath(request);

if(“".equals(resourcePath)&& null!= request.getPathInfo()){

resourcePath = request.getPathInfo();

}

if(staticResourceLoader.canHandle(resourcePath)){

// 在DefaultStaticContentLoader

:return

serveStatic

&&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

staticResourceLoader.findStaticResource(resourcePath, response);

} else {

// this is a normal request, let it pass through

chain.doFilter(request, response);

}

// The framework did its job here

return;

}

//正式开始Action的方法

dispatcher.serviceAction(request, response, servletContext, mapping);

} finally {

try {

ActionContextCleanUp.cleanUp(req);

} finally {

UtilTimerStack.pop(timerKey);

}

}

}

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

HttpServletRequest request =(HttpServletRequest)req;

request,HttpServletResponse response =(HttpServletResponse)res;

ServletContext servletContext = getServletContext();

String timerKey = ”FilterDispatcher_doFilter: “;

try {

// FIXME: this should be refactored better to not duplicate work with the action invocation

//先看看ValueStackFactory所注入的实现类OgnlValueStackFactory

//new OgnlValueStack

ValueStack

stack

= dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

ActionContext ctx = new ActionContext(stack.getContext());

ActionContext.setContext(ctx);

UtilTimerStack.push(timerKey);

//如果是multipart/form-data就用MultiPartRequestWrapper进行包装

//MultiPartRequestWrapperHttpServletRequest实现

//此时在MultiPartRequestWrapper中就会把Files给解析出来,用于文件上传

//所有request都会StrutsRequestWrapper进行包装,StrutsRequestWrapper是可以访问ValueStack

//下面是参见Dispatcher的wrapRequest

// String content_type = request.getContentType();

//if(content_type!= null&&content_type.indexOf(”multipart/form-data“)!=-1){

//MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

//request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

//} else {

//

request = new StrutsRequestWrapper(request);

// }

request = prepareDispatcherAndWrapRequest(request, response);

ActionMapping mapping;

try {

=new

StrutsRequestWrapper的子类,两者都是

//根据url取得对应的Action的配置信息

//看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存储在 ActionMapping对象中

mapping

} catch(Exception ex){

log.error(”error getting ActionMapping“, ex);

dispatcher.sendError(request,return;

}

//如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等

//这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到404

if(mapping == null){

// there is no action in this request, should we look for a static resource?

String resourcePath = RequestUtils.getServletPath(request);

if(”“.equals(resourcePath)&& null!= request.getPathInfo()){

resourcePath = request.getPathInfo();

}

if(staticResourceLoader.canHandle(resourcePath)){

// 在DefaultStaticContentLoader

:return

serveStatic

&&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

staticResourceLoader.findStaticResource(resourcePath, response);

} else {

// this is a normal request, let it pass through

chain.doFilter(request, response);

}

// The framework did its job here

return;

}

request,response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

=

actionMapper.getMapping(request, dispatcher.getConfigurationManager());

//正式开始Action的方法

dispatcher.serviceAction(request, response, servletContext, mapping);

} finally {

try {

ActionContextCleanUp.cleanUp(req);

} finally {

UtilTimerStack.pop(timerKey);

}

}

}

//下面是ActionMapper接口的实现类 DefaultActionMapper的getMapping()方法的源代码:

public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

ActionMapping mapping = new ActionMapping();

String uri = getUri(request);//得到请求路径的URI,如:testAtcion.action或testAction.do

int indexOfSemicolon = uri.indexOf(”;“);//修正url的带;jsessionid 时找不到而且的bug

uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

uri = dropExtension(uri, mapping);//删除扩展名,默认扩展名为action

if(uri == null){

return null;

}

parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

handleSpecialParameters(request, mapping);//去掉重复参数

//如果Action的name没有解析出来,直接返回

if(mapping.getName()== null){

returnnull;

}

//下面处理形如testAction!method格式的请求路径

if(allowDynamicMethodCalls){

// handle ”name!method“ convention.String name = mapping.getName();

int exclamation = name.lastIndexOf(”!“);//!是Action名称和方法名的分隔符

if(exclamation!=-1){

mapping.setName(name.substring(0, exclamation));//提取左边为name

mapping.setMethod(name.substring(exclamation + 1));//提取右边的method

}

}

return mapping;

}

//下面是ActionMapper接口的实现类 DefaultActionMapper的getMapping()方法的源代码:

public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

ActionMapping mapping = new ActionMapping();

String uri = getUri(request);//得到请求路径的URI,如:testAtcion.action或testAction.do

int indexOfSemicolon = uri.indexOf(”;“);//修正url的带;jsessionid 时找不到而且的bug

uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

uri = dropExtension(uri, mapping);//删除扩展名,默认扩展名为action

if(uri == null){

return null;

}

parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

handleSpecialParameters(request, mapping);//去掉重复参数

//如果Action的name没有解析出来,直接返回

if(mapping.getName()== null){

returnnull;

}

//下面处理形如testAction!method格式的请求路径

if(allowDynamicMethodCalls){

// handle ”name!method“ convention.String name = mapping.getName();

int exclamation = name.lastIndexOf(”!“);//!是Action名称和方法名的分隔符

if(exclamation!=-1){

mapping.setName(name.substring(0, exclamation));//提取左边为name

mapping.setMethod(name.substring(exclamation + 1));//提取右边的method

}

}

return mapping;

}

从代码中看出,getMapping()方法返回ActionMapping类型的对象,该对象包含三个参数:Action的name、namespace和要调用的方法method。

如果getMapping()方法返回ActionMapping对象为null,则FilterDispatcher认为用户请求不是Action,自然另当别论,FilterDispatcher会做一件非常有意思的事:如果请求以/struts开头,会自动查找在web.xml文件中配置的 packages初始化参数,就像下面这样:

struts2

org.apache.struts2.dispatcher.FilterDispatcher

packages

com.lizanhong.action

struts2

org.apache.struts2.dispatcher.FilterDispatcher

packages

com.lizanhong.action

FilterDispatcher会将com.lizanhong.action包下的文件当作静态资源处理,即直接在页面上显示文件内容,不过会忽略扩展名为class的文件。比如在com.lizanhong.action包下有一个aaa.txt的文本文件,其内容为“中华人民共和国”,访问

http://localhost:8081/Struts2Demo/struts/aaa.txt时会输出txt中的内容

FilterDispatcher.findStaticResource()方法

protectedvoid findStaticResource(String

name,HttpServletRequest

request, HttpServletResponse response)throws IOException {

if(!name.endsWith(”.class“)){//忽略class文件

//遍历packages参数

for(String pathPrefix : pathPrefixes){

InputStream is = findInputStream(name, pathPrefix);//读取请求文件流

if(is!= null){

...// set the content-type header

String contentType = getContentType(name);//读取内容类型

if(contentType!= null){

response.setContentType(contentType);//重新设置内容类型

}

...try {

//将读取到的文件流以每次复制4096个字节的方式循环输出

copy(is, response.getOutputStream());

} finally {

is.close();

}

return;

}

}

}

}

protectedvoid findStaticResource(String

name,HttpServletRequest

request, HttpServletResponse response)throws IOException {

if(!name.endsWith(”.class“)){//忽略class文件

//遍历packages参数

for(String pathPrefix : pathPrefixes){

InputStream is = findInputStream(name, pathPrefix);//读取请求文件流

if(is!= null){

...// set the content-type header

String contentType = getContentType(name);//读取内容类型

if(contentType!= null){

response.setContentType(contentType);//重新设置内容类型

}

...try {

//将读取到的文件流以每次复制4096个字节的方式循环输出

copy(is, response.getOutputStream());

} finally {

is.close();

}

return;

}

}

}

}

如果用户请求的资源不是以/struts开头——可能是.jsp文件,也可能是.html文件,则通过过滤器链继续往下传送,直到到达请求的资源为止。

如果getMapping()方法返回有效的ActionMapping对象,则被认为正在请求某个Action,将调用 Dispatcher.serviceAction(request, response, servletContext, mapping)方法,该方法是处理Action的关键所在。

下面就来看serviceAction,这又回到全局变量dispatcher中了

//Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping)throws ServletException {

//createContextMap方法主要把Application、Session、Request的key value值拷贝到Map中

Map extraContext = createContextMap(request, response, mapping, context);

// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action

ValueStack

stack

=

(ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

boolean nullStack = stack == null;

if(nullStack){

ActionContext ctx = ActionContext.getContext();

if(ctx!= null){

stack = ctx.getValueStack();

}

}

if(stack!= null){

extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));

}

String timerKey = ”Handling request from Dispatcher“;

try {

UtilTimerStack.push(timerKey);

String namespace = mapping.getNamespace();

String name = mapping.getName();

String method = mapping.getMethod();

Configuration config = configurationManager.getConfiguration();

//创建一个Action的代理对象,ActionProxyFactory是创建ActionProxy的工厂

//参考实现类:DefaultActionProxy和DefaultActionProxyFactory

ActionProxy

proxy

= config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

// if the ActionMapping says to go straight to a result, do it!

//如果是Result,则直接转向,关于Result,ActionProxy,ActionInvocation下一讲中再分析

if(mapping.getResult()!= null){

Result result = mapping.getResult();

result.execute(proxy.getInvocation());

} else {

//执行Action

proxy.execute();

}

// If there was a previous value stack then set it back onto the request

if(!nullStack){

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);

}

} catch(ConfigurationException e){

// WW-2874 Only log error if in devMode

if(devMode){

LOG.error(”Could not find action or result“, e);

}

else {

LOG.warn(”Could not find action or result“, e);

}

sendError(request, HttpServletResponse.SC_NOT_FOUND, e);

} catch(Exception e){

sendError(request,} finally {

UtilTimerStack.pop(timerKey);

}

} 下面开始讲一下主菜ActionProxy了.在这之前最好先去了解一下动态Proxy的基本知识.ActionProxy是Action的一个代理类,也就是说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法。归根到底,最后调用的是DefaultActionInvocation.invokeAction()方法。DefaultActionInvocation()->init()->createAction()。

最后

用ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction()这里的步骤是先由ActionProxyFactory创建ActionInvocation和ActionProxy.public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

container.inject(inv);

return }

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

response,context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);

response,context,ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

container.inject(inv);

return }

下面先看DefaultActionInvocation的init方法

public void init(ActionProxy proxy){

this.proxy = proxy;

Map contextMap = createContextMap();

// Setting this so that other classes, like object factories, can use the ActionProxy and other

// contextual information to operate

ActionContext actionContext = ActionContext.getContext();

if(actionContext!= null){

actionContext.setActionInvocation(this);

}

//创建Action,struts2中每一个Request都会创建一个新的Action

createAction(contextMap);

if(pushAction){

stack.push(action);

contextMap.put(”action“, action);

}

invocationContext = new ActionContext(contextMap);

invocationContext.setName(proxy.getActionName());

// get a new List so we don't get problems with the iterator if someone changes the list

List

interceptorList

=

new ArrayList(proxy.getConfig().getInterceptors());

interceptors = interceptorList.iterator();

createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

}

protected void createAction(Map contextMap){

// load action

String timerKey = ”actionCreate: “ + proxy.getActionName();

try {

UtilTimerStack.push(timerKey);

//默认为SpringObjectFactory:struts.objectFactory=spring.这里非常巧妙,在struts.properties中可以重写这个属性

//在前面BeanSelectionProvider中通过配置文件为ObjectFactory设置实现类

//这里以Spring为例,这里会调到SpringObjectFactory的buildBean方法,可以通过ApplicationContext的getBean()方法得到Spring的Bean

action

=

objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);

} catch(InstantiationException e){

throw new

XWorkException(”Unable

to

intantiate

Action!“,e, proxy.getConfig());

} catch(IllegalAccessException e){

throw new XWorkException(”Illegal access to constructor, is it public?", e, proxy.getConfig());

} catch(Exception e){

...} finally {

UtilTimerStack.pop(timerKey);

}

if(actionEventListener!= null){

action = actionEventListener.prepare(action, stack);

}

}

//SpringObjectFactory

public Object buildBean(String beanName, Map extraContext, boolean injectInternal)throws Exception {

Object o = null;

try {

//SpringObjectFactory

web.xml

中的

第三篇:实验三 Struts2框架编程-实验报告纸

南京信息工程大学 实验(实习)报告

实验(实习)名称 Struts2框架编程 实验(实习)日期 得分 指导教师 院 计软 专业 计科 年级 2013级 班次 3 姓名 张文娇 学号 20131308081

1.实验目的:

1)掌握Struts2框架和工作流程。2)熟悉Struts标签库的使用。

3)掌握Struts 2拦截器的原理,并能进行相关设置和编程。4)了解和掌握文件上传等功能实现

2.实验内容:

1)采用Struts2框架,创建三个JSP页面(hello.jsp、welcome.jsp)和一个Action实现类(StrutsAction),并对web.xml和Struts.xml进行必要配置,实现用户登录功能的处理。(参考教材3.1节)

2)采用Struts2相关技术,实现“学生综合管理系统”的“添加学生信息”功能(具体需求详见教材3.7所述)

3.实验步骤

{对每个实验题目进行简要步骤描述,包括源码和实验结果截图} 1)

1.启动MyEclips 8.5 2.创建web project项目命名为FirstStruts2 3.添加支持包 4.配置web.xml struts2.0 org.apache.struts2.dispatcher.FilterDispatcher struts2.0 /*

5.在工程中创建LoginAction.jsp import dao.CustomerDAO;public class LoginAction {

private String name;private String password;/**在此方法里实现业务逻辑处理*/ public String execute()throws Exception {

CustomerDAO dao=new CustomerDAO();boolean boo=dao.check(name, password);if(boo)return “success”;

} else return “error”;public String getName(){ return name;} public void setName(String name){ this.name = name;} public String getPassword(){ return password;} public void setPassword(String password){this.password = password;} } 6.配置struts.xml文件

/success.jsp /error.jsp 7.创建login.jsp

用户名:
密码:

第四篇:struts2框架的6个配置文件

Struts2的6个配置文件,分别是struts-default.xml,default.properties,struts-plugin.xml,struts.xml,struts.properties,web.xml

1、struts-default.xml,里面放置的是struts2框架的核心东西,如bean类,package包,result type,interceptor拦截器等

2、default.properties,properties类型的文件里面放置的是键值对,key和value,主要是对一些常量进行设定。

3、struts-plugin.xml,与第三方插件进行整合时需要使用的配置文件。如我们和spring进行整合时,就需要使用到struts-spring-plugin.xml这个配置文件

4、struts.xml,需要我们程序员在src目录下手动创建,在这个里面也可以对常量进行设定,使用的是constant标签,包含name和value属性。

5、struts.properties,这里也是对常量进行设定

6、web.xml,这里设定struts2的启动项,使用的是filter和filter-mapping标签,也可以进行常量的设定,在filter标签里使用init-param标签。但是我们一般不再这里设定。

这里有4个配置文件,可以对常量进行设定。分别是default.properties,struts.xml,struts.properties,web.xml。他们的优先级顺序是web.xml优先级最高,其次是struts.properties,struts.xml,最后是default.properties。我们最主要进行学习的就是struts.xml,其他的作为了解内容就可以了。

第五篇:Struts2介绍

Struts2集成指南

关于Struts2 Struts是Apache软件基金会(ASF)赞助的一个开源项目。它最初是Jakarta项目中的一个子项目,并在2004年3月成为ASF的顶级项目。它通过采用Java Servlet/JSP技术,实现了基于Java EE Web应用的Model-View-Controller〔MVC〕设计模式的应用框架〔Web Framework〕,是MVC经典设计模式中的一个经典产品。

Struts,a history 在Java EE的Web应用发展的初期,除了使用Servlet技术以外,普遍是在JavaServer Pages(JSP)的源代码中,采用HTML与Java代码混合的方式进行开发。因为这两种方式不可避免的要把表现与业务逻辑代码混合在一起,都给前期开发与后期维护带来巨大的复杂度。为了摆脱上述的约束与局限,把业务逻辑代码从表现层中清晰的分离出来,2000年,Craig McClanahan采用了MVC的设计模式开发Struts。后来该框架产品一度被认为是最广泛、最流行JAVA的WEB应用框架。

Craig McClanahan 2006年,WebWork与Struts这两个优秀的Java EE Web框架(Web Framework〕的团体,决定合作共同开发一个新的,整合了WebWork与Struts优点,并且更加优雅、扩展性更强的框架,命名为“Struts 2”,原Struts的1.x版本产品称为“Struts 1”。

至此,Struts项目并行提供与维护两个主要版本的框架产品——Struts 1与Struts 2。Struts1 vs.Struts2 侵入性

Struts 1 在编程方面是面向抽象类编程,而不是面向接口编程。Struts 1要求自定义Action 类继承一个特定的抽象基类Action。另一方面,Struts 1的 Action 依赖于 Servlet API,因为Struts 1 Action 的execute 方法中有HttpServletRequest 和HttpServletResponse 方法。例如 e.g.public class LogonAction extends Action {

public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response){

} }

Struts 2 Action 类可以实现一个Action接口,也可以实现其他接口,甚至不实现任何接口。这使得可选的和定制的服务成为可能。e.g.public class ExampleAction {

public String doSomething(){

return “success”;} }

线程模式

Struts 1 Action类 是单例模式并且必须是线程安全的,因为在web容器中,仅有Action类 的一个实例来处理所有的请求。

Struts2 Web容器为每一个请求产生一个Action类实例,因此没有线程安全问题。可测试性

Struts1 由于对Servlet API的依赖,使得针对于自定义Action类的测试变得复杂。

Struts2 由于自定义Action可以为POJO,所以可以向测试一个POJO一样来测试Action类。

请求参数封装

Struts1 使用ActionForm 对象封装用户的请求参数,所有的 ActionForm 必须继承一个基类:ActionForm。普通的JavaBean 不能用作ActionForm,并且需要在配置文件中定义ActionForm。e.g.public class LogonForm extends ActionForm {

private String userpassword;

private String username;}

Struts2 直接使用Action属性来封装用户请求属性,避免了开发者需要大量开发ActionForm类的烦琐,实际上,这些属性还可以是包含子属性的 Rich对象类型。e.g.public class ExampleAction {

private String responseMessage;private String requestMessage;

public String getResponseMessage(){

return responseMessage;}

public void setResponseMessage(String responseMessage){

this.responseMessage = responseMessage;}

public String getRequestMessage(){

return requestMessage;

} } public void setRequestMessage(String requestMessage){ } this.requestMessage = requestMessage;public String doSomething(){

} setMessage(“Hi, ” + getRequestMessage());return “success”;EL Struts1 整合了 JSTL,因此可以使用JSTL 表达式语言。JSTL有基本对象图遍历,但在对集合和索引属性的支持上则功能不强。在向视图绑定值时,Struts1 使用标准JSP 机制把对象绑定到视图页面。

Struts2 Struts 2 可以使用JSTL,但它整合了一种更强大和灵活的表达式语言:OGNL(Object Graph Notation Language),因此,Struts 2 下的表达式语言功能更加强大。在向视图绑定值时,Struts2 使用“ValueStack ”技术,使标签库能够访问值,而不需要把对象和视图页面绑定在一起。

校验框架

Struts1 Struts1 支持在 ActionForm 重写validate 方法中手动校验,或者通过整合 Commons-validator 框架来完成数据校验。

Struts2 Struts 2 支持通过重写validate方法进行校验,也支持整合XWork 校验框架进行校验。Struts2 architacture

名词约定

凡是代码、配置文件、IDE中出现的名词,均采用英文原称。

Roadmap 本文档的目标是,帮助读者在Eclipse中将Struts2集成至一个崭新的Dynamic Web Project。集成步骤大致如下:配置Struts2的代码环境-> 在web.xml中加入Struts2功能-> 测试Struts2。文档目标达成的标志是:页面请求能够通过Struts2的Action Mapping成功转发,并且基于Java的Struts2验证框架能够生效。

集成步骤

引入Struts2相关的jar文件

Struts2 jars           commons-fileupload-1.2.2.jar commons-io-2.1.jar commons-lang-2.4.jar commons-logging-1.1.1.jar freemarker-2.3.16.jar javassist.jar jstl-1.2.jar ognl-3.0.1.jar struts2-core-2.2.3.jar xwork-core-2.2.3.jar 加入build path 将以上10个jar文件,拷贝至WebContent/WEB-INF/lib下:

对于Web Dynamic Project,一般情况下,当你向lib目录下copy了jar文件,eclipse会自动将jar文件加入build path下的名为Web App Libraries的Library。请确认在工程下出现了名为Web App Libraries的Library。如果有,说明这些jar文件已经被添加至build path了:

如果在工程目录下找不到名为Web App Libraries的Library,说明jar文件没有被添加至build path,需要进行手动添加。首先进入build path设置界面,选中Libraries 页,并点击Add JARs:

在JAR Selection窗口中,选中lib下所有的jar文件。选中后点击OK:

你将看到被选中的jar文件已经被添加至build path:

在工程中会出现一个名为Referenced Libraries的Libraries。这说明jar文件已经被添加至build path:

以上两种方法都可以将jar文件添加至build path,它们的效果是一样的。

配置web.xml 添加filter 在web.xml中添加一个filter:

struts2

org.apache.struts2.dispatcher.FilterDispatcher

filter-name表示filter的名字,你可以任意决定这个名字。filter-class表示使用哪个类作为filter,从这个类的全称来判断,可以发现FilterDispatcher是Struts2提供的一个类。它是Struts2转发请求的起点。在web.xml中添加一个filter-mapping:

struts2

/*

filter-mapping用来映射url和filter的映射关系。filter-name表示filter的名字,这个名字必须和之前filter声明中的filter-name一致。url-pattern表示哪些格式的url会被此filter滤中。/*表示在此web应用域名下,所有的地址都会被filter滤中,换言之,所有的http请求都会通过Struts2进行转发。

filter的作用

通过以上的配置,FilterDispatcher和url与filter-name联系在了一起。

由于在web容器中注册了FilterDispatcher这个filter,Struts2可以收到所有http://localhost:8080/tyland-b2b 的http请求。随后,FilterDispatcher会根据我们定义的action-mapping规则,将请求分发到指定的action类以及它的拦截器栈。最后,Struts2按照action-mapping规则,将后台计算的结果返回给指定页面。笼统地来说,Struts2就是这样工作的,所以说,FilterDispatcher是Struts2工作的入口。

编写代码,测试Struts2 Struts2的环境已经配置好了,基于action-mapping的转发机制已经可以运行了。为了证明这一点,请编写一些测试jsp页面和java代码。

在编写代码的过程中,请确保代码文件的位置如下图所示:

代码清单如下:

Java代码

UserVO.java package com.tyland.b2b.vo;

// 一个Value Object(Data Model),用来存放用户名、密码 public class UserVO {

private String username;private String password;

// 成员变量password的getter方法。

// 在Strtus2中,用来在页面和服务器间传值的Value Object必须有getter方法

public String getPassword(){

return password;

} } // 成员变量password的setter方法。

// 在Strtus2中,用来在页面和服务器间传值的Value Object必须有setter方法 public void setPassword(String password){ } this.password = password;// 同password

public String getUsername(){ } return username;// 同password

public void setUsername(String username){ } this.username = username;BaseAction.java package com.tyland.b2b.web.base;

import com.opensymphony.xwork2.ActionSupport;

// 为了代码的灵活性和可扩展性,请声明一个BaseAction基类

// BaseAction继承Struts2的ActionSupport,因为我们想使用Struts2的一些额外帮助。// 对于ActionSupport的继承不是必须的

public class BaseAction extends ActionSupport {

private static final long serialVersionUID = ***74952195L;} UserAction.java package com.tyland.b2b.web;

import com.tyland.b2b.vo.UserVO;import com.tyland.b2b.web.base.BaseAction;

// 自定义的Action类,继承BaseAction // 由于继承了ActionSupport,我们可以使用Struts2默认的action方法execute()// 由于继承了ActionSupport,我们可以使用Struts2默认的校验方法validate()public class UserAction extends BaseAction {

private static final long serialVersionUID =-7***3684190L;

// 用来在页面和服务器之间传递用户名、密码的Value Object。变量名任意。

private UserVO userVO;

执行。// 用来在页面和服务器之间传递message变量。名称任意。private String message;//用来在页面和服务器之间传递sayHiTo变量。名称任意。private String sayHiTo;// 用来传值的变量必须有getter方法 public UserVO getUserVO(){ return userVO;}

//用来传值的变量必须有setter方法

public void setUserVO(UserVO userVO){ } this.userVO = userVO;public String getMessage(){ } return message;public void setMessage(String message){ } this.message = message;public String getSayHiTo(){ } return sayHiTo;public void setSayHiTo(String sayHiTo){ } this.sayHiTo = sayHiTo;// Override声明说明这个方法复写或实现了父类或接口方法。

// 如action-mapping中不显示指定别的方法,struts2会将execute()作为默认的action方法// 返回的SUCCESS常量,来自ActionSupport,值为“success”。

// action-mapping会根据不同的返回值采取不同的转发或页面跳转动作。@Override

public String execute()throws Exception {

} System.out.println(“******execute******”);System.out.println(userVO.getUsername()+ “ logins”);return SUCCESS;

// 在Struts2执行execute()之前,会先执行validateExecute()进行用户输入验证 // 这个方法名必须符合Struts2验证框架所规定的命名规范 public void validateExecute(){

}

} System.out.println(“******validateExecute******” + userVO.getUsername());if(null == userVO.getUsername()|| userVO.getUsername().length()< 5){ this.addFieldError(“username”, “USERNAME ERROR”);} if(null == userVO.getPassword()|| userVO.getPassword().length()< 5){ this.addFieldError(“password”, “PASSWORD ERROR”);} // 一个自定义方法。通过在action-mapping中的设置,可以实现使用POJO的自定义服务配置 public String sayHi()throws Exception {

} System.out.println(“say hi to ” + getSayHiTo());return SUCCESS;// 符合验证框架命名规范的、真对于sayHi()的验证方法 public void validateSayHi(){

} System.out.println(“******validateSayHi******” + getSayHiTo());if(null == getSayHiTo()|| getSayHiTo().length()< 5){ this.addFieldError(“sayHiTo”, “SAYHITO ERROR”);} ExampleAction.java package com.tyland.b2b.web;

import com.tyland.b2b.web.base.BaseAction;

public class ExampleAction extends BaseAction {

private static final long serialVersionUID =-***7281L;

private String message;private String sayHiTo;

public String getMessage(){

return message;}

public void setMessage(String message){

this.message = message;}

public String getSayHiTo(){

return sayHiTo;}

} public void setSayHiTo(String sayHiTo){ } this.sayHiTo = sayHiTo;public String finish(){

} System.out.println(“example finished”);setMessage(getSayHiTo());return SUCCESS;JSP代码

index.jsp <%@ page language=“java” contentType=“text/html;charset=UTF-8”

pageEncoding=“UTF-8”%>

<%@ taglib uri = “http://java.sun.com/jsp/jstl/core” prefix = “c” %>

Hello World

下载Struts 2框架分析word格式文档
下载Struts 2框架分析.doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    Struts2试题

    Struts2 试题 1.struts2的执行流程? 客户端提交一个HttpServletRequest请求(action或JSP页面) 请求被提交到一系列Filter过滤器,如ActionCleanUp和FiterDispatcher等 FilterDisp......

    struts2课件

    —高级软件人才实作培训专家!Struts2的启动配置在struts1.x中,struts框架是通过Servlet启动的。在struts2中,struts框架是通过Filter启动的。他在web.xml中的配置如下:struts2o......

    Struts2习题

    Struts2习题1 1.struts中的package的作用是什么?namespace可以为空吗?如果namespace为空会意味着什么呢? 标识、 可以 、如果没写,说明该包为默认空间 2.Action 的实现通集成常......

    struts2源代码分析(个人觉得非常经典)

    本章讲述Struts2的工作原理。 读者如果曾经学习过Struts1.x或者有过Struts1.x的开发经验,那么千万不要想当然地以为这一章可以跳过。实际上Struts1.x与Struts2并无我们想象的......

    struts2复习题(含答案)

    Struts2复习题 1. 以下属于struts2的控制器组件是: A.ActionB.ActionForm C.ActionServlet D.dispatchAction 2. 以下属于struts2配置文件中的配置元素是:(多选) A. B. C. D......

    struts2综合试卷范文合集

    Struts2学习增强练习课程名称: Struts2学习增强练习考试时间 xx分钟(闭卷■) 不定项选择题 1. 开发struts2 web项目,需要导入哪些jar包 A 必须导入struts2 解压lib下所有......

    struts2知识总结

    struts2知识总结 1.全局的逻辑控制器为一个过滤器,负责过滤所有的请求。该过滤器引用的API类为org.apache.struts2.disapatcher.FilterDispatcher 2.MVC:页面请求(jsp)—......

    公司分析报告框架

    上市公司初步分析框架 一、 公司概况 公司概况性的介绍信息,包括公司名称、所属行业、地址、成立年份,历史沿革等。 二、 行业分析 公司所属的行业的竞争情况,发展前景,行业所处......