strtus2之核心原理和constant详解

1 strtus2核心概念

1.1 FilterDispatcher

FilterDispatcherStruts2的前端控制器,也是Struts2MVC中的控制器部分。在实际开发中,只需要在web.xml中配置一次即可,如下所示:

  <filter>
        <filter-name>Struts2</filter-name>
        <filter-class>
        org.apache.struts2.dispatcher.FilterDispatcher
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

但是一定要注意,如果还有其他的过滤器,那么FilterDispatcher的配置通常要出现在最后。

1.2 Action

Action动作类,作为MVC中的模型部分,既封装业务数据,也负责处理用户的请求,execute方法就是默认的动作处理方法。

1.3 Result

结果,代表Action运行之后要转向的下一个页面。Struts2本身支持多种结果类型,如jspvelocityfreemarkerjasperreports等,在同一个web应用中,各种结果类型还能混用。

1.4 Interceptor

拦截器是Struts2中一个重要的概念。每一个Struts2工程都使用了拦截器,只是使用了Struts2自带的内建拦截器与默认拦截器配置而已。
Struts2的许多功能都是由拦截器完成的,比如:

  • 帮你把request参数设置到Action的属性中。
  • 实现上传文件
  • 防止重复提交
  • 实现验证框架
  • 通用错误处理
  • 程序国际化

1.5 ActionContext、值栈与OGNL

Struts2在每个Action刚开始运行的时候,都会单独为它建立一个ActionContext,把所有能访问的数据,包括请求参数(requestparameter)、请求的属性(requestAttribute)、会话(session)信息等等,都放到ActionContext中。这样一来,在以后取值、赋值的时候,就只需要访问ActionContext就可以了,所以说ActionContext可以被认为是每个Action拥有的一个独立的内存数据中心

对象图导航语言OGNLObject-Graph Navigation Language的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL)。它通过简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。

值栈可以用来容纳多个对象,主要用来存放一些临时对象。当使用OGNL访问值栈中对象的属性的时候,指定属性的引用会引用更靠近值栈栈顶方向对象,晚进栈的对象会覆盖早进栈的对象。简单点说,Struts2用值栈为我们使用Struts2做了很多引用上的简化,主要是缩短了OGNL表达式的长度。另外,值栈也可以作为一个内存数据中心,来存放一些Struts2标签临时定义的数据。

1.6 Struts2标签

Struts2的标签库功能强大,使用简单,大大简化了视图开发的工作。而且,它与框架的其他部分也非常自然的结合,如国际化、验证等等。

1.7 自动类型转换

Action中可以有多种方式来对应页面的数据,从而自动获取页面的值。但是,从request里面接收的值都是String类型的,而Action的属性可以是各种类型的。这就需要Struts2的类型转换机制来支持,它节省了我们大量的手工进行类型转换的开发时间。

Struts2已经内置了大量的类型转换方式:

  • 各种私有类型及其包装类
  • 常见的各种数据类型,如String、Date、BigDecimal等等
  • 各种集合概念,包括数组、Set、List、Map
  • 甚至可以是枚举

Struts2提供的这些就已经够用了,还可以自己实现特殊的类型转换器,以满足特殊的功能需要。

1.8 国际化

i18n通常作为国际化的简称,其来源是英文单词internationalization的首末字符i和n18为中间的字符数。

web应用通常应该支持多国语言,可以根据客户端请求所来自的国家和语言显示不同语种的用户界面。这样,当需要在应用程序中添加对一种新语言的支持时,就无需修改应用程序的代码了。

Struts2非常自然的实现了国际化,我们不需要考虑更多的事情,只是按照Struts2的要求,把不同语言的信息,放到对应的位置即可。

1.9 验证框架

作为一个成熟、稳定的web应用,无论如何服务器端验证是少不了的。通常情况下,我们不会完全相信客户端传递过来的数据,应该在真正调用业务逻辑之前对数据进行校验,如果用户提交的数据不符合要求,就不会去调用业务逻辑。

Struts2为我们提供了一套完整、严密,可扩展的验证框架,保证在Action运行之前会判断用户提交的信息是否完整、符合条件。

2 struts2系统架构

Struts2的官方文档里附带了Struts2的架构图,下面这张图上展示了Struts2的内部模块,以及它们的运行流程。
请添加图片描述
这张图上分了好多块,彼此之间相互联系,先浏览一下各块的名字,再留心一下运行图最下面的图例,分为四种颜色:

  • 橙色是Servlet Filters,过滤器链,所有的请求都要经过Filter链的处理。
  • 浅蓝色是Struts CoreStruts2的核心部分,Struts2中已经做好的功能,在实际开发中不需要动它们。
  • 浅绿色是InterceptorsStruts2的拦截器。Struts2提供了很多默认的拦截器,可以完成日常开发的绝大部分工作;当然,也可以自定义拦截器,用来实现具体业务需要的功能。
  • 浅黄色是User Created,由开发人员创建的,包括struts.xmlActionTemplate,是每个使用Struts2来进行开发的人员都必须会的。

2.1 各模块说明

架构图上有好多东西,接下来逐个击破。首先看看它们各自是做什么的,跟着图上的箭头一个一个来看:

  • FilterDispatcher是整个Struts2的调度中心,根据ActionMapper的结果来决定是否处理请求,如果ActionMapper指出该URL应该被Struts2处理,那么它将会执行Action处理,并停止过滤器链上还没有执行的过滤器。(补充: 先过dispatcher dispatcher持有actionmapperactionmapper决定走哪个actionfilterdispatcher里面持有actionmapper
  • ActionMapper提供了HTTP请求与action执行之间的映射,简单点说,ActionMapper会判断这个请求是否应该被Struts2处理,如果需要Struts2处理,ActionMapper会返回一个对象来描述请求对应的ActionInvocation的信息。
  • ActionProxy是一个特别的中间层,位于Actionxwork之间,使得我们在将来有机会引入更多的实现方式,比如通过WebService来实现等。
  • ConfigurationManagerxwork配置的管理中心,通俗的讲,可以把它看做struts.xml这个配置文件在内存中的对应。
  • struts.xmlStruts2的应用配置文件,负责诸如URLAction之间映射的配置、以及执行后页面跳转的Result配置等。
  • ActionInvocation:真正调用并执行Action,它拥有一个Action实例和这个Action所依赖的拦截器实例。ActionInvocation会执行这些拦截器、Action以及相应的Result
  • Interceptor(拦截器):拦截器是一些无状态的类,拦截器可以自动拦截Action,它们给开发者提供了在Action运行之前或Result运行之后来执行一些功能代码的机会。类似于我们熟悉的javax.servlet.Filter
  • Action:动作类是Struts2中的动作执行单元。用来处理用户请求,并封装业务所需要的数据。
  • ResultResult就是不同视图类型的抽象封装模型,不同的视图类型会对应不同的Result实现,Struts2中支持多种视图类型,比如JspFreeMarker等。
  • Templates:各种视图类型的页面模板,比如JSP就是一种模板页面技术。
  • Tag SubsystemStruts2的标签库,它抽象了三种不同的视图技术JSPvelocityfreemarker,可以在不同的视图技术中,几乎没有差别的使用这些标签。

3 struts2运行流程

3.1 前提条件

在讲解流程之前,假设已经建立了的一个名为strutsDeepenweb工程,该工程仅仅实现了简单的用户登陆与欢迎界面。具体的实现为:

  • web.xml中配置了Struts2的过滤器
  • 写了一个Action类,名称为loginAction
  • struts.xml中配置了这个Action
  • 写了两个页面,一个是登录页面,一个是欢迎页面

只做了这么点事情,就可以在Struts2的帮助下顺利完成功能调用,那么Struts2内部是怎么运行的呢?逐步来根据系统架构图进行分析。

3.2 运行流程

当用户提交登录请求后,请求的URL为:/strutsDeepen/loginAction.action,请求会被Tomcat服务器接收到,Tomcat服务器会根据请求URL中的web上下文,也就是/strutsDeepen,来选择处理这个请求的Web应用,那就是由strutsDeepen这个web工程来处理这个请求。
Web容器会去读取strutsDeepen这个工程的web.xml,在web.xml中进行匹配,发现后缀为.action的请求,由struts2这个过滤器来进行处理,根据Filter的配置,找到实际的类为FilterDispatcher

Web容器会获取FilterDispatcher这个类的实例,然后回调doFilter方法,进行真正的处理。FilterDispatcher作为前端控制器,是整个Struts2的调度中心。

注意:在架构图上,可以看到有三个过滤器层次,分别是ActionContextCleanUpSiteMesh等其他过滤器和FilterDispatcher。这三个层次中,ActionContextCleanUpFilterDispatcherStruts2的过滤器,而SiteMeshSiteMesh等其他过滤器不是。

FilterDispatcher是任何一个Struts2应用都需要配置的,一般出现在过滤器链的最后;如果在FilterDispatcher前出现了如SiteMesh这种特殊的过滤器,还必须在SiteMesh前引用Struts2ActionContextCleanUp过滤器。

在前面的strutsDeepen中,并没有出现SiteMesh这种特殊的过滤器,所以只需要引用FilterDispatcher就可以了。

(补充:先过dispatcher dispatcher持有actionmapperactionmapper决定走哪个actionfilterdispatcher里面持有actionmapper

FilterDispatcher将请求转发给ActionMapperActionMapper负责识别当前的请求是否需要Struts2做出处理。
ActionMapper告诉FilterDispatcher,需要处理这个请求,FilterDispatcher会停止过滤器链以后的部分,所以通常情况下:FilterDispatcher应该出现在过滤器链的最后。然后建立一个ActionProxy对象,这个对象作为Actionxwork之间的中间层,会代理Action的运行过程。

ActionProxy对象刚被创建出来的时候,并不知道要运行哪个Action,它手里只有从FilterDispatcher中拿到的请求的URL。这时候,它去向ConfigurationManager询问到底要运行哪个Action。某个特定的URL由哪个Action响应由谁负责,定义在什么地方呢?没错,在struts.xml里面。而ConfigurationManager就是负责读取并管理struts.xml的,可以简单的理解为ConfigurationManagerstruts.xml在内存中的映像。在服务器启动的时候,ConfigurationManager会一次性的把struts.xml中的所有信息读到内存里,并缓存起来,以保证ActionProxy拿着来访的URL向他询问要运行哪个Action的时候,就可以直接匹配、查找并回答了。

ActionProxy拿到了运行哪个Action、相关的拦截器以及所有可能使用的result信息,就可以着手建立ActionInvocation对象了,ActionInvocation对象描述了Action运行的整个过程。

注意Action运行绝不仅仅只是运行Actionexecute方法这么简单,还包括其他部分,完整的调用过程由ActionInvocation对象负责。

回忆一下,strutsDeepenActionexecute方法运行的时候,是不是它的属性就已经有了请求中的参数呢?这说明,在execute方法之前,有人偷偷的帮我们做了这件事,把请求中的参数赋值到了Action的属性上,这个有人就是刚刚说的拦截器。拦截器的运行被分成两部分,一部分在Action之前运行,一部分在Result之后运行,而且顺序是刚好反过来的。也就是在Action执行前的顺序,比如是拦截器1、拦截器2、拦截器3,那么运行Result之后,再次运行拦截器的时候,顺序就变成拦截器3、拦截器2、拦截器1了。
总之ActionInvocation对象执行的时候比较复杂,会做很多事:

  • 首先,按照拦截器的引用顺序依次执行各个拦截器的前置部分;
  • 然后,执行Actionexecute方法;
  • 然后,根据execute方法返回的结果,也就是Result,在struts.xml中匹配选择下一个页面;
  • 找到页面后,由于现在的页面一般都是模板页面,在页面上,可以通过Struts2自带的标签库来访问需要的数据,并生成最终页面;
  • 最后,ActionInvocation对象再按照拦截器的引用顺序的倒序依次执行各个拦截器的后置部分。
  • ActionInvocation对象执行完毕后,实际上就已经得到响应对象了,也就是HttpServletResponse对象,最后按与过滤器器配置定义相反的顺序依次经过过滤器,向用户展示出响应的结果。

4 constant详解

<constant name="struts.i18n.encoding" value="UTF-8" /> :指定Web应用的默认编码集,相当于调用HttpServletRequest``setCharacterEncoding方法

<constant name="struts.action.extension" value="do" /> :该 属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即 所有匹配*.action的请求都由Struts 2处理。如 果用户需要指定多个请求后缀,则多个后缀之间以英文逗号()隔开

<constant name="struts.serve.static.browserCache " value="false" />:设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭,当应用处于开发阶段时,我们希望每次请求都获得服务器的最新响应,则可设置该属性为false

<constant name="struts.configuration.xml.reload" value="true" />:当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生 产环境下使用),开发阶段最好打开

<constant name="struts.devMode" value="true" /> :开发模式下使用,这样可以打印出更详细的错误信息

<constant name="struts.ui.theme" value="simple" /> :默认的视图主题

<constant name="struts.objectFactory" value="spring" />:该 属性指定Struts2中的actionSpring容器创建

struts.enable.DynamicMethodInvocation:该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false

struts.enable.SlashesInActionNames:该属性设置Struts 2是否允许在Action名中使用斜线,该属性的默认值是false。如果开发者希望允许在Action名中使用斜线,则可设置该属性为true

struts.tag.altSyntax:该属性指定是否允许在Struts 2标签中使用表达式语法,因为通常都需要在标签中使用表达式语法,故此属性应该设置为true,该属性的默认值是true

struts.i18n.reload:该属性设置是否每次HTTP请求到达时,系统都重新加载资源文件。该属性默认值是false。在开发阶段将该属性设置为true会更有利于开发, 但在产品发布阶段应将该属性设置为false
提示 开发阶段将该属性设置了true,将可以在每次请求时都重新加载国际化资源文件,从而可以让开发者看到实时开发效果;产品发布阶段应该将该属性设置为 false,是为了提供响应性能,每次请求都需要重新加载资源文件会大大降低应用的性能。

struts.ui.templateDir:该属性指定视图主题所需要模板文件的位置,该属性的默认值是template,即默认加载template路径下的模板文件。

struts.ui.templateSuffix:该属性指定模板文件的后缀,该属性的默认属性值是ftl。该属性还允许使用ftlvmjsp,分别对应FreeMarkerVelocityJSP模板。

struts.velocity.configfile:该属性指定Velocity框架所需的velocity.properties文件的位置。该属性的默认值为velocity.properties

struts.velocity.contexts:该属性指定Velocity框架的Context位置,如果该框架有多个Context,则多个Context之间以英文逗号(,)隔开。

struts.velocity.toolboxlocation:该属性指定Velocity框架的toolbox的位置。

struts.url.http.port:该属性指定Web应用所在的监听端口。该属性通常没有太大的用户,只是当Struts 2需要生成URL时(例如Url标签),该属性才提供Web应用的默认端口。

struts.url.https.port:该属性类似于struts.url.http.port属性的作用,区别是该属性指定的是Web应用的加密服务端口。

struts.url.includeParams:该属性指定Struts 2生成URL时是否包含请求参数。该属性接受nonegetall三个属性值,分别对应于不包含、仅包含GET类型请求参数和包含全部请求参数。

struts.custom.i18n.resources:该属性指定Struts 2应用所需要的国际化资源文件,如果有多份国际化资源文件,则多个资源文件的文件名以英文逗号(,)隔开。

struts.dispatcher.parametersWorkaround:对 于某些Java EE服务器,不支持HttpServlet Request调用getParameterMap()方法,此时可以设置该属性值为true来解决该问题。该属性的默认值是false。对于 WebLogicOrionOC4J服务器,通常应该设置该属性为true

struts.freemarker.manager.classname:该属性指定Struts 2使用的FreeMarker管理器。该属性的默认值org.apache.struts2.views.freemarker.FreemarkerManager,这是 Struts 2内建的FreeMarker管理器。

struts.freemarker.wrapper.altMap:该属性只支持truefalse两个属性值,默认值是true。通常无需修改该属性值。

struts.xslt.nocache:该属性指定XSLT Result是否使用样式表缓存。当应用处于开发阶段时,该属性通常被设置为true;当应用处于产品使用阶段时,该属性通常被设置为false

struts.configuration.files:该属性指定Struts 2框架默认加载的配置文件,如果需要指定默认加载多个配置文件,则多个配置文件的文件名之间以英文逗号(,)隔开。该属性的默认值为struts-default.xml,struts-plugin.xml,struts.xml,看到该属性值,读者应该明白为什么Struts 2框架默认加载struts.xml文件了。

struts.objectFactory:该属性指定Struts 2中的action由哪个容器创建

struts.convention.default.parent.package:这个常量表示缺省的包名是什么,因为在实际应用中,我们常常定义一个缺省的包,这个包中定义了一大堆的拦截器等等,然后其他的包继承自这个包。这个常量可以配也可以不配

struts.convention.package.locators:这个常量表示你的action类的java包的包名的后缀是啥:比如action。这个常量也可以不配;

struts.convention.package.locators.basePackage:这个常量表示你的action类的javapackage的名字是啥;这个常量也可以不配;

posted @ 2021-09-29 10:36  上善若泪  阅读(132)  评论(0编辑  收藏  举报