1

Size: px
Start display at page:

Download "1"

Transcription

1

2 免费在线版本 ( 非印刷免费在线版 ) InfoQ 中文站出品 本书由 InfoQ 中文站免费发放, 如果您从其他渠道获取本书, 请注册 InfoQ 中文站以支持作者和出版商, 并免费下载更多 InfoQ 企业软件开发系列图书 本书主页为 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

3 深入浅出 Struts 2 Starting Struts 2 作者 :Ian Roughley 翻译 : 李剑

4 2008 C4Media Inc. 版权所有 C4Media 是 InfoQ.com 这一企业软件开发社区的出版商 本书属于 InfoQ 企业软件开发系列图书 如果您打算订购 InfoQ 的图书, 请联系 未经出版者预先的书面许可, 不得以任何方式复制或者抄袭本书的任何部分, 本书任何部分不得用于再印刷, 存储于可重复使用的系统, 或者以任何方式进行电子 机械 复印和录制等形式传播 本书提到的公司产品或者使用到的商标为产品公司所有 如果读者要了解具体的商标和注册信息, 应该联系相应的公司 英文版责任编辑 :Diana Plesa 英文版封面设计 :Dixie Press 英文版美术编辑 :Dixie Press 中文版翻译 : 李剑中文站审校 : 张凯峰霍泰稳中文版责任编辑 : 霍泰稳中文版美术编辑 : 吴志民 欢迎共同参与 InfoQ 中文站的内容建设工作, 包括原创投稿和翻译等, 请联系 editors@cn.infoq.com

5 作者致谢 如果没有 Webwork XWork 和 Struts2 所有开发人员不懈的努力, 这本书将永远无法面世 在我从一个开源项目的使用者变成一个开源项目的开发人员的过程中,Patrick Lightbody 和 Jason Carreira 对我的帮助将永远铭刻我心 同时, 我也应该感谢这几位技术评审人员 Don Brown, Philip Luppens 和 Rene Gielen, 是他们为本书内容的不断扩充提出了最终的调整方案 还有 Jim Krygowski 和 James Walker, 他们从繁忙的工作日程安排中特意抽出时间, 站在 Struts2 以外的视角上, 对本书的内容及连贯性提出了中肯的意见 如果没有他们的帮助, 本书势必失色不少 我还要感谢 Floyd Marinescu, 他对我给予了充分的信任, 并为我提供了网络版和印刷版的写作机会 我还要谢谢我才华横溢的妻子 LeAnn ( 也就是 STR Worldwide), 她一直支持着我的工作, 并且长久以来一直对书稿进行评审和非技术层面的分析, 这是我的无价之宝

6 目录 简介... 1 WEB 世界中,STRUTS2 身处何方... 4 SERVLETS...5 JSP 和 SCRIPTLET 开发...5 基于 ACTION 的框架...6 基于组件的框架...6 伟大的均衡器 AJAX...7 核心组件... 8 配置...9 ACTIONS...14 INTERCEPTORS( 拦截器 )...18 值栈与 OGNL...22 结果类型...23 结果和视图技术...24 架构目标 概念分离...29 松耦合...30 易测试性...31 模块化...34 惯例重于配置...37 提高效率技巧 重用 ACTION 的配置...39 在配置中使用模式匹配调配符...40 使用替代的 URI 映射方法...41 了解拦截器的功能...44 使用提供的拦截器栈...46 利用返回类型...47 利用数据转换...48 利用列表数据项支持...50 在 ACTION 中暴露领域模型...52 尽可能使用声明式验证...53 把 CRUD 操作放到同一个 ACTION 中...56

7 在可能的地方使用注释 视图技术选项 了解框架提供的标签库及其特性 自定义 UI 主题 为通用的输出创建全局结果 声明式异常处理 国际化 其他技术集成...77 页面修饰和布局 业务服务 / 依赖注入 数据库 安全 AJAX 关于作者...87 参考资料...88 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

8 InfoQ 中文站 Java 社区关注企业 Java 社区的变化与创新 1 简介 自从 1997 年第一个 Servlet 规范发布以来, 我们在用 Java 开发 Web 应用这条路上已经走了很远很远 在过去的时间里, 我们学会了很多, 也曾经不止一次地对开发 Web 应用的方式做出过改进 Apache Struts 的产生就是一个伟大的跨越, 它的价值远远超过了我们目光所能及的极限 Apache Struts 在 2000 年 5 月由 Craig McClanahan 发起, 并于 2001 年 7 月发布了 1.0 版本 从技术的角度上来讲, 它是在开发 Web 程序上的一次跨越性的进步, 但更重要的是, 它在最恰当的时候出现在了人们的眼前 到那时为止,Web 开发已经度过了漫长的岁月, 很多大型项目都已经完工进入了维护期, 在这个过程中, 代码的可重用性与可维护性也给开发人员好好的上了几课.com 的兴起也引发了对 Web 应用开发更好的解决方案的诉求 当 Apache Struts 在 2000 年出现的时候, Web 项目的数量仍然显著地增长着, 而且毫无终止之势 Struts 一出现便大受欢迎, 更成为了以后几年内 web 开发的实际标准 Struts2 1 是 Struts 的下一代产品 而最初提案 Struts Ti 所设想的发展方向, 在 Struts 的现有代码的基础上是很难完成的 在发起提案的时候,Patrick Lightbody 把多个不同的 Web 框架的领导者邀请到了一起, 希望大家能够达成共识, 协力完成一个通用框架 虽然最终由于各种原因,Patrick Lightbody 的愿望未能实现, 但是 WebWork 和 1 更多精彩内容 :

9 2 深入浅出 STRUTS 2 Struts Ti 却发现了二者在技术与开发人员这两个层面上的共同之处, 不久之后, 两个项目就在 WebWork 的技术基础上进行了合并 2 当我们说起 WebWork 的时候, 我们实际上说的是两个项目 XWork 和 WebWork XWork 是一个通用的命令框架, 它提供了很多核心的功能, 例如 actions, 验证和拦截器, 它可以完全独立于执行上下文运行, 并提供了一个内部的依赖注入机制, 用来做配置和工厂实现的管理 而 WebWork 则是一个完全独立的上下文 它用 Web 应用中运行所需的上下文把 XWork 包装起来, 并提供了可以简化 Web 开发的特定实现 Struts2 的目标很简单 使 Web 开发变得更加容易 为了达成这一目标,Struts2 中提供了很多新特性, 比如智能的默认设置 annotation 的使用以及 惯例重于配置 原则的应用, 而这一切都大大减少了 XML 配置 Struts2 中的 Action 都是 POJO, 这一方面增强了 Action 本身的可测试性, 另一方面也减小了框架内部的耦合度, 而 HTML 表单中的输入项都被转换成了恰当的类型以供 action 使用 开发人员还可以通过拦截器 ( 可以自定义拦截器或者使用 Struts2 提供的拦截器 ) 来对请求进行预处理和后处理, 这样一来, 处理请求就变得更加模块化, 从而进一步减小耦合度 模块化是一个通用的主题 可以通过插件机制来对框架进行扩展 ; 开发人员可以使用自定义的实现来替换掉框架的关键类, 从而获得框架本身所不具备的功能 ; 可以用标签来渲染多种主题 ( 包括自定义的主题 );Action 执行完毕以后, 可以有多种结果类型 包括渲染 JSP 页面,Velocity 和 Freemarker 模板, 但并不仅限于这些 最后, 依赖注入也成了 Struts2 王国中的一等公民, 这项功能是通过 Spring 框架的插件和 Plexus 共同提供的, 与 PicoContainer 的结合工作还正在进行中 本书的目的, 是为了帮助读者掌握 Struts2 框架, 并能够对组成框架的功能部件和可用的配置项有深刻的理解 我在书中还将介绍一些可以提高生产力的方法 包括默认配置项和应当注意的实现特性, 可用的多种配置选项和一些开发技术 本书还会就与第三方软件进行集成的话题展开讨论 2 Don Brown, Struts Ti 项目的领导, 他在文章中详细介绍了 Struts Ti 的历史, 详情请参见 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

10 简介 3 本书并不会对 Struts2 中所有的特性进行面面俱到的讲述 作为一个新项目,Struts2 仍然在不停地迎来变化 升级以及新的特性 我希望读者能够花一些时间访问一下项目的主页, 从中你可以发现很多本书中未能囊括的选项和特性 本书参考的是 Struts2 的 版本 更多精彩内容 :

11 InfoQ 中文站 Ruby 社区关注面向 Web 和企业开发的 Ruby 2 Web 世界中,Struts2 身处何方 今天, 摆在开发人员面前的是众多的 Web 开发框架 它们有些来自于开源社区, 有些来自于商业公司, 还有些是由某些团队内部 3 开发的, 以满足当前 Web 开发所需 目前大约一共有超过 40 个开源框架, 这个数目看上去挺大, 但也许还有同样多 ( 如果不是大大多于这个数量的话 ) 的内部构建的框架部署在产品环境中 既然我们有这么多选择, 那为什么要选择 Struts2 呢? 下面列出的这些特性, 可能会促使你把 Struts2 作为你的选择 : 基于 Action 的框架 拥有由积极活跃的开发人员与用户组成的成熟社区 Annotation 和 XML 配置选项 基于 POJO 并易于测试的 Action 与 Spring,SiteMesh 和 Tiles 的集成 与 OGNL 表达式语言的集成 基于主题的标签库与 Ajax 标签 多种视图选项 (JSP,Freemarker,Velocity 和 XSLT) 使用插件来扩展或修改框架特性 在选择一个框架的时候, 框架风格的选择是最具有争议性的 让我们先来了解一下 Web 应用的发展过程, 然后再来看看我们是怎样走到今天的, 以及在现在的 Web 开发场景中,Struts2 到底占据了什么位置 3 你可以访问 来获取一份各种 web 框架的列表 4

12 STRUTS 2 身处何方 5 Servlets Servlets 是 Java 在 Web 应用中的开创性的尝试 在遵循 HTTP 协议的前提下,Servlets 可以将 URL 映射到一个特定的类上, 而该类中的方法将会被调用 人们马上就意识到, 虽然这是一次大踏步式的前进, 但是这种在 Java 代码中生成 HTML 代码的方式, 对项目维护而言简直就是一场噩梦 每次当用户界面发生了变化,Java 开发人员就需要更改 Servlet 代码, 重新编译, 然后把应用重新部署到服务器上 JSP 和 Scriptlet 开发 这种 维护噩梦 的后果, 又导致开发风格的正好颠倒 现在人们不是把 HTML 代码放在 Servlet 或者 Java 代码中, 而是把 Java 代码 ( 作为 script-lets) 放在 HTML 代码中 这就是 Java Server Pages (JSP) 每一个 JSP 都同时负责处理请求和页面表现 一个问题得到了解决, 而另一个问题却又出现了 在 JSP 中, Java 代码的使用方式和在类中一样, 但这里却没有方法和类的结构 在早期的每一个 JSP 文件中, 都可以找到以下两种情况之一 : 剪切和粘贴的代码 Java 代码从一个 JSP 中复制到第二个, 第三个, 等等 这种情况会导致在原始代码中存在的缺陷或者错误传播开来, 并且大大增加了工作量, 因此必须要对此做出改变 调用通用的 Java 格式化对象 通用的格式化代码或者是逻辑代码被组织到一个可重用的对象中, 然后每一个 JSP 都会使用这个通用的对象 基于这些情况, 一种最佳实践, 或者可以称之为一种模式, 就应时而生了 在 JSP 中使用 Java 对象 随着 JSP 规范的进一步完善, 标签开始被引入进来对可重用的 Java 对象进行封装 标签提供了用以访问底层代码的表层代码, 它与 HTML 很相像, 设计人员 ( 而不是开发人员 ) 和 IDE 可以通过它与动态内容交互, 组装出页面布局 像 <jsp:usebean.. /> 和 更多精彩内容 :

13 6 深入浅出 STRUTS 2 <jsp:getproperty.. /> 就是 JSP 所提供的标签 JSP 在提供了一系列标签库的同时, 还可以支持开发人员创建自定义的标签库 基于 Action 的框架 基于 Action 的框架把 Servlet 和 JSP 的概念合并到了一起 它的想法是把对当前用户所见的页面请求的处理动作, 分拆成处理逻辑和表现逻辑, 让它们各司其职 这种实现方式使用了源自于 Smalltalk 的一个模式, 名为模型 - 视图 - 控制器 最近的叫法是前端控制器, 而 Sun 则给它起名为 Model 2 在这个模式中,Servlet 是控制器, 集中处理所有的客户端页面请求 它把所请求的 URL 与被称为 Action 的工作单元映射到一起 Action 的工作就是通过访问 HTTP 会话 HTTP 请求和表单参数等调用业务逻辑, 最后把响应映射到以 POJO(plain old java object) 形式存在的模型上, 来完成特定的功能 最后,Action 返回的结果会通过配置文件映射到 JSP 页面上,JSP 会渲染视图并显示给用户 Struts2 是一个基于 Action 的 MVC Web 框架 基于组件的框架 当 Web 应用变得更加复杂的时候, 人们便意识到一个页面已经不再是一个独立的逻辑了 一个页面上会存在多个表单, 有内容更新的链接, 还有其他很多自定义的 Widget 而这些都需要进行逻辑处理来完成各自的任务 出于解决这种复杂度的需要, 基于组件的框架开始流行起来 它们在用户界面组件和表示这些组件的类之间提供了一层紧密的连接, 它们是事件驱动型的, 并且比起基于 Action 的框架而言, 更具有面向对象的特征 一个组件可以是一个 HTML 输入框, 一个 HTML 表单, 框架所提供的或是开发人员创建的 Widget 像提交表单或者是点击链接这样的事件, 都与代表组件的类的方法或者是特定的监听类, 有着一对一的映射关系 基于组件的框架还有一个好处, 那就是你可以在多个 Web 应用之间重用组件 JSF,Wicket 和 Tapestry 等都是基于组件的框架 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

14 STRUTS 2 身处何方 7 伟大的均衡器 Ajax 在 2005 年初,Web 应用又增异彩 按照 Jesse James Garrett 的说法, Ajax 的全称是 Asynchronous JavaScript and XML 相对说来, 这些技术没有一样是新的 实际上, 早在 6 年以前 ( 从 Internet Explorer 5 开始 ), 可进行异步调用的主要 Web 浏览器组件 XMLHttpRequest 对象就已经提供了支持 真正推陈出新的是这些技术的应用 Google 地图第一个完全利用了这项技术所带来的好处, 在 Google 地图中, 网页是活动的, 你可以通过各种窗体组件与它进行交互 你可以用鼠标来拖动屏幕上的地图 ; 当你输入一个地址时, 相关信息还会在地图的对应位置显示出来 ; 最后, 当它们都与 Web 程序完美结合以后,Web 应用终于攀上了新的巅峰 这些操作都不会带来页面的刷新! 当用户界面与 Ajax 结合以后,Web 浏览器就可以只在必需的时候, 才会向服务器发起请求, 获得少量的信息 服务器返回的结果都是被格式化或者处理过的, 页面会直接把结果显示出来, 然后用户就可以在浏览器中看到变化 因为只有发生变化的那一块区域会被重新渲染, 而不是整个页面进行刷新, 所以对于用户来说, 响应速度就变得更快了 从 UI 发出的请求和事件很相似 它们是不连续的, 所传递的只是一个单独的组件或者功能的信息 现在的操作已经再也不需要获取整个页面的信息了, 它们变得更加精细, 跨应用的可重用性也变得更高 其结果就是, 当一个 Ajax 用户界面调用基于 Action 的框架时, 这个 Action 框架的反应机制就和基于组件的框架非常相似 实际上, 这二者的结合为我们带来了耦合度更低 可重用性更高的系统 同样的操作, 可以为 Ajax 组件提供 JSON XML 或者 HTML 片段视图, 又可以和其他操作组合, 为非 Ajax 的用户界面提供 HTML 视图 更多精彩内容 :

15 InfoQ 中文站 SOA 社区关注大中型企业内 SOA 的一切 3 核心组件 从全局的角度来看,Struts2 是一个 pull( 拉 ) 类型的 MVC( 或者 MVC2) 框架, 它与传统类型的 MVC 框架的不同之处就在于在 Struts2 中,Action 担任的是模型的角色, 而非控制器的角色, 虽然它的角色仍然有些重叠 pull 的动作由视图发起, 它直接从 Action 里拉取所需的数据, 而不是另外还需要一个单独的模型对象存在 我们刚刚从概念上讲述了一下 Struts2 里面的 MVC, 那么从实现的层面上来看又是什么样子呢? 在 Struts2 中, 模型 - 视图 - 控制器模式通过五个核心组件来实现 Action 拦截器? 值栈 /OGNL? 结果类型和结果 / 视图技术 图 1: MVC / Struts2 架构 8

16 核心组件 9 图 1 描述了 Struts2 架构中的模型 视图和控制器 控制器通过 Struts2 分发 Servlet 过滤器 ( 也就是人们常说的拦截器 ) 来实现, 模型通过 Action 实现, 视图则通过结果类型和结果组合实现 值栈和 OGNL 提供了公共的线程和链接, 并使得不同组件可以相互集成 当我们在本章讨论通用组件时, 其中有大量的信息是与配置相关的, 也就是对 Action 拦截器 结果等等的配置 在阅读时要注意一点, 这里的讲解只是帮助读者掌握一些背景知识, 并没有采用最有效率的配置方式 在后续的章节中, 我们会介绍一些更加简单有效的方式, 诸如 惯例重于配置 注解和零配置插件 在我们对核心组件进行深入探讨之前, 首先让我们来看看全局性的配置 配置 在配置 Struts 2 之前, 你首先要把发行版下载下来, 或者在 Maven2 的 pom.xml 文件中声明如下的依赖 : <dependency> <groupid>org.apache.struts</groupid> <artifactid>struts2-core</artifactid> <version>2.0.6</version> </dependency> Mave2 是一种管理项目整体构建过程的工具 包括编译, 运行测试, 生成报告以及管理构建的制品, 其中对开发人员最有吸引力的一项就是对构建制品 (artifact) 进行管理 应用程序的依赖库只需要在项目的 pom.xml 文件中通过 groupid artifactid 和 version 进行定义即可 在使用一个制品之前,Maven 会从本地和远程的库中进行查询, 查询的范围包括本地的缓存 网上其他组织提供的库以及 ibiblio.com 这个标准的库 如果在远程的库中找到了所需的制品,Maven 就会把它下载到本地的缓存中, 以供项目使用 当请求所需要的制品时, 这个制品相关联的依赖也会同样被下载到本地来 ( 假设在该制品的 pom.xml 文件中对所有依赖都依次进行了声明 ) 更多精彩内容 :

17 10 深入浅出 STRUTS 2 Struts2 是用 Maven2 来构建的, 在 pom 文件中, 它定义了所有依赖的配置项 您可以访问 来获得关于 Maven2 的更多信息 Struts2 的配置可以分成三个单独的文件, 如图 2 所示 图 2: 框架元素的配置文件 FilterDispatcher 是一个 servlet 过滤器, 它是整个 Web 应用的配置项, 需要在 web.xml 中进行配置 : <filter> <filter-name>action2</filter-name> <filterclass>org.apache.struts2.dispatcher.filterdispatcher</fil ter-class> </filter> <filter-mapping> <filter-name>action2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 如果是配置一个最基本的 Web 应用的话, 这样就足够了 剩下的就是自定义一些 Web 应用的执行环境和配置应用中的组件 其中前者主要通过 struts.properties 来完成, 而后者是在 struts.xml 中进行配置的 我们下面来看一下这两个配置文件的细节 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

18 核心组件 11 struts.properties 文件这个文件提供了一种更改框架默认行为方式的机制 在一般情况下, 如果不是打算让调试更加方便的话, 你根本无须更改这个文件 在 struts.properties 文件中定义的属性都可以在 web.xml 文件的 init-param 标签中进行配置, 或者通过 struts.xml 文件中的 constant 标签来修改 ( 我们在下一章中会继续讨论这个标签 ) 我们可以更改其中的一些属性来改变 Freemarker 的选项 改变 Action 映射类, 判断是否要重新载入 XML 配置文件, 以及默认的 UI 主题等等 在 Struts2 的 wiki 上有这些属性的最新信息, 地址为 在 Struts2-Core 的 jar 发行版中, 有一个默认的属性文件, 名为 default.properties 如果要对属性进行修改的话, 只需要在项目的源代码目录下, 创建一个叫做 struts.properties 的文件, 然后把想要修改的属性添加到文件中, 新的属性就会把默认的覆盖掉了 在开发环境中, 以下几个属性是可能会被修改的 :» struts.i18n.reload = true 激活重新载入国际化文件的功能» struts.devmode = true 激活开发模式, 以提供更全面的调试功能» struts.configuration.xml.reload = true 激活重新载入 XML 配置文件的功能 ( 这是为 Action 准备的 ), 当文件被修改以后, 就不需要重新载入 Servlet 容器中的整个 Web 应用了» struts.url.http.port = 8080 配置服务器运行的端口号 ( 所有生成的 URL 都会被正确创建 )» struts.xml 文件 struts.xml 文件中包含的是开发 Action 时所需要修改的配置信息 在本章接下来的内容中, 会针对特定的元素进行详细讲解, 但现在让我们先来看一下文件的固定结构 有的时候你甚至可以把整个 struts.xml 文件从应用中移走, 这完全取决于应用程序的功能需求 我们在本章中所讨论的配置信息, 更多精彩内容 :

19 12 深入浅出 STRUTS 2 都可以被其他方式所代替, 比如注解, web.xml 启动参数和和可替换的 URL 映射方案 必须要在 struts.xml 中进行配置的信息只有全局结果 异常处理和自定义的拦截器堆栈 因为这是一个 XML 文件, 所以最开始的元素就是 XML 版本和编码信息 接下来则是 XML 的文档类型定义 (DTD) DTD 提供了 XML 文件中各个元素所应使用结构信息, 而这些最终会被 XML 解析器或者编辑器使用 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" " <struts> <package name="struts2" extends="struts-default" namespace="/struts2"> </package> </struts> 我们现在看到了 <struts> 标签, 它位于 Struts2 配置的最外层, 其他标签都是包含在它里面的 Include 标签 : <include /> 是 <struts> 标签的一个子标签, 它可以把其他配置文件导入进来, 从而实现 Struts2 的模块化 它的 file 属性定义了要导入的文件的名称 该文件要和 struts.xml 一样有着相同的结构 比如说, 如果要把一个记账系统的配置分解的话, 你可能会把记账 管理和报表的功能各自组织到不同的文件中 : <struts> <include file="billing-config.xml" /> InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

20 核心组件 13 <include file="admin-config.xml" /> <include file="reports-config.xml" /> </struts> 当我们导入文件时, 一定要注意导入的顺序 因为从文件被导入的那个点开始, 该文件中的信息才能被访问到, 也就是说, 如果要使用另外一个文件中所定义的标签, 那么该文件就必须要在被引用之前就配置好 有些文件需要显式导入, 有些则会被自动导入 strutsdefault.xml 和 struts-plugin.xml 就属于后者 它们都包括有结果类型 拦截器 拦截器堆栈 包 (package) 以及 Web 应用执行环境 ( 也可以在 struts.properties 中配置 ) 的配置信息 二者的区别在于, struts-default.xml 提供的是 Struts2 的核心配置信息, 而 struts-plugin.xml 则描述了特定插件的配置信息 每个插件的 JAR 中都要有一个 struts-plugin.xml 文件, 该文件会在系统启动时被装载 The Package Tag: <package /> 标签是用来把那些需要共享的通用信息 例如拦截器堆栈或 URL 命名空间 的配置组织在一起的 它通常由 Action 的配置组成, 但也可以包括任何类型的配置信息 它还可以用来组织管理各自独立的功能 它们也可以被进一步拆分到不同的配置文件中 这个标签的属性包括有 : name 开发人员为这个 Package 指定的唯一的名字 extends 当前这个 Package 所继承的 Package 的名字, 被继承的 Package 中所有的配置信息 ( 包括 Action 的配置 ) 都可以在新的命名空间下, 新的 Package 里面被使用 namespace 命名空间提供了从 URL 到 Package 的映射 也就是说, 如果两个不同的 Package, 其命名空间分别为 package1 和 package2, 那么 URL 差不多就是 更多精彩内容 :

21 14 深入浅出 STRUTS 2 /mywebapp/package1/my.action 和 /mywebapp/package2/my.action 这样的形式 abstract 如果这个属性的值为 true, 那么这个 Package 就只是一个配置信息的组合, 也就无法通过 Package 的名字来访问其中配置的 Action 只有继承了正确的父 Package, 那么你才能用到所需的预先配置好的特性 在大多数情况下, 我们都应该继承 struts-default.xml 配置文件中的 strust-default Package, 但是如果你想要使用插件的话, 那就另当别论了 你必须要参考插件的说明文档来确认所应当继承的父 Package 后面我们会继续讲解 Package 标签的详细配置信息 还有两个标签也可以和 <struts> 标签一起使用, 它们是 <bean /> 和 <constant /> 这两个标签为重新配置框架提供了更高级的方式, 我们在下一章讲述插件的时候会介绍它们的使用方法和配置细节 Actions 在大多数的 Web 应用框架中,Action 都是一个最基本的概念, 也是可以与用户发出的 HTTP 请求相关联的最小的工作单元 在 Struts2 中,Action 可以以几种不同的方式来工作 单个结果 Action 最常用也是最基本的用法就是执行操作后返回单个结果 这种 Action 看上去就是这样的 : class MyAction { } public String execute() throws Exception { return "success"; } InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

22 核心组件 15 这样简单的几行代码当然说明不了什么 但首先, 这个 Action 类不需要继承其它类, 也不需要实现其他接口 这样的类就是一个简单的 POJO 其次, 在这个类中有一个名为 execute 的方法 这个方法名是依照惯例命名的, 如果你想用其他名字的话, 那么只需要在 Action 的配置文件中做出更改 无论方法名是什么, 它们都被认为会返回一个 String 类型的值 Action 的配置文件会将该 Action 的返回代码与要呈现给用户的结果进行匹配 另外, 该方法还可以在需要的时候抛出异常 下面是最简单的配置信息 : <action name="my" class="com.fdar.infoq.myaction" > <result>view.jsp</result> </action> name 属性提供了执行 Action 所对应的 URL 地址, 在这里就是 my.action.action 的扩展名是在 struts.properties 4 文件中配置的 class 属性指定了要执行的 action 所对应的类的全限定名 多个结果现在情况稍微复杂了一些,Action 需要根据逻辑运算的结果, 来生成多个结果 下面的代码和刚才那个类看上去很像 : class MyAction { } public String execute() throws Exception { if( mylogicworked() ) { return "success"; } else { return "error"; } } 因为这里有两个结果, 所以就为每一种不同的情况来配置要呈现给用户的结果 配置文件就变成了如下的样子 : 4 只需要更改 struts.action.extension 这个属性的值 更多精彩内容 :

23 16 深入浅出 STRUTS 2 <action name="my" class="com.fdar.infoq.myaction" > <result>view.jsp</result> <result name="error">error.jsp</result> </action> 我们可以看到在 result 节点中多了 name 属性, 实际上这个属性是一直都存在的, 如果开发人员没有显式指定它的值, 那么它的默认值就是 success ( 第一个 result 的配置就是如此 ) 前面我们已经看到了定义 Action 结果的最通用的方式 而实际上我们还有另外四种方式 : 1. Action 方法返回一个字符串 这个返回的字符串与 struts.xml 的一个 action 配置相匹配 例子中已经演示这一种方式 2. 使用 Code behind 插件 当使用这个插件的时候, 它会将 Action 的名字和 Action 返回的结果字符串进行连接来得到视图模板 比如说, 如果 URL 是 /adduser.action, 而 Action 返回了 success, 那么要渲染的页面就是 /adduser-success.jsp 更多信息请参见 3. 注解 action 注解来标注多个不同的结果 Action 所返回的字符串需要与所注解的结果之一相匹配 4. 方法返回一个 Result 类的实例 Action 不必一定要返回一个字符串, 它可以返回一个 Result 类的实例, 该实例应当是已经配置好可使用的 结果类型 Action 生成并返回给用户的结果可能会有多个值, 而且也可能是不同的类型 success 的结果可能会渲染一个 JSP 页面, 而 error 的结果可能需要向浏览器发送一个 HTTP 头 结果类型 ( 本章中稍后会详细讨论 ) 是通过 result 节点的 type 属性来定义的 和 name 属性一样, 这个属性有一个默认值 dispatcher 用来渲染 JSP 大多数情况下, 你只需要使用默认的结果类型就可以了, 但是你可以提供自定义的实现 请求和表单类型 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

24 核心组件 17 Action 为了执行操作, 并为数据库持久化对象提供数据, 就必须要访问请求字符串和表单中的数据 Struts2 采用了 JavaBean 的风格 要访问数据的话, 就给字段提供一个 getter 和 setter, 要访问请求字符串和表单也是一样的道理 每一个请求字符串和表单的值都是一个简单的名 / 值对, 所以要设定一个特定名称的值的话, 就要为它提供一个 setter 比如, 如果一个 JSP 调用了 /home.action?framework=struts&version=2 这样一个请求, 那么 action 就应该提供如下两个 setter: setframework( String frameworkname ) 和 setversion( int version ) 我们可以看到, 例子中的 setter 并不是只接受 String 类型的参数 在默认情况下,Struts2 可以把 String 类型的值转换成 action 所需要的类型, 这条规则对于所有的 primitive 类型和基本对象类型的值都适用, 当然你也可以对其进行配置, 让它也适用于你所创建的类 Struts2 还可以在更加复杂的对象图中进行定位后赋值, 比如说如果一个表单元素的名字是 person.address.home.postcode, 其值为 2, 那么 Struts2 就会调用 getperson().getaddress().gethome().setpostcode(2) 这个方法 访问业务服务到现在为止, 我们已经讨论了很多有关 Action 配置的问题, 以及如何根据不同的结果代码来控制返回给用户的结果 这是 Action 的一个很重要的功能, 但是, 它必须要完成一些操作之后, 才能返回结果 因此它们需要访问多种类型的对象 业务对象, 数据访问对象或者其他资源 Struts2 使用了名为依赖注入 5 又名控制反转 的技术来降低系统的耦合性 依赖注入可以通过构造器注入, 接口注入和 setter 注入来实现 Struts2 中用的是 setter 注入 这就是说, 你只需要提供一个 setter, 对应的对象就可以被 Action 使用了 Struts2 推荐的依赖注入框架是 Spring 框架, 并通过插件对它进行配置 你还可以使用 Plexus, 或者是提供自定义的实现 5 Martin Fowler 写过一篇文章, 对依赖注入进行了完整的描述 : 更多精彩内容 :

25 18 深入浅出 STRUTS 2 还有些对象是不受 Spring 框架管理的, 例如 HttpServletRequest 这些对象是通过 setter 注入和接口注入混合处理的 对于每一个非业务的对象而言, 都有一个对应的接口 ( 也就是 aware 接口 ), 需要 action 对其进行实现 在最开始的时候,WebWork 有它自己独有的依赖注入框架 但自从 2.2 版本以后, 该框架就被 Spring 取代了 原先的那种组件框架是基于接口的, 所以每一个组件都需要有一个接口和一个对应的实现类 另外, 每一个对象都有一个 Aware 接口, 为组件提供了 setter 方法 对于 UserDAO 接口而言, 对应的 aware 接口按照惯例就会被命名为 UserDAOAware, 其中有一个 setter 方法 void setuserdao( UserDAO dao ); 当必需的接口和 setter 齐备以后, 拦截器就会对对象的注入进行管理了 从 Action 中访问数据在有些情况下我们需要查看被 Action 修改过的对象 有好几种技术可以帮助我们做到这一点 对于开发人员而言, 最常用的方法就是把所需要访问的对象放到 HttpServletRequest 或者 HttpSession 里面 这可以通过实现 aware 接口 ( 让依赖注入来工作 ), 并设置为可以通过要求的名称来访问的方式来达到 如果你打算使用内建的标签库或者是 JSTL 支持的话, 访问数据就会更简单了 这两种方法都可以通过值栈来访问 Action 开发人员唯一要另外做的就是在 Action 里面为所要访问的对象提供 getter 方法 在下个关于值栈的小节中我们会进行更深入的介绍 Interceptors( 拦截器 ) Struts2 中提供的很多特性都是通过拦截器实现的, 例如异常处理, 文件上传, 生命周期回调与验证 拦截器从概念上来讲和 Servlet 过滤器或者 JDK 的 Proxy 类是一样的 它提供了一种对 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

26 更多精彩内容 : 核心组件 19 Action 进行预处理和事后处理的功能 和 Servlet 过滤器一样, 拦截器可以被分层和排序 它还可以访问所执行的 Action 和所有的环境变量与执行属性 让我们从依赖注入来开始对拦截器的介绍 正如我们已经看到的一样, 依赖注入可以多种不同的实现方式 下面就是对应于不同实现方式的拦截器 : Spring 框架 ActionAutowiringInterceptor 拦截器 请求字符串和表单值 ParametersInterceptor 拦截器 基于 Servlet 的对象 ServletConfigInterceptor 拦截器 前两种拦截器可以独立工作, 不需要 Action 的帮助, 但是最后一种不同, 它是在以下几种接口的辅助下工作的 : SessionAware 通过 Map 来提供对所有 session 属性的访问 ServletRequestAware 提供对 HttpServletRequest 对象的访问 RequestAware 通过 Map 来提供对所有 request 属性的访问 ApplicationAware 通过 Map 来提供对所有 applicatin 属性的访问 ServletResponseAware 提供对 HttpServletResponse 对象的访问 ParameterAware 通过 Map 来提供对所有 request string 和表单数据的访问 PrincipalAware 提供对 PrincipleProxy 对象的访问 ; 该对象实现了 HttpServletRequest 对象的有关 principle 和 role 的方法, 但是它提供了一个 Proxy, 因此所有的实现都是独立于 Action 的 ServletContextAware 提供对 ServletContext 对象的访问 如果要把数据注入到 Action 中去, 那么对应的数据就需要实现必需的接口 配置如果要在 Action 中激活依赖注入功能 ( 或其他任何由拦截器提供的功能 ), 就必须要对 Action 进行配置 和其他元素一样, 许多

27 20 深入浅出 STRUTS 2 拦截器都已经提供了默认的配置项 你只需要确认一下 Action 所在的 Package 继承了 struts-default package 在配置一个新的拦截器之前, 首先要对它进行定义 <interceptors /> 和 <interceptor /> 标签都要直接放到 <package> 标签里面 像我们上面提到的那些拦截器, 它们的配置项就是这样的 : <interceptors> <interceptor name="autowiring" class=" xwork2.spring.interceptor.actionautowiringinte rceptor"/> </interceptors> 我们同时还要确保 Action 中应用了所需的拦截器 这可以通过两种方式来实现 第一种是把拦截器独立的分配给每一个 Action: <action name="my" class="com.fdar.infoq.myaction" > <result>view.jsp</result> <interceptor-ref name="autowiring"/> </action> 在这种情况下,Action 所应用的拦截器是没有数量限制的 但是拦截器的配置顺序必须要和执行的顺序一样 第二种方式是在当前的 Package 下面配置一个默认的拦截器 : <default-interceptor-ref name="autowiring"/> 这个声明也是直接放在 <package /> 标签里面, 但是只能有一个拦截器被配置为默认值 现在拦截器已经被配置好了, 每一次 Action 所映射的 URL 接到请求时, 这个拦截器就会被执行 但是这个功能还是很有限的, 因为在大多数情况下, 一个 Action 都要对应有多个拦截器 实际上, 由于 Struts2 的很多功能都是基于拦截器完成的, 所以一个 Action 对应有 7 8 个拦截器也并不稀奇 可以想象的到, 如果要为每一个 Action 都逐一配置各个拦截器的话, 那么我们很快就会变得焦头烂额 因此一般我们都用拦截器栈 (interceptor stack) 来管理拦截器 下面是 struts-default.xml 文件中的一个例子 : <interceptor-stack name="basicstack"> InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

28 核心组件 21 <interceptor-ref name="exception"/> <interceptor-ref name="servlet-config"/> <interceptor-ref name="prepare"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionerror"/> </interceptor-stack> 这个配置节点是放在 <package /> 节点中的 每一个 <interceptor-ref /> 标签都引用了在此之前配置的拦截器或者是拦截器栈 我们已经看到了如何在 Action 中应用拦截器, 而拦截器栈的用法也是一模一样的, 而且还是同一个标签 : <action name="my" class="com.fdar.infoq.myaction" > <result>view.jsp</result> <interceptor-ref name="basicstack"/> </action> 默认拦截器的情况也是一样的 只需要把单个拦截器的名字换成拦截器栈的名字就可以了 <default-interceptor-ref name="basicstack"/> 由上面的种种情况可以得出, 当配置初始的拦截器与拦截器栈时, 必须要确保它们的名字是唯一的 实现拦截器在应用程序中使用自定义的拦截器是一种优雅的提供跨应用特性的方式 我们只需要实现 XWork 框架中一个简单的接口, 它只有三个方法 : public interface Interceptor extends Serializable { void destroy(); void init(); String intercept(actioninvocation invocation) throws Exception; } 更多精彩内容 :

29 22 深入浅出 STRUTS 2 如果我们不需要执行其他初始化或清理动作的话, 还可以直接继承 AbstractInterceptor 这个类对 destroy 和 init 方法进行了重写, 但在方法中没有执行任何操作 ActionInvocation 对象可以用来访问运行时环境, 以及 Action 本身 ; 上下文 ( 包括了 Web 应用的请求参数,session 参数, 用户 Local 等等 );Action 的执行结果 ; 还有那些调用 Action 的方法并判断 Action 是否已被调用 在上一小节中我们知道了配置拦截器和配置拦截器栈的方式是相同的, 如果你需要创建自己的拦截器的话, 那么也应当考虑一下创建自定义的拦截器栈 这样才能确保新的拦截器在应用的时候可以贯穿所有需要该拦截器的 Action 值栈与 OGNL 本节所要介绍的两部分内容是密切相关的 值栈的含义正如它的名字所表示的那样 对象所组成的栈 OGNL 的全称是 Object Graph Navigational Language( 对象图导航语言 ), 提供了访问值栈中对象的统一方式 值栈中的对象构成及其排列顺序如下所示 : 1. 临时对象 在执行过程中, 临时对象被创建出来并放到了值栈中 举个例子来说, 像 JSP 标签所遍历的对象容器中, 当前访问到的值就是临时对象 2. 模型对象 如果模型对象正在使用, 那么会放在值栈中 action 的上面 3. Action 对象 正在被执行的 action 4. 固定名称的对象 (Named Objects) 这些对象包括有 #application, #session, #request, #attr 和 #parameters, 以及相应的 servlet 作用域 访问值栈可以有很多方法, 其中最常用的一种就是使用 JSP, Velocity 或者 Freemarker 提供的标签 还有就是使用 HTML 标签访问值栈中对象的属性 ; 结合表达式使用控制标签 ( 例如 if,elseif 和 iterator); 使用 data 标签 (set 和 push) 来控制值栈本身 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

30 核心组件 23 在使用值栈时, 我们无须关心目标对象的作用域 如果要使用名为 name 的属性, 直接从值栈中进行查询就可以了 值栈中的每一个元素, 都会按照排列顺序依次检查是否拥有该属性 如果有的话, 那么就返回对应的值, 查询结束 如果没有的话, 那么下一个元素就会被访问 直到到达值栈的末尾 这个功能非常强大, 我们根本不需要知道所需要的值在什么地方 存在于 Action, 模型或是 HTTP 请求中 只要这个值存在, 它就会被返回 但它也有个缺点 如果所请求的是很常见的属性 ( 例如 id ), 而你想要从某个特定的对象中 ( 例如 action) 获取该属性的值, 这时候值栈中第一个满足条件的对象返回的属性值就可能不是所想要的结果了 返回结果的确是 id 属性的值, 但它可能来自 JSP 标签, 临时对象或者模型对象 这时候就需要用到 OGNL 来增强值栈的功能了 OSGL 并不仅限于访问对象属性, 如果我们知道某个 action 在值栈中的深度, 那么就可以用 [2].id 来替换掉 id 实际上 OGNL 是一套完整的表达式语言 在 OGNL 里面, 可以用. 来遍历对象图 ( 比如说, 使用 person.address 而不是 getperson().getaddress() ), 它还提供了类型转换, 方法调用, 集合的操作与生成, 集合间的映射, 表达式运算和 lambda 表达式 OGNL 的网站上提供了一套完整的指南, 地址为 ml 结果类型 在前面我们已经演示过如何配置 Action 来向用户返回一个 JSP 但这只是 Action 的结果之一 Struts 2 里面提供了多种结果类型, 有些是可见的, 有些只是与运行环境之间的交互 type 属性被用来配置 Action 的结果类型, 如果没有配置该属性的话, 那么默认类型就是 dispatcher, 它将会渲染一个 JSP 结果并返回给用户 下面就是这样的 Action 配置 : <action name="my" class="com.fdar.infoq.myaction" > <result type="dispatcher">view.jsp</result> </action> 更多精彩内容 :

31 24 深入浅出 STRUTS 2 配置结果类型的配置项在 <package /> 标签内部, 和拦截器的配置看上去很相似 name 属性提供了结果类型的统一标识, class 属性描述了实现类的全限定名 它多出了第三个属性 : default 通过这个属性可以修改默认的结果类型 如果一个 Web 应用是基于 Velocity 而不是 JSP 的话, 那么把默认结果类型修改一下, 就可以节省很多配置的时间 <result-types> <result-type name="dispatcher" default="true" class="org.apache.struts2.dispatcher.servletdis patcherresult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.servletred irectresult"/> </result-types> 实现结果类型和拦截器一样, 你也可以创建自己的结果类型并在 Web 应用中加以配置 Struts 2 中已经有了很多常用的结果类型, 所以在创建自己的结果类型之前, 你应该检查一下你想要的类型是否已经存在 创建一个新的结果类型需要实现 Result 接口 public interface Result extends Serializable { public void execute(actioninvocation invocation) throws Exception; } ActionInvocation 对象可以用来访问运行时环境, 新的结果类型还可以通过它来访问刚刚执行的 Action 以及 Action 执行的上下文 在上下文中包括有 HttpServletRequest 对象, 可以用来访问当前请求的输入流 结果和视图技术 在上面的所有示例中, 我们假设了所使用的视图技术都是对 JSP 进行渲染, 虽然这是最常用的方式, 但并不是渲染结果的唯一方式 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

32 核心组件 25 结果类型是与所使用的视图技术联系在一起的 我们在前面的小节中看到过, 如果没有 type 属性或者该属性的值是 dispatcher 的话, 那么最后就会渲染 JSP 页面 在 Struts 2 应用中, 有其他三种技术可以用来替代 JSP: Velocity Templates Freemarker Templates XSLT Transformations 另外, 你还可以为任何一种已有的视图技术实现一种新的结果类型, 这样就可以得到另外的结果了 抛开各自的语法差异不谈,Freemarker 和 Velocity 还是和 JSP 很相似的 Action 的所有属性都可以被模板访问 ( 通过 getter 方法 ), 就像使用 JSP 标签库和在标签库中使用 OGNL 一样 在 action 的配置文件中, 只需要把 JSP 模板的名字换成 Velocity 或者 Freemarker 模板的名字就可以了 下面的配置文件中, 用 Freemarker 代替了 JSP 的返回结果 : <action name="my" class="com.fdar.infoq.myaction" > <result type="freemarker">view.ftl</result> </action> XSLT 结果和其他的有所不同 它不是用 stylesheet 名代替模板名, 而是使用了另外的参数 stylesheetlocation 参数提供了用于渲染 XML 文件的 stylesheet 如果没有为该参数赋值的话, 那么返回给用户的就是未经转换过的 XML 文件 exposedvalue 属性用来提供将要作为 XML 来展现的 Action 属性或是 OGNL 表达式 如果该参数没有赋值的话, 那么 Action 本身就会被作为 XML 显示出来 <result type="xslt"> <param name="stylesheetlocation">render.xslt</param> <param name="exposedvalue">model.address</param> </result> 在使用 XSLT 作为结果的时候, 还可以使用 struts.properties 来进行属性配置 该属性为 struts.xslt.nocache, 它决定了 stylesheet 是否会被缓存 在开发的过程中, 你可能需要移除所有的缓存, 以提 更多精彩内容 :

33 26 深入浅出 STRUTS 2 高开发速度 但是当应用被部署到产品环境以后, 被缓存的 stylesheet 就会提高渲染性能 标签库标签库常用来定义一些提供了可重用性的 JSP 专属特性 在 Freemarker 和 Velocity 中虽然没有同样的概念, 但却提供了渲染引擎的模型或者上下文, 以及可以访问这些对象的被渲染的模板 当我们讨论 Struts 2 中的标签库时, 我们实际上讨论的是与 JSP 标签库一样提供了相同功能的对象, 它们可以被所有的视图技术 JSP Velocity 和 Freemarker 访问 在这里定义标签库时, 步骤要更多一些, 但是内在的功能是相同的 为对象内部的方法进行访问 通过这项功能, 逻辑代码得到了更好的封装, 同时也避免了到处的剪切和粘贴代码, 从而提高了程序的可维护性 JSP 的标签库中有另外一个今天看上去已经过时的特性 把要显示的文本放在标签库自己的 Java 代码中 Struts 2 中又重新拾起了这种思想, 为标签专门创建了一种第二等的 MVC 模式 在该模式中, 由 Java 类处理逻辑, 但是页面渲染的工作放在了 Freemarker 模板中 ( 默认情况下 ) 整体架构如下图所示 : 这个架构的核心是一组组件对象 组件对象以最基本的形式来表示每一个标签, 并且提供了所有必需的逻辑, 例如管理和渲染模板 每一个不同的结果 / 视图技术都对组件进行了封装, 在封装中把原始页面中的标签进行了转换, 以满足特定的需要 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

34 核心组件 27 在结合 Freemarker 模板渲染使用标签的时候, 还需要进行额外的配置 我们要在 web.xml 文件中配置一个 servlet, 这样 Freemarker 才能得到渲染所需的信息 : <servlet> <servlet-name>jspsupportservlet</serlet-name> <servlet-class> org.apache.struts.action2.views.jspsupportservlet.jspsupportservlet </servlet-class> <load-on-startup>10</load-on-startup> </servlet> 每一个组件都有与其相关联的模板 如果原始的标签中还包含有其它标签 ( 例如 form 标签 ), 那么就会对应有一个开放的模板和封闭的模板 如果原始标签是自包含的 ( 例如 checkbox 标签 ), 那么就对应的就只有一个封闭的模板 就像把 UI 架构中的文本与逻辑分离一样, 为标签提供模板也会带来额外的好处 开发人员可以为同样的标签来组合和匹配不同的模板, 这种特性叫做 主题 (themes) 目前共有 3 个主题 6 : simple, xhtml 和 css_xhtml simple 主题只是简单输出标签, 不做任何的格式调整 xhtml 主题作出了一些格式处理 ; 比如对于 HTML 的表单标签, 这种主题使用 HTML 表格形式提供了两列的格式 ( 即名称标签和输入域两列 ) 对 CSS 的信仰者来说, 这里为他们提供了 css_xhtml 主题 与 xhtml 主题相似的是, 这种主题也是提供了格式转换的功能, 但是它用的不是 HTML 表格, 而是 CSS DIV 这种方式不会带来 HTML 的混乱 xhtml 和 css_xhtml 主题为开发者自己动手实践提供了很好的范例 通过实现一个主题来为 HTML 提供特定的格式 在同一个页面上, 可以组合和匹配多种主题, 当前标签所使用的主题是通过 theme 属性来定义的 如果在整个应用中, 你只需要使用一个主题的话, 那么就可以在 struts.properties 文件中, 将 struts.ui.theme 属性的值配置为要使用的主题 6 单纯从技术角度来讲, 应该有 4 种主题 第 4 种是 ajax 主题 Struts2 已经决定在下个版本中把 Ajax 的功能从核心框架里移走, 放到插件里面 所以在本节中没有对其进行介绍 更多精彩内容 :

35 28 深入浅出 STRUTS 2 每一种标签 (control 标签,data 标签,form 标签和 non-form 标签 ) 都可以使用主题 ; 但是如果要创建一个新主题的话, 那么它只有对可视化的标签才能起到作用 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

36 InfoQ 中文站.NET 社区.NET 相关企业软件开发解决方案 4 架构目标 对于一个特定的代码库而言, 要谈它的架构目标是很困难的 通常在开发之前, 其最终目标就写进了文档中 ; 但这是理想化的状态, 当开始开发之后, 代码往往就会向着另外的方向发展 然后就有了代码库的典型特征 ; 它们很难被发现, 在不同的 package 或者特性之间有可能表现出不一致, 并且更像是脱离计划之外的演变产物 在本章中, 我们将要讲述 Struts 2 代码库中五种这样的特征 从 2002 年的代码库演变起始 从最开始的 WebWork, 到 WebWork 分离成为 WebWork2 和 XWork, 再到最后的 Struts 2, 这些架构思想一直延续到了今天 概念分离 以下这些不同层次的功能都是 Web 开发人员应当了解的 : 在请求 / 响应周期中, 所完成的核心任务是执行特定于每个 Action 的逻辑功能 Action 要完成逻辑功能或者访问资源的话, 必须要访问或者持有业务对象 在把 HTML 中基于字符串的值转换成原始数据类型或其他对象类型, 以及把视图对象转换成业务对象或者数据表表示的过程中, 这期间需要完成多种转化, 映射和变换 有一些横切 (cross-cutting) 的目的是为成组的 action, 或者应用中的所有 action 提供功能的 29

37 30 深入浅出 STRUTS 2 在 Struts 2 的架构中, 以上的每一种概念都是被单独分离的 功能和逻辑不再是 Action 独享的 让我们看一下上面提到的概念是如何被分离的 : 每个 Action 的逻辑 (Per-Action Logic) 这是最简单的概念 ; 每一个 Action 都要为它所提供的逻辑或功能负责 访问 / 持有业务对象 (Accessing/Obtaining Business Objects ) Struts 2 使用了依赖注入机制来把 Action 所需的对象注入到 Action 中去 转化 / 映射 / 变换 (Translation/Mapping/Conversions ) 这三个概念两两之间都有着细微的区别, 但它们都为 Action 核心逻辑提供了辅助功能 类型的转化和变换是由框架本身完成的 在 Action 开始进行处理之前,HTML 中的字符串值就被转化成了基本类型, 然后注入进 Action 里面 所需的东西就齐备了 映射是通过特定的拦截器完成的 我们需要通过某种方式对 Action 进行配置, 让它拥有一个领域模型, 并正确指定 HTML 中相应的字段, 这样框架就会把 UI 与领域模型进行映射 它甚至还可以贯穿一个对象图 横切的概念 (Cross-cutting Concerns ) 横切功能主要是由拦截器提供的 开发人员可以实现拦截器, 然后让它们横切所有的 Action, 横切特定 Package 中的 Action, 或者还可以选择所要横切的 Action 另外一个横切的概念是 UI 布局 在这里 Struts 2 提供了被称作 主题 的支持标签 不同的主题可以提供不同的布局选项, 并可以应用到每一个独立的标签中, 或是整个应用程序 ( 把该主题设置为默认值 ) 松耦合 WebWork 早期的目标之一就是提供一个松耦合的框架 WebWork2.0 版本更强化了这一点, 把代码拆分成了两个项目 : XWork 一个通用的命令框架 ;WebWork XWork 的针对 Web 的接口 WebWork 在架构上做出的根本性变化创造了一种共生的关系 我们现在所知的 WebWork 实际上是 WebWork 和 XWork 的合并 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

38 架构目标 31 XWork 作为一个独立的项目, 可以作为其他项目的一部分加以利用 事实也是如此 Swingwork 7 就是这样一个项目 它是基于 Swing 的 MVC 框架, 在底层使用了 XWork 另外一个例子是一个 JMS 前端, 它在 Web UI 中执行或共享 XWork 的 action 这些都是高度松耦合的精彩示例 Struts 2 也是 XWork 的一个受益者 松耦合的思想在 Struts 2 中得到了更好的传播, 它贯穿了整个框架的始终 从最开始 Action 的处理过程到最后一步结束 实际上, 在 Struts 2 中几乎没有什么是不可以被配置的 我相信这是 Struts 2 中最强有力的地方之一, 但也是最虚弱的地方之一 松耦合的配置有一些常见示例 : 把 URL 映射到 Action 把不同的 Action 结果映射到被渲染的页面 把处理过程中发生的异常映射到被渲染的异常页面 稍微少见一些的 Struts 2 特有的示例有 : 在不想用 Spring 的情况下配置业务对象工厂 改变 URL 与 Action 类的映射方式 添加新的 Action 结果类型 为新的框架功能添加插件 通过拦截器配置框架层的功能 松耦合系统的好处是广为人知的 增加易测试性, 更容易扩展框架功能, 等等 但是这里还有一点坏处 强大的配置管理功能, 尤其是拦截器在其中至关重要的作用, 使得开发人员已经很难理解某个 Action 的执行过程 这一点在调试时尤为突出 一个不了解内部流程的开发者很难提高调试的速度或效率, 因为他根本就无法理解这中间发生了什么 这种问题可能简单如拦截器的配置错误, 甚或是拦截器的配置顺序不对 如果我们能够充分理解处理过程中的每一个细节, 那么很快就能找到解决方案了 易测试性 7 Swingwork 的地址为 这个项目已经停止开发 了

39 32 深入浅出 STRUTS 2 在过去的几年里, 单元测试已经成为了软件开发领域内的事实标准 测试不仅能够保证逻辑的正确性, 而且在开发所要测试的类的时候 ( 如果在此之前则更好 ), 通过编写单元测试还可以得到更简洁强壮的设计 Struts2 的前身 WebWork, 就是在这种环境下开发的 在与框架元素保持松耦合的情况下, 测试变得更加简单 Action 拦截器 结果 对象工厂以及在 Web 应用开发过程中开发出的其他组件, 都可以不依赖于框架进行测试 因为 Action 和拦截器是最常用的, 所以下面我们来看一下怎么样对它们进行测试 Actions Actions 在框架中一般都是通过 execute() 方法被调用的, 在更改配置以后, 任何返回 String 类型值的方法都可以用来调用 Action 站在易测试性的角度来看, 这已经无法更简单了 我们先来看一个例子 下面这个 action 被用来增加一个数值 : public class MyAction { private int number; public int getnumber() { return number; } public void setnumber( int n ) { number = n; } public String execute() { number += 10; return success ; } } 因为 Action 都是 POJO, 所以单元测试只需要实例化一个 Action, 调用其中的方法, 然后确保返回的结果与所期待的一致 Action 中的数据资源都是通过 setter 方法来提供的 所以 Action 中所需的数据都可以被直接赋值 在我们的例子中需要两条断言 一个用来判断 execute 方法的输出, 一个用来验证我们所期望的 Action 的状态 下面是单元测试代码 : public class myactiontest extends TestCase { InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

40 架构目标 33 public void testexecute() { } } MyAction action = new MyAction(); Action.setNumber(5); assertequals("success", action.execute()); assertequals(15,action.getnumber()); 对于资源来说情况就复杂一些了 我们可以用类似于 JMock 8 的第三方库来提供资源的 mock 实现, 然后测试 Action 与资源之间的交互是否正确 虽然例子是用 JUnit 来写的, 但是我们同样可以使用 TestNG 或者其他的测试框架 拦截器在构建拦截器时, 测试会稍稍复杂一些 但是在代码框架中也为其提供了额外的帮助 下面是两个使用拦截器的场景 第一个是拦截器在使用时与 ActionInvocation 对象交互 在执行完以后, 你可以通过断言拦截器本身的状态来对逻辑处理进行验证 在这个场景中, 拦截器的测试方式和 action 一模一样 实例化拦截器 ; 创建一个 ActionInvocation 的 mock 实现, 用它来测试拦截器 ; 调用 intercept 方法 ; 然后断言所期望发生的变化 所断言的可能是拦截器本身, 也可能是方法调用的结果, 抑或是可能会抛出的异常 第二个场景是拦截器与运行环境或者是与拦截器栈中的其他拦截器交互 这种情况下, 测试需要通过 ActionProxy 类与 Action 交互, 同时断言也需要访问拦截器本身没有权限访问的其他环境对象 XWork 库为 JUnit 测试提供了 XWorkTestCase 类, 为 TestNG 测试提供了 TestNGStrutsTestCase 和 TestNGXWorkTestCase, 用以帮助测试拦截器 它们都为 ConfigurationManager,Configuration, Container 和 ActionProxyFactory 类的实例提供了测试实现 XWork 8 请参见 以获得更多信息

41 34 深入浅出 STRUTS 2 同时还提供了其他一些类, 比如 XWorkTestCaseHelper 和 MockConfiguration 现在我们已经有了建立测试环境的底层架构, 测试本身就变得容易了 只需要按照第一个场景中的步骤执行就可以了 唯一的区别就是在调用拦截器的 intercept() 方法时, 同时还需要调用 ActionProxy 的 execute 方法, 例如下面的代码 : ActionProxy proxy = actionproxyfactory.createactionproxy(namespace, NAME,null); assertequals("success", proxy.execute()); 在这个场景中, 测试代码可以断言的期望值包括 :Action 的结果,Action 的值或是值栈中的值 下面的方法可以在 Action 的执行前或者执行后获取这个 Action 对象 : MyAction action = (MyAction)proxy.getInvocation().getAction(); 下面的方法可以用来得到值栈 : proxy.getinvocation().getstack() 模块化 当应用的规模变大以后, 把程序分拆成各个模块的重要性就不言而喻了 这样一来, 我们就可以把一个项目中开发的功能或者新的框架特性打包, 并且在其他项目中重用 Struts 2 已经把模块化作为了体系架构中的基本思想, 开发人员可以独立工作, 然后在其他人的工作基础上进行构建 下面是将应用程序模块化的几种方法 : 将配置信息拆分成多个文件 它本身不会对应用程序的分包造成影响, 但是配置信息按照功能的界限进行拆分以后, 管理起来就容易了很多, 也减小了开发的难度把自包含的应用模块创建为插件 所有用来提供某一种特性的功能组成 包括 Action 拦截器 拦截器栈 视图模板 ( 除了 JSP 以外 ) 等等 都可以被打包在一起, 并 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

42 架构目标 35 作为独立的插件发布 例如配置浏览器插件 9, 该插件提供了一个完整的模块, 该模块可以为所在的应用程序添加一个用来查看配置信息的 Web 接口 创建新的框架特性 与特定应用无关的新功能可以组织成插件, 应用到多个应用中 从技术角度来讲, 这几种模块化的方式其实是一样的 它们都有同样的配置元素 ( 除了名字可能不同以外, 在使用插件时, struts-plugin.xml 文件会作为配置文件被自动加载 ), 同样的目录结构, 并且可以包括同样的框架和应用元素 上面的两种插件类型的唯一区别在于你从怎么概念上去理解它们, 在发行包中放入的是哪些元素和配置文件 额外的配置元素因为插件可以为内部的框架功能提供替代的实现方式, 所以需要做一些额外的配置 这些配置元素可以在 struts.xml 配置文件中使用, 也用在了 struts-default.xml 文件中, 但是它们更常用的情况是用来配置插件 在插件中, 替代的实现方式是分两步来配置的 : 1. 使用 <bean /> 标签来定义替换的接口实现, 并用一个唯一的 key 来标识 2. 使用 <constant /> 标签来在多种可能的接口实现中进行选择 下面我们来看看每一步的具体细节 <bean /> 标签可以用来为扩展点提供实现信息 下面的例子是 struts-default.xml 配置文件中一个对象工厂的配置 : <bean name="struts" type="com.opensymphony.xwork2.objectfactory" class="org.apache.struts2.impl.strutsobjectfactory" /> 在配置项的属性中包含了用来在 Struts 2 里创建和使用替代对象实现 (alternate object implementation) 的所有信息 这些属性包括 : class 类的全名 9 config browser 插件的文档地址为

43 36 深入浅出 STRUTS 2 type 类所实现的接口 name 每个 type 的唯一简称 static 是否把静态对象方法注入到类实例中 scope 实例的作用域, 可以是 default, request, session, singleton 或 thread optional 当值为 true 时, 即使创建类实例的过程中发生错误, 也会继续装载 然后, 开发人员可以用 <constant /> 标签来选择使用哪一个配置 这里只有两个属性 name 属性提供了扩展点的名字, 这个扩展点是在新的实现中会被更改的, value 属性的值是在 <bean /> 标签中配置的唯一标识 /> <constant name="struts.objectfactory" value="plexus" <constant /> 标签是把一个新值赋给已知属性的一种方式, 但并不是唯一的方式 新值还可以在 web.xml 文件的 initparam 中修改, 或者作为一个名 - 值对写入 struts.properties 配置文件 如果你不是在开发插件, 而是在普通的 struts.xml 文件中使用这些技术, 那么还有捷径可走 把一般来说会放在 <bean /> 标签中的类名放进在 <constant /> 标签中 这样就避免了使用 <bean /> 标签 下表列出了可配置的扩展点对应的接口与属性名 接口 属性名 Scope Description com.opensymphony. xwork2.objectfactory struts.objectfactory singleton 创建在框架中用到的对象 Action, 结果, 拦截器, 业务对象等等 com.opensymphony. xwork2. ActionProxyFactory com.opensymphony. xwork2.util. struts. actionproxyfactory struts. objecttypedeterminer singleton singleton InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新 创建 ActionProxy 判断一个 map 或者 collection

44 架构目标 37 ObjectTypeDeterminer org.apache.struts2. dispatcher.mapper. ActionMapper org.apache.struts2. dispatcher.multipart. MultiPartRequest org.apache.struts2. views.freemarker. FreemarkerManager org.apache.struts2. views.velocity. VelocityManager 中的 key 和元素是什么 struts.mapper.class singleton 从请求中得到 ActionMapping 并从 ActionMapping 中得到 URI struts.multipart. per 解析多部件请 parser request 求 ( 文件上 传 ) struts.freemarker. manager.classname struts.velocity. manager.classname singleton singleton 载入和处理 Freemarker 模板载入和处理 Velocity 模板 <constant /> 标签和 web.xml 文件中的 init-param 不仅仅可以用来定义扩展点属性 struts.properties 文件中的所有属性都可以通过二者进行修改 惯例重于配置 惯例重于配置是 Rails 带入主流应用开发中的概念 它不是提供那些对于各个应用而言都很相似的配置文件, 而是假定在绝大多数情况下, 开发人员都会遵守特定的模式 这种模式具有足够的通用性, 所以可以被认为是一种开发惯例, 框架会默认使用这种模式, 而不是为每一个新的应用都提供配置 在默认情况下, 开发人员就不必再管理种种配置信息了 如果有的需求与惯例的配置信息不同, 那么还可以根据需求进行修改, 把默认模式覆盖掉 Struts 2 采用了这个概念 松耦合在给 Struts 2 带来高度灵活性的同时, 也带来了配置上的高度复杂性 惯例在这二者之间做出了平衡, 为我们提供了简洁而高效的开发者体验 Struts 2 中 惯例重于配置 的应用可以通过以下几个例子来说明 :

45 38 深入浅出 STRUTS 2 隐式的配置文件加载 不需要显式配置 strutsdefault.xml 和 struts-plugin.xml ( 对每一个插件而言 ) 文件, 它们会被自动加载 Code Behind 插件 在使用 code behind 插件时, 它会混合使用 action 名和结果字符串在结果模板中进行自动搜索, 所以 /user/add.action 这个 action 的 success 结果会返回 /user/add-success.jsp 结果模板, error 结果会返回 /user/add-error.jsp 结果模板 默认的结果和结果类型 在配置 Action 的时候, 如果使用默认的 success 结果和 JSP 结果类型的话, 就不需要对它们进行配置 织入 (Wiring)Spring 业务服务 在安装了 Spring 框架插件以后, 就不必为每个 Action 所需的 Spring 提供的业务服务进行配置, 这些业务服务会被自动织入到 Action 里 在前面的章节里, 我们看到了很多默认的设置, 包括如何通过配置来重写属性值和提供新的默认设置 在下面一章中, 我们将要介绍的是如何通过更多的配置项和惯例来提高生产力 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

46 InfoQ 中文站 Agile 社区关注敏捷软件开发和项目管理 5 提高效率技巧 本章所要介绍的是一些在使用 Struts 2 开发 web 应用时, 能够提高生产效率的技巧 技术与特性, 这些都是开发人员应当牢记的 这些 tip 范围很广, 包括从列出默认值, 到说明应当实现的接口, 以及如何创建自定义的声明式验证 本章中描述的信息只是一个简单的介绍 如果你对哪一个 tip 感兴趣, 就不妨深入研究一下 你可以参考 Struts2 的文档 或者是通过搜索来看看其他开发人员的想法, 以及他们是如何进行应用的 最后, 当你阅读每一个小节的时候, 都应该想一下当前的 tip 应该如何与其他 tip 配合使用, 它与其他 tip 的区别是什么, 你又该怎样把它应用到 web 开发中去 这样你对它的理解才能更上一个台阶 Struts2 的插件体系结构保证了它的可持续发展 你需要常常访问 Struts2 的插件注册页面以获得最新的开发进展 这个页面中包括了所有的插件相关的声明, 地址为 它上面已经有了很多第三方的插件, 例如 JSON,GWT 和 Spring WebFlow 重用 Action 的配置 我们曾经讲过把 action 以 package 的组织形式来配置管理, 并且描述了 package 如何继承其它的 package 但是这样做所带来的好处还没有说清楚 下面我们来看一个完整的例子 这个应用程序用来向游客提供动物园信息 每个洲都会对应有一个 portal 页面, 提供动物, 地图等等数据 39

47 40 深入浅出 STRUTS 2 完成这项功能的一种方式是让用户可以调用类似 这样的 URL 这样强化了应用程序的逻辑性, 并且可以很容易判断现在所请求的是哪个洲的信息 但是, 当我们依赖于要渲染给用户的信息的定义方式时, 灵活性就丧失了, 因为硬编码的路径信息被添加到了 action 或者视图中 灵活一点的方式是提供类似 这样的 URL 在使用这种方案时, 我们可以提供一个 action 基类, 并配置到默认的 package 下面 每一个继承的 package 都可以访问这个 action 基类 所以如果不进行额外配置的话, 实际上调用的就是 更进一步来说, 视图也可以不用任何额外的配置来进行自定义 如果默认的 package 下面的 action 是这样的 : > <action name="home" class="com.fdar.infoq.homeaction" <result>portal.jsp</result> </action> 那么 Struts2 所渲染的 JSP 就会依赖于 URL 所提供的, 用户调用的命名空间 于是如果 URL 为 那么 /portal.jsp 就会被渲染, 如果 URL 为 那么被渲染的页面就是 /asia/portal.jsp 强调一下, 这个功能并没有进行多余的配置 因为配置信息提供的是一个 JSP 相对路径而不是特定的路径名 在配置中使用模式匹配调配符 有的时候,action 的配置文件大小会以令人难以置信的速度增加 为了避免这种现象, 我们需要使用模式匹配 它的工作方式是定义一个或多个模式, 而 URL 会与这些模式保持一致 举个例子会更容易说明这一点 假设你的应用中 URL 的模式是这样的 : /{module}/{entity}/{action}.action 这是很常见的模 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

48 式, 对应的 URL 可能是 : /admin/user/edit.action, /admin/user/list.action 和 /admin/user/add.action 提高效率技巧 41 在类的配置中, 会有一个 Struts2 的 action 类, 名字为 {entity}action, 而每一个 {Action} 都是 action 类里面的一个方法 所有对 action 中方法的调用要么返回一个被显示的实体的更新页面, 要么返回所有被显示的实体的一个列表 在我们的例子中, struts.xml 配置就是这样的 : <action name= */*/* method= {3} class= com.infoq.actions.{1}.{2}action > <result name= view >/{1}/update{2}.jsp</result> <result name= list >/{1}/list.jsp</result> </action> 在 action 的名字中, 每一个星号都是一个通配符 在这个例子中, 我们全都用了星号 其实也不必如此 比如说, 如果你想要把所有对实体的 view 动作映射到一起, 那么类似于 name= /*/View* 这样的配置就能完成要求 形如 {1},{2} 等等的标识符用来获取通配符所对应的值 ( 数字表示了所要获取的值对应的通配符的位置, 顺序是从左到右 ) 在 struts.properties 文件中 ( 或者使用 struts.xml 的 constant 标签 ), 你需要确保正确配置了下面的属性 : struts.enable.slashesinactionnames = true 这个属性设为 true 以后,action 的名字中就可以使用斜杠了 Struts2 的默认设置是不允许 action 的名字中出现斜杠的, 需要用 package 来分割命名空间 最后, 如果你是提供验证和转换的属性文件而不是注解的话, 那么就没有什么捷径了 我们会在下面的部分谈到这一点 每一项都要包括 action 的全名和所需的扩展 : 例如, 前面的例子就要包括 editvalidation.xml 和 edit-conversion.xml, 以及 com.infoq.actions.admin 这个 package 使用替代的 URI 映射方法

49 42 深入浅出 STRUTS 2 我们除了在配置中使用通配符以外, 还可以使用自定义的映射方案, 改变从 URI 到 action 和被调用方法的映射关系 用这种方法可以减少配置信息, 并且可以在整个应用中保持一致 你可以把 URI 模式与 session 信息或其他任何你能想到的信息合并, 来决定要调用哪一个 action 这种方法需要实现 ActionMapper 接口, 在该接口中有两个要实现的方法 : 一个是 getmapping(), 它把 URI 转换成已知的配置 ; 另一个是 geturifromactionmapping(), 它把一个 action 配置转换成 URI 如下所示 : public interface ActionMapper { ActionMapping getmapping( HttpServletRequest request, ConfigurationManager configmanager); String geturifromactionmapping(actionmapping mapping); } ActionMapping 类中提供了要调用的 action 的命名空间, 名称, 方法, 结果和参数 ConfigurationManager 可以用来访问配置信息的提供者 ( 然后就可以进行进一步的自定义 ) Action mapper 需要在 struts.xml 中进行配置后才能被使用 Name 和 type 属性的值是不变的 只需要把 value 属性的值改成自定义的 ActionMapper 的实现类 <constant name="struts.mapper.class" value="com.fdar.infoq.myactionmapper" /> 值得高兴的是我们不需要在所有用到的地方都去实现 ActionMapper 这个接口,Struts2 已经有了几种不同类型的实现 Restful2ActionMapper 类提供了一个 ReST 型接口的实现, 它借鉴了 Ruby on Rails 里易于使用的 URI 的设计思路 要注意的是, 在 Struts2 的文档中, 这个实现还只是一个试验品 Restful2ActionMapper 首先做的事情是判断要使用的命名空间和 action, 与你所想的一样 URL 的最后一个元素是 action 名, 之前的都是命名空间 但是也有例外, 因为属性也会通过 URI InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

50 提高效率技巧 43 传入 把 action 名, 属性名和属性值映射到 URI 中的模式是这样的 : _NAME2/PARAM_VALUE2 PARAM_NAME/PARAM_VALUE 这样的名 / 值对的数量是没有限制的, 如果 PARAM_NAME1 是 id 的话, 那么 URI 可以简化为 : _VALUE2 当 action 被确定下来以后, 下一步就是要找到需要调用的方法 这可以使用 HTTP 方法来做出决定 因为 HTML 不支持 PUT 和 DELETE 方法, 所以要有另外的请求属性 http_method 来提供方法信息 下面是 HTTP 方法和 URL 合并以后的结果 : GET: /user 当 action 被单独使用时, index 方法会被调用 GET: /user/23 当 action 与参数名 / 值对一起使用时, view 方法会被调用, 在这里 id 属性的值被设为 23 POST: /user/23 这里 HTTP 方法是 POST 而非 GET, 于是 create 方法将会被调用, id 或者其他用于标识的值会被包含在 URL 中, 而包含更新信息的名 - 值对会放在 POST 数据中 PUT: /user update 方法会被调用, 与 POST 场景类似, 包含信息的名 - 值对会放在 POST 数据中而不是 URL 里面 DELTE: /user/23 remove 方法会被调用, 在 URL 里面提供了唯一的标识符 ( 在这里是 id, 其值为 23 ) GET: /user/23!edit! 被用来描述方法名, 所以这里会被调用的是 edit 方法 GET: /user/new new 后缀表示 editnew 方法会被调用

51 44 深入浅出 STRUTS 2 这里还有一个 CompositeActionMapper 类 这个实现可以帮助你把多个独立的 ActionMapper 实现类串连起来 这个串连序列中的每一个类都会被检查, 看它是否能够解析 URI 如果 URI 被解析成功, 那么就返回结果, 如果没有, 序列中的下一个类就会被继续检查 ; 如果最终也没有找到匹配的结果, 就会返回一个 null 和一般的 ActionMapper 配置一样,CompositeActionMapper 配置中包含有 constant 节点, 它列出了要被串连在一起的 ActionMapper 的实现类的名字 <bean name="struts" type="org.apache.struts2.dispatcher.mapper.action Mapper" class="org.apache.struts2.dispatcher.mapper.compo siteactionmapper" /> <constant name="struts.mapper.composite" value="org.apache.struts2.dispatcher.mapper.defau ltactionmapper, org.apache.struts2.dispatcher.mapper.restfulactio nmapper" /> 了解拦截器的功能 拦截器在 Struts2 框架中起到了至关重要的作用 通过掌握已有的拦截器, 你就可以理解在 action 处理过程中的每一个步骤了 另外一个好处会在调试 action 的时候呈现出来 有时候 action 并没有那些应有的数据 这常常都是由于拦截器没有被正确应用, 或者是拦截器应用的顺序有问题导致的 通过掌握每一个拦截器的作用, 问题的定位和解决就容易了很多 下面是一些可以立刻使用的拦截器, 并提供了对应的功能描述 拦截器名 alias chain 描述将同一个参数在请求之间进行命名转换 使上一个 action 的属性对当前 action 可用 常与 <result type="chain"> 结合使用 ( 在上一个 action 中使用 ) InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

52 提高效率技巧 45 conversionerror 把 ActionContext 的转换错误添加到 Action 的字段错误中 createsession 自动创建一个 HttpSession, 当某一个拦截器需要 HttpSession 协同工作时 ( 如 TokenInterceptor) 是很有用的 debugging 提供多个不同的调试场景, 用来查看页面背后的数据结构信息 execandwait 在后台执行 action, 并发送给用户一个等候页面 exception 把异常映射到对应的结果 fileupload 为便捷的文件上传提供支持 I18n 记忆用户 session 所使用的 locale logger 输出 action 名 model-driven 如果 action 实现了 ModelDriven, 该拦截器会将 getmodel 方法的结果放到值栈上面 scoped-model-driven 如果 action 实现了 ScopedModelDriven, 该拦截器会从 scope 中获取并存储模型, 然后通过 setmodel 方法将其赋给 action params 把请求参数赋给 action static-params 把 struts.xml 定义的参数传给 action, 它们是 <action /> 标签下的 <param /> 子标签 scope 提供了将 action 状态存储在 session 或 application scope 中的简单机制 servlet-config 提供了对表示 HttpServletRequest 和 HttpServletResponse 的 Map 的访问 timer 输出 action 的执行时间 ( 包括内嵌的拦截器和视图 ) token 验证 action 中的有效 token, 避免提交重复的表单 token-session 和 token 拦截器一行, 但是在处理无效的 token 时, 将提交的信息保存在 session 中 validation 使用在 action-validation.xml 中定义的验证器来进行验证 workflow 调用 action 中的 validate 方法 如果有异常的话, 就会返回 INPUT 视图 store 从 session 中获取和保存实现了 ValidationAware 的 action 的消息 / 异常 / 字段异常

53 46 深入浅出 STRUTS 2 checkbox profiling roles prepare 添加 checkbox 的自动处理代码, 可以检测没有被选中的 checkbox, 并给它一个默认值 ( 通常是 false), 然后作为参数添加 它使用了一个特定名称的隐藏字段来检查未提交的 checkbox 未选中的默认值可以被那些不是 boolean 值的 checkbox 重写 激活对参数的性能监测只有当用户具有正确的 JAAS 角色时才能够执行 action 如果 action 实现了 Preparable, 那么就调用它的 prepare() 方法 使用提供的拦截器栈 拦截器栈可以将那些应用于各类 action 的拦截器进行功能分组 拦截器栈构建用于 CRUD 操作, 验证 action 输入, 或是其他任何你所需的功能 但是在创建自己的栈以前, 最好先来看一下 Struts2 提供的拦截器栈 很多标准配置都已经配置完成并可以即刻使用了 另外, 每一个插件都可以提供自己的拦截器栈, 如果要使用插件所提供的功能的话就要使用插件的拦截器栈 有两种方法可以使用框架提供的拦截器栈 或者把 action 放到提供了拦截器栈 ( 通过零配置的注解或者 struts.properties 中的 constant) 的 package 下面, 或者让定义的新 package( 其中包括了你创建的 action) 继承提供了拦截器栈的 package: <package name="mypackage" extends="struts-default" namespace="/mypackage"> </package> 我们曾经说过, 在把应用程序部署为产品之前, 你需要检查一下拦截器栈, 看看你是否需要其中的某 / 每一个拦截器 paramsprepareparamsstack 和 defaultstack 里面包含有 chain, il8n, fileupload, profiling 和 debugging 这几个拦截器 它们都是不怎么常用的, 我们可以把它们移走, 减少不必要的处理工作 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

54 提高效率技巧 47 栈 basicstack validationworkflowstack fileuploadstack modeldrivenstack chainstack i18nstack paramsprepareparamsstack defaultstack completestack executeandwaitstack Description Struts2 提供的最常用的栈 提供了异常处理, 将 HTTP 对象和请求 / 表单参数注入 action, 和处理转换错误的功能 向 basic 栈中添加验证和工作流的功能 向 basic 栈中添加对自动文件上传的支持 向 basic 栈中添加对模型驱动 action 的支持 向 basic 栈中添加对 action 串连的支持 向 basic 栈中添加国际化的功能 这是 Struts2 提供的最复杂的一个栈 它的应用场合是当 action 的 prepare() 方法被调用时, 用传入的请求参数载入数据 ( 或者执行其他任务 ), 然后重新用请求参数来重写一些载入的数据 它的一个典型应用是更新对象 用 id 来从数据库中读取对象, 然后用从请求中传入的参数重写一些读取的数据 这是默认的栈 它为绝大多数的应用场景提供了所有的功能 实际上, 它包括了核心发布版中几乎所有的可用拦截器 这个栈提供了 defaultstack 的别名, 用来向后兼容 WebWork 的应用 向 basic 栈中添加异步支持 action 的功能 利用返回类型

55 48 深入浅出 STRUTS 2 返回类型使得开发者可以对要渲染给用户的元素进行组合和匹配 实际上, 一个 action 可以有多个结果, 而且每个结果都可以有不同的结果类型 另外一点也需要注意 : 结果可以是可见的, 也可以是不可见的 比如说, 我们可以返回 HTTP 头 下面是一些已经预配置好的结果类型和一些简要说明 如果你把 action 放到 struts-default package 下面, 或者是继承这个 package, 这些结果类型就可以使用了 : 名称描述 chain 将一个 action 的执行与另外一个配置好的 action 串连起来 用第一个 action 的 getter 方法和第二个 action 的 setter 方法来完成 action 之间属性的复制 dispatcher 渲染 JSP 这是默认的结果类型, 如果在 action 配置中没有配置其他的结果类型, 它就会被使用 freemarker 渲染 Freemarker 模板 httpheader 返回 HTTP 头和用户定义的值 redirect 重定向到任意的 URL redirect-action 重定向到配置好的 action 可以用来提供 post 完成以后的重定向功能 stream 将数据流返回给浏览器 可以用来把数据注入 PDF,Microsoft Work, 图像或其他数据中 velocity 渲染 Velocity 模板 xslt 使用 XSLT 来转换已执行完毕的 action 的属性格式 利用数据转换 Web 开发的一个常见任务就是把基于字符串的表单数据转换成适当的类型, 交给模型或者业务服务方法使用 通常这是繁重的人工处理过程 Struts2 提供了数据转化功能, 将这个过程做了简化 内置的转换机制可以将 String 转化成下面任意一种格式 : InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

56 String Boolean 或 boolean Character 或 char Integer 或 int Float 或 float Long 或 long Double 或 double Date 使用与当前请求相关联的 locale 提高效率技巧 49 这样 action 中的 setter 方法就可以从 setid(string id) 改成 setid(int id) 了 我们再也无须为每一个值进行类型转换, 因为它们会以正确的类型传给 action, 我们只需简单使用即可 要进行自定义的类型转换时, 你需要实现 StrutsTypeConverter 这个类 里面有两个需要实现的方法 ; 一个是把字符串转换成新类型的类, 一个是把新的类型转换成字符串 public class MyTypeConverter extends StrutsTypeConverter { public Object convertfromstring( Map context, String[] values, Class toclass) { } public String converttostring(map context, Object o) { } } 如果在类型转换时出现问题, 那么应该抛出一个 TypeConversonException, 告知框架转换无法完成 在 action 中使用新的转换器之前, 需要对它进行配置 这里可以使用注解 ( 下一节会进行解释 ) 或是使用一个单独的 *- conversion.properties 文件 如果正在使用转换功能的 action 叫做 MyAction, 那么你需要在同一个 package 下面创建一个名为 MyAction-conversion.properties 的文件 文件内容为 : typeval = MyTypeConverter

57 50 深入浅出 STRUTS 2 等式左边的 typeval 是请求名或是需要转换的表单值, 等式右边是转换类的全限定名 如果你在多个 action 中都使用转换功能的话, 那么就可以使用一个全局的配置文件 xwork-conversion.properties 这个文件放在应用程序的 classpath 根目录下 其内容为 : MyType = MyTypeConverter 等式左右是要转换的类型和转换器所对应的类的全限定名 注意这里用的是要转换的类型的类名, 而不是请求名或表单值 所以 action 的 setter 就是 settypevalue( MyType type) 利用列表数据项支持 Struts2 可以通过 list 来把列表数据在 HTML 用户界面和 action 之间进行便捷的传递 让我们看一个例子 这是一个 Person 类, 每一个属性都有对应的 getter 和 setter( 这里省略掉了 ):: public class Person { int id; String name; int age; float height; } 我们的 action 需要有一个 person 列表 : public class MyAction { public List getpeoplelist() { } public void setpeoplelist( List peoplelist ) { } } 在把 Person 类作为 MyAction 中的一个元素使用之前, 我们需要添加一些配置信息 在 MyAction 的同一个 package 下面创建一个名为 MyAction-conversion.properties 的文件 该文件名和验证文件的命名方式一样, 在 action 名字后面跟着 *-conversion.properties 后缀 文件内容为 : InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

58 提高效率技巧 51 Element_peopleList=Person Element_ 前缀是一个常量, 它后面的 peoplelist 是 action 类中的 list 属性名 等式右边是要放到 list 里面的类的全限定名 最后, 我们还需要把这个 list 渲染给用户 : <ww:iterator value="peoplelist" status="stat"> <s:property value="peoplelist[#stat.index].id" /> <s:property value="peoplelist[#stat.index].name" /> <s:property value="peoplelist[#stat.index].age" /> <s:property value="peoplelist[#stat.index].height" /> </ww:iterator> 因为 list 是有索引的, 所以我们使用了迭代器状态对象的索引属性来引用被显示的对象 对当前的例子而言, 这不是最有效率的办法 ; 因为 <s:property /> 标签的 value 还可以简化成 id, name, age 和 height 这里只是想让你明白, 要得到可编辑的表单需要哪些东西 对于一个使用了相同元素的列表型可编辑的表单, 其 JSP 为 : <s:form action="update" method="post" > <s:iterator value="peoplelist" status="stat"> <s:hidden name="peoplelist[%{#stat.index}].id" value="%{peoplelist[#stat.index].id}"/> <s:textfield label="name" name="peoplelist[%{#stat.index}].name" value="%{peoplelist[#stat.index].name}" /> <s:textfield label="age" name="peoplelist[%{#stat.index}].age" value="%{peoplelist[#stat.index].age}" /> <s:textfield label="height" name="peoplelist[%{#stat.index}].height" value="%{peoplelist[#stat.index].height}" /> <br/> </s:iterator>

59 52 深入浅出 STRUTS 2 <s:submit value="update"/> </s:form> 注意这段代码中的 name 和 value 属性和上面的 value 属性很相似 区别在于, 在 name 属性中, 我们需要用正确的 token 把 #stat.index 包起来, 从而得到实际的索引值, 再用它来获取真正的值 而在 value 中, 整个表达式都被包了起来 Struts2 用这段代码生成一个 ArrayList, 里面都是计算后的 People 对象, 然后用 setpeoplelist() 方法把这个 ArrayList 赋值给 action 为了允许 Struts2 可以在这个 list 中创建新的对象 ( 可能你是在用户界面中动态创建对象的 ), 把下面这行代码加入 MyActionconversion.properties 文件中 : CreateIfNull_peopleList = true 在 Action 中暴露领域模型 介绍过数据转换和容器后, 有一扇门已经向你打开了 我们用不着非要在 HTML 表单字段中使用 String 值, 使用正确的类型就行 我们还看到通过正确的 setter 方法, 请求属性和表单字段值都可以直接赋给 action 我们还可以更进一步 Struts2 中有一种名为 模型驱动 action 的概念, 可以减少在调用业务服务时, 用来把用户界面的字段映射为领域对象或者值对象的代码 模型驱动的 action 需要实现 ModelDriven 接口 这个接口只有一个方法, 用来把 action 被指派的对象作为模型返回 public interface ModelDriven { } java.lang.object getmodel(); 被用来处理 action 的拦截器栈也需要包含 模型驱动 的拦截器 包括这样一个拦截器的栈有以下几种 : modeldriven, defaultstack, paramsprepareparamsstack 和 completestack 这个拦截器会从 action 中得到模型对象, 把它放 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

60 提高效率技巧 53 到值栈中相应的 action 上面的位置, 这样请求或者表单值就会直接赋值给模型而不是 action 同样, 反过来讲, 在 JSP 使用和显示的值也就会从模型中获取 这不是那种 要么全是, 要么全非 的场景, 如果有的请求或者表单值在模型中找不到对应的 setter, 那么它们就会被传递给 action 同时, 如果 JSP 在模型中找不到所需的值, 它也会在值栈中向下查找, 然后从 action 得到想要的结果 通过综合运用这几种技术, 你可以在模型或者 action 中进行赋值, 或者读取相应的值, 而不必显式指定要操作的目标 尽可能使用声明式验证 在 Struts2 应用中提供验证的方式有两种 编程式和声明式 要提供编程式验证的话,action 就要实现 Validateable 接口 该接口只有一个方法, 在方法中需要执行验证操作 : void validate(); 为了将验证中出现的问题反馈给用户,action 还需要实现 ValidationAware 接口 这个接口更为复杂一些, 它里面的方法可以用来添加验证错误, 判断当前是否有验证错误, 等等 如果可能的话, 你的 action 可以继承 ActionSupport 类, 在该类中提供了以上这些接口的缺省实现 只有当验证操作极其复杂的时候, 我们才该使用编程式验证 更好的解决方案是采用声明式验证 每一个需要声明式验证的 action 都需要在类中进行注解 ( 后面对此会进行讨论 ), 或者要有一个相应的 XML 文件 对于 MyAction 这个类, 其 XML 文件就是 MyAction-validation.xml, 并会和它放在同一个 package 下面 处理这个 action 的拦截器栈需要包含有 validation ( 用来进行验证 ) 和 workflow ( 当验证失败时用来进行重定向, 以返回到 input 结果 ) 拦截器 这样的拦截器栈有以下几个 : validationworkflowstack,

61 54 深入浅出 STRUTS 2 paramsprepareparamsstack, defaultstack 和 completestack 下面是验证文件的一个例子 : <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" " dtd"> <validators> <field name="count"> <field-validator type="int" shortcircuit="true"> <param name="min">1</param> <param name="max">100</param> <message key="invalid.count"> Value must be between ${min} and ${max} </message> </field-validator> </field> <field name="name"> <field-validator type="requiredstring"> <message>you must enter a name.</message> </field-validator> </field> <validator type="expression" short-circuit="true"> <param name="expression"> .equals( 2)</param> <message> not the same as 2</message> </validator> </validators> 在这个例子中, 有些东西是应该注意的 : 每一个字段都可以含有一个或多个 field-validator 节点 每一个字段的 validator 是按照定义顺序执行的 每一个字段的 validator 都有一个 short-circuit 属性 ; 如果其值为 true 而验证失败, 那么剩下的所有验证都会被跳过, 该字段就会直接返回一个失败的结果 Message 节点可以包含一个 key 属性, 用来从 message bundle 中查找需要显示给用户的消息 ; 如果找不到对应的 message bundle key 的话, 那么就返回节点的 value 属性的值 InfoQ 中文站 : 时刻关注企业软件开发领域的变化与创新

62 提高效率技巧 55 Validator 的配置信息 ( 例如 min 和 max) 和值栈中的值一样, 都可以通过把值放在 ${ 和 } 之间, 来显示到验证消息中 Validators 的作用域可以是 field 或者 expression ; 具有 expression 作用域的 validator 可以同时作用于多个字段 下面是关于 validator 类型和相应描述的一个完整列表 在 可以得到包括配置相关的更多信息 名称 required requiredstring stringlength int double date expression fieldexpression url conversion regex visitor 描述确保该属性不是 null 确保一个 String 类型的属性不是 null, 并且非空检查 String 的长度范围是否与所期望的一致检查 int 类型的数字是否超出所期望的大小范围检查 double 类型的数字是否超出所期望的大小范围检查 date 类型的属性是否超出所期望的范围使用值栈来估算一个 ONGL 表达式 ( 必须要返回 boolean 值 ) 使用 OGNL 表达式来验证字段保证该属性是一个有效的 地址保证该属性是一个有效的 URL 检查该属性是否有转换错误检查该属性的值是否与某个正则表达式相匹配 Visitor validator 可以把对字段的验证动作推迟到这个字段所属的类的特有的另一个验证文件中执行 比如说, 你在使用模型驱动的 action, 在模型中有一个对应于 Person 类的 person 属性 如果该模型正在被多个 Action 使用, 那么你大概就会想要把验证信息抽取出来进行重用 Visitor 验证提供了这样的功能 另外, 你还可以创建自己的 validator 你自定义的 validator 需要实现 Validator 接口 ( 用于表达式验证 ) 或 FieldValidator 接口 ( 用于字段验证 ).

本章学习目标 小风 Java 实战系列教程 SpringMVC 简介 SpringMVC 的入门案例 SpringMVC 流程分析 配置注解映射器和适配器 注解的使用 使用不同方式的跳转页面 1. SpringMVC 简介 Spring web mvc

本章学习目标 小风 Java 实战系列教程 SpringMVC 简介 SpringMVC 的入门案例 SpringMVC 流程分析 配置注解映射器和适配器 注解的使用 使用不同方式的跳转页面 1. SpringMVC 简介 Spring web mvc 本章学习目标 SpringMVC 简介 SpringMVC 的入门案例 SpringMVC 流程分析 配置注解映射器和适配器 配置视图解析器 @RequestMapping 注解的使用 使用不同方式的跳转页面 1. SpringMVC 简介 Spring web mvc 和 Struts2 都属于表现层的框架, 它是 Spring 框架的一部分, 我们可 以从 Spring 的整体结构中看得出来 :

More information

Microsoft Word - Hibernate与Struts2和Spring组合指导.doc

Microsoft Word - Hibernate与Struts2和Spring组合指导.doc 1.1 组合 Hibernate 与 Spring 1. 在 Eclipse 中, 新建一个 Web project 2. 给该项目增加 Hibernate 开发能力, 增加 Hibernate 相关类库到当前项目的 Build Path, 同时也提供了 hibernate.cfg.xml 这个配置文件 3. 给该项目增加 Spring 开发能力, 增加 spring 相关类库到当前项目的 Build

More information

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP:  ******************* * 关于 Java 测试试题 ****** ******************* * 关于 Java 测试试题 ******************* 問 1 运行下面的程序, 选出一个正确的运行结果 public class Sample { public static void main(string[] args) { int[] test = { 1, 2, 3, 4, 5 ; for(int i = 1 ; i System.out.print(test[i]);

More information

untitled

untitled JavaEE+Android - 6 1.5-2 JavaEE web MIS OA ERP BOSS Android Android Google Map office HTML CSS,java Android + SQL Sever JavaWeb JavaScript/AJAX jquery Java Oracle SSH SSH EJB+JBOSS Android + 1. 2. IDE

More information

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double

More information

(TestFailure) JUnit Framework AssertionFailedError JUnit Composite TestSuite Test TestSuite run() run() JUnit

(TestFailure) JUnit Framework AssertionFailedError JUnit Composite TestSuite Test TestSuite run() run() JUnit Tomcat Web JUnit Cactus JUnit Java Cactus JUnit 26.1 JUnit Java JUnit JUnit Java JSP Servlet JUnit Java Erich Gamma Kent Beck xunit JUnit boolean JUnit Java JUnit Java JUnit Java 26.1.1 JUnit JUnit How

More information

J2EE MVC with Webwork2 Xwork, to J2EE MVC with Webwork2 Xwork

J2EE MVC with Webwork2 Xwork,  to J2EE MVC with Webwork2 Xwork MVC with Webwork2 Xwork Action...1 ActionContext...3 ActionProxyFactory Factory...4 ActionProxyFactory Proxy AOP...7 XworkInterceptor...8 Interceptor...9 LoginAction...10 LoginInterceptor...12 Action Result

More information

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 ->

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 -> 目录 1 大概思路... 1 2 创建 WebAPI... 1 3 创建 CrossMainController 并编写... 1 4 Nuget 安装 microsoft.aspnet.webapi.cors... 4 5 跨域设置路由... 4 6 编写 Jquery EasyUI 界面... 5 7 运行效果... 7 8 总结... 7 1 1 大概思路 创建 WebAPI 创建 CrossMainController

More information

EJB-Programming-3.PDF

EJB-Programming-3.PDF :, JBuilder EJB 2.x CMP EJB Relationships JBuilder EJB Test Client EJB EJB Seminar CMP Entity Beans Value Object Design Pattern J2EE Design Patterns Value Object Value Object Factory J2EE EJB Test Client

More information

基于CDIO一体化理念的课程教学大纲设计

基于CDIO一体化理念的课程教学大纲设计 Java 语 言 程 序 设 计 课 程 教 学 大 纲 Java 语 言 程 序 设 计 课 程 教 学 大 纲 一 课 程 基 本 信 息 1. 课 程 代 码 :52001CC022 2. 课 程 名 称 :Java 语 言 程 序 设 计 3. 课 程 英 文 名 称 :Java Programming 4. 课 程 类 别 : 理 论 课 ( 含 实 验 上 机 或 实 践 ) 5. 授

More information

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 4 月 19 日晚 9 点 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double x) { d

More information

Struts2自定义类型转换.doc

Struts2自定义类型转换.doc Struts2 自定义类型转换 原理 struts2 的自定义类型转换机制为复杂类型的输入输出处理提供了便捷.struts2 已经为我们提供了几乎所有的 primitive 类型以及常用类型 ( 如 Date) 的类型转换器, 我们也可以为我们自定义类添加自定义类型转化器. struts2 为我们提供了一个类型转化器的入口 : ognl.defaulttypeconverter, 或继承 org.apache.struts2.util.strutstypeconverter,

More information

untitled

untitled -JAVA 1. Java IDC 20 20% 5 2005 42.5 JAVA IDC JAVA 60% 70% JAVA 3 5 10 JAVA JAVA JAVA J2EE J2SE J2ME 70% JAVA JAVA 20 1 51 2. JAVA SUN JAVA J2EE J2EE 3. 1. CSTP CSTP 2 51 2. 3. CSTP IT CSTP IT IT CSTP

More information

获取 Access Token access_token 是接口的全局唯一票据, 接入方调用各接口时都需使用 access_token 开发者需要进行妥善保存 access_token 的存储至少要保留 512 个字符空间 access_token 的有效期目前为 2 个小时, 需定时刷新, 重复

获取 Access Token access_token 是接口的全局唯一票据, 接入方调用各接口时都需使用 access_token 开发者需要进行妥善保存 access_token 的存储至少要保留 512 个字符空间 access_token 的有效期目前为 2 个小时, 需定时刷新, 重复 获取 Access Token access_token 是接口的全局唯一票据, 接入方调用各接口时都需使用 access_token 开发者需要进行妥善保存 access_token 的存储至少要保留 512 个字符空间 access_token 的有效期目前为 2 个小时, 需定时刷新, 重复 获取将导致上次获取的 access_token 失效 接入方可以使用 AppID 和 AppSecret

More information

在所有的项目开发中, 一定是多人协作的团队开发, 但是使用框架就会出现一个问题, 我们所 有的 Action 以及相关的路径都要求在我们的 struts.xml 文件中配置, 如果所有的人去修改一个 文件, 那么就会变得混乱, 而且有可能出现冲突, 那么在 struts.xml 文件中为了解决这个问

在所有的项目开发中, 一定是多人协作的团队开发, 但是使用框架就会出现一个问题, 我们所 有的 Action 以及相关的路径都要求在我们的 struts.xml 文件中配置, 如果所有的人去修改一个 文件, 那么就会变得混乱, 而且有可能出现冲突, 那么在 struts.xml 文件中为了解决这个问 内置对象的取得和多人开发 一 内置对象的取得 在使用的 servlet 的时候可以通过 HttpServletResquest 获取到一些内置对象, 但是在 struts2 中为了方便取得内置对象, 专门提供了一个 ServletActionContext 这个类取得取得内置对象, 观察如下方法 public static javax.servlet.jsp.pagecontext() 取得 pagecontext

More information

拦截器(Interceptor)的学习

拦截器(Interceptor)的学习 二 拦截器 (Interceptor) 的学习 拦截器可以监听程序的一个或所有方法 拦截器对方法调用流提供了细粒度控制 可以在无状态会话 bean 有状态会话 bean 和消息驱动 bean 上使用它们 拦截器可以是同一 bean 类中的方法或是一个外部类 下面介绍如何在 Session Bean 类中使用外部拦截器类 @Interceptors 注释指定一个或多个在外部类中定义的拦截器 下面拦截器

More information

Spring3.x开发入门

Spring3.x开发入门 Spring Bean 管理 Spring 的工厂类 课程安排 Spring 的 Bean 管理 (XML 方式 ) Spring 的属性注入 (XML 方式 ) Spring 的 Bean 管理 ( 注解方式 ) Spring 的属性注入 ( 注解方式 ) Spring 的工厂类 Spring 的 Bean 管理 (XML 方式 ) 三种实例化 Bean 的方式 使用类构造器实例化 ( 默认无参数

More information

PowerPoint 演示文稿

PowerPoint 演示文稿 The BitCoin Scripting Language 交易实例 交易结构 "result": { "txid": "921a dd24", "hash": "921a dd24", "version": 1, "size": 226, "locktime": 0, "vin": [ ], "vout": [ ], "blockhash": "0000000000000000002c510d

More information

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 odps-sdk 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基 开放数据处理服务 ODPS SDK SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基础功能的主体接口, 搜索关键词 "odpssdk-core" 一些

More information

EJB-Programming-4-cn.doc

EJB-Programming-4-cn.doc EJB (4) : (Entity Bean Value Object ) JBuilder EJB 2.x CMP EJB Relationships JBuilder EJB Test Client EJB EJB Seminar CMP Entity Beans Session Bean J2EE Session Façade Design Pattern Session Bean Session

More information

res/layout 目录下的 main.xml 源码 : <?xml version="1.0" encoding="utf 8"?> <TabHost android:layout_height="fill_parent" xml

res/layout 目录下的 main.xml 源码 : <?xml version=1.0 encoding=utf 8?> <TabHost android:layout_height=fill_parent xml 拓展训练 1- 界面布局 1. 界面布局的重要性做应用程序, 界面是最基本的 Andorid 的界面, 需要写在 res/layout 的 xml 里面, 一般情况下一个 xml 对应一个界面 Android 界面布局有点像写 html( 连注释代码的方式都一样 ), 要先给 Android 定框架, 然后再在框架里面放控件,Android 提供了几种框架,AbsoluteLayout,LinearLayout,

More information

无类继承.key

无类继承.key 无类继承 JavaScript 面向对象的根基 周爱 民 / aimingoo aiming@gmail.com https://aimingoo.github.io https://github.com/aimingoo rand = new Person("Rand McKinnon",... https://docs.oracle.com/cd/e19957-01/816-6408-10/object.htm#1193255

More information

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1 C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 月 3 日 1 1 INPUTOUTPUT 1 InputOutput 题目描述 用 cin 输入你的姓名 ( 没有空格 ) 和年龄 ( 整数 ), 并用 cout 输出 输入输出符合以下范例 输入 master 999 输出 I am master, 999 years old. 注意 "," 后面有一个空格,"." 结束,

More information

Microsoft PowerPoint - 05-Status-Codes-Chinese.ppt

Microsoft PowerPoint - 05-Status-Codes-Chinese.ppt 2004 Marty Hall 服务器响应的生成 : HTTP 状态代码 JSP, Servlet, & Struts Training Courses: http://courses.coreservlets.com Available in US, China, Taiwan, HK, and Worldwide 2 JSP and Servlet Books from Sun Press: http://www.coreservlets.com

More information

没 有 多 余 的 Contruol 或 Action 了 原 来 Domain 层 被 服 务 层 Service layer 遮 挡, 在 右 边 图 中, 则 Domain 层 直 接 暴 露 给 前 台 了, 没 有 被 遮 挡, 裸 露 了 这 样 一 步 到 位 实 现 领 域 模 型

没 有 多 余 的 Contruol 或 Action 了 原 来 Domain 层 被 服 务 层 Service layer 遮 挡, 在 右 边 图 中, 则 Domain 层 直 接 暴 露 给 前 台 了, 没 有 被 遮 挡, 裸 露 了 这 样 一 步 到 位 实 现 领 域 模 型 文 章 编 号 :1007-757X(2012)1-0036-04 领 域 驱 动 模 型 的 WEB 软 件 系 统 设 计 研 究 摘 要 : J2EE 3 JDK1.7 Tomcat WEB 关 键 词 : 中 图 分 类 号 :TP311 文 献 标 志 码 :A 0 引 言 Web 软 件 系 统 的 分 层 结 构 典 型 的 J2EE 软 件 系 统 开 发 方 法 分 为 三 层 结

More information

优迈科技教学大纲2009版本

优迈科技教学大纲2009版本 java 软 件 工 程 师 培 训 教 学 大 纲 1 JAVA 软 件 工 程 师 培 训 教 学 大 纲 深 圳 软 件 园 人 才 实 训 基 地 2009 年 3 月 目 录 java 软 件 工 程 师 培 训 教 学 大 纲 2 教 学 阶 段...3 第 一 章 JAVA 起 步...3 第 二 章 面 向 对 象 的 编 程...4 第 三 章 数 据 结 构 IO 线 程 网 络...5

More information

Microsoft Word - 01.DOC

Microsoft Word - 01.DOC 第 1 章 JavaScript 简 介 JavaScript 是 NetScape 公 司 为 Navigator 浏 览 器 开 发 的, 是 写 在 HTML 文 件 中 的 一 种 脚 本 语 言, 能 实 现 网 页 内 容 的 交 互 显 示 当 用 户 在 客 户 端 显 示 该 网 页 时, 浏 览 器 就 会 执 行 JavaScript 程 序, 用 户 通 过 交 互 式 的

More information

Guava学习之Resources

Guava学习之Resources Resources 提供提供操作 classpath 路径下所有资源的方法 除非另有说明, 否则类中所有方法的参数都不能为 null 虽然有些方法的参数是 URL 类型的, 但是这些方法实现通常不是以 HTTP 完成的 ; 同时这些资源也非 classpath 路径下的 下面两个函数都是根据资源的名称得到其绝对路径, 从函数里面可以看出,Resources 类中的 getresource 函数都是基于

More information

Kubenetes 系列列公开课 2 每周四晚 8 点档 1. Kubernetes 初探 2. 上 手 Kubernetes 3. Kubernetes 的资源调度 4. Kubernetes 的运 行行时 5. Kubernetes 的 网络管理理 6. Kubernetes 的存储管理理 7.

Kubenetes 系列列公开课 2 每周四晚 8 点档 1. Kubernetes 初探 2. 上 手 Kubernetes 3. Kubernetes 的资源调度 4. Kubernetes 的运 行行时 5. Kubernetes 的 网络管理理 6. Kubernetes 的存储管理理 7. Kubernetes 包管理理 工具 Helm 蔺礼强 Kubenetes 系列列公开课 2 每周四晚 8 点档 1. Kubernetes 初探 2. 上 手 Kubernetes 3. Kubernetes 的资源调度 4. Kubernetes 的运 行行时 5. Kubernetes 的 网络管理理 6. Kubernetes 的存储管理理 7. Kubernetes

More information

國家圖書館典藏電子全文

國家圖書館典藏電子全文 EAI EAI Middleware EAI 3.1 EAI EAI Client/Server Internet,www,Jav a 3.1 EAI Message Brokers -Data Transformation Business Rule XML XML 37 3.1 XML XML XML EAI XML 1. XML XML Java Script VB Script Active

More information

在Spring中使用Kafka:Producer篇

在Spring中使用Kafka:Producer篇 在某些情况下, 我们可能会在 Spring 中将一些 WEB 上的信息发送到 Kafka 中, 这时候我们就需要在 Spring 中编写 Producer 相关的代码了 ; 不过高兴的是,Spring 本身提供了操作 Kafka 的相关类库, 我们可以直接通过 xml 文件配置然后直接在后端的代码中使用 Kafka, 非常地方便 本文将介绍如果在 Spring 中将消息发送到 Kafka 在这之前,

More information

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例 帝国 CMS 下在 PHP 文件中调用数据库类执行 SQL 语句实例 这篇文章主要介绍了帝国 CMS 下在 PHP 文件中调用数据库类执行 SQL 语句实例, 本文还详细介绍了帝国 CMS 数据库类中的一些常用方法, 需要的朋友可以参考下 例 1: 连接 MYSQL 数据库例子 (a.php)

More information

新・解きながら学ぶJava

新・解きながら学ぶJava 481! 41, 74!= 40, 270 " 4 % 23, 25 %% 121 %c 425 %d 121 %o 121 %x 121 & 199 && 48 ' 81, 425 ( ) 14, 17 ( ) 128 ( ) 183 * 23 */ 3, 390 ++ 79 ++ 80 += 93 + 22 + 23 + 279 + 14 + 124 + 7, 148, 16 -- 79 --

More information

2. AOP 底层技术实现 小风 Java 实战系列教程 关键词 : 代理模式 代理模型分为两种 : 1) 接口代理 (JDK 动态代理 ) 2) 子类代理 (Cglib 子类代理 ) 需求 :CustomerService 业务类, 有 save,update 方法, 希望在 save,updat

2. AOP 底层技术实现 小风 Java 实战系列教程 关键词 : 代理模式 代理模型分为两种 : 1) 接口代理 (JDK 动态代理 ) 2) 子类代理 (Cglib 子类代理 ) 需求 :CustomerService 业务类, 有 save,update 方法, 希望在 save,updat 本章学习目标 小风 Java 实战系列教程 AOP 思想概述 AOP 底层技术实现 AOP 术语介绍 SpringAOP 的 XML 方式 HelloWorld SpringAOP 的 XML 方式配置细节 SpringAOP 的注解方式 SpringAOP 的零配置方式 1. AOP 思想概述 1.1. AOP 思想简介 1.2. AOP 的作用 2. AOP 底层技术实现 小风 Java 实战系列教程

More information

jsp

jsp JSP Allen Long Email: allen@huihoo.com http://www.huihoo.com 2004-04 Huihoo - Enterprise Open Source http://www.huihoo.com 1 JSP JSP JSP JSP MVC Huihoo - Enterprise Open Source http://www.huihoo.com 2

More information

IoC容器和Dependency Injection模式.doc

IoC容器和Dependency Injection模式.doc IoC Dependency Injection /Martin Fowler / Java Inversion of Control IoC Dependency Injection Service Locator Java J2EE open source J2EE J2EE web PicoContainer Spring Java Java OO.NET service component

More information

IDEO_HCD_0716

IDEO_HCD_0716 IDEO HCD Toolkit Tencent CDC ...? Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC Tencent CDC

More information

设计模式 Design Patterns

设计模式 Design Patterns 丁勇 Email:18442056@QQ.com 学习目标 描述 JSP 表达式语言的语法 认识使用 JSP 表达式的优点 在 JSP 中使用表达式语言 表达式语言简介 5 1 EL 为表达式语言 由两个组开发 JSP 标准标签库专家组 JSP 2.0 专家组 JSP 表达式语言的语法 ${EL Expression} JSP EL 表达式用于以下情形 静态文本 标准标签和自定义标签 表达式语言简介

More information

设计模式 Design Patterns

设计模式 Design Patterns 丁勇 Email:18442056@QQ.com 学习目标 掌握 Model I 体系结构 掌握 Model II 体系结构 掌握 MVC 应用程序 Model I 体系结构 6 1 Model I 体系结构结合使用 JSP 页面和 Bean 来开发 Web 应用程序 应用服务器 请求 JSP 页面 响应 Bean 数据库服务器 Model I 体系结构 6 2 Model I 体系结构用于开发简单的应用程序

More information

Untitled

Untitled Spring 4.0.0 spring-framework-reference QQ 413615763 Weibo le Email not-three@foxmail.com 2013.12.16 2.2 2013.12.17 2.3 : 2013.12.18 2.3 : 2013.12.18 2.3 :- Commons Logging Spring Spring Spring IoC StrutsHibernate

More information

设计模式 Design Patterns

设计模式 Design Patterns 丁勇 Email:18442056@QQ.com 组件技术概述 现在软件开发都已经转向了基于组件的开发, 目前具备代表性的组件技术有微软的 COM COM+, 有 Sun 的 Bean 和 EJB(Enterprise Bean), 另外还有 CORBA(Common Object Request Broker Architecture, 公 共对象请求代理结构 ) Bean Bean 规范将 软件组件

More information

untitled

untitled 653 JAVA 2008 11 Institution of Software Engineer... 2... 4... 4... 5... 5... 8... 8... 8... 8... 8... 9... 9... 9... 11... 13... 13... 13... 13... 15... 15... 15... 15... 16... 16... 17... 17... 17...

More information

OOP with Java 通知 Project 3: 3 月 29 日晚 9 点 4 月 1 日上课

OOP with Java 通知 Project 3: 3 月 29 日晚 9 点 4 月 1 日上课 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 3: 3 月 29 日晚 9 点 4 月 1 日上课 复习 Java 包 创建包 : package 语句, 包结构与目录结构一致 使用包 : import restaurant/ - people/ - Cook.class - Waiter.class - tools/ - Fork.class

More information

论文,,, ( &, ), 1 ( -, : - ), ; (, ), ; ;, ( &, ),,,,,, (, ),,,, (, ) (, ),,, :. : ( ), ( ) ( ) ( ) ( ) ( ) ( ) ( ) ( ), ( ),,,, 1 原译作 修补者, 但在英译版本中, 被译作

论文,,, ( &, ), 1 ( -, : - ), ; (, ), ; ;, ( &, ),,,,,, (, ),,,, (, ) (, ),,, :. : ( ), ( ) ( ) ( ) ( ) ( ) ( ) ( ) ( ), ( ),,,, 1 原译作 修补者, 但在英译版本中, 被译作 * 夏传玲 : 本文简要回顾了国内外定性研究在最近 多年的发展概况, 总结 了定性研究的六个发展趋势和分析策略上的三种流派 在上述两种背景下, 本文探讨了计算机辅助的定性分析给定性研究带来的机遇和挑战, 特别是它和手工操作对比时的优势和劣势, 以及应用这种定性分析技术所可能面临的困难 : 定性研究定性分析 文化差异,, (, ),,,, ( - ) ( - ) ( - ) ( - ) ( - ) (

More information

OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料

OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢   学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 Email: 51141201063@ecnu.cn 学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料 OOP with Java Java 类型 引用 不可变类型 对象存储位置 作用域 OOP

More information

09 (File Processes) (mkdir) 9-3 (createnewfile) 9-4 (write) 9-5 (read) 9-6 (deletefile) 9-7 (deletedir) (Exercises)

09 (File Processes) (mkdir) 9-3 (createnewfile) 9-4 (write) 9-5 (read) 9-6 (deletefile) 9-7 (deletedir) (Exercises) 09 (File Processes) 9-1 9-2 (mkdir) 9-3 (createnewfile) 9-4 (write) 9-5 (read) 9-6 (deletefile) 9-7 (deletedir) (Exercises) Java Servlet 9-1 Servlet (File Processes) Client Servlet Servlet Java Java (Stream)

More information

OSWorkflow Documentation

OSWorkflow Documentation OSWorkflow Documentation Update Time: 05/09/15 OSWorkflow Java workflow engine API 理 flow 行 XML 來 流 Database UI 不 流 GUI Designer end user 行 JSP+Servlet 行 OSWorkflow 2.8 說 2.7 2.7 了 OSWorkflow library library

More information

OOP with Java 通知 Project 4: 5 月 2 日晚 9 点

OOP with Java 通知 Project 4: 5 月 2 日晚 9 点 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 4: 5 月 2 日晚 9 点 复习 类的复用 组合 (composition): has-a 关系 class MyType { public int i; public double d; public char c; public void set(double x) { d =

More information

3.1 num = 3 ch = 'C' 2

3.1 num = 3 ch = 'C' 2 Java 1 3.1 num = 3 ch = 'C' 2 final 3.1 final : final final double PI=3.1415926; 3 3.2 4 int 3.2 (long int) (int) (short int) (byte) short sum; // sum 5 3.2 Java int long num=32967359818l; C:\java\app3_2.java:6:

More information

1.JasperReport ireport JasperReport ireport JDK JDK JDK JDK ant ant...6

1.JasperReport ireport JasperReport ireport JDK JDK JDK JDK ant ant...6 www.brainysoft.net 1.JasperReport ireport...4 1.1 JasperReport...4 1.2 ireport...4 2....4 2.1 JDK...4 2.1.1 JDK...4 2.1.2 JDK...5 2.1.3 JDK...5 2.2 ant...6 2.2.1 ant...6 2.2.2 ant...6 2.3 JasperReport...7

More information

使用Cassandra和Spark 2.0实现Rest API服务

使用Cassandra和Spark 2.0实现Rest API服务 使用 Cassandra 和 Spark 2.0 实现 Rest API 服务 在这篇文章中, 我将介绍如何在 Spark 中使用 Akkahttp 并结合 Cassandra 实现 REST 服务, 在这个系统中 Cassandra 用于数据的存储 我们已经见识到 Spark 的威力, 如果和 Cassandra 正确地结合可以实现更强大的系统 我们先创建一个 build.sbt 文件, 内容如下

More information

李 琼 评扎迪 史密斯的 白牙 要是他 指艾伯特 加勒比海移民 真的回去 了 那么他将要面临的失败是明摆在那儿的 因为当地并没有发生什么变化 这就是移民的悲剧 他们比他们离弃的故乡变化得更 快 于是他们永远也不可能因回到家乡而感 到幸福 可是 他们在移居的国家也不幸福 因为这不是家乡 瞿世镜

李 琼 评扎迪 史密斯的 白牙 要是他 指艾伯特 加勒比海移民 真的回去 了 那么他将要面临的失败是明摆在那儿的 因为当地并没有发生什么变化 这就是移民的悲剧 他们比他们离弃的故乡变化得更 快 于是他们永远也不可能因回到家乡而感 到幸福 可是 他们在移居的国家也不幸福 因为这不是家乡 瞿世镜 略论英国移民族群认同的发展和走向 李 琼 李 琼 评扎迪 史密斯的 白牙 要是他 指艾伯特 加勒比海移民 真的回去 了 那么他将要面临的失败是明摆在那儿的 因为当地并没有发生什么变化 这就是移民的悲剧 他们比他们离弃的故乡变化得更 快 于是他们永远也不可能因回到家乡而感 到幸福 可是 他们在移居的国家也不幸福 因为这不是家乡 瞿世镜 年 外国文学 第 期 这些天来 我觉得来到这个国家 就像是和魔鬼签了协议

More information

(CIP) Web /,. :,2005. 1 ISBN 7 81058 782 X.W............T P393.4 CIP (2004) 118797 Web ( 99 200436) ( http:/ / www.shangdapress.com 66135110) : * 787

(CIP) Web /,. :,2005. 1 ISBN 7 81058 782 X.W............T P393.4 CIP (2004) 118797 Web ( 99 200436) ( http:/ / www.shangdapress.com 66135110) : * 787 Web (CIP) Web /,. :,2005. 1 ISBN 7 81058 782 X.W............T P393.4 CIP (2004) 118797 Web ( 99 200436) ( http:/ / www.shangdapress.com 66135110) : * 787 1092 1/ 16 30.75 748 2005 1 1 2005 1 1 : 1 3 100

More information

Microsoft PowerPoint - 02-Servlet-Basics-Chinese.ppt

Microsoft PowerPoint - 02-Servlet-Basics-Chinese.ppt 2004 Marty Hall servlet 基础 JSP, Servlet, & Struts Training Courses: http://courses.coreservlets.com Available in US, China, Taiwan, HK, and Worldwide 2 JSP and Servlet Books from Sun Press: http://www.coreservlets.com

More information

目 录 1. 业 务 流 程 系 统 开 发 面 临 的 挑 战 与 机 遇... 3 1.1 业 务 流 程 管 理... 4 2. 新 一 代 开 源 业 务 流 程 开 发 平 台 BPMX3... 5 2.1 BPMX3 是 什 么... 5 2.2 为 什 么 要 优 先 采 用 BPMX

目 录 1. 业 务 流 程 系 统 开 发 面 临 的 挑 战 与 机 遇... 3 1.1 业 务 流 程 管 理... 4 2. 新 一 代 开 源 业 务 流 程 开 发 平 台 BPMX3... 5 2.1 BPMX3 是 什 么... 5 2.2 为 什 么 要 优 先 采 用 BPMX BPMX3 技 术 白 皮 书 业 务 流 程 开 发 平 台 介 绍 目 录 1. 业 务 流 程 系 统 开 发 面 临 的 挑 战 与 机 遇... 3 1.1 业 务 流 程 管 理... 4 2. 新 一 代 开 源 业 务 流 程 开 发 平 台 BPMX3... 5 2.1 BPMX3 是 什 么... 5 2.2 为 什 么 要 优 先 采 用 BPMX3... 5 2.2.1 BPMX3

More information

Microsoft Word - 第7章 初识Hibernate—教学大纲.doc

Microsoft Word - 第7章 初识Hibernate—教学大纲.doc SSH 框架整合实战教程 课程教学大纲 ( 课程英文名称 ) 课程编号 : 学分 : 5 学分学时 : 108 学时 ( 其中 : 讲课学时 :76 上机学时 :32) 先修课程 :Java 基础入门 MySQL 数据库入门 JavaWeb 程序开发入门 JavaWeb 程序开发进阶适用专业 : 信息及其计算机相关专业开课部门 : 计算机系 一 课程的性质与目标 SSH 框架整合实战教程 是面向计算机相关专业的一门专业

More information

设计模式 Design Patterns

设计模式 Design Patterns 丁勇 Email:18442056@QQ.com 学习目标 理解 Struts 框架的工作原理 掌握使用 Struts 框架开发 Web 应用的基本步骤 熟悉 MyEclipse 对 Struts 开发的支持 Web 框架事实标准 : Web 框架的事实标准 http://struts.apache.org Java EE 主流技术趋势图 主流 Web 框架趋势图 使用 Struts 实现加法器 使用开发的

More information

Office Office Office Microsoft Word Office Office Azure Office One Drive 2 app 3 : [5] 3, :, [6]; [5], ; [8], [1], ICTCLAS(Institute of Computing Tech

Office Office Office Microsoft Word Office Office Azure Office One Drive 2 app 3 : [5] 3, :, [6]; [5], ; [8], [1], ICTCLAS(Institute of Computing Tech - OfficeCoder 1 2 3 4 1,2,3,4 xingjiarong@mail.sdu.edu.cn 1 xuchongyang@mail.sdu.edu.cn 2 sun.mc@outlook.com 3 luoyuanhang@mail.sdu.edu.cn 4 Abstract. Microsoft Word 2013 Word 2013 Office Keywords:,, HTML5,

More information

前言 C# C# C# C C# C# C# C# C# microservices C# More Effective C# More Effective C# C# C# C# Effective C# 50 C# C# 7 Effective vii

前言 C# C# C# C C# C# C# C# C# microservices C# More Effective C# More Effective C# C# C# C# Effective C# 50 C# C# 7 Effective vii 前言 C# C# C# C C# C# C# C# C# microservices C# More Effective C# More Effective C# C# C# C# Effective C# 50 C# C# 7 Effective vii C# 7 More Effective C# C# C# C# C# C# Common Language Runtime CLR just-in-time

More information

TopTest_Adminstrator.doc

TopTest_Adminstrator.doc 壹 前 言... 3 貳 系 統 簡 介... 4 一 TKB multimedia Top-Test 系 統 架 構...4 1. 使 用 者 介 面 層 (Presentation tier)...5 2. 商 業 邏 輯 層 (business logic tier)...5 3. 資 料 服 務 層 (data services tier)...5 二 TKB Multimedia Top-Test

More information

声 明 本 公 司 及 全 体 董 事 监 事 高 级 管 理 人 员 承 诺 不 存 在 任 何 虚 假 记 载 误 导 性 陈 述 或 重 大 遗 漏, 并 对 其 真 实 性 准 确 性 完 整 性 承 担 个 别 和 连 带 的 法 律 责 任 本 公 司 负 责 人 和 主 管 会 计 工

声 明 本 公 司 及 全 体 董 事 监 事 高 级 管 理 人 员 承 诺 不 存 在 任 何 虚 假 记 载 误 导 性 陈 述 或 重 大 遗 漏, 并 对 其 真 实 性 准 确 性 完 整 性 承 担 个 别 和 连 带 的 法 律 责 任 本 公 司 负 责 人 和 主 管 会 计 工 Shenzhen WitSoft Information Technology Co., Ltd. 主 办 券 商 二 〇 一 六 年 二 月 声 明 本 公 司 及 全 体 董 事 监 事 高 级 管 理 人 员 承 诺 不 存 在 任 何 虚 假 记 载 误 导 性 陈 述 或 重 大 遗 漏, 并 对 其 真 实 性 准 确 性 完 整 性 承 担 个 别 和 连 带 的 法 律 责 任 本

More information

通过Hive将数据写入到ElasticSearch

通过Hive将数据写入到ElasticSearch 我在 使用 Hive 读取 ElasticSearch 中的数据 文章中介绍了如何使用 Hive 读取 ElasticSearch 中的数据, 本文将接着上文继续介绍如何使用 Hive 将数据写入到 ElasticSearch 中 在使用前同样需要加入 elasticsearch-hadoop-2.3.4.jar 依赖, 具体请参见前文介绍 我们先在 Hive 里面建个名为 iteblog 的表,

More information

數位圖書館/博物館相關標準 2

數位圖書館/博物館相關標準 2 數 2 立 XML (Extensibility) XML 行 (Self-description) (Structure) XML (Validation) XML DTD 行 XML 列 XML-Language SGML without tears Self-describing Documents Well-formed and Valid Documents XML-Link Power

More information

目 录(目录名)

目  录(目录名) 目录 目录...1-1 1.1 域名解析配置命令... 1-1 1.1.1 display dns domain... 1-1 1.1.2 display dns dynamic-host... 1-1 1.1.3 display dns server... 1-2 1.1.4 display ip host... 1-3 1.1.5 dns domain... 1-4 1.1.6 dns resolve...

More information

PowerPoint Presentation

PowerPoint Presentation 1 版权所有 2011,Oracle 和 / 或其分支机构 保留所有权利 从幻灯片 8 中插入信息保护策略分类 WAC Widget Java ME 手机新动向陈志宇 2 版权所有 2011,Oracle 和 / 或其分支机构 保留所有权利 从幻灯片 8 中插入信息保护策略分类 以下内容旨在概述我们产品总的发展方向 该内容仅供参考, 不可纳入任何合同 该内容不构成提供任何材料 代码或功能的承诺, 并且不应该作为制定购买决策的依据

More information

Servlet

Servlet Servlet Allen Long Email: allen@huihoo.com http://www.huihoo.com 2004-04 Huihoo - Enterprise Open Source http://www.huihoo.com 1 Huihoo - Enterprise Open Source http://www.huihoo.com 2 GET POST Huihoo

More information

1. 2. Flex Adobe 3.

1. 2. Flex Adobe 3. 1. 2. Flex Adobe 3. Flex Adobe Flex Flex Web Flex Flex Flex Adobe Flash Player 9 /rich Internet applications/ria Flex 1. 2. 3. 4. 5. 6. SWF Flash Player Flex 1. Flex framework Adobe Flex 2 framework RIA

More information

第四章 102 图 4唱16 基于图像渲染的理论基础 三张拍摄图像以及它们投影到球面上生成的球面图像 拼图的圆心是相同的 而拼图是由球面图像上的弧线图像组成的 因此我 们称之为同心球拼图 如图 4唱18 所示 这些拼图中半径最大的是圆 Ck 最小的是圆 C0 设圆 Ck 的半径为 r 虚拟相机水平视域为 θ 有 r R sin θ 2 4畅11 由此可见 构造同心球拼图的过程实际上就是对投影图像中的弧线图像

More information

软件工程文档编制

软件工程文档编制 实训抽象类 一 实训目标 掌握抽象类的定义 使用 掌握运行时多态 二 知识点 抽象类的语法格式如下 : public abstract class ClassName abstract void 方法名称 ( 参数 ); // 非抽象方法的实现代码 在使用抽象类时需要注意如下几点 : 1 抽象类不能被实例化, 实例化的工作应该交由它的子类来完成 2 抽象方法必须由子类来进行重写 3 只要包含一个抽象方法的抽象类,

More information

计算机软件技术专业教学计划

计算机软件技术专业教学计划 计 算 机 软 件 技 术 专 业 人 才 培 养 方 案 ( 服 务 外 包 方 向 ) 专 业 大 类 名 称 ( 代 码 ):++(++) 专 业 类 名 称 ( 代 码 ):++++++(++++) 专 业 名 称 ( 代 码 ):+++++++(++++++) 修 业 年 限 : 三 年, 全 日 制 招 生 对 象 : 三 年 制 普 通 高 中 及 对 口 中 职 专 业 毕 业 生

More information

基于ECO的UML模型驱动的数据库应用开发1.doc

基于ECO的UML模型驱动的数据库应用开发1.doc ECO UML () Object RDBMS Mapping.Net Framework Java C# RAD DataSetOleDbConnection DataGrod RAD Client/Server RAD RAD DataReader["Spell"].ToString() AObj.XXX bug sql UML OR Mapping RAD Lazy load round trip

More information

OOP with Java 通知 Project 3 提交时间 3 月 29 日晚 9 点 Piazza Project 2 投票

OOP with Java 通知 Project 3 提交时间 3 月 29 日晚 9 点 Piazza Project 2 投票 OOP with Java Yuanbin Wu cs@ecnu OOP with Java 通知 Project 3 提交时间 3 月 29 日晚 9 点 Piazza Project 2 投票 复习 创建对象 构造函数 函数重载 : 函数 = 函数名 + 参数列表 public class MyType { int i; double d; char c; void set(double x)

More information

J2ME ISBN J2ME MIDP MIDP 2.0 API J2ME Netbeans IDE 4.1 Mobility Pack 4.1 MIDlet MIDlet MIDP PUSH API PDA API Ja

J2ME ISBN J2ME MIDP MIDP 2.0 API J2ME Netbeans IDE 4.1 Mobility Pack 4.1 MIDlet MIDlet MIDP PUSH API PDA API Ja Java JBuilder 2005 2005 6 ISBN 7-121-01166-2 69.00 1 688 JBuilder JBuilder 2005 JBuilder JBuilder 2005 JBuilder 2005 Java Java Java JBuilder 17 J2ME 2006 1 ISBN 7-121-02210-9 39.00 1 436 J2ME MIDP MIDP

More information

ASP 電子商務網頁設計

ASP 電子商務網頁設計 Flash Flash CSIE, NTU December 22, 2007 Outline & Flash National Taiwan University December 22, 2007 Page 2 Outline & Flash National Taiwan University December 22, 2007 Page 3 Course Introduction (1/3)

More information

untitled

untitled Work Managers 什 Work Managers? WebLogic Server 9.x 行 (thread) 理 thread pool 數量 立 execute queues 來 量 理 thread count, thread priority 參數 理 thread pool 數量? WebLogic Server 9.x 理 行 (thread) (self-tuning) 句

More information

一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页

一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页 第 1 页共 32 页 crm Mobile V1.0 for IOS 用户手册 一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页 二 crm Mobile 界面介绍 : 第 3 页共 32 页 三 新建 (New) 功能使用说明 1 选择产品 第 4 页共 32 页 2 填写问题的简要描述和详细描述 第 5 页共

More information

Microsoft PowerPoint - ch6 [相容模式]

Microsoft PowerPoint - ch6 [相容模式] UiBinder wzyang@asia.edu.tw UiBinder Java GWT UiBinder XML UI i18n (widget) 1 2 UiBinder HelloWidget.ui.xml: UI HelloWidgetBinder HelloWidget.java XML UI Owner class ( Composite ) UI XML UiBinder: Owner

More information

水晶分析师

水晶分析师 大数据时代的挑战 产品定位 体系架构 功能特点 大数据处理平台 行业大数据应用 IT 基础设施 数据源 Hadoop Yarn 终端 统一管理和监控中心(Deploy,Configure,monitor,Manage) Master Servers TRS CRYSTAL MPP Flat Files Applications&DBs ETL&DI Products 技术指标 1 TRS

More information

resp.getwriter().print(j + "*" + i + "=" + j * i+" "); resp.getwriter().print("<br/>"); protected void dopost(httpservletrequest req, HttpServletRespo

resp.getwriter().print(j + * + i + = + j * i+ ); resp.getwriter().print(<br/>); protected void dopost(httpservletrequest req, HttpServletRespo 第三章补充案例 案例 3-1 HttpServlet 一 案例描述 1 考核知识点名称 :HttpServlet 编号 : 2 练习目标 掌握 HttpServlet 的 doget() 方法和 dopost() 方法 3 需求分析由于大多数 Web 应用都是通过 HTTP 协议和客户端进行交互, 因此, 在 Servlet 接口中, 提供了 一个抽象类 javax.servlet.http.httpservlet,

More information

KillTest 质量更高 服务更好 学习资料 半年免费更新服务

KillTest 质量更高 服务更好 学习资料   半年免费更新服务 KillTest 质量更高 服务更好 学习资料 http://www.killtest.cn 半年免费更新服务 Exam : 310-065Big5 Title : Sun Certified Programmer for the Java 2 Platform, SE 6.0 Version : Demo 1 / 14 1. 35. String #name = "Jane Doe"; 36. int

More information

59 1 CSpace 2 CSpace CSpace URL CSpace 1 CSpace URL 2 Lucene 3 ID 4 ID Web 1. 2 CSpace LireSolr 3 LireSolr 3 Web LireSolr ID

59 1 CSpace 2 CSpace CSpace URL CSpace 1 CSpace URL 2 Lucene 3 ID 4 ID Web 1. 2 CSpace LireSolr 3 LireSolr 3 Web LireSolr ID 58 2016. 14 * LireSolr LireSolr CEDD Ajax CSpace LireSolr CEDD Abstract In order to offer better image support services it is necessary to extend the image retrieval function of our institutional repository.

More information

ChinaBI企业会员服务- BI企业

ChinaBI企业会员服务- BI企业 商业智能 (BI) 开源工具 Pentaho BisDemo 介绍及操作说明 联系人 : 杜号权苏州百咨信息技术有限公司电话 : 0512-62861389 手机 :18616571230 QQ:37971343 E-mail:du.haoquan@bizintelsolutions.com 权限控制管理 : 权限控制管理包括 : 浏览权限和数据权限 ( 权限部分两个角色 :ceo,usa; 两个用户

More information

付宝容器 jsapi 档 册 PDF 版本 本版本为实验版本, 为线下独 查看使, 受制于 成 PDF 程序的限制, 样式问题还没有很好的解决, 例如分 切图 代码 亮 推荐使 在线版本, 便实时查看 jsapi 运 效果 如需搜索, 使 阅读 PDF 软件 带功能即可 更多细节样式调整和 录索引探

付宝容器 jsapi 档 册 PDF 版本 本版本为实验版本, 为线下独 查看使, 受制于 成 PDF 程序的限制, 样式问题还没有很好的解决, 例如分 切图 代码 亮 推荐使 在线版本, 便实时查看 jsapi 运 效果 如需搜索, 使 阅读 PDF 软件 带功能即可 更多细节样式调整和 录索引探 付宝容器 jsapi 档 册 PDF 版本 本版本为实验版本, 为线下独 查看使, 受制于 成 PDF 程序的限制, 样式问题还没有很好的解决, 例如分 切图 代码 亮 推荐使 在线版本, 便实时查看 jsapi 运 效果 如需搜索, 使 阅读 PDF 软件 带功能即可 更多细节样式调整和 录索引探索建设中 成时间 : 2017-07-20 12:13:21 Since 8.6 定义键盘 定义键盘使

More information

Microsoft Word - D2Z

Microsoft Word - D2Z 第 章 Struts 2 基础 Struts 是 Apache 软件基金会赞助的一个开源项目, 它最初是 Jakarta 项目中的一个子项目 Struts 2 是以 Webwork 设计思想为核心, 吸收原 Struts 的优点而形成的, 旨在帮助程序员更方便地运用 MVC 模式来开发 Java EE 应用 2. 1 Struts 2 框架开发入门 2.1.1 MVC 基本思想 MVC 是一种通用的

More information

停止混流接口 请注意 : 该功能需要联系 ZEGO 技术支持开通 1 接口调用说明 http 请求方式 : POST/FORM, 需使用 https 正式环境地址 access_token=access_token (http

停止混流接口 请注意 : 该功能需要联系 ZEGO 技术支持开通 1 接口调用说明 http 请求方式 : POST/FORM, 需使用 https 正式环境地址   access_token=access_token (http 停止混流接口 请注意 : 该功能需要联系 ZEGO 技术支持开通 1 接口调用说明 http 请求方式 : POST/FORM, 需使用 https 正式环境地址 https://webapi.zego.im/cgi/stop-mix? access_token=access_token (https://webapi.zego.im/cgi/stop-mix? access_token=access_token)

More information

骨头的故事

骨头的故事 头 1 图 206 33 7 12 5 5 4 12 2 54 10 200-400 3 500 图 类 图 图 动 节 4 5 图 发 图 节 180 Youtube 180 [1] 7 2 7 6 9 270 6 图 树懒 块颈 13-25 14 17 25 7 图 扭头 头鹰 鹅 8 图 红 为 关节 绿 为 关节 9 图 类 10 图 类 11 图 盘 动 类 图 阴 犸 艺 你可能会以为图

More information

chapter 2 HTML5 目錄iii HTML HTML HTML HTML HTML canvas

chapter 2 HTML5 目錄iii HTML HTML HTML HTML HTML canvas Contents 目錄 chapter 1 1-1... 1-2 1-2... 1-3 HTML5... 1-3... 1-5 1-3... 1-9 Web Storage... 1-9... 1-10 1-4 HTML5... 1-14... 1-14... 1-15 HTML5... 1-15... 1-15... 1-16 1-5... 1-18 Apps... 1-18 HTML5 Cache

More information

Fun Time (1) What happens in memory? 1 i n t i ; 2 s h o r t j ; 3 double k ; 4 char c = a ; 5 i = 3; j = 2; 6 k = i j ; H.-T. Lin (NTU CSIE) Referenc

Fun Time (1) What happens in memory? 1 i n t i ; 2 s h o r t j ; 3 double k ; 4 char c = a ; 5 i = 3; j = 2; 6 k = i j ; H.-T. Lin (NTU CSIE) Referenc References (Section 5.2) Hsuan-Tien Lin Deptartment of CSIE, NTU OOP Class, March 15-16, 2010 H.-T. Lin (NTU CSIE) References OOP 03/15-16/2010 0 / 22 Fun Time (1) What happens in memory? 1 i n t i ; 2

More information

第 章 Struts2 核心组件 2.1 Struts2 动作 (Action) Action 的作用 Struts2 的动作 (Action) 组件是 Struts2 框架的核心 Action 主要有三个作用 : 第一, 为给定的请求封装需要做的实际工作 ; 第二, 在从请求到视图的框

第 章 Struts2 核心组件 2.1 Struts2 动作 (Action) Action 的作用 Struts2 的动作 (Action) 组件是 Struts2 框架的核心 Action 主要有三个作用 : 第一, 为给定的请求封装需要做的实际工作 ; 第二, 在从请求到视图的框 第 章 Struts2 核心组件 2.1 Struts2 动作 (Action) 2.1.1 Action 的作用 Struts2 的动作 (Action) 组件是 Struts2 框架的核心 Action 主要有三个作用 : 第一, 为给定的请求封装需要做的实际工作 ; 第二, 在从请求到视图的框架自动数据传输中作为中介 ; 第三, 帮助框架确定要返回的视图 1. 动作封装工作单元动作在框架中可作为

More information

长 安 大 学 硕 士 学 位 论 文 基 于 数 据 仓 库 和 数 据 挖 掘 的 行 为 分 析 研 究 姓 名 : 杨 雅 薇 申 请 学 位 级 别 : 硕 士 专 业 : 计 算 机 软 件 与 理 论 指 导 教 师 : 张 卫 钢 20100530 长安大学硕士学位论文 3 1 3系统架构设计 行为分析数据仓库的应用模型由四部分组成 如图3 3所示

More information

新美大酒店开放平台SDK(.NET版)使用说明.pages

新美大酒店开放平台SDK(.NET版)使用说明.pages SDK(.NET 版 ) 使 用说明 1 SDK 包说明 1.1 获取 SDK SDK 可以在数据平台下载, 也可直接通过下载地址获得 下载地址 : http://s3.meituan.net/v1/mss_de81c933e113413ea913a772b707b9c9/open-platform-sdk/mthotelopenplatform-sdk-1.0-net.zip 下载成功后, 解压后可获得

More information

软 件 工 程 专 业 习 指 南 目 录 一 软 件 工 程 专 业 设 置 背 景 与 发 展 前 景... 3 二 软 件 工 程 专 业 实 践 教 条 件... 4 三 软 件 工 程 专 业 课 程 类 型 及 核 方 式... 6 1. 软 件 工 程 专 业 课 程 类 型...7

软 件 工 程 专 业 习 指 南 目 录 一 软 件 工 程 专 业 设 置 背 景 与 发 展 前 景... 3 二 软 件 工 程 专 业 实 践 教 条 件... 4 三 软 件 工 程 专 业 课 程 类 型 及 核 方 式... 6 1. 软 件 工 程 专 业 课 程 类 型...7 计 算 机 系 软 件 工 程 专 业 习 指 南 广 东 科 技 院 计 算 机 系 2015-9-1 软 件 工 程 专 业 习 指 南 目 录 一 软 件 工 程 专 业 设 置 背 景 与 发 展 前 景... 3 二 软 件 工 程 专 业 实 践 教 条 件... 4 三 软 件 工 程 专 业 课 程 类 型 及 核 方 式... 6 1. 软 件 工 程 专 业 课 程 类 型...7

More information

<ADB6ADB1C25EA8FAA6DB2D4D56432E706466>

<ADB6ADB1C25EA8FAA6DB2D4D56432E706466> packages 3-31 PART 3-31 03-03 ASP.NET ASP.N MVC ASP.NET ASP.N MVC 4 ASP.NET ASP.NE MVC Entity Entity Framework Code First 2 TIPS Visual Studio 20NuGetEntity NuGetEntity Framework5.0 CHAPTER 03 59 3-3-1

More information

PrintWriter s = new PrintWriter(writer); ex.printstacktrace(s); mv.addobject("exception", writer.tostring()); mv.setviewname("error"); return

PrintWriter s = new PrintWriter(writer); ex.printstacktrace(s); mv.addobject(exception, writer.tostring()); mv.setviewname(error); return 本章学习目标 小风 Java 实战系列教程 SpringMVC 异常处理 SpringMVC 文件上传 SpringMVC 处理 JSON 格式数据 SpringMVC 拦截器 SpringMVC 对 restful 风格的支持 1. SpringMVC 异常处理 1.1. @ExceptionHandler 注解处理异常 @ExceptionHandler 该注解使用在异常处理方法上面 1.1.1.

More information

JSP基础编程

JSP基础编程 JSP 基础编程 报告人 : 包亮 邮箱 :rslab@lzb.ac.cn HTTP 基础 HTTP is a simple, stateless protocol. A client, such as a web browser, makes a request, the web server responds, and the transaction is done. Client 发出一个请求

More information

Professional Ajax Ajax Adaptive Path, LLC Jesse James Garrett Ajax php Garrett WebG

Professional Ajax Ajax Adaptive Path, LLC Jesse James Garrett Ajax   php Garrett WebG 1 何謂 Ajax? 2001 2005World Wide Web Web Google Google Google Labhttp:// labs.google.com Google LabGoogle Suggest Google Maps JavaScript remotingweb Professional Ajax Ajax 2005 2Adaptive Path, LLC Jesse

More information

Microsoft Word - 第3章.doc

Microsoft Word - 第3章.doc 第 3 章 Struts2 框架是 Apache 开源社区原有的 Struts 框架和 Open Symphony 社区 WebWork2 框架的合并版本, 它集成了这两大流行的 MVC 框架各自的优点, 主要以 WebWork 的设计思想为核心, 提供了更加灵活的控制层和组件实现技术 Struts2 的体系结构 Struts2 的安装与配置 Struts2 框架的主要配置文件 3.1 Struts2

More information

Spark读取Hbase中的数据

Spark读取Hbase中的数据 Spark 读取 Hbase 中的数据 Spark 和 Flume-ng 整合, 可以参见本博客 : Spark 和 Flume-ng 整合 使用 Spark 读取 HBase 中的数据 如果想及时了解 Spark Hadoop 或者 Hbase 相关的文章, 欢迎关注微信公共帐号 :iteblog_hadoop 大家可能都知道很熟悉 Spark 的两种常见的数据读取方式 ( 存放到 RDD 中 ):(1)

More information

RUN_PC連載_8_.doc

RUN_PC連載_8_.doc PowerBuilder 8 (8) Web DataWindow ( ) DataWindow Web DataWindow Web DataWindow Web DataWindow PowerDynamo Web DataWindow / Web DataWindow Web DataWindow Wizard Web DataWindow Web DataWindow DataWindow

More information