第 5 章 struts2 的核心概念
DESCRIPTION
第 5 章 Struts2 的核心概念. 本章将深入探讨了 Struts2 的核心概念,首先介绍的是 Struts2 的体系结构和几个重要的配置文件,并会举例说明 Struts2 的核心对象如何配置。然后介绍 Struts2 最重要的 3 个组成部分 Action 、 Result 、 Interceptor (拦截器)的原理和使用方法。. 5.1 术语概述. - PowerPoint PPT PresentationTRANSCRIPT
第 5 章 Struts2 的核心概念• 本章将深入探讨了 Struts2 的核心概念,首先介绍的是 Struts2 的体系结构和几个重要的配置文件,并会举例说明 Struts2 的核心对象如何配置。然后介绍 Struts2 最重要的 3 个组成部分 Action 、Result 、 Interceptor (拦截器)的原理和使用方法。
5.1 术语概述• Action 在 Struts2 中是负责 Web 应用程序中具体逻辑实现的。 Action 是一个 Java 类,一般的继承于 com.opensymphony.xwork.ActionSupport类,这个类在 Struts2 的 Dispatcher 接受到 HTTP 请求的时候被调用。• 当一个 action 执行完毕之后,它将返回一个返回码,譬如“ SUCCESS”“INPUT” 或者其他“返回代码”。这些“返回代码”通过查找 struts.xml中的定义告诉 Struts2 下一步该做什么而这个下一步就称为 result 。 Struts2 支持许多种不同的 result 类型,比如返回结果页面给用户。可选择的显示模板技术有 JSP 、 Velocity 或者是 FreeMarker 。
5.2 Struts2 的体系结构• Struts2 的核心体系结构如图 5.1 所示。用户在 Struts2 框架下只需编写自己的 Action 类来处理逻辑、编写 JSP 页面(或者其他方式)来展示用户界面和在 struts.xml 配置映射关系就可以完成基本的业务流程。
5.3 Struts2 的配置文件• Struts2 框架主要有两个核心配置文件: struts.properties和 struts.xml 。 struts.xml 与 Struts1 版本中的 struts-config.xml 非常类似,主要负责管理应用中的 Action 映射,以及该 Action 包含的 Result 定义等,而 struts.properties 文件则定义了 Struts2 框架的全局属性。所有的配置文件说明见表所示,图展示了几个配置文件所在位置和相互关系。
5.3.1 全局配置文件 --struts.properties • struts.properties 文件是一个标准的 Properties文件,该文件包含了系列的 key-value 对象,每个 key 就是一个 Struts2 属性,该 key 对应的 value 就是一个 Struts2 属性值。 struts.properties文件通常放在 Web 应用的 WEB-INF/classes 路径下,实际上,只要将该文件放在 Web 应用的 CLASSPATH 路径下, Struts2 框架就可以加载该文件。以下是一部分配置片段。• struts.enable.DynamicMethodInvocation=false"• struts.devMode=false
5.3.2 核心配置文件 --struts.xml• struts.xml 文件主要负责管理应用中的 action 映射,以及该 action 包含的 result 定义等。在 struts.properties 配置中的有一项 struts.configuration.files ,这里可以看出 struts.xml 这个文件名不一定是固定的,可以配置为其他文件名的。 struts.xml内容主要包括: Action 、 Interceptor 、 Packages 、 Namespace 等。后面的章节将详细介绍如何配置这些元素。• 在 struts.xml 中可以使用 <include>标签把内容分到几个文件中去。这里非常像 JSP 中的 <jsp : include> 动作标签,可以把其他文件的内容导入进来,被导入的每个配置文件必须和 struts.xml 文件有一样的格式。 <include>标签的格式如下所示。
5.3.3 struts.xml 的缺省实现• struts-default.xml 这个文件被包含在 struts2-core.jar 中,文件名已经可以看出这个文件的作用是 struts.xml 的缺省配置,它将自动被加载然后导入到 struts.xml 中去。代码 5-1 是 struts-default.xml 的部分片段。
5.3.4 Velocity 模板规则文件• 如果在程序中使用了 Velocity (一个基于 java 的模板引擎,可以替代 JSP作为显示页面)可以把文件 velocity.properties 放到 classpath 中去,系统将自动加载。同时还要配置 struts-default.vm 文件,• 代码 velocity.properties• # Velocity 资源定义 .• velocimacro.library = action-default.vm , tigris-macros.vm , myapp.vm
5.4 struts.xml 的配置• Struts2绝大多数的配置都是在 struts.xml 中完成的,学习 struts.xml 文件是学习使用 struts2的基础。本节将详细讲述如何在 struts.xml 中定义和配置各种元素。
5.4.1 action 配置• action 是 Struts2 的基础“工作单元”。配置一个基本的 action 只需要两个信息: action名字和对应的 action 类,这两部分就建立了一个最简单的 action 配置。属性“ method” 用来告诉 Struts2 调用 action 的那个方法。在 action 处理之后一般的需要展示处理结果给用户,所以还需要把 action 和 result 映射在一起。如代码所示。• 代码 Action 配置: struts.xml• <!—Struts action 配置 -->• <action name="helloWorld" class="example.HelloWorld" method=”doWork”>• <result name="failure" path="Error.jsp"/>• <result name=”ok” path="HelloWorld.jsp"/>• </action>
5.4.2 result 配置• Struts2 定义了一些默认 result : error , input , login ,none 和 success 。开发者当然也可以根据应用情况自由的定义结果。结果以“名字 - 值”的形式影射到结果类型。 result 标签告诉 Strtus 2 在 action 被调用以后下一步做什么。 result 在 struts.xml 文件中定义,嵌套在 <action>标签里。如果 location参数是唯一的参数,可以这样简单的定义:• <!—在 result 中添加参数 -->• <action name="bar" class="myPackage.barAction">• <result name="success" type="dispatcher">• <param name="location">foo.jsp</param>• </result>• </action>
5.4.3 拦截器( interceptor )配置• interceptor 是能在一个 action 执行的前后执行的代码。它是做 Web 应用程序时很有用的工具。最常见的由 Interceptor 实现的功能如:安全检查( 确保访问者是登陆用户 )、跟踪日志 (记录每个 action)、效率瓶颈检查 ( 记录每个 action开始和结束的时间以检查程序中的瓶颈 )。也可以把 interceptor连在一起组成 interceptor栈( interceptor-stack )。比如在 action 执行前同时做登陆检查,安全检查和记录日志,可以定义一个 interceptor的栈。 interceptor必须事先定义好,然后可以连在一起组成一个栈。如代码 5-7所示,定义了一个interceptor 和一个 interceptor栈。
5.4.4 包( package )配置• 所谓 packages 就是把 actions 、 results 、 results 、 types 、 interceptors 这些元素打包到一个逻辑单元中去,从概念上讲, packages 就更像一个程序中的对象,可以被其他子包从写,而且可以拥有自己独立的部分。 Name 属性是 packages 的必填元素,它作为一个关键字被后边的包引用; extends元素是可选的,它允许包扩展一个和多个前边定义的包。 Abstract元素是可选的,如抽象类和抽象函数一样它是必须被继承的,可以申明一个不包含 actions 的 package 。
5.4.5 命名空间( Namespace )配置• 命名空间属性允许把 action 配置分成不同的命名空间,这样可以使功能不同 action 中使用相同的名字。默认命名空间用“” ( 空字符串 )表示。如果系统在指定的命名空间中没有找到某个 action ,就会到默认命名空间中查找。可以在所有用 "extends" 扩展的命名空间外配置全局 action 不指定命名空间。• Struts2 中有以“ /”命名的根命名空间,它是请求直接来自应用程序根路径的时候的命名空间。和其他命名空间一样,如果在根命名空间中没有所需的action别名,系统会回到默认命名空间中查找。如代码 5-9所示,这里使用了默认命名空间、“ /”和声明了的命名空间“ barspace”
5.4.6 在 struts.xml 中定义 Bean• 在 struts.xml 中还可以作 JavaBean 的定义如下: s• <!-- 在 struts.xml 中定义 Bean --->• <struts>• <bean type="com.opensymphony.xwork2.ObjectFactory" • name="myfactory"• class="com.company.myapp.MyObjectFactory" />• </struts>
5.4.7 在 struts.xml 中使用通配符• 当配置文件中 action mapping 的数量很多的时候,使用通配符是一个很好的办法,可以将一些相似的 mapping绑在一起,用一个比较通用的 mapping 来表示。在路径中用 *来代替变化的部分,而 action 的处理类和 JSP 中 {1} 刚好是代替这个变量。• <!-- 在 struts.xml 中使用通配符 -->• <action name="/edit*” class="example.Edit{1}Action">• <result name="failure" path="/mainMenu.jsp"/>• <result name=”ok” path="/\{1\}.jsp"/>• </action>
5.5 实现 Action• Action 是 Struts2 编程的核心部分,反映了对 Web 应用程序的功能需求。 Action 在 MVC 模式中担任控制部分的角色,在 Struts2 中也使用的最多。每个请求的动作都对应于一个相应的 action , action还可以负责存储数据 /状态(以 getter 和 setter 的方式)并且执行逻辑处理。• 在本章中将关注如何实现 action ,以及 action 如何提供Web 应用程序中所需的通用功能。除了 Action 接口之外,Struts2 的 action也可以选择实现其他可选择的接口,从而使 action能够提供诸如国际化、校验、负责工作流和错误信息处理等功能。 ActionSupport 基类实现了 Action 接口并提供了大部分可选择口默认实现,将在本章深入讲述这个类。除此之外,也将探讨 action 是如何通过使用 JavaBean 属性提供输入和输出的,最后将介绍如何处理文件上传。
5.5.1 实现 Aciton 接口• Struts2 的 Action 接口来源于 WebWork ,全包名为 com.opensymphony.xwork2.Action 如代码 5-10所示。在 Struts2 中定义 action 类时已经可以不实现 Aciton 接口, Struts2 会以反射的方式来调用 action 类。
5.5.2 扩展 ActionSupport 类• ActionSupport 是一个让 action 类能够更快开始工作的基类。它包含了 action能够提供的许多可选服务的默认实现,让开发者更容易地开始开发自己的 action 类,不需要在为这些可选服务提供具体实现了。同时能够改写可选择接口的任意一个方法实现并保持其他方法的默认实现。由于 ActionSupport预建了许多开箱即用的功能,建议读者创建自己的 action 时都扩展 ActionSupport类。 ActionSupport 实现了以下可选择接口,
5.5.3 实现基本校验• 通常在执行业务逻辑之前,校验用户提供的数据是十分表要的。这种字段校验包括“某个字段是必须的”、“某个字段必须大于某个值,小于某个值“等内容。为了自动执行校验, Sturts 2提供了一种能够在 excuete()方法被调用之前调用其他方法对 action进行处理的机制,这个机制由 com.opensymphony.xwork2.Validateable 接口提供,它包含了一个方法:• public void validate()• Validateable 接口为 action增加了一个标记,通过以上方法使得 action能够自动被校验。• 保存和显示校验的错误信息有接口 ValidationAware 来负责,这两个接口一般会同时使用。
5.5.4 使用本地的资源文件• 本节中将介绍另外两个接口 TextProvider 和 LocalProvider ,它们都是为了使用本地的资源文件而设计的。• 在 Java 中用户语言和地区的信息被封装在 java.util.Local 类中,而 action 则通过一个定义与 com.opensymphony.xwork.LocaleProvider 接口的方法判断使用哪个 Locale获取用于显示的信息文本,这个接口中只定义了一个方法:• Public Locale getLocale()• 在 ActionSupport 中,这个方法的默认实现为:通过调用 AcitonContext.getContext ().getLocale()方法,利用 ActionContext获得 locale 的值(关于 ActionContext 的使用将在后面的章节详细描述)。 Struts2 通过查询 HttpServletRequest 对象并调用它的 getLocale () 方法将 Local 与 action 调用联系起来。
5.5.5 用 ActionContext 与 Web容器发生联系• 在 Action 的接口定义中, excute()方法并没有 HttpServletRequest 和 HttpServletResponse参数也就是说 Struts2 的 Action 不用去依赖于任何 Web容器(不像 Struts 1必须在 Web容器中才能运行),不用与那些 JavaServlet复杂的请求( Request )、响应 (Response)关联在一起。但在 Web 应用程序开发中,往往需要在 Action里直接获取请求 (Request)或会话( Session )的一些信息,甚至需要直接对 JavaServlet Http 的请求、响应操作。 Struts2 提供了一个工具,用 ActionContext 对象来与 Web容器发生联系。• ActionContext ( com.opensymphony.xwork.ActionContext )是 Action 执行时的上下文,上下文可以把它看作是一个 Map ,它存放是 Action 在执行时需要用到的对象,比如:上下文放有请求的参数( Parameter )、会话( Session )、 Servlet上下文( ServletContext )、本地化( Locale )信息等。在每次执行 Action之前都会创建新的 ActionContext , ActionContext 是线程安全的,也就是说在同一个线程里 ActionContext里的属性是唯一的,这样的 Action 就可以在多线程中使用。
5.5.6 高级输入• 应用程序经常使用 JavaBean 表示一个域中的对象,包括 User 、 Address 、 Block 在内地的类就是这种 JavaBean很好的例子。而在 Web 程序中很大一部工作都是将信息填充到这些对象中去和从 Bean 中获取数据信息在网页中表现。本节将以一个完整的实例来说明 Sturts 2 在这些方面提供了那些便利。
5.5.7 使用 Model-Driven• Struts2 中,提供了两种 Action驱动模式: Property-Driven (属性驱动), Model-Driven (模型驱动的)。• 模型驱动的 Action很像 Struts1 中的 FormBean ,在传递过程中有一个单独的值对象来作为参数的载体,但在 Struts2 中这个值对象不必再继承任何接口,只要普通 JavaBean 就可以充当模型部分。很多情况下 Bean 的定义已经存在了,而且是不能修改的(如从外部引入的类或者是已经被大量代码引用的类),如果必须实现某个接口才能作为 FromBean ,不得不再新增一个类, Struts2 的这个改进非常及时。
5.5.8 使用 Property-Driven• Property-Driven 就是 Action 将直接用自己的字段来充当 FormBean 的功能,在 Struts2 入门一章中, HelloReader 这个例子就是采用的这种方法,在 Action 中直接包含了 message 属性和它set 、 get 方法。它一般用在页面表单比较简单的情况使用,而且可以直接把属性作为 Action 的字段,这样就不用在另写 FormBean ,减少了重复代码。• 上一节的例子如果使用 Property-Driven 方法,那就是将 User 与 action 类合并定义,把 User中的属性值直接转移到 action 中去,在配置文件中也不必再增加modelDriven 这个过滤器。
5.6 Result 类型介绍• Result 是在 Action 执行完,一个结果返回后决定发生什么事的类。开发者可以自由的根据他们的应用和环境的需要创建自己的 Result 类型。例如在 Struts2 中 Servlet 和 Velocity 结果类型已经被创建用来显示 web 应用程序的画面。本节将介绍 Struts2 内置的几种 Result 类型和如何自定义开发 Result 。
5.6.1 内置 Result 类型• 所有的 Result 类型都实现了 com.opensymphony.xwork.Result 接口。这个接口是所有 action执行结果的通用接口,不管这个结果是用来显示一个网页还是产生一个 E-mail ,发送一个 JMS消息还是别的。• 在 struts-default.xml 中定义了系统提供的缺省Result 类型,把它们映射为 action 配置中可以引用的名字,在 action 配置就就不用再使用长类名直接使用这些别名就可以了。
5.6.2 默认 Result • Dispatcher Result 是最常用的一种 result ,它也是 Struts2默认的 result ,又称为通用 resut 。 action 执行完后,请求会导向对应的 View ,相当于 <jsp:forword>标签实现的跳转功能。将同一个HTTP 请求中的内容分发至某一个页面 (dispatcher 类型的 result 的使用 )只要配置文件包含了 struts-default.xml ,而且 package 继承了 struts-default ,那么使用 dispatcher result 并不需要其他设置。示例:• <result name="success" type="dispatcher">• <param name="location">foo.jsp</param>• </result>
5.6.3 页面跳转 Result• Redirect Result 与 Dispatcher Result作用类似也是实现页面跳转。对上次的响应将重定向到指定的位置,可以理解为在客户端跳转用户又重新请求了一个新的 URL。 redirect 是重新产生一个新的 request ,因此原来 request保存的东西将不再有效,比如不能通过再 requet.getAtrribute() 取得对象,也不能取得 action 的实例、 errors 、field errors 等。• Redirect Result 与 Dispatcher Result 的区别于源于 JSP篇中 <jsp:forward>标签与 response.redeiret()的区别。
5.6.4 创建 action链• Chain Result 是一种 result 类型,它基于自己的拦截器 stack (堆栈)和 result 调用一个 action ,这样允许一个 action附带着原来的状态将请求转到目标 action• Struts2提供把多个 Action按照预先定义好的顺序或者流程链接起来的能力。这个特性通过给指定的 Action设置一个 Chain Result ,然后通过一个 ChainingInterceptor 拦截目标 Action 来实现。
5.6.5 整合各种 View 技术• Velocity 、 Freemarker 、 JasperReports 、 xslt 这 4种result都是为了整合不同的视图技术而设计的。• 1. Velocity Result:Velocity 是一个基于 java 的模板引擎( template engine )。• 2. Freemarker Result:Freemarker也是一个模板引擎,允许 JavaServlet保持图形设计同应用程序逻辑的分离,这是通过在模板中密封 HTML完成的。模板用 servlet提供的数据动态地生成 HTML。• 3. JasperReports result:JasperReports 是一个基于 Java 的开源报表工具,它可以在 Java环境下像其他 IDE报表工具一样来制作报表。• 4. XSLT Result:XSLT Result 用 XSLT 来转换 action 对象到 XML。
5.6.6 自定义 result• Struts2也允许用户自定义自己的 result 类型,只要实现 com.opensymphony.xwork2.Result接口就可以了。如代码 5-29所示,模拟了一种 result作用是根据处理结果将给指用户发送一份E-mail 。这个 result 需要 4个参数 to 、 from 、subject 和 body
5.7 拦截器( Interceptors )介绍• 拦截器( Interceptor )是 Struts2 的一个强有力的工具,有许多功能都是构建于它之上,如国际化、转换器,校验等。 Interceptor 是 Struts2 的一大特色,在执行 action 之前和之后可以使请求通过一个或多个 Interceptor 。多个连接器组合在一起实现某一个功能称为 interceptor链( Interceptor Chain ,在 Struts2 中称为拦截器栈 Interceptor Stack )。 interceptor链就是将 interceptor按一定的顺序联结成一条链。在访问被拦截的方法或字段时, interceptor链中的 interceptor 就会按其之前定义的顺序被调用。
5.7.1 Interceptor 的原理• Struts2 的 interceptor 实现相对简单。当请求到达 Struts2 的 ServletDispatcher 时, Struts2 会查找配置文件,并根据其配置实例化相对的 interceptor 对象,然后串成一个列表( list ),最后一个一个地调用列表中的拦截器,
5.7.2 内置拦截器介绍• Struts2 包含了许多内置的 interceptor ,它们提供了很多核心功能和可选的高级特性。 interceptor 在 struts.default.xml 文件中被定义,而一些默认的 interceptor栈及 interceptor 的命名也被定义其中。框架中提供了很多实用的 Interceptor ,可以随时使用它们的名字来调用这些 interceptor ,
5.7.3 使用内置 interceptor• 本节将介绍几种常用 interceptor 的用法:• 1.使用 timer 为 action即时• 2.使用 logger 为 aciton提供日志• 3.使用校验• 4.准备 action• 5.实现 ModelDriven• 6. token 和 token-session
5.7.4 内置拦截器栈介绍• 除了内置的 interceptor 之外, struts.xml还包含了内置的 interceptor 组合,可以通过具体的命名的 interceptor栈来使用它们。
5.7.5 自定义拦截器• 自定义一个拦截器需要 3 个步骤:• ( 1 )自定义一个实现 Interceptor 接口的类。• ( 2 )在 strutx.xml 中注册上一步中定义的拦截器。• ( 3 )在需要使用的 Action 中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的 Action都被这个拦截器拦截。
5.8 小结• 本章讲述的是 Struts2 的核心构成元素及其使用方法,使读者对 Sturts 2 的体系结构有了一个清晰的认识。 Struts2 是一个开放的系统,它的很多实现对用户来说都是透明的,它们在 struts-default.xml 中配置,开发人员配置自己的元素在 struts.xml 中,这个文件是可以拆分并按用户需要组织的。 Struts2 的核心部分由 action 、 interceptor 、 result3 个主要部分构成, Interceptor是它最大特色。