穆茂强的博客 : 张开涛的博客 : 2

Size: px
Start display at page:

Download "穆茂强的博客 :http://blog.csdn.net/mhmyqn 张开涛的博客 :http://jinnianshilongnian.iteye.com/ 2"

Transcription

1 Java Servlet 规范 版本 3.1( 最终版 ) Shing Wai Chan Rajiv Mordani [ 作者 ] 穆茂强张开涛 [ 译者 ] 2012 年 6 月翻译 2013 年 7 月修订 Oracle 公司 1

2 穆茂强的博客 : 张开涛的博客 : 2

3 Servlet3.1(JSR340) 规范目前已经发布最终版本了, 已包含在 Java EE 7 平台 Servlet3.0(JSR 315) 已经 包含在 Java EE 6 平台 具体请参考本规范网站 : 前言 此文档是 Java Servlet 规范, 版本 :3.1 此文档描述了 Java Servlet API 标准 其他资料 该规范制定的目的是给 Java Servlets 一个完整和清晰的解释 如果有仍有问题, 可以查阅以下资料 : 一个参考实现 (reference implementation 简称 RI) 已经实现并提供了本规范的行为基准 (behavioral benchmark) 该参考实现没有对一个详细的特性实现去诠释, 其他实现者可以以参考实现作为原型, 以此原型完成规范 一个兼容性测试套件 (compatibility test suite 简称 CTS) 用来验证实现是否兼容 Java Servlet API 标准需求 并且测试结果为分析一个实现是不是标准实现提供了一个规范值 如果需要进一步澄清疑问, 可以咨询 Java 社区进程 (Java Community Process 简称 JCP) 控制下的 Java Servlet API 工作组, 他们是问题的最终判定者 非常欢迎建议和反馈, 这些信息可以用来改善未来版本 谁应该读此规范 规范的目标读者有如下几种 : Web Server 和 Application Server 供应商, 用于开发符合此标准的 servlet 引擎 工具供应商, 想要开发符合此规范的 Web 应用的支持工具 熟练的 servlet 开发者, 想要弄明白 servlet 技术的底层机制 此规范不是 servlet 开发人的用户指南, 而且也并不打算被用作这样 用于此目的参考文献可以到 查找 API 规范 定义了 Java Servlet API 中类 接口 方法签名的完整规范, 且附带的 Javadoc 文档有可用的在线版 其他的 Java 平台规范 此规范参考如下其他 Java API 规范 : Java Platform, Enterprise Edition ("Java EE"), version 7 JavaServer Pages ("JSP "), version 2.2 3

4 Java Naming and Directory Interface ("J.N.D.I."). Context and Dependency Injection for the Java EE Platform Managed Beans specification 这些规范可以在 Java Platform, Enterprise Edition 网站中找到 : 其他重要参考资料 以下 Internet 规范提供了一些有关开发和实现 Java Servlet API 和标准 servlet 引擎的信息 : RFC 1630 Uniform Resource Identifiers (URI) RFC 1738 Uniform Resource Locators (URL) RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax RFC 1808 Relative Uniform Resource Locators RFC 1945 Hypertext Transfer Protocol (HTTP/1.0) RFC 2045 MIME Part One: Format of Internet Message Bodies RFC 2046 MIME Part Two: Media Types RFC 2047 MIME Part Three: Message Header Extensions for non-ascii text RFC 2048 MIME Part Four: Registration Procedures RFC 2049 MIME Part Five: Conformance Criteria and Examples RFC 2109 HTTP State Management Mechanism RFC 2145 Use and Interpretation of HTTP Version Numbers RFC 2324 Hypertext Coffee Pot Control Protocol (HTCPCP/1.0)1 RFC 2616 Hypertext Transfer Protocol (HTTP/1.1) RFC 2617 HTTP Authentication: Basic and Digest Authentication RFC 3986 Uniform Resource Identifier (URI): Generic Syntax RFC 在线版本请访问 : 万维网联盟 ( 是影响本规范和实现的 HTTP 相关来源信息的权威 可扩展的标记语言 (XML): 用于此规范第 13 章描述的部署描述 更多的 XML 信息可以在以下网站找到 : 提供反馈 我们欢迎大家提供此规范的任意和所有的反馈 请发送你的建议到 jsr-315-comments@jcp.org 邮箱 4

5 请注意, 由于我们收到大量的反馈意见, 你可能不能正常收到来自工程师的回复 尽管如此, 规范团队会阅读 评估 存档每一个建议 专家组成员 Deepak Anupalli (Pramati Technologies) Euigeun Chung (TmaxSoft, Inc) Ted Goddard (Icesoft Technologies Inc) Robert Goff (IBM) Richard Hightower Seth Hodgson (Adobe Systems Inc.) Remy Maucherat (RedHat) Minoru Nitta (Fujitsu Limited) Chang Paek (TmaxSoft, Inc) Ramesh PVK (Pramati Technnologies) Alex Rojkov (Caucho Technologies) Mark Thomas (VMware) Gregory John Wilkins Wenbo Zhu (Google Inc.) 答谢 Oracle 的 Bill Shannon 为该规范提供了非常宝贵的技术投入 Oracle 的 Ron Monzillo 帮助推动了一些建议和围绕安全方面的技术讨论 5

6 目录 前言... 3 其他资料...3 谁应该读此规范...3 API 规范...3 其他的 Java 平台规范...3 其他重要参考资料...4 提供反馈...4 专家组成员...5 答谢...5 目录... 6 概览 什么是 Servlet? 什么是 Servlet 容器? 例子 Servlet 与其他技术的比较 与 Java 平台企业版的关系 与 Java Servlet 规范 2.5 版本间的兼容性 监听器 (Listener) 顺序 注解处理...14 Servlet 接口 请求处理方法 基于 Http 规范的请求处理方法 附加的方法 有条件 GET 支持 实例数量 关于 Single Thread Model Servlet 生命周期 加载和实例化 初始化 请求处理 终止服务 (End of Service)...27 Request HTTP 协议参数 当参数可用时 文件上传 属性 头 请求路径元素 路径转换方法

7 3.7 非阻塞 IO Cookies SSL 属性 国际化 请求数据编码 Request 对象的生命周期...34 Servlet Context ServletContext 接口介绍 ServletContext 接口作用范围 初始化参数 配置方法 编程式添加和配置 Servlet 编程式添加和配置 Filter 编程式添加和配置 Listener 上下文属性 资源 多主机和 Servlet 上下文 Reload 注意事项 临时工作目录...40 Response 缓冲 头信息 非阻塞 IO 简便方法 国际化 结束响应对象 Response 的生命周期...44 过滤器 什么是过滤器 过滤器组件示例 主要概念 过滤器生命周期 包装请求和响应 过滤器环境 在 Web 应用中配置过滤器 过滤器和 RequestDispatcher...49 会话 会话跟踪机制 Cookies SSL 会话 URL 重写 会话完整性 创建会话

8 7.3 会话范围 绑定 Session 属性 会话超时 最后访问时间 重要的会话语义 多线程问题 分布式环境 客户端语义...54 注解和可插拔性 注解和可插拔性 其他注解 / 惯例 可插拔性 web.xml 模块 web.xml 和 web-fragment.xml 顺序 装配 web.xml web-fragment.xml 描述符和注解 共享库 / 运行时可插拔性 JSP 容器可插拔性 处理注解和 fragment...74 分派请求 获得一个 RequestDispatcher 请求调度器路径中的查询字符串 请求调度器的使用 Include 方法 内置请求参数 Forward 方法 查询字符串 转发的请求参数 错误处理 获得一个异步上下文对象 Dispatch 方法 查询字符串 调度请求参数...78 Web 应用 Web 服务器中的 Web 应用程序 与 ServletContext 的关系 Web 应用的要素 部署层次结构 目录结构

9 应用程序目录结构示例 Web 应用程序归档文件 Web 应用程序部署描述文件 扩展的依赖关系 Web 应用程序类加载器 更新 Web 应用 错误处理 请求属性 错误页面 错误过滤器 欢迎文件 Web 应用程序环境 Web 应用程序部署 包含 web.xml 部署描述文件...86 应用生命周期事件 介绍 事件监听器 事件类型和监听器接口 监听器使用的一个例子 监听器类配置 提供监听器类 部署声明 监听器注册 关闭时通知 部署描述符示例 监听器实例和线程 监听器异常 分布式容器 会话事件...90 映射请求到 Servlet 使用 URL 路径 映射规范 隐式映射 示例映射集合...92 安全 介绍 声明式安全 编程式安全 编程式安全策略配置...94 注解 ServletRegistration.Dynamic 的 setservletsecurity 角色 认证

10 HTTP 基本认证 HTTP 摘要认证 基于表单的认证 HTTPS 客户端认证 其他容器认证机制 服务器跟踪认证信息 指定安全约束 组合约束 示例 处理请求 未覆盖的 HTTP 协议方法 默认策略 登录和退出 部署描述文件 部署描述文件元素 部署描述符处理规则 部署描述文件 部署描述文件图解 web-app 元素 description 元素 display-name 元素 icon 元素 distributable 元素 context-param 元素 filter 元素 filter-mapping 元素 listener 元素 servlet 元素 servlet-mapping 元素 session-config 元素 mime-mapping 元素 welcome-file-list 元素 error-page 元素 jsp-config 元素 security-constraint 元素 login-config 元素 security-role 元素 env-entry 元素 ejb-ref 元素 ejb-local-ref 元素 service-ref 元素 resource-ref 元素 resource-env-ref 元素 message-destination-ref 元素 message-destination 元素

11 28 locale-encoding-mapping-list 元素 实例 一个简单的例子 安全示例 与其它规范有关的要求 会话 Web 应用程序 Web 应用程序类加载器 Web 应用程序环境 Web 模块上下文根 URL 的 JNDI 名称 安全性 EJB 调用传播的安全标识 容器授权的要求 容器认证的要求 部署 部署描述符元素 打包和 JAX-WS 组件部署 处理部署描述符的规则 注解和资源注入 注解 注解 注解 注解 注解 注解 Annotation 注解 注解 注解 注解 注解 注解 JavaEE 要求的上下文和依赖注入 变更历史 A.1 自 Servlet3.0 以后的变更 A.2 自 Servlet 3.0 Proposed Final Draft 以后的变更 A.3 自 Servlet 3.0 Public Review 以后的变更 A.4 自 Servlet 3.0 EDR 以后的变更 A.5 自 Servlet 2.5 MR6 以后的变更 A.6 自 Servlet 2.5 MR 5 以后的变更 A.6.1 明确 SRV 8.4 Forward 方法 A.6.2 更新部署描述符 http-method values allowed A.6.3 明确 SRV 多线程问题

12 A.7 自 Servlet 2.5 MR 2 以后的变更 A.7.1 更新 JavaEE 容器注解的要求 A.7.2 更新 Java 企业版的要求 A.7.3 明确 HttpServletRequest.getRequestURL() A.7.4 从 HttpSession.getId() 移除 IllegalStateException A.7.5 ServletContext.getContextPath() A.7.6 web 应用中的 web.xml 的要求 A.8 自 Servlet 2.4 以后的变更 A.8.1 Session 解释 A.8.2 过滤所有分派 A.8.3 多次出现的 Servlet 映射 A.8.4 多次出现 Filter 映射 A.8.5 授权约束支持其他的 HTTP 方法 A.8.6 最低 J2SE 要求 A.8.7 注解和资源注入 A.8.8 移除了 SRV.9.9( 错误处理 ) 要求 A.8.9 明确 HttpServletRequest.isRequestedSessionIdValid() A.8.10 明确 SRV.5.5 ( 结束响应对象 ) A.8.11 明确 ServletRequest.setCharacterEncoding() A.8.12 Java 企业版要求 A.8.13 新增了 Servlet 2.4 MR 更新的变更历史 A.8.14 明确同步访问 Session 对象 A.9 自 Servlet 2.3 以后的变更 词汇表 A D P R S U W

13 概览 1.1 什么是 Servlet? Servlet 是基于 Java 技术的 web 组件, 容器托管的, 用于生成动态内容 像其他基于 Java 的组件技术一样, Servlet 也是基于平台无关的 Java 类格式, 被编译为平台无关的字节码, 可以被基于 Java 技术的 web server 动态加载并运行 容器, 有时候也叫做 servlet 引擎, 是 web server 为支持 servlet 功能扩展的部分 客户端通过 Servlet 容器实现的请求 / 应答模型与 Servlet 交互 1.2 什么是 Servlet 容器? Servlet 容器是 web server 或 application server 的一部分, 提供基于请求 / 响应发送模型的网络服务, 解码基于 MIME 的请求, 并且格式化基于 MIME 的响应 Servlet 容器也包含了管理 Servlet 生命周期 Servlet 容器可以嵌入到宿主的 web server 中, 或者通过 Web Server 的本地扩展 API 单独作为附加组件安装 Servelt 容器也可能内嵌或安装到包含 web 功能的 application server 中 所有 Servlet 容器必须支持基于 HTTP 协议的请求 / 响应模型, 比如像基于 HTTPS(HTTP over SSL) 协议的请求 / 应答模型可以选择性的支持 容器必须实现的 HTTP 协议版本包含 HTTP/1.0 和 HTTP/1.1 因为容器或许支持 RFC2616 (HTTP/1.1) 描述的缓存机制, 缓存机制可能在将客户端请求交给 Servlet 处理之前修改它们, 也可能在将 Servlet 生成的响应发送给客户端之前修改它们, 或者可能根据 RFC2616 规范直接对请求作出响应而不交给 Servlet 进行处理 Servlet 容器应该使 Servlet 执行在一个安全限制的环境中 在 Java 平台标准版 (J2SE, v.1.3 或更高 ) 或者 Java 平台企业版 (Java EE, v.1.3 或更高 ) 的环境下, 这些限制应该被放置在 Java 平台定义的安全许可架构中 比如, 高端的 application server 为了保证容器的其他组件不受到负面影响可能会限制 Thread 对象的创建 Java SE 6 是构建 Servlet 容器最低的 Java 平台版本 1.3 例子 以下是一个典型的事件序列 : 1 客户端( 如 web 浏览器 ) 发送一个 HTTP 请求到 web 服务器 ; 2 Web 服务器接收到请求并且交给 servlet 容器处理,servlet 容器可以运行在与宿主 web 服务器同一个进程中, 也可以是同一主机的不同进程, 或者位于不同的主机的 web 服务器中, 对请求进行处理 3 servlet 容器根据 servlet 配置选择相应的 servlet, 并使用代表请求和响应对象的参数进行调用 4 servlet 通过请求对象得到远程用户,HTTP POST 参数和其他有关数据可能作为请求的一部分随请求一起发送过来 Servlet 执行我们编写的任意的逻辑, 然后动态产生响应内容发送回客户端 发送数据到客户端是通过响应对象完成的 5 一旦 servlet 完成请求的处理,servlet 容器必须确保响应正确的刷出, 并且将控制权还给宿主 Web 服务器 13

14 1.4 Servlet 与其他技术的比较 从功能上看,servlet 位于公共网关接口 (CGI) 程序和私有的 server 扩展如 Netscape Server API(NSAPI) 或 Apache Modules 这两者之间 相对于其他 server 扩展机制 Servlet 有如下优势 : 它们通常比 CGI 脚本更快, 因为采用不同的处理模型 它们采用标准的 API 从而支持更多的 Web Server 它们拥有 Java 编程语言的所有优势, 包括容易开发和平台无关 它们可以访问 Java 平台提供的大量的 API 1.5 与 Java 平台企业版的关系 Java Servlet API 3.1 版本是 Java 平台企业版 7 版本 ( 必须的 API Servlet 容器和 servlet 被部署到平台中, 为了能在 Java EE 环境中执行, 必须满足 JavaEE 规范中描述的额外的一些要求 1.6 与 Java Servlet 规范 2.5 版本间的兼容性 监听器 (Listener) 顺序 该规范之前发布的版本, 监听器以随机顺序被调用 从 Servlet3.0 开始, 监听器调用顺序定义在第 8 76 页的 web.xml 装配描述符,web- fragment.xml 和注解 部分 注解处理 在 servlet 2.5 中不存在 web-fragments 的概念, 因此在 servlet2.5 中 metadata-complete 仅影响部署时的注解扫描 然而, 在 servlet 3.0 和后来版本中, 在运行时,metadata-complete 将影响扫描指定部署信息的所有注解和 web-fragments 在一个 web 应用程序中, 描述符的版本不能影响你扫描哪些注解 规范的一个典型版本实现必须扫描配置中支持的所有注解, 除非 metadata-complete 被指定 14

15 Servlet 接口 Servlet 接口是 Java Servlet API 的核心抽象 所有 Servlet 类必须直接或间接的实现该接口, 或者更通常做法 是通过继承一个实现了该接口的类从而复用许多共性功能 目前有 GenericServlet 和 HttpServlet 这两个类实 现了 Servlet 接口 大多数情况下, 开发者只需要继承 HttpServlet 去实现自己的 Servlet 即可 2.1 请求处理方法 Servlet 基础接口定义了用于客户端请求处理的 service 方法 当有请求到达时, 该方法由 servlet 容器路由到一个 servlet 实例 Web 应用程序的并发请求处理通常需要 Web 开发人员去设计适合多线程执行的 Servlet, 从而保证 service 方法能在一个特定时间点处理多线程并发执行 ( 注 : 即 Servlet 默认是线程不安全的, 需要开发人员处理多线程问题 ) 通常 Web 容器对于并发请求将使用同一个 servlet 处理, 并且在不同的线程中并发执行 service 方法 基于 Http 规范的请求处理方法 HttpServlet 抽象子类在 Servlet 接口基础之上添加了些协议相关的方法, 并且这些方法能根据 HTTP 请求类型自动的由 HttpServlet 中实现的 service 方法转发到相应的协议相关的处理方法上 这些方法是 : doget 处理 HTTP GET 请求 dopost 处理 HTTP POST 请求 doput 处理 HTTP PUT 请求 dodelete 处理 HTTP DELETE 请求 dohead 处理 HTTP HEAD 请求 dooptions 处理 HTTP OPTIONS 请求 dotrace 处理 HTTP TRACE 请求一般情况下, 当开发基于 HTTP 协议的 Servlet 时,Servlet 开发人员将仅去实现 doget 和 dopost 请求处理方法即可 如果开发人员想使用其他处理方法, 其使用方式跟之前的是类似的, 即 HTTP 编程都是类似 附加的方法 doput 和 dodelete 方法允许 Servlet 开发人员让支持 HTTP/1.1 的客户端使用这些功能 HttpServlet 中的 dohead 方法可以认为是 doget 方法的一个特殊形式, 它仅返回由 doget 方法产生的 header 信息 dooptions 方法返回当前 servlet 支持的 HTTP 方法 ( 译者注 : 通过 Allow 响应头返回支持的 HTTP 操作, 如 GET POST) dotrace 方法返回的响应包含 TRACE 请求的所有头信息 15

16 2.1.3 有条件 GET 支持 HttpServlet 定义了用于支持有条件 GET 操作的 getlastmodified 方法 所谓的有条件 GET 操作是指客户端 通过 GET 请求获取资源时, 当资源自第一次获取那个时间点发生更改后才再次发生数据, 否则将使用客户 端缓存的数据 在一些适当的场合, 实现此方法可以更有效的利用网络资源, 减少不必要的数据发送 2.2 实例数量 通过注解描述的 ( 第 8 章注解和可插拔性 ) 或者在 Web 应用程序的部署描述符 ( 第 14 章部署描述符 ) 中描述的 servlet 声明, 控制着 servlet 容器如何提供 servlet 实例 对于未托管在分布式环境中 ( 默认 ) 的 servlet 而言,servlet 容器对于每一个 Servlet 声明必须且只能产生一个实例 不过, 如果 Servlet 实现了 SingleThreadModel 接口,servlet 容器可以选择实例化多个实例以便处理高负荷请求或者串行化请求到一个特定实例 如果 servlet 以分布式方式进行部署, 容器可以为每个虚拟机 (JVM) 的每个 Servlet 声明产生一个实例 但是, 如果在分布式环境中 servlet 实现了 SingleThreadModel 接口, 此时容器可以为每个容器的 JVM 实例化多个 Servlet 实例 关于 Single Thread Model SingleThreadModel 接口的作用是保证一个特定 servlet 实例的 service 方法在一个时刻仅能被一个线程执行, 一定要注意, 此保证仅适用于每一个 servlet 实例, 因此容器可以选择池化这些对象 有些对象可以在同一时刻被多个 servlet 实例访问, 如 HttpSession 实例, 可以在一个特定的时间对多个 Servlet 可用, 包括那些实现了 SingleThreadModel 接口的 Servlet 2.3 Servlet 生命周期 Servlet 是按照一个严格定义的生命周期被管理, 该生命周期规定了 Servlet 如何被加载 实例化 初始化 处理客户端请求, 以及何时结束服务 该声明周期可以通过 javax.servlet.servlet 接口中的 init service 和 destroy 这些 API 来表示, 所有 Servlet 必须直接或间接的实现 GenericServlet 或 HttpServlet 抽象类 加载和实例化 Servlet 容器负责加载和实例化 Servlet 加载和实例化可以发生在容器启动时, 或者延迟初始化直到容器决定有请求需要处理时 当 Servlet 引擎启动后,servlet 容器必须定位所需要的 Servlet 类 Servlet 容器使用普通的 Java 类加载设施加载 Servlet 类 可以从本地文件系统或远程文件系统或者其他网络服务加载 加载完 Servlet 类后, 容器就可以实例化它并使用了 初始化 一旦一个 Servlet 对象实例化完毕, 容器接下来必须在处理客户端请求之前初始化该 Servlet 实例 初始化的目的是以便 Servlet 能读取持久化配置数据, 初始化一些代价高的资源 ( 比如 JDBC API 连接 ), 或者执行一些一次性的动作 容器通过调用 Servlet 实例的 init 方法完成初始化,init 方法定义在 Servlet 接口中, 并且提供一个唯一的 ServletConfig 接口实现的对象作为参数, 该对象每个 Servlet 实例一个 16

17 配置对象允许 Servlet 访问由 Web 应用配置信息提供的键 - 值对的初始化参数 该配置对象也提供给 Servlet 去访问一个 ServletContext 对象,ServletContext 描述了 Servlet 的运行时环境 请参考第 4 章, Servlet Context 获取 ServletContext 接口的更多信息 初始化时的错误条件在初始化阶段,servlet 实现可能抛出 UnavailableException 或 ServletException 异常 在这种情况下,Servlet 不能放置到活动服务中, 而且 Servlet 容器必须释放它 如果初始化没有成功,destroy 方法不应该被调用 在实例初始化失败后容器可能再实例化和初始化一个新的实例 此规则的例外是, 当抛出的 UnavailableException 表示一个不可用的最小时间, 容器在创建和初始化一个新的 servlet 实例之前必须等待一段时间 使用工具时的注意事项当一个工具加载并内省某个 Web 应用程序时触发的静态初始化, 这种用法与调用 init 初始化方法是有区别的 在 Servlet 的 init 方法没被调用, 开发人员不应该假定其处于活动的容器环境内 比如, 当某个 Servlet 仅有静态方法被调用时, 不应该与数据库或企业级 JavaBean(EJB) 容器建立连接 请求处理 Servlet 完成初始化后,Servlet 容器就可以使用它处理客户端请求了 客户端请求由 ServletRequest 类型的 request 对象表示 Servlet 封装响应并返回给请求的客户端, 该响应由 ServletResponse 类型的 response 对象表示 这两个对象 (request 和 response) 是由容器通过参数传递到 Servlet 接口的 service 方法的 在 HTTP 请求的场景下, 容器提供的请求和响应对象具体类型分别是 HttpServletRequest 和 HttpServletResponse 需要注意的是, 由 Servlet 容器初始化的某个 Servlet 实例在服务期间, 可以在其生命周期中不处理任何请求 多线程问题 Servlet 容器可以并发的发送多个请求到 Servlet 的 service 方法 为了处理这些请求,Servlet 开发者必须为 service 方法的多线程并发处理做好充足的准备 一个替代的方案是开发人员实现 SingleThreadModel 接口, 由容器保证一个 service 方法在同一个时间点仅被一个请求线程调用, 但是此方案是不推荐的 Servlet 容器可以通过串行化访问 Servlet 的请求, 或者维护一个 Servlet 实例池完成该需求 如果 Web 应用中的 Servlet 被标注为分布式的, 容器应该为每一个分布式应用程序的 JVM 维护一个 Servlet 实例池 对于那些没有实现 SingleThreadModel 接口的 Servlet, 但是它的 service 方法 ( 或者是那些 HttpServlet 中通过 service 方法分派的 doget dopost 等分派方法 ) 是通过 synchronized 关键词定义的,Servlet 容器不能使用实例池方案, 并且只能使用序列化请求进行处理 强烈推荐开发人员不要去通过 service 方法 ( 或者那些由 Service 分派的方法 ), 因为这将严重影响性能 请求处理时的异常 Servlet 在处理一个请求时可能抛出 ServletException 或 UnavailableException 异常 ServletException 表示在处理请求时出现了一些错误, 容器应该采取适当的措施清理掉这个请求 UnavailableException 表示 servlet 目前无法处理请求, 或者临时性的或者永久性的 如果 UnavailableException 表示的是一个永久性的不可用,Servlet 容器必须从服务中移除这个 Servlet, 调用 17

18 它的 destroy 方法, 并释放 Servlet 实例 所有被容器拒绝的请求, 都会返回一个 SC_NOT_FOUND (404) 响应 如果 UnavailableException 表示的是一个临时性的不可用, 容器可以选择在临时不可用的这段时间内路由任何请求到 Servlet 所以在这段时间内被容器拒绝的请求, 都会返回一个 SC_SERVICE_UNAVAILABLE (503) 响应状态码, 且同时会返回一个 Retry-After 头指示此 Servlet 什么时候可用 容器可以选择忽略永久性和临时性不可用的区别, 并把 UnavailableExceptions 视为永久性的, 从而 Servlet 抛出 UnavailableException 后需要把它从服务中移除 异步处理有时候,Filter 及 / 或 Servlet 在生成响应之前必须等待一些资源或事件以便完成请求处理 比如,Servlet 在进行生成一个响应之前可能等待一个可用的 JDBC 连接, 或者一个远程 web 服务的响应, 或者一个 JMS 消息, 或者一个应用程序事件 在 Servlet 中等待是一个低效的操作, 因为这是阻塞操作, 从而白白占用一个线程或其他一些受限资源 许多线程为了等待一个缓慢的资源比如数据库经常发生阻塞, 可能引起线程饥饿, 且降低整个 Web 容器的服务质量 当 Servlet 3.0 引入了异步处理请求的能力, 使线程可以返回到容器, 从而执行更多的任务 当开始异步处理请求时, 另一个线程或回调可以或者产生响应, 或者调用完成 (complete) 或请求分派 (dispatch), 这样, 它可以在容器上下文使用 AsyncContext.dispatch 方法运行 一个典型的异步处理事件顺序是 : 1. 请求被接收到, 通过一系列如用于验证的等标准的 filter 之后被传递到 Servlet 2. servlet 处理请求参数及 ( 或 ) 内容体从而确定请求的类型 3. 该 servlet 发出请求去获取一些资源或数据, 例如, 发送一个远程 web 服务请求或加入一个等待 JDBC 连接的队列 4. servlet 不产生响应并返回 5. 过了一段时间后, 所请求的资源变为可用, 此时处理线程继续处理事件, 要么在同一个线程, 要么通过 AsyncContext 分派到容器中的一个资源上 Java 企业版的功能, 如第 节, 在第 页的 Web 应用环境 和第 节, 在第 页的 EJB 调用的安全标识传播, 仅提初始化请求的线程执行, 或者请求经过 AsyncContext.dispatch 方法被分派到容器 Java 企业版的功能可能支持由 AsyncContext.start(Runnable) 方法使用其他线程直接操作响应对象 注解有一个属性 asyncsupported,boolean 类型默认值为 false 当 asyncsupported 设置为 true, 应用通过执行 startasync( 见下文 ) 可以启动一个单独的线程中进行异步处理, 并把请求和响应的引用传递给这个线程, 然后退出原始线程所在的容器 这意味着响应将遍历 ( 相反的顺序 ) 与进入时相同的过滤器 ( 或过滤器链 ) 直到 AsyncContext 调用 complete( 见下文 ) 时响应才会被提交 如果异步任务在容器启动的分派之前执行, 且调用了 startasync 并返回给容器, 此时应用需负责处理请求和响应对象的并发访问 从一个 Servlet 分派时, 把 asyncsupported=true 设置为 false 是允许的 这种情况下, 当 servlet 的 service 方法不支持异步退出时, 响应将被提交, 且容器负责调用 AsyncContext 的 complete, 以便所有感兴趣的 AsyncListener 得到触发知 过滤器作为清理要完成的异步任务持有的资源的一种机制, 也应该使用 AsyncListener. oncomplete 触发的结果 从一个同步 Servlet 分派到另一个异步 Servlet 是非法的 不过与该点不同的是当应用调用 startasync 时将抛出 IllegalStateException 这将允许 servlet 只能作为同步的或异步的 Servlet 18

19 应用在一个与初始请求所用的不同的线程中等待异步任务直到可以直接写响应, 这个线程不知道任何过滤器 如果过滤器想处理新线程中的响应, 那就必须在处理进入时的初始请求时包装 response, 并且把包装的 response 传递给链中的下一个过滤器, 并最终交给 Servlet 因此, 如果响应是包装的 ( 可能被包装多次, 每一个过滤器一次 ), 并且应用处理请求并直接写响应, 这将只写响应的包装对象, 即任何输出的响应都会由响应的包装对象处理 当应用在一个单独的线程中读请求时, 写内容到响应的包装对象, 这其实是从请求的包装对象读取, 并写到响应的包装对象, 因此对包装对象操作的所有输入及 ( 或 ) 输出将继续存在 如果应用选择这样做的话, 它将可以使用 AsyncContext 从一个新线程发起到容器资源的分派请求 这将允许在容器范围内使用像 JSP 这种内容生成技术 除了注解属性外, 我们还添加了如下方法 / 类 : ServletRequest public AsyncContext startasync(servletrequest req, ServletResponse res) 这个方法的作用是将请求转换为异步模式, 并使用给定的请求及响应对象和 getasynctimeout 返回的超时时间初始化它的 AsyncContext ServletRequest 和 ServletResponse 参数必须是与传递给 servlet 的 service 或 filter 的 dofilter 方法相同的对象, 或者是 ServletRequestWrapper 和 ServletResponseWrapper 子类的包装对象 当应用退出 service 方法时, 调用该方法必须确保 response 没有被提交 当调用返回的 AsyncContext 的 AsyncContext.complete 或 AsyncContext 超时并且没有监听器处理超时时, 它将被提交 异步超时定时器直到请求和它关联的响应从容器返回时才启动 AsyncContext 可以被异步线程用来写响应, 它也能用来通知没有关闭和提交的响应 如果请求在不支持异步操作的 servlet 或 filter 范围中调用 startasync, 或者响应已经被提交或关闭, 或者在同一个分派期间重复调用, 这些是非法的 从调用 startasync 返回的 AsyncContext 可以接着被用来进行进一步的异步处理 调用返回的 AsyncContext 的 hasoriginalrequestresponse() 方法将返回 false, 除非传过去的 ServletRequest 和 ServletResponse 参数是最原始的那个或不是应用提供的包装器 在请求设置为异步模式后, 在入站调用期间添加的一些请求及 ( 或 ) 响应的包装器可能需要在异步操 作期间一直保持, 并且它们关联的资源可能也不会释放, 出站方向调用的所有过滤器可以以此作为一 个标志 一个在入站调用期间的过滤器应用的 ServletRequestWrapper 可以被出站调用的过滤器释放, 只有当给 定的 ServletRequest 是由 AsyncContext 初始化的且通过调用 AsyncContext.getRequest() 返回的, 不包括 之前说的 ServletRequestWrapper 这规则同样适用于 ServletResponseWrapper 实例 public AsyncContext startasync() 是一个简便方法, 使用原始请求和响应对象用于异步处理 请注意, 如果它们在你想调用此方法之前被包装了, 这个方法的使用者应该刷出 (flush) 响应, 确保数据写到 19

20 被包装的响应中没有丢失 public AsyncContext getasynccontext() 返回由 startasync 调用创建的或初始化的 AsyncContext 如 果请求已经被设置为异步模式, 调用 getasynccontext 是非法的 public boolean isasyncsupported() 如果请求支持异常处理则返回 true, 否则返回 false 一旦请求传 给了过滤器或 servlet 不支持异步处理 ( 通过指定的注解或声明 ), 异步支持将被禁用 public boolean isasyncstarted() 如果请求的异步处理已经开始将返回 true, 否则返回 false 如果这 个请求自从被设置为异步模式后已经使用任意一个 AsyncContext.dispatch 方法分派, 或者成功调用了 AsynContext.complete 方法, 这个方法将返回 false public DispatcherType getdispatchertype() 返回请求的分派器 (dispatcher) 类型 容器使用请求的分派器类型来选择需要应用到请求的过滤器 只有匹配分派器类型和 url 模式 (url pattern) 的过滤器才会被应用 允许一个过滤器配置多个分派器类型, 过滤器可以根据请求的不同分派器类型处理请求 请求的初始分派器类型定义为 DispatcherType.REQUEST 使用 RequestDispatcher.forward(ServletRequest, ServletResponse) 或 RequestDispatcher.include(ServletRequest, ServletResponse) 分派时, 它们的请求的分派器类型分别是 DispatcherType.FORWARD 或 DispatcherType.INCLUDE, 当一个异步请求使用任意一个 AsyncContext.dispatch 方法分派时该请求的 分派器类型是 DispatcherType.ASYNC 最后, 由容器的错误处理机制分派到错误页面的分派器类型是 DispatcherType.ERROR AsyncContext 该类表示在 ServletRequest 启动的异步操作执行上下文,AsyncContext 由之前描述的 ServletRequest.startAsync 创建并初始化 AsyncContext 的方法 : public ServletRequest getrequest() 返回调用 startasync 用于初始化 AsyncContext 的请求对象 当在 异步周期之前调用了 complete 或任意一个 dispatch 方法, 调用 getrequest 将抛出 IllegalStateException public ServletResponse getresponse() 返回调用 startasync 用于初始化 AsyncContext 的响应对象 当 在异步周期之前调用了 complete 或任意一个 dispatch 方法, 调用 getresponse 将抛出 IllegalStateException public void settimeout(long timeoutmilliseconds) 设置异步处理的超时时间, 以毫秒为单位 该方法调用将覆盖容器设置的超时时间 如果没有调用 settimeout 设置超时时间, 将使用容器默认的超时时间 一个小于等于 0 的数表示异步操作将永不超时 当调用任意一个 ServletRequest.startAsync 方法时, 一旦容器启动的分派返回到容器, 超时时间将应用到 AsyncContext 当在异步周期开始时容器启动的 20

21 分派已经返回到容器后, 再设置超时时间是非法的, 这将抛出一个 IllegalStateException 异常 public long gettimeout() 获取 AsyncContext 关联的超时时间的毫秒值 该方法返回容器默认的超时 时间, 或最近一次调用 settimeout 设置超时时间 public void addlistener(asynclistener listener, ServletRequest req, ServletResponse res) 注册一个用于 接收的 ontimeout, onerror, oncomplete 或 onstartasync 通知的监听器 前三个是与最近通过调用任意 ServletRequest.startAsync 方法启动的异步周期相关联的 onstartasync 是与通过任意 ServletRequest.startAsync 启动的一个新的异步周期相关联的 异步监听器将以它们添加到请求时的顺序得到通知 当 AsyncListener 得到通知, 传入到该方法的请求响应对象与 AsyncEvent.getSuppliedRequest() 和 AsyncEvent.getSuppliedResponse() 是完全相同的 不应该对这些对象进行读取或写入, 因为自从注册了 AsyncListener 后可能发生了额外的包装, 不过可以被用来按顺序释放与它们关联的资源 容器启动的分派在异步周期启动后返回到容器后, 或者在一个新的异步周期启动之前, 调用该方法是非法的, 将抛出 IllegalStateException public <T extends AsyncListener> createlistener(class<t> clazz) 实例化指定的 AsyncListener 类 返回的 AsyncListener 实例在使用下文描述的 addlistener 方法注册到 AsyncContext 之前可能需要进一步的自定义 给定的 AsyncListener 类必须定义一个用于实例化的空参构造器, 该方法支持适用于 AsyncListener 的所有注解 public void addlistener(asynclistener) 注册给定的监听器用于接收 ontimeout, onerror, oncomplete 或 onstartasync 通知 前三个是与最近通过调用任意 ServletRequest.startAsync 方法启动的异步周期相关联的 onstartasync 是与通过任意 ServletRequest.startAsync 启动的一个新的异步周期相关联的 异步监听器将以它们添加到请求时的顺序得到通知 当 AsyncListener 接收到通知, 如果在请求时调用 startasync(req, res) 或 startasync(), 从 AsyncEvent 会得到同样的请求和响应对象 请求和响应对象可以是或者不是被包装的 异步监听器将以它们添加到请求时的顺序得到通知 容器启动的分派在异步周期启动后返回到容器后, 或者在一个新的异步周期启动之前, 调用该方法是非法的, 将抛出 IllegalStateException public void dispatch(string path) 将用于初始化 AsyncContext 的请求和响应分派到指定的路径的资源 该路径以相对于初始化 AsyncContext 的 ServletContext 进行解析 与请求查询方法相关的所有路径, 必须反映出分派的目标, 同时原始请求的 URI, 上下文, 路径信息和查询字符串都可以从请求属性中获取, 请求属性定义在 9-98 页的 章节, 分派的请求参数 这些属性必须反映最原始的路径元素, 即使在多次分派之后 21

22 public void dispatch() 一个简便方法, 使用初始化 AsyncContext 时的请求和响应进行分派, 如下所示 如果使用 startasync(servletrequest, ServletResponse) 初始化 AsyncContext, 且传入的请求是 HttpServletRequest 的一个实例, 则使用 HttpServletRequest.getRequestURI() 返回的 URI 进行分派 否则分派的是容器最后分派的请求 URI 下面的代码示例 2-1, 代码示例 2-2 和代码示例 2-3 演示了不同情况下分派的目标 URI 是什么 代码示例 2-1: // 请求到 /url/a AsyncContext ac = request.startasync();... ac.dispatch(); // 异步分派到 /url/a 代码示例 2-2 : // 请求到 /url/a // 转发到 /url/b request.getrequestdispatcher( /url/b ).forward(request, response); // 从 FORWARD 的目标内启动异步操作 AsyncContext ac = request.startasync(); ac.dispatch(); // 异步分派到 /url/a 代码示例 2-3: // 请求到 /url/a // 转发到 /url/b request.getrequestdispatcher( /url/b ).forward(request, response); // 从 FORWARD 的目标内启动异步操作 AsyncContext ac = request.startasync(request, response); ac.dispatch(); // 异步分派到 /url/b public void dispatch(servletcontext context, String path) - 将用于初始化 AsyncContext 的请求和响应分 派到指定 ServletContext 的指定路径的资源 之上定义了 dispatch 方法的全部 3 个变体, 调用这些方法且将请求和响应对象传入到容器的一个托管线程后将立即返回, 在托管线程中异步操作将被执行 请求的分派器类型设置为异步 (ASYNC) 不同于 RequestDispatcher.forward(ServletRequest, ServletResponse) 分派, 响应的缓冲区和头信息将不会重置, 即使响应已经被提交分派也是合法的 控制委托给分派目标的请求和响应, 除非调用了 22

23 ServletRequest.startAsync() 或 ServletRequest.startAsync(ServletRequest, ServletResponse), 否则响应将在分派目标执行完成时被关闭 在调用了 startasync 方法的容器启动的分派没有返回到容器之前任何 dispatch 方法的调用将没有任何作用 AsyncListener.onComplete(AsyncEvent), AsyncListener.onTimeout(AsyncEvent) 和 AsyncListener.onError(AsyncEvent) 的调用将被延迟到容器启动的分派返回到容器之后 通过调用 ServletRequest.startAsync. 启动的每个异步周期至多只有一个异步分派操作 相同的异步周期内任何试图执行其他的异步分派操作是非法的并将导致抛出 IllegalStateException 如果后来在已分派的请求上调用 startasync, 那么所有的 dispatch 方法调用将和之上具有相同的限制 任何在执行 dispatch 方法期间可能抛出的错误或异常必须由容器抓住和处理, 如下所示 : i. 调用所有由 AsyncContext 创建的并注册到 ServletRequest 的 AsyncListener 实例的 AsyncListener.onError(AsyncEvent) 方法, 可以通过 AsyncEvent.getThrowable() 获取到捕获的 Throwable ii. 如果没有监听器调用 AsyncContext.complete 或任何 AsyncContext.dispatch 方法, 然后执行一 个状态码为 HttpServletResponse.SC_INTERNAL_SERVER_ERROR 的出错分派, 并且可以通过 RequestDispatcher.ERROR_EXCEPTION 请求属性获取 Throwable 值 iii. 如果没有找到匹配的错误页面, 或错误页面没有调用 AsyncContext.complete() 或任何 AsyncContext.dispatch 方法, 则容器必须调用 AsyncContext.complete public boolean hasoriginalrequestandresponse() 该方法检查 AsyncContext 是否以原始的请求和响 应对象调用 ServletRequest.startAsync() 完成初始化的, 或者是否通过调用 ServletRequest.startAsync(ServletRequest, ServletResponse) 完成初始化的, 且传入的 ServletRequest 和 ServletResponse 参数都不是应用提供的包装器, 这样的话将返回 true 如果 AsyncContext 使用包装的请求及 ( 或 ) 响应对象调用 ServletRequest.startAsync(ServletRequest, ServletResponse) 完成初始化, 那么将返回 false 在请求处于异步模式后, 该信息可以被出站方向调用的过滤器使用, 用于决定是否在入站调用时添加的请求及 ( 或 ) 响应包装器需要在异步操作期间被维持或者被释放 public void start(runnable r) 该方法导致容器分派一个线程, 该线程可能来自托管的线程池, 用于 运行指定的 Runnable 对象 容器可能传播相应的上下文信息到该 Runnable 对象 public void complete() 如果调用了 request.startasync, 则必须调用该方法以完成异步处理并提交和 关闭响应 如果请求分派到一个不支持异步操作的 Servlet, 或者由 AsyncContext.dispatch 调用的目标 23

24 servlet 之后没有调用 startasync, 则 complete 方法会由容器调用 这种情况下, 容器负责当 servlet 的 service 方法一退出就调用 complete() 如果 startasync 没有被调用则必须抛出 IllegalStateException 在调用 ServletRequest.startAsync() 或 ServletRequest.startAsync(ServletRequest, ServletResponse) 之后且在调用任意 dispatch 方法之前的任意时刻调用 complete() 是合法的 在调用了 startasync 方法的容器启动的分派没有返回到容器之前该方法的调用将没有任何作用 AsyncListener.onComplete(AsyncEvent) 的调用将被延迟到容器启动的分派返回到容器之后 ServletRequestWrapper public boolean iswrapperfor(servletrequest req)- 检查该包装器是否递归的包装了给定的 ServletRequest, 如果是则返回 true, 否则返回 false ServletResponseWrapper public boolean iswrapperfor(servletresponse res)- 检查该包装器是否递归的包装了给定的 ServletResponse, 如果是则返回 true, 否则返回 false AsyncListener public void oncomplete(asyncevent event) 用于通知监听器在 Servlet 上启动的异步操作完成了 public void onerror(asyncevent event) 用于通知监听器异步操作未能完成 public void onstartasync(asyncevent event) 用于通知监听器正在通过调用一个 ServletRequest.startAsync 方法启动一个新的异步周期 正在被重新启动的异步操作对应的 AsyncContext 可以通过调用给定的 event 上调用 AsyncEvent.getAsyncContext 获取 在异步操作超时的情况下, 容器必须按照如下步骤运行 : 当异步操作启动后调用注册到 ServletRequest 的所有 AsyncListener 实例的 AsyncListener.onTimeout 方 法 如果没有监听器调用 AsyncContext.complete() 或任何 AsyncContext.dispatch 方法, 执行一个状态码 为 HttpServletResponse.SC_INTERNAL_SERVER_ERROR 出错分派 如果没有找到匹配的错误页面, 或者错误页面没有调用 AsyncContext.complete() 或任何 AsyncContext.dispatch 方法, 则容器必须调用 AsyncContext.complete() 如果在 AsyncListener 中调用方法抛出异常, 将记录下来且将不影响任何其他 AsyncListener 的调用 24

25 默认情况下是不支持 JSP 中的异步处理, 因为它是用于内容生成且异步处理可能在内容生成之前已经完 成 这取决于容器如何处理这种情况 一旦完成了所有的异步活动, 使用 AsyncContext.dispatch 分派到的 JSP 页面可以用来生成内容 下面所示的图 2-1 描述了各种异步操作的状态转换 25

26 线程安全 除了 startasync 和 complete 方法, 请求和响应对象的实现都不保证线程安全 这意味着它们应该仅在请求 26

27 处理线程范围内使用或应用确保线程安全的访问请求和响应对象 如果应用使用容器管理对象创建一个线程, 例如请求或响应对象, 这些对象必须在其生命周期内被访问, 就像定义在 3-31 页 3.12 节的 Request 对象的生命周期 和 5.7 节的 Response 对象的生产周期 请注意, 除了 startasync 和 complete 方法, 请求和响应对象不是线程安全的 如果这些对象需要多线程访问, 需要同步这些访问或通过包装器添加线程安全语义, 比如, 同步化调用访问请求属性的方法, 或者在线程内为响应对象使用一个局部输出流 升级处理在 HTTP/1.1,Upgrade 通用头 (general-header) 允许客户端指定其支持和希望使用的其他通信协议 如果服务器找到合适的切换协议, 那么新的协议将在之后的通信中使用 Servlet 容器提供了 HTTP 升级机制 不过,Servlet 容器本身不知道任何升级协议 协议处理封装在 HttpUpgradeHandler 协议处理器 在容器和 HttpUpgradeHandler 协议处理器之间通过字节流进行数据读取或写入 当收到一个升级 (upgrade) 请求,servlet 可以调用 HttpServletRequest.upgrade 方法启动升级处理 该方法实例化给定的 HttpUpgradeHandler 类, 返回的 HttpUpgradeHandler 实例可以被进一步的定制 应用准备和发送一个合适的响应到客户端 退出 servlet service 方法之后,servlet 容器完成所有过滤器的处理并标记连接已交给 HttpUpgradeHandler 协议处理器处理 然后调用 HttpUpgradeHandler 协议处理器的 init 方法, 传入一个 WebConnection 以允许 HttpUpgradeHandler 协议处理器访问数据流 Servlet 过滤器仅处理初始的 HTTP 请求和响应, 然后它们将不会再参与到后续的通信中 换句话说, 一旦 请求被升级, 它们将不会被调用 协议处理器 (ProtocolHandler) 可以使用非阻塞 IO(non blocking IO) 消费和生产消息 当处理 HTTP 升级时, 开发人员负责线程安全的访问 ServletInputStream 和 ServletOutputStream 当升级处理已经完成, 将调用 HttpUpgradeHandler.destroy 方法 终止服务 (End of Service) Servlet 容器没必要保持装载的 Servlet 持续任何特定的一段时间 一个 Servlet 实例可能会在 servlet 容器内 保持活跃 (active) 持续一段时间 ( 以毫秒为单位 ),Servlet 容器的寿命可能是几天, 几个月, 或几年, 或 者是任何之间的时间 当 Servlet 容器确定 servlet 应该从服务中移除时, 将调用 Servlet 接口的 destroy 方法以允许 Servlet 释放它使 用的任何资源和保存任何持久化的状态 例如, 当想要节省内存资源或它被关闭时, 容器可以做这个 27

28 在 servlet 容器调用 destroy 方法之前, 它必须让当前正在执行 service 方法的任何线程完成执行, 或者超过 了服务器定义的时间限制 一旦调用了 servlet 实例的 destroy 方法, 容器无法再路由其他请求到该 servlet 实例了 如果容器需要再次 使用该 servlet, 它必须用该 servlet 类的一个新的实例 在 destroy 方法完成后,servlet 容器必须释放 servlet 实例以便被垃圾回收 28

29 Request 请求对象封装了客户端请求的所有信息 在 HTTP 协议中, 这些信息是从客户端发送到服务器请求的 HTTP 头部和消息体 3.1 HTTP 协议参数 servlet 的请参数以字符串的形式作为请求的一部分从客户端发送到 servlet 容器 当请求是一个 HttpServletRequest 对象, 且符合第 24 页中 参数可用时 描述的条件时, 容器从 URI 查询字符串和 POST 数据中填充参数 参数以一系列的名 - 值对的形式保存 任何给定的参数的名称可存在多个参数值 ServletRequest 接口的下列方法可访问这些参数 : getparameter getparameternames getparametervalues getparametermap getparametervalues 方法返回一个 String 对象的数组, 包含了与参数名称相关的所有参数值 getparameter 方法的返回值必须是 getparametervalues 方法返回的 String 对象数组中的第一个值 getparametermap 方法 返回请求参数的一个 java.util.map 对象, 其中以参数名称作为 map 键, 参数值作为 map 值 查询字符串和 POST 请求的数据被汇总到请求参数集合中 查询字符串数据在 POST 数据之前发送 例如, 如果请求由查询字符串 a =hello 和 POST 数据 a=goodbye&a=world 组成, 得到的参数集合顺序将是 =(hello,goodbye,world) 这些 API 不会暴露 GET 请求 (HTTP 1.1 所定义的 ) 的路径参数 他们必须从 getrequesturi 方法或 getpathinfo 方法返回的字符串值中解析 当参数可用时 以下是在 POST 表单数据填充到参数集前必须满足的条件 : 1 该请求是一个 HTTP 或 HTTPS 请求 2 HTTP 方法是 POST 3 内容类型是 application/x-www-form-urlencoded 4 该 servlet 已经对 request 对象的任意 getparameter 方法进行了初始调用 如果不满足这些条件, 而且参数集中不包括 POST 表单数据, 那么 servlet 必须可以通过 request 对象的输入流得到 POST 数据 如果满足这些条件, 那么从 request 对象的输入流中直接读取 POST 数据将不再有效 29

30 3.2 文件上传 当数据以 multipart/form-data 的格式发送时,servlet 容器支持文件上传 如果满足以下任何一个条件,servlet 容器提供 multipart/form-data 格式数据的处理, servlet 处理第 节,8-68 标注的请求 为了 servlet 处理请求, 部署描述符包含了一个 multipart-config 元素 如何使 request 中 multipart/form-data 类型的数据可用, 取决于 servlet 容器是否提供 multipart/form-data 格式数据的处理 : 如果 servlet 容器提供 multipart/form-data 格式数据的处理, 可通过 HttpServletRequest 中的以下方法得到 : public Collection<Part> getparts() public Part getpart(string name) 译者注 :Part 类代表从 multipart/form-data 格式的 POST 请求中接收到的一个部分或表单项 每个 part 都可通过 Part.getInputStream 方法访问头部, 相关的内容类型和内容 对于表单数据的 Content-Disposition, 即使没有文件名, 也可使用 part 的名称通过 HttpServletRequest 的 getparameter 和 getparametervalues 方法得到 part 的字符串值 如果 servlet 的容器不提供 multi-part/form-data 格式数据的处理, 这些数据将可通过 HttpServletReuqest.getInputStream 得到 3.3 属性 属性是与请求相关联的对象 属性可以由容器设置来表达信息, 否则无法通过 API 表示, 或者由 servlet 设置将信息传达给另一个 servlet( 通过 RequestDispatcher) 属性通过 ServletRequest 接口中下面的方法来访问 : getattribute getattributenames setattribute 只有一个属性值可与一个属性名称相关联 以前缀 java. 和 javax. 开头的属性名称是本规范的保留定义 同样地, 以前缀 sun. 和 com.sun.,oracle 和 com.oracle 开头的属性名是 Oracle Corporation 的保留定义 建议属性集中所有属性的命名与 Java 编程语言的规范 1 为包命名建议的反向域名约定一致 3.4 头 servlet 可以通过 HttpServletRequest 接口的下面方法访问 HTTP 请求的头部信息 : getheader getheaders getheadernames 30

31 getheader 方法返回给定头名称的头 多个头可以具有相同的名称, 例如 HTTP 请求中的 Cache-Control 头 如果多个头的名称相同,getHeader 方法返回请求中的第一个头 getheaders 方法允许访问所有与特定头名称相关的头值, 返回一个 String 对象的枚举 头可包含由 String 形式的 int 或 Date 数据 HttpServletRequest 接口提供如下方便的方法访问这些类型的头数据 : getintheader getdateheader 如果 getintheader 方法不能转换为 int 的头值, 则抛出 NumberFormatException 异常 如果 getdateheader 方法不能把头转换成一个 Date 对象, 则抛出 IllegalArgumentException 异常 3.5 请求路径元素 引导 servlet 服务请求的请求路径由许多重要部分组成 以下元素从请求 URI 路径得到, 并通过 request 对象公开 : Context Path: 与 ServletContext 相关联的路径前缀是这个 servlet 的一部分 如果这个上下文是基于 Web 服务器的 URL 命名空间基础上的 默认 上下文, 那么这个路径将是一个空字符串 否则, 如果上下文不是基于服务器的命名空间, 那么这个路径以 / 字符开始, 但不以 / 字符结束 Servlet Path: 路径部分直接与激活请求的映射对应 这个路径以 / 字符开头, 如果请求与 / * 或 模式匹配, 在这种情况下, 它是一个空字符串 PathInfo: 请求路径的一部分, 不属于 Context Path 或 Servlet Path 如果没有额外的路径, 它要么是 null, 要么是以 '/' 开头的字符串 使用 HttpServletRequest 接口中的下面方法来访问这些信息 : getcontextpath getservletpath getpathinfo 重要的是要注意, 除了请求 URI 和路径部分的 URL 编码差异外, 下面的等式永远为真 : requesturi = contextpath + servletpath + pathinfo 举几个例子来澄清上述各点, 请考虑以下几点 : 表 3-1 上下文设置的例子 Context Path Servlet Mapping Servlet Mapping Servlet Mapping /catalog Pattern: /lawn/* Servlet: LawnServlet Pattern: /garden/* Servlet: GardenServlet Pattern: *.jsp Servlet: JSPServlet 31

32 遵守下列行为 : 表 3-2 遵守路径元素行为 请求路径 /catalog/lawn/index.html /catalog/garden/implements/ /catalog/help/feedback.jsp 路径元素 ContextPath: /catalog ServletPath: /lawn PathInfo: /index.html ContextPath: /catalog ServletPath: /garden PathInfo: /implements/ ContextPath: /catalog ServletPath: /help/feedback.jsp PathInfo: null 3.6 路径转换方法 在 API 中有两个方便的方法, 允许开发者获得与某个特定的路径等价的文件系统路径 这些方法是 : ServletContext.getRealPath HttpServletRequest.getPathTranslated getrealpath 方法需要一个字符串参数, 并返回一个字符串形式的路径, 这个路径对应一个在本地文件系统上的文件 getpathtranslated 方法推断出请求的 pathinfo 的实际路径 ( 译者注 : 把 URL 中 servlet 名称之后, 查询字符串之前的路径信息转化成实际的路径 ) 这些方法在 servlet 容器无法确定一个有效的文件路径的情况下, 如 Web 应用程序从归档中, 在不能访问本地的远程文件系统上, 或在一个数据库中执行时, 这些方法必须返回 null JAR 文件中 META-INF/resources 目录下的资源, 只有当调用 getrealpath() 方法时才认为容器已经从包含它的 JAR 文件中解压, 在这种情况下, 必须返回解压缩后位置 3.7 非阻塞 IO Web 容器中的非阻塞请求处理有助于提高对改善 Web 容器可扩展性不断增加的需求, 增加 Web 容器可同时处理请求的连接数量 servlet 容器的非阻塞 IO 允许开发人员在数据可用时读取数据或在数据可写时写数据 非阻塞 IO 仅对在 Servlet 和 Filter( 节定义的, 异步处理 ) 中的异步请求处理和升级处理 ( 节定义的, 升级处理 ) 有效 否则, 当调用 ServletInputStream.setReadListener 或 ServletOutputStream.setWriteListener 方法时将抛出 IllegalStateException ReadListener 为非阻塞 IO 提供了下面的回调方法 : ReadListener ondataavailable(). 当可以从传入的请求流中读取数据时 ReadListener 的 ondataavailable 方法被调用 当数据可读时容器初次调用该方法 当且仅当下面描述的 ServletInputStream 的 isready 方法返回 false, 容器随后将调用 ondataavailable 方法 onalldataread(). 当读取完注册了此监听器的 ServletRequest 的所有数据时调用 onalldataread 方法 32

33 onerror(throwable t). 处理请求时如果有任何错误或异常发生时调用 onerror 方法 容器必须线程安全的访问 ReadListener 中的方法 除了上述 ReadListener 定义的方法外, 下列方法已被添加到 ServletInputStream 类中 : ServletInputStream boolean isfinished(). 与 ServletReader/ServletInputStream 相关的请求的所有数据已经读取完时 isfinished 方法返回 true 否则返回 false boolean isready(). 如果可以无阻塞地读取数据 isready 方法返回 true 如果没有数据可以无阻塞地读取该方法返回 false 如果 isready 方法返回 false, 调用 read 方法是非法的, 且必须抛出 IllegalStateException void setreadlistener(readlistener listener). 设置上述定义的 ReadListener, 调用它以非阻塞的方式读取数据 一旦把监听器与给定的 ServletInputStream 关联起来, 当数据可以读取, 所有的数据都读取完或如果处理请求时发生错误, 容器调用 ReadListener 的方法 注册一个 ReadListener 将启动非阻塞 IO 在那时切换到传统的阻塞 IO 是非法的, 且必须抛出 IllegalStateException 在当前请求范围内, 随后调用 setreadlistener 是非法的且必须抛出 IllegalStateException 3.8 Cookies HttpServletRequest 接口提供了 getcookies 方法来获得请求中的 cookie 的一个数组 这些 cookie 是从客户端发送到服务器端的客户端发出的每个请求上的数据 典型地, 客户端发送回的作为 cookie 的一部分的唯一信息是 cookie 的名称和 cookie 值 当 cookie 发送到浏览器时可以设置其他 cookie 属性, 诸如注释, 这些信息不会返回到服务器 该规范还允许的 cookies 是 HttpOnly cookie HttpOnly cookie 暗示客户端它们不会暴露给客户端脚本代码 ( 它没有被过滤掉, 除非客户端知道如何查找此属性 ) 使用 HttpOnly cookie 有助于减少某些类型的跨站点脚本攻击 3.9 SSL 属性 如果请求已经通过一个安全协议发送过, 如 HTTPS, 必须通过 ServletRequest 接口的 issecure 方法公开该信 息 Web 容器必须公开下列属性给 servlet 程序员 : 表 3-3 协议属性 属性 属性名称 Java 类型 密码套件 javax.servlet.request.cipher_suite String 算法的位大小 javax.servlet.request.key_size Integer SSL 会话 id javax.servlet.request.ssl_session_id String 如果有一个与请求相关的 SSL 证书, 它必须由 servlet 容器以 java.security.cert.x509certificate 类型的对象数组暴露给 servlet 程序员并可通过一个 javax.servlet.request.x509certificate 类型的 ServletRequest 属性访问 这个数组的顺序是按照信任的升序顺序 证书链中的第一个证书是由客户端设置的, 第二个是用来验证第一个的, 等等 33

34 3.10 国际化 客户可以选择希望 Web 服务器用什么语言来响应 该信息可以和使用 Accept-Language 头与 HTTP/1.1 规范中描述的其他机制的客户端通信 ServletRequest 接口提供下面的方法来确定发送者的首选语言环境 : getlocale getlocales 的 getlocale 方法将返回客户端要接受内容的首选语言环境 要了解更多关于 Accept-Language 头必须被解释为确定客户端首选语言的信息, 请参阅 RFC 2616(HTTP/1.1)14.4 节 getlocales 方法将返回一个 Locale 对象的枚举, 从首选语言环境开始顺序递减, 这些语言环境是可被客户接受的语言环境 如果客户端没有指定首选语言环境,getLocale 方法返回的语言环境必须是 servlet 容器默认的语言环境, 而 getlocales 方法必须返回只包含一个默认语言环境的 Local 元素的枚举 3.11 请求数据编码 目前, 许多浏览器不随着 Content-Type 头一起发送字符编码限定符, 而是根据读取 HTTP 请求确定字符编码 如果客户端请求没有指定请求默认的字符编码, 容器用来创建请求读取器和解析 POST 数据的编码必须是 ISO 然而, 为了向开发人员说明客户端没有指定请求默认的字符编码, 在这种情况下, 客户端发送字符编码失败, 容器从 getcharacterencoding 方法返回 null 如果客户端没有设置字符编码, 并使用不同的编码来编码请求数据, 而不是使用上面描述的默认的字符编码, 那么可能会发生破坏 为了弥补这种情况,ServletRequest 接口添加了一个新的方法 setcharacterencoding(string enc) 开发人员可以通过调用此方法来覆盖由容器提供的字符编码 必须在解析任何 post 数据或从请求读取任何输入之前调用此方法 此方法一旦调用, 将不会影响已经读取的数据的编码 3.12 Request 对象的生命周期 每个 request 对象只在 servlet 的 service 方法的作用域内, 或过滤器的 dofilter 方法的作用域内有效, 除非该组件启用了异步处理并且调用了 request 对象的 startasync 方法 在发生异步处理的情况下,request 对象一直有效, 直到调用 AsyncContext 的 complete 方法 容器通常会重复利用 request 对象, 以避免创建 request 对象的性能开销 开发人员必须注意的是, 不建议在上述范围之外保持 startasync 方法还没有被调用的请求对象的引用, 因为这样可能产生不确定的结果 在升级情况下, 如上描述仍成立 34

35 Servlet Context 4.1 ServletContext 接口介绍 ServletContext(Servlet 上下文 ) 接口定义了 servlet 运行在的 Web 应用的视图 容器供应商负责提供 Servlet 容器的 ServletContext 接口的实现 Servlet 可以使用 ServletContext 对象记录事件, 获取 URL 引用的资源, 存取当前上下文的其他 Servlet 可以访问的属性 ServletContext 是 Web 服务器中已知路径的根 例如,Servlet 上下文可以从 找出,/catalog 请求路径称为上下文路径, 所有以它开头的请求都会被路由到与 ServletContext 相关联的 Web 应用 4.2 ServletContext 接口作用范围 每一个部署到容器的 Web 应用都有一个 Servlet 接口的实例与之关联 在容器分布在多台虚拟机的情况下, 每个 JVM 的每个 Web 应用将有一个 ServletContext 实例 如果容器内的 Servlet 没有部署到 Web 应用中, 则隐含的作为 默认 Web 应用的一部分, 并有一个默认的 ServletContext 在分布式的容器中, 默认的 ServletContext 是非分布式的且仅存在于一个 JVM 中 4.3 初始化参数 如下 ServletContext 接口方法允许 Servlet 访问由应用开发人员在 Web 应用中的部署描述符中指定的上下文初始化参数 : getinitparameter getinitparameternames 应用开发人员使用初始化参数来表达配置信息 代表性的例子是一个 Webmaster 的 地址, 或保存关键数据的系统名称 4.4 配置方法 下面的方法从 Servlet 3.0 开始添加到 ServletContext, 以便启用编程方式定义 Servlet Filter 和它们映射到的 url 模式 (url pattern ) 这些方法只能从 ServletContextListener 实现的 contexinitialized 方法或者 ServletContainerInitializer 实现的 onstartup 方法进行的应用初始化过程中调用 除了添加 Servlet 和 Filter, 也可以查找关联到 Servlet 或 Filter 的一个 Registration 对象实例, 或者到 Servlet 或 Filter 的所有 Registration 对象的 map 如果 ServletContext 传到了 ServletContextListener 的 contextinitialized 方法, 但该 ServletContextListener 即没有在 web.xml 或 web-fragment.xml 注解, 则在 ServletContext 中定义的用于 35

36 Servlet Filter 和 Listener 的编程式配置的所有方法必须抛出 UnsupportedOperationException 编程式添加和配置 Servlet 编程式添加 Servlet 到上下文对框架开发者是很有用的 例如, 框架可以使用这个方法声明一个控制器 Servlet 这个方法将返回一个 ServletRegistration 或 ServletRegistration.Dynamic 对象, 允许我们进一步配置如 init-params,url-mapping 等 Servlet 的其他参数 下面描述了该方法的三个重载版本 addservlet(string servletname, String classname) 该方法允许应用以编程方式声明一个 Servlet 它添加以给定的名称和 class 名称的 Servlet 到 servlet 上下文 addservlet(string servletname, Servlet servlet) 该方法允许应用以编程方式声明一个 Servlet 它添加以给定的名称和 Servlet 实例的 Servlet 到 servlet 上下文 addservlet(string servletname, Class <? extends Servlet> servletclass) 该方法允许应用以编程方式声明一个 Servlet 它添加以给定的名称和 Servlet 类的一个实例的 Servlet 到 servlet 上下文 <T extends Servlet> T createservlet(class<t> clazz) 该方法实例化一个给定的 Servlet class, 该方法必须支持适用于 Servlet 的所有注解 返回的 Servlet 实例通过调用上边定义的 addservlet(string, Servlet) 注册到 ServletContext 之前, 可以进行进一步的定制 ServletRegistration getservletregistration(string servletname) 该方法返回与指定名字的 Servlet 相关的 ServletRegistration, 或者如果没有该名字的 ServletRegistration 则返回 null 如果 ServletContext 传到了 ServletContextListener 的 contextinitialized 方法, 但该 ServletContextListener 即没有在 web.xml 或 web-fragment.xml 中声明也没有使用 javax.servlet.annotation.weblistener 注解, 则必须抛出 UnsupportedOperationException Map<String,? extends ServletRegistration> getservletregistrations() 该方法返回 ServletRegistration 对象的 map, 由名称作为键并对应着注册到 ServletContext 的所有 Servlet 如果没有 Servlet 注册到 ServletContext 则返回一个空的 map 返回的 Map 包括所有声明和注解的 Servlet 对应的 ServletRegistration 对象, 也包括那些使用 addservlet 方法添加的所有 Servlet 对于的 ServletRegistration 对象 返回的 Map 的任何改变不影响 ServletContext 如果 ServletContext 传到了 ServletContextListener 的 contextinitialized 方法, 但该 ServletContextListener 即没有在 web.xml 或 web-fragment.xml 中声明也没有使用 javax.servlet.annotation.weblistener 注解, 则必须抛出 UnsupportedOperationException 编程式添加和配置 Filter addfilter(string filtername, String classname) 该方法允许应用以编程方式声明一个 Filter 它添加以给定的名称和 class 名称的 Filter 到 web 应用 addfilter(string filtername, Filter filter) 36

37 该方法允许应用以编程方式声明一个 Filter 它添加以给定的名称和 filter 实例的 Filter 到 web 应用 addfilter(string filtername, Class <? extends Filter> filterclass) 该方法允许应用以编程方式声明一个 Filter 它添加以给定的名称和 filter 类的一个实例的 Filter 到 web 应用 <T extends Filter> T createfilter(class<t> clazz) 该方法实例化一个给定的 Filter class, 该方法必须支持适用于 Filter 的所有注解 返回的 Filter 实例通过调用上边定义的 addservlet(string, Filter) 注册到 ServletContext 之前, 可以进行进一步的定制 给定的 Filter 类必须定义一个用于实例化的空参构造器 FilterRegistration getfilterregistration(string filtername) 该方法返回与指定名字的 Filter 相关的 FilterRegistration, 或者如果没有该名字的 FilterRegistration 则返回 null 如果 ServletContext 传到了 ServletContextListener 的 contextinitialized 方法, 但该 ServletContextListener 即没有在 web.xml 或 web-fragment.xml 中声明也没有使用 javax.servlet.annotation.weblistener 注解, 则必须抛出 UnsupportedOperationException Map<String,? extends FilterRegistration> getfilterregistrations() 该方法返回 FilterRegistration 对象的 map, 由名称作为键并对应着注册到 ServletContext 的所有 Filter 如果没有 Filter 注册到 ServletContext 则返回一个空的 Map 返回的 Map 包括所有声明和注解的 Filter 对应的 FilterRegistration 对象, 也包括那些使用 addfilter 方法添加的所有 Servlet 对于的 ServletRegistration 对象 返回的 Map 的任何改变不影响 ServletContext 如果 ServletContext 传到了 ServletContextListener 的 contextinitialized 方法, 但该 ServletContextListener 即没有在 web.xml 或 web-fragment.xml 中声明也没有使用 javax.servlet.annotation.weblistener 注解, 则必须抛出 UnsupportedOperationException 编程式添加和配置 Listener void addlistener(string classname) 往 ServletContext 添加指定 class 名称的监听器 ServletContext 将使用由与应用关联的 classloader 装载加载该给定名称的 class, 且它们必须实现一个或多个以下接口 : javax.servlet.servletcontextattributelistener javax.servlet.servletrequestlistener javax.servlet.servletrequestattributelistener javax.servlet.http.httpsessionlistener javax.servlet.http.httpsessionattributelistener javax.servlet.http.httpsessionidlistener 如果 ServletContext 传到了 ServletContainerInitializer 的 onstartup 方法, 则给定名字的类可以实现除上面列出的接口之外的 javax.servlet.servletcontextlistener 作为该方法调用的一部分, 容器必须装载指定类名的 class, 以确保其实现了所需的接口之一 如果给定名字的类实现了一个监听器接口, 则其调用顺序和声明 37

38 顺序是一样的, 换句话说, 如果它实现了 javax.servlet.servletrequestlistener 或 javax.servlet.http.httpsessionlistener, 那么新的监听器将被添加到该接口的有序监听器列表的末尾 <T extends EventListener> void addlistener(t t) 往 ServletContext 添加一个给定的监听器 给定的监听器实例必须实现是一个或多个如下接口 : javax.servlet.servletcontextattributelistener javax.servlet.servletrequestlistener javax.servlet.servletrequestattributelistener javax.servlet.http.httpsessionlistener javax.servlet.http.httpsessionattributelistener javax.servlet.http.httpsessionidlistener 如果 ServletContext 传到了 ServletContainerInitializer 的 onstartup 方法, 则给定的监听器实例可以实现除上面列出的接口之外的 javax.servlet.servletcontextlistener 如果给定的监听器实例实现了一个监听器接口, 则其调用顺序和声明顺序是一样的, 换句话说, 如果它实现了 javax.servlet.servletrequestlistener 或 javax.servlet.http.httpsessionlistener, 那么新的监听器将被添加到该接口的有序监听器列表的末尾 void addlistener(class <? extends EventListener> listenerclass) 往 ServletContext 添加指定 class 类型的监听器 给定的监听器类必须实现是一个或多个如下接口 : javax.servlet.servletcontextattributelistener javax.servlet.servletrequestlistener javax.servlet.servletrequestattributelistener javax.servlet.http.httpsessionlistener javax.servlet.http.httpsessionattributelistener javax.servlet.http.httpsessionidlistener 如果 ServletContext 传到了 ServletContainerInitializer 的 onstartup 方法, 则给定的监听器类可以实现除上面列出的接口之外的 javax.servlet.servletcontextlistener 如果给定的监听器类实现了一个监听器接口, 则其调用顺序和声明顺序是一样的, 换句话说, 如果它实现了 javax.servlet.servletrequestlistener 或 javax.servlet.http.httpsessionlistener, 那么新的监听器将被添加到该接口的有序监听器列表的末尾 <T extends EventListener> void createlistener(class<t> clazz) 该方法实例化给定的 EventListener 类 指定的 EventListener 类必须实现至少一个如下接口 : javax.servlet.servletcontextattributelistener javax.servlet.servletrequestlistener javax.servlet.servletrequestattributelistener javax.servlet.http.httpsessionlistener javax.servlet.http.httpsessionattributelistener 38

39 javax.servlet.http.httpsessionidlistener 该方法必须支持该规范定义的适用于如上接口的所有注解 返回的 EventListener 实例可以在通过调用 addlistener(t t) 注册到 ServletContext 之前进行进一步的定制 给定的 EventListener 必须定义一个用于实例化的空参构造器 用于编程式添加 Servlet Filter 和 Listener 的注解处理需求除了需要一个实例的 addservlet 之外, 当使用编程式 API 添加 Servlet 或创建 Servlet 时, 以下类中的有关的注解必须被内省且其定义的元数据必须被使用, 除非它被 ServletRegistration.Dynamic / ServletRegistration 中调用的 对于没有注解的 Filter 和 Listener 也需要内省 除了通过需要一个实例的方法添加的那些组件, 编程式添加或创建的所有组件 (Servlet,Filter 和 Listener) 上的资源注入, 只有当组件是一个 CDI Managed Bean 时才被支持 进一步了解更多细节请参考 页的 , JavaEE 要求的上下文和依赖注入 4.5 上下文属性 Servlet 可以使用指定的名字将对象属性绑定到上下文 同一个 Web 应用内的其他任何 Servlet 都可以使用绑定到上下文的任意属性 以下 Servlet 接口中的方法允许访问此功能 : setattribute getattribute getattributenames removeattribute 分布式容器中的上下文属性在 JVM 中创建的上下文属性是本地的, 这可以防止从一个分布式容器的共享内存存储中获取 ServletContext 属性 当需要在运行在分布式环境的 Servlet 之间共享信息时, 该信息应该被放到 session( 请看第 7 章, 会话 ), 或存储到数据库, 或者设置到企业级 JavaBean 组件 (Enterprise JavaBeans ) 4.6 资源 ServletContext 接口提供了直接访问 Web 应用中静态内容层次结构的文件的方法, 包括 HTML,GIF 和 JPEG 文件 : getresource getresourceasstream getresource 和 getresourceasstream 方法需要一个以 / 开头的 String 字符串作为参数, 给定的资源路径是相对于上下文的根, 或者相对于 web 应用的 WEB-INF/lib 目录下的 JAR 文件中的 META-INF/resources 目录 这两个方法首先根据请求的资源查找 web 应用上下文的根, 然后查找所有 WEB-INF/lib 目录下的 JAR 文件 查找 WEB-INF/lib 目录中 JAR 文件的顺序是不确定的 这种层次结构的文件可以存在于服务器的文件系统,Web 应用的归档文件, 远程服务器, 或在其他位置 39

40 这两个方法不能用于获取动态内容 例如, 在支持 JavaServer Pages 规范 (JavaServer Pages 规范可以在 找到 ) 的容器中, 如 getresource("/index.jsp") 形式的方法调用将返回 JSP 源码而不是处理后的输出 请看第 9 章, 分派请求 获取更多关于动态内容的信息 可以使用 getresourcepaths(string path) 方法访问 Web 应用中的资源的完整列表 该方法的语义的全部细节可以从本规范的 API 文档中找到 4.7 多主机和 Servlet 上下文 Web 服务器可以支持多个逻辑主机共享一个服务器 IP 地址 有时, 这种能力被称为 虚拟主机 这种情况下, 每一个逻辑主机必须有它自己的上下文或一组上下文 Servlet 上下文不会在虚拟主机之间共享 ServletContext 接口的 getvirtualservername 方法允许访问 ServletContext 部署在的逻辑主机的配置名字 该方法必须对所有部署在逻辑主机上的所有 servlet context 返回同一个名字 且该方法返回的名字必须是明确的 每个逻辑主机稳定的 和适合用于关联服务器配置信息和逻辑主机 4.8 Reload 注意事项 尽管容器供应商不需要实现类的重新加载 (reload) 模式以便易于开发, 但是任何此类的实现必须确保所有 servlet 及它们使用的类 (Servlet 使用的系统类异常可能使用的是一个不同的 class loader) 在一个单独的 class loader 范围内被加载 为了保证应用像开发人员预期的那样工作, 该要求是必须的 作为一个开发辅助, 容器应支持到 session 绑定到的监听器的完整通知语义以用于当 class 重新加载时 session 终结的监控 之前几代的容器创建新的 class loader 来加载 servlet, 且与用于加载在 servlet 上下文中使用的其他 Servlet 或类的 class loader 是完全不同的 这可能导致 servlet 上下文中的对象引用指向意想不到的类或对象, 并引起意想不到的行为 为了防止因创建新的 class loader 所引起的问题, 该要求是必须的 临时工作目录 每一个 servlet 上下文都需要一个临时的存储目录 Servlet 容器必须为每一个 servlet 上下文提供一个私有的临时目录, 并将通过 javax.servlet.context.tempdir 上下文属性使其可用, 关联该属性的对象必须是 java.io.file 类型 该要求公认为在多个 servlet 引擎实现中提供一个通用的便利 当 servlet 容器重启时, 它不需要去保持临时目录中的内容, 但必须确保一个 servlet 上下文的临时目录中的内容对运行在同一个 servlet 容器的其他 Web 应用的上下文不可见 40

41 Response 响应 (response) 对象封装了从服务器返回到客户端的所有信息 在 HTTP 协议中, 从服务器传输到客户端 的信息通过 HTTP 头信息或响应的消息体 5.1 缓冲 Servlet 容器允许但不必为了提高效率而缓冲到客户端的输出 典型的服务器默认都是缓冲的, 但允许 servlet 指定缓冲参数 ServletResponse 接口的如下方法允许 servlet 访问和设置缓冲信息 : getbuffersize setbuffersize iscommitted reset resetbuffer flushbuffer 不管 Servlet 使用的是一个 ServletOutputStream 还是一个 Writer,ServletResponse 接口提供的这些方法允许执行缓冲操作 getbuffersize 方法返回使用的底层缓冲区大小 如果没有使用缓冲, 该方法必须返回一个 int 值 0 Servlet 可以请求 setbuffersize 方法设置一个最佳的缓冲大小 不一定分配 servlet 请求大小的缓冲区, 但至少与请求的大小一样大 这允许容器重用一组固定大小的缓冲区, 如果合适, 可以提供一个比请求时更大的缓冲区 该方法必须在使用 ServletOutputStream 或 Writer 写任何内容之前调用 如果已经写了内容或响应对象已经提交, 则该方法必须抛出 IllegalStateException iscommitted 方法返回一个表示是否有任何响应字节已经返回到客户端的 boolean 值 flushbuffer 方法强制刷出缓冲区的内容到客户端 当响应没有提交时,reset 方法清空缓冲区的数据 头信息, 状态码和在调用 reset 之前 servlet 调用 getwriter 或 getoutputstream 设置的状态也必须被清空 如果响应没有被提交,resetBuffer 方法将清空缓冲区中的内容, 但不清空请求头和状态码 如果响应已经提交并且 reset 或 resetbuffer 方法已被调用, 则必须抛出 IllegalStateException, 响应及它关联的缓冲区将保持不变 当使用缓冲区时, 容器必须立即刷出填满的缓冲区内容到客户端 如果这是最早发送到客户端的数据, 且认为响应被提交了 5.2 头信息 Servlet 可以使用如下 HttpServletResponse 接口中的方法设置 HTTP 响应头 : 41

42 setheader addheader setheader 方法设置一个给定名字和值的 header 之前的 header 将被新的 header 替换 如果已经存在同名的 header 值的 set,set 中的值会被清空并用新的值替换 addheader 方法使用给定的名字添加一个 header 值到 set 如果没有 header 与给定的名字关联, 则创建一个新的 set Header 可能包含表示 int 或 Date 对象的数据 以下 HttpServletResponse 接口提供的便利方法允许 Servlet 对适当的数据类型用正确的格式设置一个 header: setintheader setdateheader addintheader adddateheader 为了成功的传回给客户端,header 必须在响应提交前设置 响应提交后的 Header 设置将被 servlet 容器忽略 Servlet 程序员负责保证为 Servlet 生成的内容设置合适的 response 对象的 Content-Type header HTTP 1.1 规范中没有要求在 HTTP 响应中设置此 header 当 Servlet 程序员没有设置该类型时,Servlet 容器也不能设置默认的内容类型 建议容器使用 X-Powered-By HTTP header 公布它的实现信息 该字段值应考虑一个或多个实现类型, 如 "Servlet/3.1" 容器应该可以配置来隐藏该 header 可选的容器补充的信息和底层 Java 平台可以被放在括号内并添加到实现类型之后 X-Powered-By: Servlet/3.1 X-Powered-By: Servlet/3.1 JSP/2.2 (GlassFish Open Source Edition 4.0 Java/Oracle Corporation/1.7) 5.3 非阻塞 IO 非阻塞 IO 仅对在 Servlet 和 Filter( 节定义的, 异步处理 ) 中的异步请求处理和升级处理 ( 节定义的, 升级处理 ) 有效 否则, 当调用 ServletInputStream.setReadListener 或 ServletOutputStream.setWriteListener 方法时将抛出 IllegalStateException 为了支持在 Servlet 容器中的非阻塞写, 除了在 3-28 页 3.7 节描述的 非阻塞 IO 对 ServletRequest 做的更改之外, 下面做出的更改以便于处理响应相关的类 / 接口 WriteListener 提供了如下适用于容器调用的回调方法 WriteListener void onwritepossible(). 当一个 WriteListener 注册到 ServletOutputStream 时, 当可以写数据时该方法将被容器首次调用 当且仅当下边描述的 ServletOutputStream 的 isready 方法返回 false, 容器随后将调用该方法 onerror(throwable t). 当处理响应过程中出现错误时回调 除了 WriteListener 外, 还有如下方法被添加到 ServletOutputStream 类并允许开发人员运行时检查是否可以 42

43 写数据发送到客户端 ServletOutputStream boolean isready(). 如果往 ServletOutputStream 写会成功, 则该方法返回 true, 其他情况会返回 false 如果该方法返回 true, 可以在 ServletOutputStream 上执行写操作 如果没有后续的数据能写到 ServletOutputStream, 那么直到底层的数据被刷出之前该方法将一直返回 false 且在此时容器将调用 WriteListener 的 onwritepossible 方法 随后调用该方法将返回 true void setwritelistener(writelistener listener). 关联 WriteListener 和当且的 ServletOutputStream, 当 ServletOutputStream 可以写入数据时容器会调用 WriteListener 的回调方法 注册了 WriteListener 将开始非阻塞 IO 此时再切换到传统的阻塞 IO 是非法的 容器必须线程安全的访问 WriteListener 中的方法 5.4 简便方法 HttpServletResponse 提供了如下简便方法 : sendredirect senderror sendredirect 方法将设置适当的 header 和内容体将客户端重定向到另一个地址 使用相对 URL 路径调用该方法是合法的, 但是底层的容器必须将传回到客户端的相对地址转换为全路径 URL 无论出于什么原因, 如果给定的 URL 是不完整的, 且不能转换为一个有效的 URL, 那么该方法必须抛出 IllegalArgumentException senderror 方法将设置适当的 header 和内容体用于返回给客户端返回错误消息 可以 senderror 方法提供一个可选的 String 参数用于指定错误的内容体 如果响应已经提交并终止, 这两个方法将对提交的响应产生负作用 这两个方法调用后 servlet 将不会产生到客户端的后续的输出 这两个方法调用后如果有数据继续写到响应, 这些数据被忽略 如果数据已经写到响应的缓冲区, 但没有返回到客户端 ( 例如, 响应没有提交 ), 则响应缓冲区中的数据必须被清空并使用这两个方法设置的数据替换 如果想要已提交, 这两个方法必须抛出 IllegalStateException 5.5 国际化 Servlet 应设置 response 的 locale 和字符集 使用 ServletResponse.setLocale 方法设置 locale 该方法可以重复的调用 ; 但响应被提交后调用该方法不会产生任何作用 如果在页面被提交之前 Servlet 没有设置 locale, 容器的默认 locale 将用来确定响应的 locale, 但是没有制定与客户端通信的规范, 例如使用 HTTP 情况下的 Content-Language header <locale-encoding-mapping-list> <locale-encoding-mapping> <locale>ja</locale> <encoding>shift_jis</encoding> </locale-encoding-mapping> </locale-encoding-mapping-list> 43

44 如果该元素不存在或没有提供 mapping,setlocale 使用容器依赖的 mapping setcharacterencoding, setcontenttype 和 setlocale 方法可以被重复的调用来改变字符编码 如果在 servlet 响应的 getwriter 方法已经调用之后或响应被提交之后, 调用相关方法设置字符编码将没有任何作用 只有当给定的 content type 字符串提供了一个 charset 属性值, 调用 setcontenttype 可以设置字符编码 只有当既没有调用 setcharacterencoding 也没有调用 setcontenttype 去设置字符编码之前调用 setlocale 可以设置字符编码 在 ServletResponse 接口的 getwriter 方法被调用或响应被提交之前, 如果 servlet 没有指定字符编码, 默认使用 ISO 如果使用的协议提供了一种这样做的方式, 容器必须传递 servlet 响应的 writer 使用的 locale 和字符编码到客户端 使用 HTTP 的情况下,locale 可以使用 Content-Language header 传递, 字符编码可以作为用于指定文本媒体类型的 Content-Type header 的一部分传递 注意, 如果没有指定 content type, 字符编码不能通过 HTTP header 传递 ; 但是仍使用它来编码通过 servlet 响应的 writer 写的文本 5.6 结束响应对象 当响应被关闭时, 容器必须立即刷出响应缓冲区中的所有剩余的内容到客户端 以下事件表明 servlet 满足了请求且响应对象即将关闭 : servlet 的 service 方法终止 响应的 setcontentlength 或 setcontentlengthlong 方法指定了大于零的内容量, 且已经写入到响应 senderror 方法已调用 sendredirect 方法已调用 AsyncContext 的 complete 方法已调用 5.7 Response 的生命周期 每个响应对象是只有当在 servlet 的 service 方法的范围内或在 filter 的 dofilter 方法范围内是有效的, 除非该组件关联的请求对象已经开启异步处理 如果相关的请求已经启动异步处理, 那么直到 AsyncContext 的 complete 方法被调用, 请求对象一直有效 为了避免响应对象创建的性能开销, 容器通常回收响应对象 在相关的请求的 startasync 还没有调用时, 开发人员必须意识到保持到响应对象引用, 超出之上描述的范围可能导致不确定的行为 44

45 过滤器 过滤器 (Filter) 是 Java 组件, 允许运行过程中改变进入资源的请求和资源返回的响应中的有效负载和 header 信息 本章描述了 Java Servlet v3.0 API 类和方法, 它们提供了一种轻量级的框架用于过滤动态和静态内容 还描述了如何在 Web 应用配置 Filter, 它们实现的约定和语义 网上提供了 Servlet 过滤器的 API 文档 过滤器的配置语法在第 14 章的 部署描述符 中的部署描述符模式部分给出 当阅读本章时, 读者应该是一这些资源作为参考 6.1 什么是过滤器 过滤器是一种代码重用的技术, 它可以改变 HTTP 请求的内容, 响应, 及 header 信息 过滤器通常不产生响应或像 servlet 那样对请求作出响应, 而是修改或调整到资源的请求, 修改或调整来自资源的响应 过滤器可以作用于动态或静态内容 这章说的动态和静态内容指的是 Web 资源 供开发人员使用的过滤器功能有如下几种类型 : 在执行请求之前访问资源 在执行请求之前处理资源的请求 用请求对象的自定义版本包装请求对请求的 header 和数据进行修改 用响应对象的自定义版本包装响应对响应的 header 和数据进行修改 拦截资源调用之后的调用 作用在 Servlet, 一组 Servlet, 或静态内容上的零个, 一个或多个拦截器按指定的顺序执行 过滤器组件示例 验证过滤器 日志记录和审计过滤器 图像转换过滤器 数据压缩过滤器 加密过滤器 词法 (Tokenizing) 过滤器 触发资源访问事件过滤器 转换 XML 内容的 XSL/T 过滤器 MIME- 类型链过滤器 缓存过滤器 45

46 6.2 主要概念 本章描述了过滤器模型的主要概念 应用开发人员通过实现 javax.servlet.filter 接口并提供一个公共的空参构造器来创建过滤器 该类及构建 Web 应用的静态资源和 Servlet 打包在 Web 应用归档文件中 Filter 在部署描述符中通过 <filter> 元素声明 一个过滤器或一组过滤器可以通过在部署描述符中定义 <filter-mapping> 来为调用配置 可以使用 servlet 的逻辑视图名把过滤器映射到一个特定的 servlet, 或者使用 URL 模式把一组 Servlet 和静态内容资源映射到过滤器 过滤器生命周期 在 Web 应用部署之后, 在请求导致容器访问 Web 资源之前, 容器必须找到过滤器列表并按照如上所述的应用到 Web 资源 容器必须确保它为过滤器列表中的每一个都实例化了一个适当类的过滤器, 并调用其 init(filterconfig config) 方法 过滤器可能会抛出一个异常, 以表明它不能正常运转 如果异常的类型是 UnavailableException, 容器可以检查异常的 ispermanent 属性并可以选择稍候重试过滤器 在部署描述符中声明的每个 <filter> 在每个 JVM 的容器中仅实例化一个实例 容器提供了声明在过滤器的部署描述符的过滤器 config( 译者注 :FilterConfig), 对 Web 应用的 ServletContext 的引用, 和一组初始化参数 当容器接收到传入的请求时, 它将获取列表中的第一个过滤器并调用 dofilter 方法, 传入 ServletRequest 和 ServletResponse, 和一个它将使用的 FilterChain 对象的引用 过滤器的 dofilter 方法通常会被实现为如下或如下形式的子集 : 1. 该方法检查请求的头 2. 该方法可以用自定义的 ServletRequest 或 HttpServletRequest 实现包装请求对象为了修改请求的头或数据 3. 该方法可以用自定义的 ServletResponse 或 HttpServletResponse 实现包装传入 dofilter 方法的响应对象用于修改响应的头或数据 4. 该过滤器可以调用过滤器链中的下一个实体 下一个实体可能是另一个过滤器, 或者如果当前调用的过滤器是该过滤器链配置在部署描述符中的最后一个过滤器, 下一个实体是目标 Web 资源 调用 FilterChain 对象的 dofilter 方法将影响下一个实体的调用, 且传入的它被调用时请求和响应, 或传入它可能已经创建的包装版本 由容器提供的过滤器链的 dofilter 方法的实现, 必须找出过滤器链中的下一个实体并调用它的 dofilter 方法, 传入适当的请求和响应对象 另外, 过滤器链可以通过不调用下一个实体来阻止请求, 离开过滤器负责填充响应对象 service 方法必须和应用到 servlet 的所有过滤器运行在同一个线程中 5. 过滤器链中的下一个过滤器调用之后, 过滤器可能检查响应的头 6. 另外, 过滤器可能抛出一个异常以表示处理过程中出错了 如果过滤器在 dofilter 处理过程中抛出 UnavailableException, 容器必须停止处理剩下的过滤器链 如果异常没有标识为永久的, 它或许选择稍候重试整个链 7. 当链中的最后的过滤器被调用, 下一个实体访问的是链最后的目标 servlet 或资源 46

47 8. 在容器能把服务中的过滤器实例移除之前, 容器必须先调用过滤器的 destroy 方法以便过滤器释放资源 并执行其他的清理工作 包装请求和响应 过滤器的核心概念是包装请求或响应, 以便它可以覆盖行为执行过滤任务 在这个模型中, 开发人员不仅可以覆盖请求和响应对象上已有的方法, 也能提供新的 API 以适用于对过滤器链中剩下的过滤器或目标 web 资源做特殊的过滤任务 例如, 开发人员可能希望用更高级别的输出对象如 output stream 或 writer 来扩展响应对象, 如 API, 允许 DOM 对象写回客户端 为了支持这种风格的过滤器, 容器必须支持如下要求 当过滤器调用容器的过滤器链实现的 dofilter 方法时, 容器必须确保请求和响应对象传到过滤器链中的下一个实体, 或如果过滤器是链中最后一个, 将传入目标 web 资源, 且与调用过滤器传入 dofilter 方法的对象是一样的 当调用者包装请求或响应对象时, 对包装对象的要求同样适用于从 servlet 或过滤器到 RequestDispatcher.forward 或 RequestDispatcher.include 的调用 在这种情况下, 调用 servlet 看到的请求和响应对象与调用 servlet 或过滤器传入的包装对象必须是一样的 过滤器环境 可以使用部署描述符中的 <init-params> 元素把一组初始化参数关联到过滤器 这些参数的名字和值在过滤器运行期间可以使用过滤器的 FilterConfig 对象的 getinitparameter 和 getinitparameternames 方法得到 另外, FilterConfig 提供访问 Web 应用的 ServletContext 用于加载资源, 记录日志, 在 ServletContext 的属性列表存储状态 链中最后的过滤器和目标 servlet 或资源必须执行在同一个调用线程 在 Web 应用中配置过滤器 过滤器可以通过规范的第 8-67 页的 注解定义或者在部署描述符中使用 <filter> 元素定义 在这个元素中, 程序员可以声明如下内容 : filter-name: 用于映射过滤器到 servlet 或 URL filter-class: 由容器用于表示过滤器类型 init-params: 过滤器的初始化参数程序员可以选择性的指定 icon 图标, 文字说明, 和工具操作显示的名字 容器必须为部署描述符中定义的每个过滤器声明实例化一个 Java 类实例 因此, 如果开发人员对同一个过滤器类声明了两次, 则容器将实例化两个相同的过滤器类的实例 下面是一个过滤器声明的例子 : <filter> <filter-name>image Filter</filter-name> <filter-class>com.acme.imagefilter</filter-class> </filter> 一旦在部署描述符中声明了过滤器, 装配人员使用 <filter-mapping> 定义 Web 应用中的 servlet 和静态资源到过滤器的应用 过滤器可以使用 <servlet-name> 元素关联到一个 Servlet 例如, 以下示例代码映射 Image Filter 47

48 过滤器到 ImageServlet servlet: <filter-mapping> <filter-name>image Filter</filter-name> <servlet-name>imageservlet</servlet-name> </filter-mapping> 过滤器可以使用 <url-pattern> 风格的过滤器映射关联到一组 servlet 和静态内容 : <filter-mapping> <filter-name>logging Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 在这里,Logging 过滤器应用到 Web 应用中的所有 servlet 和静态资源, 因为每一个请求的 URI 匹配 /* URL 模式 当使用 <url-pattern> 风格配置 <filter-mapping> 元素, 容器必须使用定义在 12 章 映射请求到 Servlet 中的路径映射规则 (path mapping rule) 决定 <url-pattern> 是否匹配请求 URI 容器使用的用于构建应用到一个特定请求 URI 的过滤器链的顺序如下所示 : 1. 首先, <url-pattern> 按照在部署描述符中的出现顺序匹配过滤器映射 2. 接下来,<servlet-name> 按照在部署描述符中的出现顺序匹配过滤器映射 如果过滤器映射同时包含了 <servlet-name> 和 <url-pattern>, 容器必须展开过滤器映射为多个过滤器映射 ( 每一个 <servlet-name> 和 <url-pattern> 一个 ), 保持 <servlet-name> 和 <url-pattern> 元素顺序 例如, 以下过滤器映射 : <filter-mapping> <filter-name>multipe Mappings Filter</filter-name> <url-pattern>/foo/*</url-pattern> <servlet-name>servlet1</servlet-name> <servlet-name>servlet2</servlet-name> <url-pattern>/bar/*</url-pattern> </filter-mapping> 等价于 : 48

49 <filter-mapping> <filter-name>multipe Mappings Filter</filter-name> <url-pattern>/foo/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>multipe Mappings Filter</filter-name> <servlet-name>servlet1</servlet-name> </filter-mapping> <filter-mapping> <filter-name>multipe Mappings Filter</filter-name> <servlet-name>servlet2</servlet-name> </filter-mapping> <filter-mapping> <filter-name>multipe Mappings Filter</filter-name> <url-pattern>/bar/*</url-pattern> </filter-mapping> 关于过滤器链顺序的要求意味着容器, 当接收到传入的请求, 按照如下方式处理请求 : 按照 120 页的 映射规则 识别目标 Web 资源 如果有过滤器使用 servlet name 匹配到具有 <servlet-name> 的 Web 资源, 容器以声明在部署描述符中的顺序构建过滤器链 该链中的最后一个过滤器, 即最后一个 <servlet-name> 匹配的过滤器将调用目标 Web 资源 如果有过滤器使用 <url-pattern> 匹配且该 <url-pattern> 按照第 12.2 节 映射规则 中的规则匹配请求的 URI, 容器容器以声明在部署描述符中的顺序构建 <url-pattern> 匹配到的过滤器链 该链中的最后一个过滤器是在部署描述符中对当前请求 URI 最后一个 <url-pattern> 匹配的过滤器 链中的最后一个过滤器将调用 <servlet-name> 匹配的链中的第一个过滤器, 或如果没有, 则调用目标 Web 资源 想要高性能 Web 容器将缓存过滤器链从而不需要根据每个请求重新计算它们 过滤器和 RequestDispatcher Java Servlet 规范自从 2.4 新版本以来, 能够在请求分派器 forward() 和 include() 调用情况下配置可被调用的过滤器 通过在部署描述符中使用新的 <dispatcher> 元素, 开发人员可以为 filter-mapping 指定是否想要过滤器应用到请求, 当 : 1. 请求直接来自客户端 可以由一个带有 REQUEST 值的 <dispatcher> 元素, 或者没有任何 <dispatcher> 元素来表示 2. 使用表示匹配 <url-pattern> 或 <servlet-name> 的 Web 组件的请求分派器的 forward() 调用情况下处理请求 可以由一个带有 FORWARD 值的 <dispatcher> 元素表示 3. 使用表示匹配 <url-pattern> 或 <servlet-name> 的 Web 组件的请求分派器的 include() 调用情况下处理请求 49

50 可以由一个带有 INCLUDE 值的 <dispatcher> 元素表示 4. 使用第 106 页 错误处理 指定的错误页面机制处理匹配 <url-pattern> 的错误资源的请求 可以由一个带有 ERROR 值的 <dispatcher> 元素表示 5. 使用第 10 页指定的 异步处理 中的异步上下文分派机制对 web 组件使用 dispatch 调用处理请求 可以由一个带有 ASYNC 值的 <dispatcher> 元素表示 6. 或之上 1,2,3,4 或 5 的任何组合 例如 : <filter-mapping> <filter-name>logging Filter</filter-name> <url-pattern>/products/*</url-pattern> </filter-mapping> 客户端以 /products/... 开始的请求将导致 Logging Filter 被调用, 但不是在以路径 /products/... 开始的请求分派器调用情况下 LoggingFilter 将在初始请求分派和恢复请求时被调用 如下代码 : <filter-mapping> <filter-name>logging Filter</filter-name> <servlet-name>productservlet</servlet-name> <dispatcher>include</dispatcher> </filter-mapping> 客户端到 ProductServlet 的请求将不会导致 Logging Filter 被调用, 且也不会在请求分派器 forward() 调用到 ProductServlet 情况时, 仅在以 ProductServlet 名字开头的请求分派器 include() 调用时被调用 如下代码 : <filter-mapping> <filter-name>logging Filter</filter-name> <url-pattern>/products/*</url-pattern> <dispatcher>forward</dispatcher> <dispatcher>request</dispatcher> </filter-mapping> 客户端以 /products/... 开始的请求, 或在以路径 /products/... 开始的请求分派器 forward() 调用情况时, 将导致 Logging Filter 被调用 最后, 如下代码使用特殊的 servlet 名字 * : <filter-mapping> <filter-name>all Dispatch Filter</filter-name> <servlet-name>*</servlet-name> <dispatcher>forward</dispatcher> </filter-mapping> 在按名字或按路径获取的所有请求分派器 forward() 调用时该代码将导致 All Dispatch Filter 被调用 50

51 会话 超文本传输协议 (HTTP) 被设计为一种无状态协议 为构建有效的 Web 应用, 必须与来自一个特定的客户端的请求彼此是相互关联 随时间的推移, 演变了许多会话跟踪机制, 这些机制直接使用对程序员而言是困难或麻烦的 该规范定义了一个简单的 HttpSession 接口, 允许 servlet 容器使用几种方法来跟踪用户会话, 而不会使应用开发人员陷入到这些方法的细节中 7.1 会话跟踪机制 以下章节描述了跟踪用户会话 (session) 的方法 Cookies 通过 HTTP cookie 的会话跟踪是最常用的会话跟踪机制, 且所有 servlet 容器都应该支持 容器向客户端发送一个 cookie, 客户端后续到服务器的请求都将返回该 cookie, 明确地将请求与会话关联 会话跟踪 cookie 的标准名字必须是 JSESSIONID, 所有 3.0 兼容的容器必须支持 容器也允许通过容器指定的配置自定义会话跟踪 cookie 的名字 所有 servlet 容器必须提供能够配置容器是否标记会话跟踪 cookie 为 HttpOnly 已建立的配置必须应用到所有上下文中还没有建立特定的配置 ( 见 SessionCookieConfig javadoc 获取更多细节 ) 如果 web 应用为其会话跟踪 cookie 配置了一个自定义的名字, 则如果会话 id 编码到 URL 中那么相同的自定义名字也将用于 URI 参数的名字 ( 假如 URL 重写已开启 ) SSL 会话 安全套接字层, 在 HTTPS 使用的加密技术, 有一种内置机制允许多个来自客户端的请求被明确识别为同一会话 Servlet 容器可以很容易地使用该数据来定义会话 URL 重写 URL 重写是会话跟踪的最低标准 当客户端不接受 cookie 时, 服务器可使用 URL 重写作为会话跟踪的基础 URL 重写涉及添加数据 会话 ID 容器解析 URL 路径从而请求与会话相关联 会话 ID 必须被编码为 URL 字符串中的一个路径参数 参数的名字必须是 jsessionid 下面是一个 URL 包含编码的路径信息的例子 : URL 重写在日志 书签 referer header 缓存的 HTML URL 工具条中暴露会话标识 在支持 cookie 或 SSL 会话的情况下, 不应该使用 URL 重写作为会话跟踪机制 51

52 7.1.4 会话完整性 当服务的来自客户端的请求不支持使用 cookie 时,Web 容器必须能够支持 HTTP 会话 为了满足这个要 求, Web 容器通常支持 URL 重写机制 7.2 创建会话 当会话仅是一个未来的且还没有被建立时会话被认为是 新 的 因为 HTTP 是一种基于请求 - 响应的协议, 直到客户端 加入 到 HTTP 会话之前它都被认为是新的 当会话跟踪信息返回到服务器指示会话已经建立时客户端加入到会话 直到客户端加入到会话, 不能假定下一个来自客户端的请求被识别为同一会话 如果以下之一是 true, 会话被认为是 新 的 : 客户端还不知道会话 客户端选择不加入会话 这些条件定义了 servlet 容器没有机制能把一个请求与之前的请求相关联的情况 Servlet 开发人员必须设计他的应用以便处理客户端没有, 不能, 或不会加入会话的情况 与每个会话相关联是一个包含唯一标识符的字符串, 也被称为会话 ID 会话 ID 的值能通过调用 javax.servlet.http.httpsession.getid() 获取, 且能在创建后通过调用 javax.servlet.http.httpservletrequest.changesessionid() 改变 7.3 会话范围 HttpSession 对象必须被限定在应用 ( 或 servlet 上下文 ) 级别 底层的机制, 如使用 cookie 建立会话, 不同的上下文可以是相同, 但所引用的对象, 包括包括该对象中的属性, 决不能在容器上下文之间共享 用一个例子来说明该要求 : 如果 servlet 使用 RequestDispatcher 来调用另一个 Web 应用的 servlet, 任何创建的会话和被调用 servlet 所见的必须不同于来自调用会话所见的 此外, 一个上下文的会话在请求进入那个上下文时必须是可恢复的, 不管是直接访问它们关联的上下文还是在请求目标分派时创建的会话 7.4 绑定 Session 属性 servlet 可以按名称绑定对象属性到 HttpSession 实现, 任何绑定到会话的对象可用于任意其他的 Servlet, 其属于同一个 ServletContext 且处理属于相同会话中的请求 一些对象可能需要在它们被放进会话或从会话中移除时得到通知 这些信息可以从 HttpSessionBindingListener 接口实现的对象中获取 这个接口定义了以下方法, 用于标识一个对象被绑定到会话或从会话解除绑定时 valuebound valueunbound 在对象对 HttpSession 接口的 getattribute 方法可用之前 valuebound 方法必须被调用 在对象对 HttpSession 52

53 接口的 getattribute 方法不可用之后 valueunbound 方法必须被调用 7.5 会话超时 在 HTTP 协议中, 当客户端不再处于活动状态时没有显示的终止信号 这意味着当客户端不再处于活跃状态时可以使用的唯一机制是超时时间 Servlet 容器定义了默认的会话超时时间, 且可以通过 HttpSession 接口的 getmaxinactiveinterval 方法获取 开发人员可以使用 HttpSession 接口的 setmaxinactiveinterval 方法改变超时时间 这些方法的超时时间以秒为单位 根据定义, 如果超时时间设置为 0 或更小的值, 会话将永不过期 会话不会生效, 直到所有 servlet 使用的会话已经退出其 service 方法 一旦会话已失效, 新的请求必须不能看到该会话 7.6 最后访问时间 HttpSession 接口的 getlastaccessedtime 方法允许 servlet 确定在当前请求之前的会话的最后访问时间 当会话中的请求是 servlet 容器第一个处理的时该会话被认为是访问了 7.7 重要的会话语义 多线程问题 在同一时间多个 Servlet 执行请求的线程可能都有到同一会话的活跃访问 容器必须确保, 以一种线程安全的方式维护表示会话属性的内部数据结构 开发人员负责线程安全的访问属性对象本身 这样将防止并发访问 HttpSession 对象内的属性集合, 消除了应用程序导致破坏集合的机会 分布式环境 在一个标识为分布式的应用程序中, 会话中的所有请求在同一时间必须仅被一个 JVM 处理 容器必须能够使用适当的 setattribute 或 putvalue 方法把所有对象放入到 HttpSession 类实例 以下限制被强加来满足这些条件 : 容器必须接受实现了 Serializable 接口的对象 容器可以选择支持其他指定对象存储在 HttpSession 中, 如 Enterprise JavaBeans 组件和事务的引用 由特定容器的设施处理会话迁移 当分布式 servlet 容器不支持必需的会话迁移存储对象机制时容器必须抛出 IllegalArgumentException 分布式 servlet 容器必须支持迁移的对象实现 Serializable 的必要机制 这些限制意味着开发人员确保除在非分布式容器中遇到的问题没有额外的并发问题 容器供应商可以确保可扩展性和服务质量的功能, 如负载平衡和故障转移通过把会话对象和它的内容从分布式系统的任意一个活跃节点移动到系统的一个不同的节点上 如果分布式容器持久化或迁移会话提供服务质量特性, 它们不限制使用原生的 JVM 序列化机制用于序列化 HttpSession 和它们的属性 如果开发人员实现 session 属性上的 readobject 和 writeobject 方法, 他们也不 53

54 能保证容器将调用这些方法, 但保证 Serializable 结束它们的属性将被保存 容器必须在迁移会话时通知实现了 HttpSessionActivationListener 的所有会话属性 它们必须在序列化会话之前通知钝化监听器, 在反序列化之后通知激活监听器 写分布式应用的开发人员应该意识到容器可能运行在多个 Java 虚拟机中, 开发人员不能依赖静态变量存储应用状态 他们应该用企业 Bean 或数据库存储这种状态 客户端语义 由于 Cookie 或 SSL 证书通常由 Web 浏览器进程控制, 且不与浏览器的任意特定窗口关联, 从客户端应用程序发起的到 servlet 容器的请求可能在同一会话 为了最大的可移植性, 开发人员应该假定客户端所有窗口参与同一会话 54

55 注解和可插拔性 本章描述了注解的使用和使 web 应用内使用的框架和库能够可插拔的增强 8.1 注解和可插拔性 在 web 应用中, 使用注解的类仅当它们位于 WEB-INF/classes 目录中, 或它们被打包到位于应用的 WEB-INF/lib 中的 jar 文件中时它们的注解才将被处理 Web 应用部署描述符的 web-app 元素包含一个新的 metadata-complete 属性 metadata-complete 属性定义了 web 描述符是否是完整的, 或是否应该在部署时检查 jar 包中的类文件和 web fragments 如果 metadata-complete 设置为 true, 部署工具必须必须忽略存在于应用的类文件中的所有指定部署信息的 servlet 注解和 web fragments 如果 metadata-complete 属性没有指定或设置为 false, 部署工具必须检查应用的类文件的注解, 并扫描 web fragments 以下注解必须被 Servlet 3.0 兼容的容器支持 该注解用于在 Web 应用中定义 Servlet 组件 该注解在一个类上指定并包含声明 Servlet 的元数据 必须指定注解的 urlpatterns 或 value 属性 所有其他属性是可选的默认设置 ( 请参考 javadoc 获取更多细节 ) 当注解上唯一属性是 url 模式时推荐使用 value 且当也有使用其他属性时使用 urlpatterns 属性 在同一注解上同时使用 value 和 urlpatterns 属性是非法的 如果没有指定 Servlet 名字则默认是全限定类名 被注解的 sevlet 必须指定至少一个 url 模式进行部署 如果同一个 Servlet 类以不同的名字声明在部署描述符中, 必须实例化一个新的 Servlet 实例 如果使用不同名字添加的同一个 Servlet 类使用定义在 4-35 页的 节 编程式添加和配置 Servlet 的编程式 API 添加到 ServletContext, 注解声明的属性值必须被忽略, 必须创建一个指定名字的 Servlet 注解的类必须继承 javax.servlet.http.httpservlet 类 下面是如何使用该注解的一个示例 代码示例 /foo ) public class CalculatorServlet extends HttpServlet{ //... } 下面是如何使用该注解指定更多的属性的一个示例 代码示例 MyServlet, urlpatterns={"/foo", "/bar"}) public class SampleUsingAnnotationAttributes extends HttpServlet{ public void doget(httpservletrequest req, HttpServletResponse res) { } } 55

56 该注解用于在 Web 应用中定义 Filter 该注解在一个类上指定且包含声明过滤器的元数据 如果没有指定 Filter 名字则默认是全限定类名 注解的 urlpatterns 属性, servletnames 属性或 value 属性必须被指定 所有其他属性是可选的默认设置 ( 请参考 javadoc 获取更多细节 ) 当注解上唯一属性是 url 模式时推荐使用 value 且当也有使用其他属性时使用 urlpatterns 属性 在同一注解上同时使用 value 和 urlpatterns WebFilter 注解的类必须实现 javax.servlet.filter 下面是如何使用该注解的一个示例 代码示例 /foo ) public class MyFilter implements Filter { public void dofilter(httpservletrequest req, HttpServletResponse res) {... } } 该注解用于指定必须传递到 Servlet 或 Filter 的任何初始化参数 它是 WebServlet 和 WebFilter 注解的一个属性 WebListener 注解用于注解用来获得特定 web 注解的类必须实现以下接口 : javax.servlet.servletcontextlistener javax.servlet.servletcontextattributelistener javax.servlet.servletrequestlistener javax.servlet.servletrequestattributelistener javax.servlet.http.httpsessionlistener javax.servlet.http.httpsessionattributelistener javax.servlet.http.httpsessionidlistener 示例 : 56

57 @WebListener public class MyListener implements ServletContextListener{ public void contextinitialized(servletcontextevent sce) { ServletContext sc = sce.getservletcontext(); sc.addservlet("myservlet", "Sample servlet", "foo.bar.myservlet", null, -1); sc.addservletmapping("myservlet", new String[] { "/urlpattern/*" }); } } 该注解, 当指定在 Servlet 上时, 表示请求期望是 mime/multipart 类型 相应 servlet 的 HttpServletRequest 对象必须使用 getparts 和 getpart 方法遍历各个 mime 附件以获取 mime 附件 javax.servlet.annotation.multipartconfig 的 location 属性和 <multipart-config> 的 <location> 元素被解析为一个绝对路径且默认为 javax.servlet.context.tempdir 如果指定了相对地址, 它将是相对于 tempdir 位置 绝对路径与相对地址的测试必须使用 java.io.file.isabsolute 其他注解 / 惯例 除了这些注解, 定义在第 页 15.5 节的 注解和资源注入 将继续工作在这些新注解上下文中 默认情况下, 所有应用将有 index.htm(l) 和 index.jsp 在 welcome-file-list 列表中 该描述符可以用来覆盖这些默认设置 当使用注解时, 从 WEB-INF/classes 或 WEB-INF/lib 中的不同框架 jar 包 / 类加载监听器 Servlet 的顺序是没有指定的 如果顺序是很重要的, 那么请看 web.xml 模块部分和后面的 web.xml 和 web-fragment.xml 顺序部分 顺序仅能在部署描述符中指定 8.2 可插拔性 web.xml 模块 使用上述定义的注解, 使得使用 web.xml 可选 然而, 对于覆盖默认值或使用注解设置的值, 需要使用部署描述符 如前所述, 如果 web.xml 描述符中的 metadata-complete 元素设置为 true, 则存在于 class 文件和绑定在 jar 包中的 web-fragments 中的指定部署信息的注解将不被处理 这意味着, 所有应用的元数据通过 web.xml 描述符指定 为了给开发人员更好的可插拔性和更少的配置, 在这个版本 (Servlet 3.0) 的规范中, 我们引入了 web 模块部署描述符片段 (web fragment) 的概念 web fragment 是 web.xml 的部分或全部, 可以在一个类库或框架 jar 包的 META-INF 目录指定和包括 在 WEB-INF/lib 目录中的普通的老的 jar 文件即使没有 web-fragment.xml 也可能被认为是一个 fragment, 任何在它中指定的注解都将按照定义在 节的规则处理, 容器将会取出并按照如下定义的规则进行配置 web fragment 是 web 应用的一个逻辑分区, 以这样一种方式, 在应用中使用的框架可以定义所有制品 (artifact) 而无需要求开发人员在 web.xml 中编辑或添加信息 它几乎包含 web.xml 描述符中使用的所有 57

58 相同元素 不过描述符的顶级元素必须是 web-fragment 且对应的描述符文件必须被称为 web-fragment.xml, 相关元素的顺序在 web-fragment.xml 和 web.xml 也是不同的, 请参考定义在第 14 章的部署描述符一章中对应的 web-fragment schema 如果框架打包成 jar 文件, 且有部署描述符的形式的元数据信息, 那么 web-fragment.xml 描述符必须在该 jar 包的 META-INF/ 目录中 如果框架想使用 META-INF/web-fragment.xml, 以这样一种方式, 它扩充了 web 应用的 web.xml, 框架必须被绑定到 Web 应用的 WEB-INF/lib 目录中 为了使框架中的任何其他类型的资源 ( 例如, 类文件 ) 对 web 应用可用, 把框架放置在 web 应用的 classloader 委托链的任意位置即可 换句话说, 只有绑定到 web 应用的 WEB-INF/lib 目录中的 JAR 文件, 但不是那些在类装载委托链中更高的, 需要扫描其 web-fragment.xml 在部署期间, 容器负责扫描上面指定的位置和发现 web-fragment.xml 并处理它们 存在于当前的单个 web.xml 的名字唯一性的要求, 也同样适用于一组 web.xml 和所有能适用的 web-fragment.xml 文件 如下是库或框架可以包括什么的例子 <web-fragment> <servlet> <servlet-name>welcome</servlet-name> <servlet-class> WelcomeServlet </servlet-class> </servlet> <listener> <listener-class> RequestListener </listener-class> </listener> </web-fragment> 以上的 web-fragment.xml 将被包括在框架的 jar 文件的 META-INF / 目录 web-fragment.xml 配置和应该应用的注解的顺序是未定义的 如果顺序对于某一应用是很重要的方面, 请参考下面如何实现所需的顺序定义的规则 web.xml 和 web-fragment.xml 顺序 由于规范允许应用配置由多个配置文件组成 (web.xml 和 web-fragment.xml) 的资源, 从应用中多个不同位置发现和加载, 顺序问题必须被解决 本节详述了配置资源的作者如何声明他们制品 (artifact) 的顺序要求 web-fragment.xml 可以有一个 javaee:java-identifiertype 类型的顶级 <name> 元素, 且在一个 web-fragment.xml 中仅能有一个 <name> 元素 如果存在一个 <name> 元素, 它必须考虑用于 artifact 顺序 ( 除非出现重复名异常, 如上文所述 ) 两种情况必须被考虑, 以允许应用程序配置资源来表达它们的顺序配置 1. 绝对顺序 : 在 web.xml 中的 <absolute-ordering> 元素 在一个 web.xml 中仅能有一个 <absolute-ordering> 元素 58

59 a. 在这种情况下, 第二种情况处理的顺序配置必须被忽略 b. web.xml 和 WEB-INF/classes 必须在列在 absolute-ordering 元素中的所有 web-fragment 之前处理 c. <absolute-ordering> 的任何直接子 <name> 元素必须被解释为在这些被指定的 web-fragment 中表示绝对顺序, 不管它存不存在, 必须被处理 d. <absolute-ordering> 可以包含零个或一个 <others /> 元素 下面描述此元素必需的功能 如果 <absolute-ordering> 元素没有包含 <others/> 元素, 没有在 <name /> 明确提到的 web-fragment 必须被忽略 不会扫描被排除的 jar 包中的注解 Servlet Filter 或 Listener 然而, 如果是被排除的 jar 包中的 servlet filter 或 listener, 其列在 web.xml 或非排除的 web-fragment.xml 中, 那么它的注解将使用除非另外使用 metadata-complete 排除 在排除的 jar 包的 TLD 文件中发现的 ServletContextListener 不能使用编程式 API 配置 Filter 和 Servlet, 任何试图这样做将导致 IllegalStateException 如果发现的 ServletContainerInitializer 是从一个被排除的 jar 包中装载的, 它将被忽略 无论是否设置了 metadata-complete, 通过 <absolute-ordering> 排除的 jar 包不扫描被任何 ServletContainerInitializer 处理的类 e. 重复名字异常 : 如果, 当遍历 <absolute-ordering> 子元素, 遇到多个子元素具有相同 <name> 元素, 只需考虑首次出现的 2. 相对顺序 : 在 web-fragment.xml 中的 <ordering> 元素, 一个 web-fragment.xml 只能有一个 <ordering> 元素 a. web-fragment.xml 可以有一个 <ordering> 元素 如果是这样, 该元素必须包含零个或一个 <before> 元素和零个或一个 <after> 元素 这些元素的含义在下面进行说明 b. web.xml 和 WEB-INF/classes 必须在列在 ordering 元素中的所有 web-fragment 之前处理 c. 重复命名异常 : 如果, 当遍历 web-fragments, 遇到多个成员具有相同 <name> 元素, 应用必须记录包含帮助解决这个问题的提供有用信息的错误消息, 且部署必须失败 例如, 一种解决该问题的办法是用户使用绝对顺序, 在这种情况下相对顺序被忽略 d. 思考这个简短的但具说明下的例子 3 个 web-fragment - 作为应用一部分的 MyFragment1 MyFragment2 和 MyFragment3, 也包括一个 web.xml web-fragment.xml <web-fragment> <name>myfragment1</name> <ordering><after><name>myfragment2</name></after></ordering>... </web-fragment> web-fragment.xml <web-fragment> <name>myfragment2</name>.. </web-fragment> 59

60 web-fragment.xml <web-fragment> <name>myfragment3</name> <ordering><before><others/></before></ordering>.. </web-fragment> web.xml <web-app>... </web-app> 在该示例中, 处理顺序将是 : web.xml MyFragment3 MyFragment2 MyFragment1 前面的示例说明了一些, 但不是全部, 以下是全部原则 <before> 意味着文档必须被安排在指定在嵌套 <name> 元素的 name 匹配的文档之前 <after> 意味着文档必须被安排在指定在嵌套 <name> 元素的 name 匹配的文档之后 在 <before> 或 <after> 可以包括特殊的 <others/> 元素零次或一次, 或直接包括在 <absolute-ordering> 元素中零次或一次 <others/> 元素必须作如下处理 如果 <before> 元素包含一个嵌套的 <others/>, 该文档将被移动有序的文档列表开头 如果有多个文指定 <before><others/>, 则它们将都在有序的文档列表开头, 但该组文档的顺序是未指定的 如果 <after> 元素包含一个嵌套的 <others/>, 该文档将被移动有序的文档列表末尾 如果有多个文指定 <after><others/>, 则它们将都在有序的文档列表末尾, 但该组文档的顺序是未指定的 在一个的 <before> 或 <after> 元素内, 如果存在一个 <others/> 元素, 但在它的父元素内 <name> 元素不是唯一的, 父元素内的其他元素必须按照顺序处理 如果 <others/> 直接出现在 <absolute-ordering> 内,runtime 必须确保任何 web-fragment 未明确指定在 <absolute-ordering> 部分的以处理的顺序包括在这一点上 如果 web-fragment.xml 文件没有 <ordering> 或 web.xml 没有 <absolute-ordering> 元素, 则 artifact 被假定没有任何顺序依赖 如果 runtime 发现循环引用, 必须记录提供有用信息的消息, 应用必须部署失败 此外, 用户采取的一系列动作可能是在 web.xml 中使用绝对顺序 之前的示例可以被扩展以说明当 web.xml 包含顺序部分的情况 60

61 web.xml <web-app> <absolute-ordering> <name>myfragment3</name> <name>myfragment2</name> </absolute-ordering>... </web-app> 在该示例中, 各种元素的顺序将是 : web.xml MyFragment3 MyFragment2 下面包括了一些额外的示例场景 所有这些适用于相对顺序且不是绝对顺序 Document A: <after> <others/> <name> C </name> </after> Document B: <before> <others/> </before> Document C: <after> <others/> </after> Document D: 没有指定顺序 Document E: 没有指定顺序 Document F: 61

62 <before> <others/> <name> B </name> </before> 产生的解析顺序 : web.xml, F, B, D, E, C, A Document <no id>: <after> <others/> </after> <before> <name> C </name> </before> Document B: <before> <others/> </before> Document C: 没有指定顺序 Document D: <after> <others/> </after> Document E: <before> <others/> </before> Document F: 没有指定顺序 产生的解析顺序可能是下列之一 : B, E, F, <no id>, C, D 62

63 B, E, F, <no id>, D, C E, B, F, <no id>, C, D E, B, F, <no id>, D, C E, B, F, D, <no id>, C B, E, F, D, <no id>, C Document A: <after> <name> B </name> </after> Document B: 没有指定顺序 Document C: <before> <others/> </before> Document D: 没有指定顺序 产生的解析顺序 : C, B, D, A 解析的顺序也可能是 : C, D, B, A 或 C, B, A, D 装配 web.xml web-fragment.xml 描述符和注解 如果对于一个应用 Listener Servlet 和 Filter 的调用顺序是很重要的, 那么必须使用部署描述符 同样, 如果有必要, 可以使用上面定义的顺序元素 如上所述, 当时有注解定义 Listener Servlet 和 Filter, 它们调用的顺序是未指定的 下面是用于装配应用程序的最终部署描述符的一组规则 : 1. 如果有关的 Listener Servlet 和 Filter 的顺序必须指定, 那么必须指定在 web-fragment.xml 或 web.xml 2. 顺序将依据它们定义在描述符中的顺序, 和依赖于 web.xml 中的 absolute-ordering 元素或 web-fragment.xml 中的 ordering 元素, 如果存在 a. 匹配请求的过滤器链的顺序是它们在 web.xml 中声明的顺序 b. Servlet 在请求处理时实例化或在部署时立即实例化 在后一种情况, 以它们的 load-on-startup 元素表示的顺序实例化 c. 在之前发布的规范, 上下文 Listener 以随机顺序调用 在 Servlet3.0,Listener 以它们在 web.xml 中声明的顺序调用, 如下所示 : i. javax.servlet.servletcontextlistener 实现的 contextinitialized 方法以声明时顺序调用, contextdestroyed 以相反顺序调用 ii. javax.servlet.servletrequestlistener 实现的 requestinitialized 以声明时顺序调用, 63

64 requestdestroyed 方法以相反顺序调用 iii. javax.servlet.http.httpsessionlistener 实现的 sessioncreated 方法以声明时顺序调用, sessiondestroyed 方法以相反顺序调用 iv. 当相应的事件触发时, javax.servlet.servletcontextattributelistener javax.servlet.servletrequestattributelistener 和 javax.servlet.httpsessionattributelistener 的方法按照它们声明的顺序调用 3. 如果在 web.xml 使用 enabled 元素禁用引入的 servlet, 那么该 servlet 将不可以指定 url-pattern 4. 当在 web.xml web-fragment.xml 和注解之间解析发生冲突时 web 应用的 web.xml 具有最高优先级 5. 如果没有在描述符中指定 metadata-complete 或在部署描述符中设置为 false, 通过组合出现在注解和描述符中的 metadata 导出有效的 metadata 合并的规则具体如下: a. 在 web fragment 中的配置设置用于扩充那些已指定在主 web.xml 的配置设置, 使用这种方式就好像它们指定在同一个 web.xml b. 添加到主 web.xml 的 web fragment 中的配置设置的顺序由 8-70 页的 节 web.xml 和 web-fragment.xml 顺序 指定 c. 当主 web.xml 的 metadata-complete 属性设置为 true, 被认为是完整的且在部署时不会扫描注解和 fragment 如果有 absolute-ordering 和 ordering 元素将被忽略 当设置 fragment 上的为 true 时, metadata-complete 属性仅适用于在特定的 jar 包中扫描注解 d. 除非 metadata-complete 设置为 true, 否则 web fragment 被合并到主 web.xml 合并发生在相关 fragment 的注解处理之后 e. 当使用 web fragment 扩充 web.xml 时以下被认为配置冲突 : i. 多个 <init-param> 元素使用相同的 <param-name> 但不同的 <param-value> ii. 多个 <mime-mapping> 元素使用相同的 <extension> 但不同的 <mime-type> f. 上面的配置冲突被解析为如下 : i. 在主 web.xml 和 web fragment 之间的配置冲突被解析为在 web.xml 的配置具有高优先级 ii. 在两个 web fragment 之间的配置冲突, 冲突的中心元素没有出现在主 web.xml, 将导致一个错误 必须记录一个有用的消息, 且应用必须部署失败 g. 上面的冲突被解析后, 这些额外的规则适用 : i. 可以在多个 web-frament 中声明任意多次元素并生成到 web.xml 比如,<context-param> 元素可以以不同的名字添加 ii. 如果指定在 web.xml 中的覆盖了指定在 web-fragment 中的同名的值, 则可以声明任意多次元素 iii. 如果是最少出现零次且最多出现一次的元素存在于 web fragment, 且没有在主 web.xml 中, 则主 web.xml 继承 web fragment 的设置 如果元素出现在主 web.xml 和 web fragment, 则主 web.xml 的配置设置具有高优先级 例如, 如果在主 web.xml 和 web fragment 中都声明了相同的 servlet, 且声明在 web fragment 中的 servlet 指定了 <load-on-startup> 元素, 且没在主 web.xml 指定, 则 web fragment 的 <load-on-startup> 元素将被使用并合并到 web.xml iv. 如果是最少出现零次且最多出现一次的元素指定在两个 web fragment, 且没有出现在主 64

65 web.xml, 则认为是错误的 例如, 如果两个 web fragment 声明了相同的 Servlet, 但具有不同的 <load-on-startup> 元素, 且相同的 Servlet 也声明在主 web.xml, 但没有 <load-on-startup>, 则必须报告一个错误 v. <welcome-file> 声明是可添加的 vi. 具有相同 <servlet-name> 的 <servlet-mapping> 元素可以添加到多个 web-fragment 在 web.xml 中指定的 <servlet-mapping> 覆盖在 web-fragment 中指定的同名的 <servlet-name> 的 <servlet-mapping> vii. 具有相同 <filter-name> 的 <filter-mapping> 元素可以添加到多个 web-fragment 在 web.xml 中指定的 <filter-mapping> 覆盖在 web-fragment 中指定的同名的 <filter-name> 的 <filter-mapping> viii. 具有相同 <listener-class> 的多个 <listener> 元素被当作一个 <listener> 声明 ix. 合并产生的 web.xml 被认为是 <distributable>, 仅当所有它的 web fragment 也被标记为 <distributable> x. web fragment 的顶级 <icon> 和它的孩子元素,<display-name>, 和 <description> 元素被忽略 xi. jsp-property-group 是可添加的 当绑定静态资源到 jar 包的 META-INF/resources 目录, 推荐 jsp-config 元素使用 url-pattern, 反对使用 extension 映射 此外, 如果存在一个 fragment 的 JSP 资源, 则应该在一个与 fragment 同名的子目录中 这有助于防止一个 web-fragment 的 jsp-property-group 受到来自应用的主 docroot 中的 JSP 的影响和受到来自一个 fragment 的 META-INF/resources 的 JSP 的影响 h. 对于所有资源引用元素 (env-entry, ejb-ref, ejb-local-ref, service-ref, resource-ref, resource-env-ref, message-destination-ref, persistence-context-ref and persistence-unit-ref) 如下规则适用 : i. 如果任意资源引用元素出现在 web fragment, 主 web.xml 继承 web fragment 的值 如果该元素同时出现在主 web.xml 和 web fragment, 使用相同的名字,web.xml 具有高优先级 所有 fragment 的子元素除下面指定的 injection-target 被合并到主 web.xml 例如, 如果主 web.xml 和 web fragment 都使用相同的 <resource-ref-name> 声明一个 <resource-ref>, 将使用 web.xml 中的 <resource-ref> 且不会合并 fragment 中的任意子元素除下面声明的 <injection-target> ii. 如果资源引用元素指定在两个 fragment, 当没有指定在主 web.xml 中, 且资源引用元素的所有属性和子元素都是一样的, 资源引用将被合并到主 web.xml 如果使用相同名字在两个 fragment 中指定资源引用元素, 且没有在 web.xml 中指定, 属性和子元素是不一样的, 那么被认为是错误的 错误必须被报告且应用必须部署失败 例如, 如果两个 web fragment 使用相同的 <resource-ref-name> 声明了 <resource-ref> 但类型一个指定为 javax.sql.datasource 另一个指定为 JavaMail, 这是错误的且应用必须部署失败 iii. 对于在 fragment 中使用相同名称的 <injection-target> 的资源引用元素将被合并到主 web.xml i. 除了上面定义的 web-fragment.xml 的合并规则之外, @WebServiceRefs, 如果资源引用注解应用到类上, 这等价于定义了一个资源, 但是这不等价于定义一个 injection-target 在这种情况下上述规则适用于 injection-target 元素 如果在字段上使用资源引用注解, 这等价于在 web.xml 定义 injection-target 元素 但是如果在描述符中没有 injection-target 元素, 那么 fragment 中的 injection-target 仍将被合并到上面定义的 web.xml 65

66 如果从另一方面来说, 在主 web.xml 中有一个 injection-target 并同时有一个同资源名的资源引用注解, 那么这被认为是对资源引用注解的覆盖 在这种情况下, 由于在描述符中指定了一个 injection-target, 上述定义的规则将适用于除了覆盖的资源引用注解 j. 如果在两个 fragment 中指定了 data-source 元素, 而没有出现在主 web.xml, 且 data-source 元素的所有属性和子元素都是一样的,data-source 将被合并到主 web.xml 如果在两个 fragment 中指定同名的 data-source 元素, 而没有出现在主 web.xml 且两个 fragment 的属性和子元素不是一样的, 这被认为是错误的 在这种情况下, 必须报告一个错误且引用必须部署失败 下面是一些示例, 展示了在不同情况下的结果 代码示例 8-4 web.xml 没有 resource-ref 定义 Fragment 1 web-fragment.xml <resource-ref> <resource-ref-name="foo">... <injection-target> <injection-target-class> com.foo.bar.class </injection-target-class> <injection-target-name> baz </injection-target-name> </injection-target> </resource-ref> 有效的 metadata 将是 <resource-ref> <resource-ref-name="foo">... <injection-target> <injection-target-class> com.foo.bar.class </injection-target-class> <injection-target-name> baz </injection-target-name> </injection-target> </resource-ref> 66

67 代码示例 8-5 web.xml <resource-ref> <resource-ref-name="foo">... </resource-ref> Fragment 1 web-fragment.xml <resource-ref> <resource-ref-name="foo">... <injection-target> <injection-target-class> com.foo.bar.class </injection-target-class> <injection-target-name> baz </injection-target-name> </injection-target> </resource-ref> Fragment 2 web-fragment.xml <resource-ref> <resource-ref-name="foo">... <injection-target> <injection-target-class> com.foo.bar2.class </injection-target-class> <injection-target-name> baz2 </injection-target-name> </injection-target> </resource-ref> 有效的 metadata 将是 67

68 <resource-ref> <resource-ref-name="foo">... <injection-target> <injection-target-class> com.foo.bar.class </injection-target-class> <injection-target-name> baz </injection-target-name> </injection-target> <injection-target> <injection-target-class> com.foo.bar2.class </injection-target-class> <injection-target-name> baz2 </injection-target-name> </injection-target> </resource-ref> 代码示例 8-6 web.xml <resource-ref> <resource-ref-name="foo"> <injection-target> <injection-target-class> com.foo.bar3.class </injection-target-class> <injection-target-name> baz3 </injection-target-name>... </resource-ref> 68

69 Fragment 1 web-fragment.xml <resource-ref> <resource-ref-name="foo">... <injection-target> <injection-target-class> com.foo.bar.class </injection-target-class> <injection-target-name> baz </injection-target-name> </injection-target> </resource-ref> Fragment 2 web-fragment.xml <resource-ref> <resource-ref-name="foo">... <injection-target> <injection-target-class> com.foo.bar2.class </injection-target-class> <injection-target-name> baz2 </injection-target-name> </injection-target> </resource-ref> 有效的 metadata 将是 69

70 <resource-ref> <resource-ref-name="foo"> <injection-target> <injection-target-class> com.foo.bar3.class </injection-target-class> <injection-target-name> baz3 </injection-target-name> <injection-target-class> com.foo.bar.class </injection-target-class> <injection-target-name> baz </injection-target-name> <injection-target-class> com.foo.bar2.class </injection-target-class> <injection-target-name> baz2 </injection-target-name> </injection-target>... </resource-ref> Fragment1 和 2 的 <injection-target> 将被合并到主 web.xml k. 如果主 web.xml 没有指定任何 <post-construct> 元素, 且 web-fragment 中也指定了 <post-construct>, 那么 fragment 中的 <post-construct> 将被合并到主 web.xml 不过如果在主 web.xml 中至少指定一个 <post-construct> 元素, 那么 fragment 中的 <post-construct> 将不被合并 由 web.xml 的作者负责确保 <post-construct> 列表是完成的 l. 如果主 web.xml 没有指定任何 <pre-destroy> 元素, 且 web-fragment 中也指定了 <pre-destroy>, 那么 fragment 中的 <pre-destroy> 元素将被合并到主 web.xml 不过如果在主 web.xml 中至少指定一个 <pre-destroy> 元素, 那么 fragment 中的 <pre-destroy> 将不被合并 由 web.xml 的作者负责确保 <pre-destroy> 列表是完成的 m. 在处理完 web-fragment.xml 之后, 在处理下一个 fragment 之前相应 fragment 的注解被处理以完成有效的 metadata 以下规则用于处理注解: n. 通过注解指定的 metadata, 尚未存在于描述符中, 将被用来扩充有效的描述符 i. 指定在主 web.xml 或 web fragment 中的配置比通过注解指定的配置具有更高优先级 ii. 注解定义 Servlet, 要使用描述符覆盖其值, 描述符中的 servlet 名字必须匹配使用注解指定的 servlet 名字 ( 明确指定或如果注解没有指定则是默认名字 ) iii. 使用注解定义的 Servlet 和 Filter 初始化参数, 如果描述符中的初始化参数的名字完全匹配指定在注解中的名字, 则将被描述符中的覆盖 初始化参数在注解和描述符之间是可添加的 70

71 iv. url-pattern, 当以给定 servlet 名字指定在描述符中时, 将覆盖注解指定的 url pattern v. 注解定义的 Filter, 要使用描述符覆盖其值, 描述符中的 Filter 名字必须匹配使用注解指定的 Filter 名字 ( 明确指定或如果注解没有指定则是默认名字 ) vi. Filter 应用的 url-pattern, 当以给定 Filter 名字指定在描述符中时, 将覆盖注解指定的 url pattern vii. Filter 应用的 DispatcherType, 当以给定 Filter 名字指定在描述符中时, 将覆盖注解指定的 DispatcherType viii. 下面的例子演示了上面的一些规则 : 使用注解声明 Servlet 和在打包到的相应 web.xml 描述符中声明 /MyPattern, initparams={@webinitparam(name="ccc", value="333")}) public class com.acme.foo extends HttpServlet {... } web.xml <servlet> <servlet-class>com.acme.foo</servlet-class> <servlet-name>foo</servlet-name> <init-param> <param-name>aaa</param-name> <param-value>111</param-value> </init-param> </servlet> <servlet> <servlet-class>com.acme.foo</servlet-class> <servlet-name>fum</servlet-name> <init-param> <param-name>bbb</param-name> <param-value>222</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>foo</servlet-name> <url-pattern>/foo/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>fum</servlet-name> <url-pattern>/fum/*</url-pattern> </servlet-mapping> 因为使用注解声明的 Servlet 名字不匹配在 web.xml 中声明的 servlet 名字, 在 web.xml 中除了其他的声明外, 注解指定一个新的 servlet 声明, 相当于 : 71

72 <servlet> <servlet-class>com.acme.foo</servlet-class> <servlet-name>com.acme.foo</servlet-name> <init-param> <param-name>ccc</param-name> <param-value>333</param-name> </servlet> 如果上面的 web.xml 被替换为如下 : <servlet> <servlet-class>com.acme.foo</servlet-class> <servlet-name>com.acme.foo</servlet-name> <init-param> <param-name>aaa</param-name> <param-value>111</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>com.acme.foo</servlet-name> <url-pattern>/foo/*</url-pattern> </servlet-mapping> 那么有效的描述符将等价于 : <servlet> <servlet-class>com.acme.foo</servlet-class> <servlet-name>com.acme.foo</servlet-name> <init-param> <param-name>aaa</param-name> <param-value>111</param-value> </init-param> <init-param> <param-name>ccc</param-name> <param-value>333</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>com.acme.foo</servlet-name> <url-pattern>/foo/*</url-pattern> </servlet-mapping> 共享库 / 运行时可插拔性 除了支持 fragment 和使用注解的外, 要求之一是我们不仅能 plug-in 绑定在 WEB-INF/lib 下的, 也能 plugin 72

73 框架共享副本 包括能 plug-in 到容器的如建议在 web 容器之上的 JAX-WS JAX-RS 和 JSF ServletContainerInitializer 允许处理这样的使用情况下, 如下所述 ServletContainerInitializer 类通过 jar services API 查找 对于每一个应用, 应用启动时, 由容器创建一个 ServletContainerInitializer 实例 框架提供的 ServletContainerInitializer 实现必须绑定在 jar 包的 META-INF/services 目录中的一个叫做 javax.servlet.servletcontainerinitializer 的文件, 根据 jar services API, 指定 ServletContainerInitializer 的实现 除 ServletContainerInitializer 外, 我们还有一个注解 HandlesTypes 在 ServletContainerInitializer 实现上的 HandlesTypes 注解用于表示感兴趣的一些类, 它们可能指定了 HandlesTypes 的 value 中的注解 ( 类型 方法或自动级别的注解 ), 或者是其类型的超类继承 / 实现了这些类之一 无论是否设置了 metadata-complete, HandlesTypes 注解将应用 当检测一个应用的类看是否它们匹配 ServletContainerInitializer 的 HandlesTypes 指定的条件时, 如果应用的一个或多个可选的 JAR 包缺失, 容器可能遇到类装载问题 由于容器不能决定是否这些类型的类装载失败将阻止应用正常工作, 它必须忽略它们, 同时也提供一个将记录它们的配置选项 如果 ServletContainerInitializer 注解, 或如果没有匹配任何指定的 HandlesType, 那么它会为每个应用使用 null 值的集合调用一次 这将允许 initializer 基于应用中可用的资源决定是否需要初始化 Servlet/Filter 在任何 Servlet Listener 的事件被触发之前, 当应用正在启动时,ServletContainerInitializer 的 onstartup 方法将被调用 ServletContainerInitializer s 的 onstartup 得到一个类的 Set, 其或者继承 / 实现 initializer 表示感兴趣的类, 注解中的任意类注解的 下面一个具体的例子展示了这是如何工作的 让我们学习 JAX-WS web service 运行时 JAX-WS 运行时实现通常不是绑定到每个 war 包 其实现将绑定一个 ServletContainerInitializer 的实现 ( 如下所示 ) 且容器将查找使用的 services API( 绑定在 jar 包中的 META-INF/services 目录中的一个叫做 javax.servlet.servletcontainerinitializer 的文件, 它将指出如下所示的 JAXWSServletContainerInitializer implements ServletContainerInitializer { public void onstartup(set<class<?>> c, ServletContext ctx) throws ServletException { // 在此, 使用 JAX-WS 特定的代码来初始化运行库和设置 mapping 等 ServletRegistration reg = ctx.addservlet("jaxwsservlet", "com.sun.webservice.jaxwsservlet"); reg.addservletmapping("/foo"); } } 框架的 jar 包也可能被绑定到 war 报目录中的 WEB-INF/lib 目录 如果 ServletContainerInitializer 被绑定到应用的 WEB-INF/lib 目录内的一个 JAR 包中, 它的 onstartup 方法在绑定到的应用启动期间将被仅调用一次 如果, 相反,ServletContainerInitialzer 被绑定到 WEB-INF/lib 目录外的一个 JAR 包中, 但仍能被运行时的服务提供商查找机制发现时, 每次启动应用时, 它的 onstartup 方法将被调用 ServletContainerInitializer 接口的实现将被运行时的服务查找机制或语义上与它等价的容器特定机制发现 在任一种情况,web fragment JAR 包的 ServletContainerInitializer 服务被排除于一个 absolute ordering 必须 73

74 被忽略, 这些服务被发现的顺序必须遵照应用的类装载委托模型 8.3 JSP 容器可插拔性 ServletContainerInitializer 和编程式注册特性可以在 Servlet 和 JSP 容器之间提供一个清晰的职责分离, 通过由 Servlet 容器只负责解析 web.xml 和 web-fragment.xml 资源, 而解析标签库描述符 (TLD) 资源委托给 JSP 容器 在此之前,web 容器必须扫描 TLD 资源寻找任何 Listener 声明 使用 Servlet3.0 和后续版本后, 该职责可以委托给 JSP 容器 JSP 容器是内嵌到一个 Servlet3.0 兼容的 Servlet 容器中, 可以提供它自己的 ServletContainerInitializer 实现, 搜索传递到它的 onstartup 方法的 ServletContext 参数寻找任何 TLD 资源, 扫描这些资源寻找 Listener 声明, 并向 ServletContext 注册相关的 Listener 另外,Servlet3.0 之前,JSP 容器用于必须扫描应用的部署描述符寻找 jsp-config 相关的配置 使用 Servlet3.0 和后续版本后,Servlet 容器必须提供通过 ServletContext.getJspConfigDescriptor 方法得到应用的 web.xml 和 web-fragment.xml 部署描述符中的任何 jsp-config 相关的配置 在 TLD 中发现的和编程注册的任何 ServletContextListener 在它们提供的功能上是有限的 任何试图调用一个在 Servlet3.0 中加入的 ServletContext API 方法将导致一个 UnsupportedOperationException 另外,Servlet3.0 和后续版本兼容的 Servlet 容器必须提供一个名字为 javax.servlet.context.orderedlibs 的 ServletContext 属性, 它的值 (java.util.list<java.lang.string> 类型 ) 包含了由 ServletContext 所代表的应用的 WEB-INF/lib 目录中的 JAR 文件的名字列表, 按照它们的 web fragment 名字的排序 ( 可能排除如果 fragment JAR 包已经被排除在 absolute-ordering), 或者 null 如果应用没有指定任意绝对或相对顺序 8.4 处理注解和 fragment Web 应用可同时包括注解和 web.xml/web-fragment.xml 部署描述符 如果没有部署描述符, 或有一个但其 metadata-complete 没有设置为 true,web.xml web-fragment 和注解如果在应用中使用则必须被处理 下表 描述了是否处理注解和 web.xml 的 fragment 表 8-1 注解和 web fragment 处理要求 部署描述符 metadata-complete 处理注解和 web fragment web.xml 2.5 yes no web.xml 2.5 no yes web.xml 3.0 或后来的 yes no web.xml 3.0 或后来的 no yes 74

75 分派请求 构建 Web 应用时, 把请求转发给另一个 servlet 处理 或在 response 中包含另一个 servlet 的输出通常是很有 用的 RequestDispatcher 接口提供了一种机制来实现这种功能 当请求启用异步处理时,AsyncContext 允许用户将这个请求转发到 servlet 容器 9.1 获得一个 RequestDispatcher 实现了 RequestDispatcher 接口的对象, 可以从 ServletContext 中的下面方法得到 : getrequestdispatcher getnameddispatcher getrequestdispatcher 方法需要一个 String 类型的参数描述在 ServletContext 作用域内的路径 这个路径必须是相对于 ServletContext 的根路径, 或以 / 开头, 或者为空 该方法根据这个路径使用 servlet 路径匹配规则 ( 见第 12 章, 请求映射到 servlet) 来查找 servlet, 把它包装成 RequestDispatcher 对象并返回 如果基于给定的路径没有找到相应的 servlet, 那么返回这个路径内容提供的 RequestDispatcher getnameddispatcher 方法使用一个 ServletContext 知道的 servlet 名称作为参数 如果找到一个 servlet, 则把它包装成 RequestDispatcher 对象, 并返回该对象 如果没有与给定名字相关的 servlet, 该方法必须返回 null 为了让 RequestDispatcher 对象使用相对于当前请求路径的相对路径 ( 不是相对于 ServletContext 根路径 ) 获得一个 servlet, 在 ServletRequest 接口中提供了 getrequestdispatcher 方法 此方法的行为与 ServletContext 中同名的方法相似 Servlet 容器根据 request 对象中的信息把给定的相对路径转换成当前 servlet 的完整路径 例如, 在以 / 作为上下文根路径和请求路径 /garden/tools.html 中, 通过 ServletRequest.getRequestDispatcher("header.html") 获得的请求调度器和通过调用 ServletContext.getRequestDispatcher("/garden/header.html") 获得的完全一样 请求调度器路径中的查询字符串 ServletContext 和 ServletRequest 中创建 RequestDispatcher 对象的方法使用的路径信息中允许附加可选的查询字符串信息 比如, 开发人员可以通过下面的代码来获得一个 RequestDispatcher: String path = /raisins.jsp?orderno=5 ; RequestDispatcher rd = context.getrequestdispatcher(path); rd.include(request, response); 查询字符串中指定的用来创建 RequestDispatcher 的参数优先于传递给它包含的 servlet 中的其他同名参数 与 RequestDispatcher 相关的参数作用域仅适用于包含 (include) 或转发 (forward) 调用期间 9.2 请求调度器的使用 要使用请求调度器,servlet 可调用 RequestDispatcher 接口的 include 或 forward 方法 这些方法的参数既可以是 javax.servlet.servlet 接口的 service 方法传来的 request 和 response 对象实例, 也可以是本规范的 2.3 版 75

76 本中介绍的 request 和 response 包装器类的子类对象实例 对于后者, 包装器实例必须包装容器传递到 service 方法中的 request 和 response 对象 容器提供者应该保证分发到目标 servlet 的请求作为原始请求发生在的同一个 JVM 的同一个线程中 9.3 Include 方法 RequestDispatcher 接口的 include 方法可能随时被调用 Include 方法的目标 servlet 能够访问 request 对象的各个方法 (all aspects), 但是使用 response 对象的方法会受到更多限制 它只能把信息写到 response 对象的 ServletOutputStream 或 Writer 中, 或提交在最后写保留在 response 缓冲区中的内容, 或通过显式地调用 ServletResponse 接口的 flushbuffer 方法 它不能设置响应头部信息或调用任何影响响应头部信息的方法,HttpServletRequest.getSession() 和 HttpServletRequest.getSession(boolean) 方法除外 任何试图设置头部信息必须被忽略, 任何调用 HttpServletRequest.getSession() 和 HttpServletRequest.getSession(boolean) 方法将需要添加一个 Cookie 响应头部信息, 如果响应已经提交, 必须抛出一个 IllegalStateException 异常 如果默认的 servlet 是 RequestDispatch.include() 的目标 servlet, 而且请求的资源不存在, 那么默认的 servlet 必须抛出 FileNotFoundException 异常 如果这个异常没有被捕获和处理, 以及响应还未提交, 则响应状态码必须被设置为 内置请求参数 除了可以用 getnameddispatcher 方法获得 servlet 外, 已经被另一个 servlet 使用 RequestDispatcher 的 include 方法调用过的 servlet, 有权访问被调用过的 servlet 的路径 以下的 request 属性必须被设置 : javax.servlet.include.request_uri javax.servlet.include.context_path javax.servlet.include.servlet_path javax.servlet.include.path_info javax.servlet.include.query_string 这些属性可以通过包含的 servlet 的 request 对象的 getattribute 方法访问, 它们的值必须分别与被包含 servlet 的请求 RUI 上下文路径 servlet 路径 路径信息 查询字符串相等 如果随后的请求包含这些属性, 那么这些属性会被后面包含的属性值替换 如果包含的 servlet 通过 getnameddispatcher 方法获得, 那么这些属性不能被设置 9.4 Forward 方法 RequestDispatcher 接口的 forward 方法, 只有在没有输出提交到向客户端时, 通过正在被调用的 servlet 调用 如果 response 缓冲区中存在尚未提交的输出数据, 这些数据内容必须在目标 servlet 的 service 方法调用前清除 如果 response 已经提交, 必须抛出一个 IllegalStateException 异常 76

77 request 对象暴露给目标 servlet 的路径元素 (path elements) 必须反映获得 RequestDispatcher 使用的路径 唯一例外的是, 如果 RequestDispatcher 是通过 getnameddispatcher 方法获得 这种情况下,request 对象的路径元素必须反映这些原始请求 在 RequestDispatcher 接口的 forward 方法无异常返回之前, 响应的内容必须被发送和提交, 且由 Servlet 容器关闭, 除非请求处于异步模式 如果 RequestDispatcher.forward() 的目标发生错误, 异常信息会传回所有调用它经过的过滤器和 servlet, 且最终传回给容器 查询字符串 在转发或包含请求时请求调度机制负责聚集 (aggregating) 查询字符串参数 转发的请求参数 除了可以用 getnameddispatcher 方法获得 servlet 外, 已经被另一个 servlet 使用 RequestDispatcher 的 forward 方法调用过的 servlet, 有权访问被调用过的 servlet 的路径 以下的 request 属性必须设置 : javax.servlet.forward.request_uri javax.servlet.forward.context_path javax.servlet.forward.servlet_path javax.servlet.forward.path_info javax.servlet.forward.query_string 这些属性的值必须分别与 HttpServletRequest 的 getrequesturi, getcontextpath getservletpath getpathinfo getquerystring 方法的返回值相等, 这些方法在从客户端接收到的 request 对象上调用, 值传递给调用链中的第一个 servlet 对象 ( 在 request 对象上调用从客户端接收请求的调用链中的第一个 servlet 对象 ) 这些属性通过转发 servlet 的 request 对象的 getattribut 方法访问 请注意, 即使在多个转发和相继的包含 (subsequent includes) 被调用的情况下, 这些属性必须始终反映原始请求中的信息 如果转发的 servlet 使用 getnameddispatcher 方法获得, 这些属性必须不能被设置 9.5 错误处理 如果请求分发的目标 servlet 抛出运行时异常或受检查类型异常 ServletException 或 IOException, 异常应该传播到调用的 servlet 所有其它的异常都应该被包装成 ServletExceptions, 异常的根本原因设置成原来的异常, 因为它不应该被传播 9.6 获得一个异步上下文对象 实现了 AsyncContext 接口的对象可从 ServletRequest 的一个 startasync 方法中获得, 一旦有了 AsyncContext 77

78 对象, 你就能够使用它的 complete() 方法来完成请求处理, 或使用下面描述的转发方法 9.7 Dispatch 方法 可以使用 AsyncContext 中下面的方法来转发请求 : dispatch(path) 这个 dispatch 方法的 String 参数描述了一个在 ServletContext 作用域中的路径 这个路径必须是相对于 ServletContext 的根路径并以 / 开头 dispatch(servletcontext, path) 这个 dispatch 方法的 String 参数描述了一个在 ServletContext 指定作用域中的路径 这个路径必须是相对于 ServletContext 的根路径并以 / 开头 dispatch() 这个方法没有参数, 它使用原来的 URI 路径 如果 AsyncContext 已经通过 startasync(servletrequest, ServletResponse) 初始化, 且传递过来的 request 是 HttpServletRequest 的实例, 那么这个请求分发到 HttpServletRequest.getRequestURI() 返回的 URI 否则当最后转发时当由容器转发到 request 的 URI AsyncContext 接口中的 dispatch 方法可被等待异步事件发生的应用程序调用 如果 AsyncContext 已经调用了 complete() 方法, 必须抛出 IllegalStateException 异常 所有不同的 dispatch 方法会立即返回并且不会提交 response request 对象暴露给目标 servlet 的路径元素 (path elements) 必须反映 AsyncContext.dispatch 中指定的路径 查询字符串 请求调度机制是在调度请求时负责聚焦 (aggregating) 查询字符串 调度请求参数 使用 AsyncContext 的 dispatch 方法调用过的 servlet 能够访问原始请求的路径 下面的 request 属性必须设置 : javax.servlet.async.request_uri javax.servlet.async.context_path javax.servlet.async.servlet_path javax.servlet.async.path_info javax.servlet.async.query_string 这些属性的值必须分别与 HttpServletRequest 的 getrequesturi, getcontextpath getservletpath getpathinfo getquerystring 方法的返回值相等, 这些方法在从客户端接收到的 request 对象上调用, 值传递给调用链中的第一个 servlet 对象 这些属性通过转发 servlet 的 request 对象的 getattribut 方法访问 请注意, 即使在多个转发和相继的包含 78

79 (subsequent includes) 被调用的情况下, 这些属性必须始终反映原始请求中的信息 79

80 Web 应用 一个 Web 应用是由许多 servlet HTML 页面 类和其他资源组成的集合, 这些资源组成了一个运行在 Web 服务器上的完整应用程序 Web 应用程序能够捆绑和运行在来自不同提供商的不同容器上 10.1 Web 服务器中的 Web 应用程序 在 Web 服务器中 Web 应用程序的根目录是一个特定的路径 例如, 一个 catalog 应用, 可以位于 以这个前缀开始的所有请求将被路由到代表 catalog 应用的 ServletContext 环境中 servlet 容器能够制定 Web 应用程序自动生成的规则 例如, 一个 ~user/ 映射可用于映射到一个基于 /home /user/public_html/ 的 Web 应用 默认情况下, 在任何时候一个 Web 应用程序的实例必须运行在一个虚拟机 (VM) 中 如果应用程序通过其部署描述文件标记为 分布式 的, 那么可以覆盖此行为 标记为分布式的应用程序必须遵守比普通的 Web 应用程序更严格的规则 本规范中陈述了这些规则 10.2 与 ServletContext 的关系 servlet 容器必须强制 web 应用程序和 ServletContext 之间一对一进行通信 ServletContext 对象提供了一个 servlet 和它的应用程序视图 10.3 Web 应用的要素 Web 应用程序可能包括以下项目 : Servlets JSP 页面 实用工具类 静态文件 (HTML, 图像, 声音等 ) 客户端 Java applets,beans, 和类 结合上述所有要素的描述性的元信息 10.4 部署层次结构 本规范定义了一个用于部署和打包用途的, 可存在于开放文件系统 归档文件或一些其他形式中的层次结构 建议 servlet 容器支持这种结构作为运行时表示形式, 但不是必须的 10.5 目录结构 一个 Web 应用程序以结构化的目录层次结构存在 层次结构的根目录作为文件的归档目录, 这些文件是应 80

81 用的一部分 例如, 对于 Web 容器中一个 Web 应用程序的上下文路径 /catalog, 在 Web 应用程序层次结构中的 index.html 文件, 或在 WEB-INF/lib 目录下的 JAR 文件中的 META-INF/resources 目录下包括的 index.html 文件, 可以满足从 /catalog/index.html 送达的请求 如果在根上下文中和应用的 WEB-INF/lib 目录下的 JAR 文件中的 META-INF/resources 目录中都存在一个 index.html 文件, 那么必须使用根上下文中的 index.html 匹配的 URL 到上下文路径的规则安排在第 12 章 : 请求映射到 servlet 中 由于应用的上下文路径确定了 Web 应用内容的 URL 命名空间,Web 容器必须拒绝 Web 应用定义的上下文路径, 因为可能在这个 URL 命名空间中导致潜在的冲突 例如, 试图部署两个具有相同上下文路径的 Web 应用时可能发生这种情况 由于把请求匹配到资源是区分大小写的, 所以在确定潜在冲突时也必须区分大小写 应用程序层次结构中存在一个名为 WEB-INF 的特殊目录 这个目录包含了与应用程序相关的所有东西, 这些东西不在应用程序的归档目录中 大多数 WEB-INF 节点都不是应用程序公共文档树的一部分 除了静态资源和 WEB-INF/lib 目录下打包在 JAR 文件中 META-INF/resources 目录下的 JSP 文件之外,WEB-INF 目录下包含的其他任何文件都不能由容器直接提供给客户端访问 然而,WEB-INF 目录中的内容可以通过 servlet 代码调用 ServletContext 的 getresource 和 getresourceasstream 方法来访问, 并可使用 RequestDispatcher 调用公开这些内容 因此, 如果应用开发人员想通过 servlet 代码访问这些内容, 而不愿意直接对客户端公开应用程序指定配置信息, 那么可以把它放在这个目录下 由于把请求匹配到资源的映射区分大小写, 例如, 客户端请求 /WEB-INF/foo, /WEb-iNf/foo, 不应该返回位于 /WEB-INF 下的 Web 应用程序的内容, 也不应该返回其中任何形式的目录列表 WEB-INF 目录中的内容有 : /WEB-INF/web.xml 部署描述文件 servlet 和实用工具类目录 /WEB-INF/classes/ 此目录中的类对应用程序类加载器必须是可见的 java 归档文件区域 /WEB-INF/lib/*.jar 这些文件中包括了 servlet,beans, 静态资源和打包在 JAR 文件中的 JSP 文件, 以及其他对 Web 应用程序有用的实用工具类 Web 应用程序的类加载器必须能够从这些归档文件中加载类 Web 应用程序类加载器必须先从 WEB-INF/classes 目录下加载类, 然后从 WEB-INF/lib 目录下的 JAR 库中加载 此外, 除了静态资源打包在 JAR 文件中的情况外, 任何来自客户端的请求访问 WEB-INF/ 目录中的资源必须返回一个 SC_NOT_FOUND(404) 的响应 应用程序目录结构示例 下面是一个示例 Web 应用程序的文件清单 : /index.html /howto.jsp /feedback.jsp /images/banner.gif /images/jumping.gif /WEB-INF/web.xml /WEB-INF/lib/jspbean.jar /WEB-INF/lib/catalog.jar!/META-INF/resources/catalog/moreOffers/books.html 81

82 /WEB-INF/classes/com/mycorp/servlets/MyServlet.class /WEB-INF/classes/com/mycorp/util/MyUtils.class 10.6 Web 应用程序归档文件 可以使用标准的 Java 归档工具把 Web 应用程序打包并签名到一个 Web 存档格式 (WAR) 文件中 例如, 一个关于 issue tracking 的应用程序可以分布在一个称为 issuetrack.war 的归档文件中 当打包成这种形式时, 将生成一个 META-INF 目录, 其中包含了对 java 归档工具有用的信息 尽管这个目录的内容可以通过 servlet 代码调用 ServletContext 的 getresource 和 getresourceasstream 方法来访问, 容器也不能把这个目录当作内容来响应客户端请求 此外, 任何请求访问 META-INF 目录中的资源必须返回一个 SC_NOT_FOUND(404) 的响应 10.7 Web 应用程序部署描述文件 Web 应用程序部署描述文件 ( 见第 14 章, 部署描述文件 ) 的配置和部署信息包括以下几种类型 : ServletContext 的初始化参数 Session 配置 Servlet/JSP 的定义 Servlet JSP 的映射 MIME 类型映射 欢迎文件列表 错误页面 安全 扩展的依赖关系 当许多应用程序使用相同的代码或资源, 通常将它们安装在容器的库文件中 这些文件往往是通用的或标准的 API, 可以在不牺牲可移植性的情况下使用 仅由一个或几个应用程序使用的文件将作为 Web 应用程序的一部分来访问 容器必须为这些库提供一个目录 放置在这个目录中的文件必须对所有的 Web 应用可见 此目录的位置由容器指定 servlet 容器用于加载这些库文件的类加载器必须和在同一个 JVM 中的所有 Web 应用的类加载器相同 这个类加载器的实例必须在 Web 应用程序类加载器的父类加载器链中 为了保持可移植性, 应用程序开发人员需要知道 Web 容器中安装了哪些扩展, 而容器需要知道 WAR 中的 servlet 依赖哪些库 依赖这样的扩展的应用开发人员必须在 WAR 文件中提供一个列出所有 WAR 文件所需扩展的 META-INF/MANIFEST.MF 文件 清单文件的格式应该遵循标准的 JAR 清单格式 在部署 Web 应用程序的时候,Web 容器必须使正确的扩展版本对遵循可选包版本控制 (Optional Package Versioning) 机制 ( 定义的规则的应用程序可见 Web 容器也必须能够识别出 WAR 文件中 WEB-INF/lib 目录下的任意一个 JAR 包中的清单文件声明的依赖 82

83 关系 如果 Web 容器不能够满足以这种方式声明的依赖关系, 它应该使用一条有意义的错误消息拒绝该应用程序 Web 应用程序类加载器 容器用于加载 WAR 文件中 servlet 的类加载器必须允许开发人员使用 getresource 加载遵循正常 JavaSE 语义的 WAR 文件的 JAR 包中包含的任何资源 和 Java EE 许可协议中描述的一样, 不属于 Java EE 产品的 servlet 容器不应该允许应用程序覆盖 Java SE 平台中的类, 如在 java.* 和 javax.* 命名空间中的类,Java SE 不允许进行修改 容器不应该允许应用程序覆盖或访问容器的实现类 同时建议应用程序类加载器实现成 WAR 文件中的类和资源优先于属于容器范围内的 JAR 包中的类和资源加载 一个类加载器的实现必须保证对部署到容器的每个 web 应用, 调用 Thread.currentThread.getContextClassLoader() 返回一个实现了本节规定的约定的 ClassLoader 实例 此外, 部署的每个 Web 应用程序的 ClassLoader 实例必须是一个单独的实例 容器必须在任何回调 ( 包括侦听器回调 ) 到 Web 应用程序之前设置上面描述的线程上下文 ClassLoader, 一旦回调返回, 需要把它设置成原来的 ClassLoader 10.8 更新 Web 应用 服务器应该能够更新一个新版本的应用程序, 而无需重启容器 当一个应用程序更新时, 容器应提供一个可靠的方法来保存该应用程序的会话数据 10.9 错误处理 请求属性 在发生错误时,Web 应用程序必须能够详细说明, 应用程序中的其他资源被用来提供错误响应的内容主体 这些资源的规定在部署描述文件中配置 如果错误处理位于一个 servlet 或 JSP 页面 : 原来打开的由容器创建的请求和响应对象被传递给 servlet 或 JSP 页面 请求路径和属性被设置成如同 RequestDispatcher.forward 跳转到已经完成的错误资源一样 必须设置表 10-1 中的请求属性 表 10-1 请求属性和它们的类型 请求属性 javax.servlet.error.status_code javax.servlet.error.exception_type javax.servlet.error.message javax.servlet.error.exception 类型 java.lang.integer java.lang.class java.lang.class java.lang.throwable 83

84 javax.servlet.error.request_uri javax.servlet.error.servlet_name java.lang.string java.lang.string 这些属性允许 servlet 根据状态码 异常类型 错误消息 传播的异常对象 发生错误时由 servlet 处理的请求 URI( 像调用 getrequesturi 方法确定的 URI 一样 ) 以及发生错误的 servlet 的逻辑名称来生成专门的内容 由于本规范的 2.3 版本引入了异常对象属性列表, 异常类型和错误消息属性是多余的 他们保留向后兼容早期的 API 版本 错误页面 为了使开发人员能够在 servlet 产生一个错误时自定义内容的外观返回到 Web 客户端, 部署描述文件中定义了一组错误页面说明 这种语法允许当 servlet 或过滤器调用 response 的 senderror 方法指定状态码时, 或如果 servlet 产生一个异常或错误传播给容器时, 由容器返回资源配置 如果调用 response 的 senderror 方法, 容器参照为 Web 应用声明的错误页面列表, 使用状态码语法并试图匹配一个错误页面 如果找到一个匹配的错误页面, 容器返回这个位置条目指示的资源 在处理请求的时候 servlet 或过滤器可能会抛出以下异常 : 运行时异常或错误 ServletException 或它的子类异常 IOException 或它的子类异常 Web 应用程序可以使用 exception-type 元素声明错误页面 在这种情况下, 容器通过比较抛出的异常与使用 exception-type 元素定义的 error-page 列表来匹配异常类型 在容器中的匹配结果返回这个位置条目指示的资源 在类层次中最接近的匹配将被返回 如果声明的 error-page 中没有包含 exception-type 适合使用的类层次结构的匹配, 那么抛出一个 ServletException 异常或它的子类异常, 容器通过 ServletException.getRootCause 方法提取包装的异常 第二遍通过修改错误页面声明, 使用包装的异常再次尝试匹配声明的错误页面 使用 exception-type 元素声明的 error-page 在部署描述文件中必须唯一的, 由 exception-type 的类名决定它的唯一性 同样地, 使用 status-code 元素声明的 error-page 在部署描述文件中必须是唯一的, 由状态码决定它的唯一性 如果部署描述中的一个 error-page 元素没包含一个 exception-type 或 an error-code 元素, 错误页面时默认的错误页面 当错误发生时, 错误页面机制不会干预调用使用 RequestDispatcher 或 filter.dofilter 方法 用这种方法, 过滤器或 Servlet 有机会使用 RequestDispatcher 处理产生的错误 如果上述错误页面机制没有处理 servlet 产生的错误, 那么容器必须确保发送一个状态 500 的响应 默认的 servlet 和容器将使用 senderror 方法, 发送 4xx 和 5xx 状态的响应, 这样错误机制才可能会被调用 默认的 servlet 和容器将使用 setstatus 方法, 设置 2xx 和 3xx 的响应, 并不会调用错误页面机制 如果应用程序使用第 节, 第 2-10 页 异步处理 中描述的异步操作, 那么处理应用程序创建的线程的所有错误是应用程序的职责 容器应该通过 AsyncContext.start 方法注意线程发出的错误 对于处理 84

85 AsyncContext.dispatch 过程中发生的错误, 请参照第 2-16 页中看到的几节, 执行 dispatch 方法的时候可能 发生的错误或异常必须被容器按照如下的方式捕获并处理 错误过滤器 错误页面机制运行在由容器创建的原来未包装过的或未经过过滤的 request 或 response 对象上 在第 节 过滤器和请求转发 中描述的机制可以在产生一个错误响应之前用来指定要应用的过滤器 欢迎文件 Web 应用程序开发人员可以在 Web 应用程序部署描述文件中定义一个称为欢迎文件的局部 URI 有序列表 在 Web 应用程序部署描述文件模式中描述了部署描述文件中欢迎文件列表的语法 这种机制的目的是, 当一个对应到 WAR 文件中一个目录条目的请求 URI 没有映射到一个 Web 组件时, 允许部署者为容器用于添加 URI 指定局部 URI 有序列表 这种请求被认为是有效的局部请求 通过下面常见的例子来明确这种用法的便利 : 可以定义 index.html 欢迎文件, 以便像请求 URL host:port/webapp/directory/, 其中 directory 是 WAR 文件中的一个不能映射到 servlet 或 JSP 页面的条目, 以下面的形式返回给客户端 : host:port/webapp/directory/index.html 如果 Web 容器接收到一个有效的局部请求,Web 容器必须检查部署描述文件中定义的欢迎文件列表 欢迎文件列表是一个没有尾随或前导 / 的局部 URL 有序列表 Web 服务器必须把部署描述文件中按指定顺序的每个欢迎文件添加到局部请求, 并检查 WAR 文件中的静态资源是否映射到请求 URI Web 服务器必须再把部署描述文件中按指定顺序的每个欢迎文件添加到局部请求, 并检查 servlet 是否映射到请求 URI Web 容器必须将请求发送到 WAR 文件中第一个匹配的资源 容器可使用转发 重定向 或容器指定的机制将请求发送到欢迎资源, 这与直接请求没有什么区别 如果按上述的方式没有找到匹配的欢迎文件, 容器可能会使用它认为合适的方式处理该请求 对于有的配置来说, 这可能意味着返回一个目录列表, 对其他配置来说可能返回一个 404 响应 考虑一个 Web 应用程序 : 部署描述文件列出了以下的欢迎文件 <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> WAR 文件中的静态内容如下 /foo/index.html /foo/default.jsp /foo/orderform.html /foo/home.gif /catalog/default.jsp 85

86 /catalog/products/shop.jsp /catalog/products/register.jsp 请求 URI /foo 将被重定向到 URI /foo/ 请求 URI /foo/ 将返回 /foo/index.html 的 请求 URI /catalog 将被重定向到 URI /catalog/ 请求 URI /catalog/ 将返回 /catalog/default.jsp 请求 URI /catalog/index.html 将导致 404 未找到错误 请求 URI /catalog/products 将重定向到 URI /catalog/products/ 请求 URI /catalog/products/ 将被传递给 默认 的 servlet( 如果有默认的 servlet 的话 ) 如果没有映射到 默认 的 servlet, 请求可能会导致一个 404 未找到错误, 可能会导致一个包括 shop.jsp 和 register.jsp 目录列表, 或可能导致容器定义的其他行为 请参见 12.2 节, 映射规范 定义的 默认 servlet 所有上述的静态内容都可以打包到 JAR 文件的 META-INF/resources 目录中 这个 JAR 文件可以放到 Web 应用的 WEB-INF/lib 目录下 Web 应用程序环境 servlet 容器不属于 JavaEE 技术标准的实现, 鼓励实现这个容器但不是必需的, 实现应用环境的功能请参见第 节中描述的 Web 应用环境 和 JavaEE 规范 如果他们没有实现需要支持这种环境的条件, 根据部署依赖它们的应用程序, 容器应该提供一个警告 Web 应用程序部署 当一个 Web 应用程序部署到容器中, 在 Web 应用程序开始处理客户端请求之前, 必须按照下述步骤顺序执行 实例化部署描述文件中 <listener> 元素标识的每个事件监听器的一个实例 对于已实例化的实现了 ServletContextListener 接口的监听器实例, 调用 contextinitialized() 方法 实例化部署描述文件中 <filter> 元素标识的每个过滤器的一个实例, 并调用每个过滤器实例的 init() 方法 包含 <load-on-startup> 元素的 <servlet> 元素, 根据 load-on-startup 元素值定义的顺序为每个 servlet 实例化一个实例, 并调用每个 servlet 实例的 init() 方法 包含 web.xml 部署描述文件 如果 Web 应用不包含任何 servlet 过滤器 或监听器组件或使用注解声明相同的, 那么可以不需要 web.xml 文件 换句话说, 只包含静态文件或 JSP 页面的应用程序并不需要一个 web.xml 的存在 86

87 应用生命周期事件 11.1 介绍 应用事件设施给 Web 应用开发人员更好地控制 ServletContext HttpSession 和 ServletRequest 的生命周期, 可以更好地代码分解, 并在管理 Web 应用使用的资源上提高了效率 11.2 事件监听器 应用事件监听器是实现一个或多个 Servlet 事件监听器接口的类 它们是在部署 Web 应用时, 实例化并注册到 Web 容器中 它们由开发人员在 WAR 包中提供 Servlet 事件监听器支持在 ServletContext HttpSession 和 ServletRequest 状态改变时进行事件通知 Servlet 上下文监听器是用来管理应用的资源或 JVM 级别持有的状态 HTTP 会话监听器是用来管理从相同客户端或用户进入 web 应用的一系列请求关联的状态或资源 Servlet 请求监听器是用来管理整个 Servlet 请求生命周期的状态 异步监听器是用来管理异步事件, 例如超时和完成异步处理 可以有多个监听器类监听每一个事件类型, 且开发人员可以为每一个事件类型指定容器调用监听器 bean 的顺序 事件类型和监听器接口 事件类型和监听器接口用于监控下表所示的 : 表 11-1 Servlet 上下文事件 事件类型描述监听器接口 生命周期 Servlet 上下文刚刚创建 并可用于服务它的第一个请求, 或者 Servlet 上下文即将关闭 javax.servlet. ServletContextListener 更改属性在 Servlet 上下文的属性已添加 删除 或替换 javax.servlet. ServletContextAttributeListener 表 11-2 HTTP 会话事件 事件类型描述监听器接口 生命周期会话已创建 销毁或超时 javax.servlet.http. HttpSessionListener 更改属性 已经在 HttpSession 上添加 移除 或替换属性 javax.servlet.http. 87

88 HttpSessionAttributeListener 改变 ID HttpSession 的 ID 将被改变 javax.servlet.httphttpsessionidlistener 会话迁移 HttpSession 已被激活或钝化 javax.servlet.http. HttpSessionActivationListener 对象绑定 对象已经从 HttpSession 绑定或解除绑定 javax.servlet.http. HttpSessionBindingListener 表 11-3 Servlet 请求事件 事件类型描述监听器接口 生命周期一个 servlet 请求已经开始由 Web 组件处理 javax.servlet. ServletRequestListener 更改属性 已经在 ServletRequest 上添加 移除 或替换属性 javax.servlet. ServletRequestAttributeListener 异步事件超时 连接终止或完成异步处理 javax.servlet.asynclistener 监听器使用的一个例子 为了说明事件使用方案, 考虑一个包含一些使用数据库的 Servlet 的简单 Web 应用 开发人员提供了一个 Servlet 上下文监听器类用于管理数据库连接 1. 当应用启动时, 监听器类得到通知 应用登录到数据库, 并在 servlet 上下文中存储连接 2. 应用中的 Servlet 根据需要, 在 Web 应用的活动期间访问连接 3. 当 Web 服务器关闭时, 或应用从 Web 服务器移除时, 监听器类得到通知且关闭数据库连接 11.3 监听器类配置 提供监听器类 Web 应用的开发人员提供实现了一个或多个在 javax.servlet API 中的监听器接口的监听器类 每一个监听器类必须有一个无参构造器 监听器类打包到 WAR 包中, 或者在 WEB-INF/classes 归档项下, 或者在 WEB-INF/lib 目录的一个 JAR 内部 部署声明 监听器类在 Web 应用部署描述符中使用 listener 元素声明 它们根据类名列出的顺序就是它们被调用的顺 88

89 序 与其他监听器不同,AsyncListener 类型的监听器可能仅通过编程式注册 ( 使用一个 ServletRequest) 监听器注册 Web 容器创建每一个监听器类的一个实例, 并在应用处理第一个请求之前为事件通知注册它 Web 容器根据他们实现的接口注册监听器实例, 且按照它们出现在部署描述符中的顺序 在 Web 应用执行期间, 监听器按照它们注册的顺序被调用, 但也有例外, 例如,HttpSessionListener.destroy 按照相反的顺序调用 参考 节 装配 web.xml web-fragment.xml 描述符和注解 关闭时通知 在应用关闭时, 监听器以它们声明时相反的顺序得到通知, 且通知会话监听器在通知上下文监听器之前 通知会话监听器 session 失效必须在通知上下文监听器关闭之前 11.4 部署描述符示例 以下示例是注册两个 Servlet 上下文生命周期监听器和一个 HttpSession 监听器的部署语法 假设 com.acme.myconnectionmanager 和 com.acme.myloggingmodule 两个都实现了 javax.servlet.servletcontextlistener, 且 com.acme.myloggingmodule 又实现了 javax.servlet.http.httpsessionlistener 此外, 开发人员希望 com.acme.myconnectionmanager 在 com.acme.myloggingmodule 得到 Servlet 上下文生命周期事件的通知 下面是这个应用的部署描述符 : <web-app> <display-name>mylisteningapplication</display-name> <listener> <listener-class>com.acme.myconnectionmanager</listener-class> </listener> <listener> <listener-class>com.acme.myloggingmodule</listener-class> </listener> <servlet> <display-name>registrationservlet</display-name>...etc </servlet> </web-app> 89

90 11.5 监听器实例和线程 容器需要在开始执行进入应用的第一个请求之前完成 Web 应用中的监听器类的实例化 容器必须保持到每一个监听器的引用直到为 Web 应用最后一个请求提供服务 ServletContext 和 HttpSession 对象的属性改变可能会同时发生 不要求容器同步到属性监听器类产生的通知 维护状态的监听器类负责数据的完整性且应明确处理这种情况 11.6 监听器异常 一个监听器里面的应用代码在运行期间可能会抛出异常 一些监听器通知发生在应用中的另一个组件调用树过程中 这方面的一个例子是一个 Servlet 设置了会话属性, 该会话监听器抛出未处理异常 容器必须允许未处理的异常由描述在 10.9 节 错误处理 的错误页面机制处理 如果没有为这些异常指定错误页面, 容器必须确保返回一个状态码为 500 的响应 这种情况下, 不再有监听器根据事件被调用 有些异常不会发生在应用中的另一个组件调用栈过程中 这方面的一个例子 SessionListener 接收通知的会话已经超时并抛出未处理的异常, 或者 ServletContextListener 在 Servlet 上下文初始化通知期间抛出未处理异常, 或者 ServletRequestListener 在初始化或销毁请求对象的通知期间抛出未处理异常 这种情况下, 开发人员没有机会处理这种异常 容器可以以 HTTP 状态码 500 来响应所有后续的到 Web 应用的请求, 表示应用出错了 开发人员希望发生在监听器产生一个异常且在通知方法里面必须处理它们自己的异常之后的正常处理 11.7 分布式容器 在分布式 Web 容器中,HttpSession 实例被限到特定的 JVM 服务会话请求, 且 ServletContext 对象被限定到 Web 容器所在的 JVM 分布式容器不需要传播 Servlet 上下文事件或 HttpSession 事件到其他 JVM 监听器类实例被限定到每个 JVM 的每个部署描述符声明一个 11.8 会话事件 监听器类提供给开发人员一种跟踪 Web 应用内会话的方式 它通常是有用的, 在跟踪会话知道一个会话是否变为失效, 因为容器超时会话, 或因为应用内的一个 Web 组件调用了 invalidate 方法 该区别可能会间接地决定使用监听器和 HttpSession API 方法 90

91 映射请求到 Servlet Web 容器需要本章描述的映射技术去映射客户端请求到 Servlet( 该规范 2.5 以前的版本, 使用这些映射技 术是作为一个建议而不是要求, 允许 servlet 容器各有其不同的 schema 用于映射客户端请求到 servlet) 12.1 使用 URL 路径 在收到客户端请求时,web 容器确定转发到哪一个 Web 应用 选择的 Web 应用必须具有最长的上下文路径匹配请求 URL 的开始 当映射到 Servlet 时,URL 匹配的一部分是上下文 Web 容器接下来必须用下面描述的路径匹配步骤找出 servlet 来处理请求 用于映射到 Servlet 的路径是请求对象的请求 URL 减去上下文和路径参数部分 下面的 URL 路径映射规则按顺序使用 使用第一个匹配成功的且不会进一步尝试匹配 : 1. 容器将尝试找到一个请求路径到 servlet 路径的精确匹配 成功匹配则选择该 servlet 2. 容器将递归地尝试匹配最长路径前缀 这是通过一次一个目录的遍历路径树完成的, 使用 / 字符作为路径分隔符 最长匹配确定选择的 servlet 3. 如果 URL 最后一部分包含一个扩展名 ( 如.jsp),servlet 容器将视图匹配为扩展名处理请求的 Servlet 扩展名定义在最后一部分的最后一个. 字符之后 4. 如果前三个规则都没有产生一个 servlet 匹配, 容器将试图为请求资源提供相关的内容 如果应用中定义了一个 default servlet, 它将被使用 许多容器提供了一种隐式的 default servlet 用于提供内容 容器必须使用区分大小写字符串比较匹配 12.2 映射规范 在 web 应用部署描述符中, 以下语法用于定义映射 : 以 / 字符开始 以 /* 后缀结尾的字符串用于路径匹配 以 *. 开始的字符串用于扩展名映射 空字符串 是一个特殊的 URL 模式, 其精确映射到应用的上下文根, 即, 请求形式 在这种情况下, 路径信息是 / 且 servlet 路径和上下文路径是空字符串 ( ) 只包含 / 字符的字符串表示应用的 default servlet 在这种情况下,servlet 路径是请求 URL 减去上下文路径且路径信息是 null 所以其他字符串仅用于精确匹配 如果一个有效的 web.xml( 在从 fragment 和注解合并了信息后 ) 包含人任意的 url-pattern, 其映射到多个 servlet, 那么部署将失败 隐式映射 如果容器有一个内部的 JSP 容器,*.jsp 扩展名映射到它, 允许执行 JSP 页面的要求 该映射被称为隐式映 91

92 射 如果 Web 应用定义了一个 *.jsp 映射, 它的优先级高于隐式映射 Servlet 容器允许进行其他的隐式映射, 只要显示映射的优先 例如, 一个 *.shtml 隐式映射可以映射到包含 在服务器上的功能 示例映射集合 请看下面的一组映射 : 表 12-1 示例映射集合 Path Pattern /foo/bar/* /baz/* /catalog *.bop Servlet servlet1 servlet2 servlet3 servlet4 将产生以下行为 : 表 12-2 传入路径应用于示例映射 Incoming Path /foo/bar/index.html /foo/bar/index.bop /baz /baz/index.html /catalog /catalog/index.html /catalog/racecar.bop /index.bop Servlet Handling Request servlet1 servlet1 servlet2 servlet2 servlet3 default servlet servlet4 servlet4 请注意, 在 /catalog/index.html 和 /catalog/racecar.bop 的情况下, 不使用映射到 /catalog 的 servlet, 因为不是精确匹配的 92

93 安全 应用开发人员创建 Web 应用, 他给 销售或其他方式转入应用给部署人员, 部署人员覆盖安装到运行时环境 应用开发人员与部署人员沟通部署系统的安全需求 该信息可以通过应用部署描述符声明传达, 通过在应用代码中使用注解, 或通过 ServletRegistration 接口的 setservletsecurity 方法编程 本节描述了 Servlet 容器安全机制 接口 部署描述符和基于注解机制和编程机制用于传达应用安全需求 13.1 介绍 web 应用包含的资源可以被多个用户访问 这些资源常常不受保护的遍历, 开放网络如 Internet 在这样的环境, 大量的 web 应用将有安全需求 尽管质量保障和实现细节可能会有所不同, 但 servlet 容器有满足这些需求的机制和基础设施, 共用如下一些特性 : 身份认证 : 表示通信实体彼此证明他们具体身份的行为是被授权访问的 资源访问控制 : 表示和资源的交互是受限于集合的用户或为了强制完整性 保密性 或可用性约束的程序 数据完整性 : 表示用来证明信息在传输过程中没有被第三方修改 保密或数据隐私 : 表示用来保证信息只对以授权访问的用户可用 13.2 声明式安全 声明式安全是指以在应用外部的形式表达应用的安全模型需求, 包括角色 访问控制和认证需求 部署描述符是 web 应用中的声明式安全的主要手段 部署人员映射应用的逻辑安全需求到特定于运行时环境的安全策略的表示 在运行时,servlet 容器使用安全策略表示来实施认证和授权 安全模型适用于 web 应用的静态内容部分和客户端请求到的应用内的 servlet 和过滤器 安全模型不适用于当 servlet 使用 RequestDispatcher 调用静态内容或使用 forward 或 include 到的 servlet 13.3 编程式安全 当仅仅声明式安全是不足以表达应用的安全模型时, 编程式安全被用于意识到安全的应用 编程式安全包括以下 HttpServletRequest 接口的方法 : authenticate login logout 93

94 getremoteuser isuserinrole getuserprincipal login 方法允许应用执行用户名和密码收集 ( 作为一种 Form-Based Login 的替代 ) authenticate 方法允许应用由容器发起在一个不受约束的请求上下文内的来访者请求认证 logout 方法提供用于应用重置来访者的请求身份 getremoteuser 方法由容器返回与该请求相关的远程用户 ( 即来访者 ) 的名字 isuserinrole 方法确定是否与该请求相关的远程用户 ( 即来访者 ) 在一个特定的安全角色中 getuserprincipal 方法确定远程用户 ( 即来访者 ) 的 Principal 名称并返回一个与远程用户相关的 java.security.principal 对象 调用 getuserprincipal 返回的 Principal 的 getname 方法返回远程用户的名字 这些 API 允许 Servlet 基于获得的信息做一些业务逻辑决策 如果没有用户通过身份认证,getRemoteUser 方法返回 null,isuserinrole 方法总返回 false,getuserprincipal 方法总返回 null isuserinrole 方法需要一个引用应用角色的参数 对于用在调用 isuserinrole 的每一个单独的角色引用, 一个带有关联到角色引用的 role-name 的 security-role-ref 元素应该声明在部署描述符中 每一个 security-role-ref 元素应该包含一个 role-link 子元素, 其值是应用内嵌的角色引用链接到的应用安全角色名称 容器使用 security-role-ref 的 role-name 是否等于角色引用来决定哪一个 security-role 用于测试用户是否在身份中 例如, 映射安全角色应用 FOO 到 role-name 为 "manager" 的安全角色的语法是 : <security-role-ref> <role-name>foo</role-name> <role-link>manager</role-link> </security-role-ref> 在这种情况下, 如果属于 manager 安全角色的用户调用了 servlet, 则调用 isuserinrole("foo") API 的结果是 true 如果用于调用 isuserinrole 的一个角色引用, 没有匹配的 security-role-ref 存在, 容器必须默认以 security-role 的 role-name 等于用于调用的角色引用来测试用户身份 角色名 * 应该从不用作调用 isuserinrole 的参数 任何以 * 调用 isuserinrole 必须返回 false 如果 security-role 的 role-name 使用 ** 测试, 且应用没有声明一个 role-name 为 ** 的应用 security-role, isuserinrole 必须仅返回 true 如果用户已经认证 ; 即, 仅当 getremoteuser 和 getuserprincipal 将同时返回非 null 值 否则, 容器必须检查用户身份是否在应用角色中 security-role-ref 元素声明通知部署人员应用使用的角色引用和必须定义哪一个映射 13.4 编程式安全策略配置 本章定义的注解和 API 提供用于配置 Servlet 容器强制的安全约束 94

95 提供了用于定义访问控制约束的另一种机制, 相当于那些通过在便携式部署描述符中声明 式或通过 ServletRegistration 接口的 setservletsecurity 方法编程式表示 Servlet 容器必须支持在实现 javax.servlet.servlet 接口的类 ( 和它的子类 ) 注解 ServletSecurity { HttpConstraint value(); HttpMethodConstraint[] httpmethodconstraints(); } 表 13-1 ServletSecurity 接口元素描述默认值 value HttpConstraint 定义了应用到没有在 httpmethodconstraints 返回的数组中表示的所有 HTTP httpmethodconstraints HTTP 中表示应用到所有 HTTP 协议方法的安全约束, 且 HTTP 注解中 返回不同于所有默认值的组合的特殊情况,@HttpMethodConstraint 表示没有安全约束被应用到任何 HTTP 协议方法, 否则一个安全约束将应用 使用没有产生约束, 这将明确建立不受保护的访问这些方法 ; 因为, 它们没有被约束覆盖 HttpConstraint { ServletSecurity.EmptyRoleSemantic value(); java.lang.string[] rolesallowed(); ServletSecurity.TransportGuarantee transportguarantee(); } 表 13-2 HttpConstraint 接口 95

96 元素描述默认值 value 当 rolesallowed 返回一个空数组,( 只 ) 应用的默认授权语 义 PERMIT rolesallowed 包含授权角色的数组 {} transportguarantee 注解中表示在特定 HTTP 协议消息上的安全约束 HttpMethodConstraint { ServletSecurity.EmptyRoleSemantic value(); java.lang.string[] rolesallowed(); ServletSecurity.TransportGuarantee transportguarantee(); } 表 13-3 HttpMethodConstraint 接口 元素描述默认值 value emptyrolesemantic HTTP 协议方法名 当 rolesallowed 返回一个空数组,( 只 ) 应用的默认授权语义 PERMIT rolesallowed 包含授权角色的数组 {} transportguarantee 在连接的请求到达时必须满足的数据保护需求 注解可以指定在 ( 更准确地说, 目标是 ) Servlet 实现类上, 元注解定义的规则, 它的值是被子类继承的 注解实例可以出现在 Servlet 实现类上, 注解必须不指定在 ( 更准确地说, 目标是 )Java 方法上 注解中时, 定义的 security-constraint, 中标识的 HTTP 协议方法 返回所有默认值 的情况之外,@ServletSecurity 注解定义另一个 security-constraint 的 HTTP 协议方法 定义在便携式部署描述符中的 security-constraint 元素用于对所有出现在该约束中的 url-pattern 授权 当在便携式部署描述符中的一个 security-constraint 包含一个 url-pattern, 其精确匹配一个使用 96

97 @ServletSecurity 注解的模式映射到的类, 该注解必须在由容器在该模式上强制实施的约束上没有效果 当为便携式部署描述符定义了 metadata-complete=true 注解不会应用到部署描述符中的任何 url-pattern 映射到 ( 任何 servlet 映射到 ) 注解不应用到 ServletRegistration 使用 ServletContext 接口的 addservlet(string, Servlet) 方法创建的 url-pattern, 除非该 Servlet 是由 ServletContext 接口的 createservlet 方法构建的 除了上面列出的, 当一个 Servlet 该注解定义的安全约束应用到所有 url-pattern 映射到的所有 Servlet 映射到的类 注解时, 应用到从那个类映射到的 Servlet 的访问策略是由合适的 security-constraint 元素确定的, 如果有, 在相关的便携式部署描述符, 或者由约束禁止任何这样的标签, 则如果有, 为目标 servlet 通过 ServletRegistration 接口的 setservletsecurity 方法编程式确定的 示例 以下示例演示了 ServletSecurity 注解的使用 代码示例 13-1 用于所有 HTTP 方法, public class Example1 extends HttpServlet { } 代码示例 13-2 用于所有 HTTP 方法, 无认证约束, = TransportGuarantee.CONFIDENTIAL)) public class Example2 extends HttpServlet { } 代码示例 13-3 用于所有 HTTP 方法, public class Example3 extends HttpServlet { } 代码示例 13-4 用于所有 HTTP 方法, 认证约束需要成员身份在角色 R1 = "R1")) public class Example4 extends HttpServlet { } 代码示例 13-5 用于除 GET 和 POST 之外的所有 HTTP 方法, 无约束 ; 对于 GET 和 POST 方法, 认证约束需要成员身份在角色 R1 中 ; 对于 POST, 需要加密传输 97

98 @ServletSecurity((httpMethodConstraints = = "GET", rolesallowed = = "POST", rolesallowed = "R1", transportguarantee = TransportGuarantee.CONFIDENTIAL) }) public class Example5 extends HttpServlet { } 代码示例 13-6 无约束 用于除了 GET 之外的所有 HTTP 方法, 认证约束需要成员身份在 R1 角色中 ; 对于 = "R1"), httpmethodconstraints public class Example6 extends HttpServlet { } 代码示例 13-7 用于除了 TRACE 之外的所有 HTTP 方法, 认证约束需要成员身份在 R1 角色中 ; 对于 TRACE, = "R1"), httpmethodconstraints emptyrolesemantic = EmptyRoleSemantic.DENY)) public class Example7 extends HttpServlet { } 为 security-constraint 注解映射为它等价表示,security-constraint 元素 这提供了使用已存在容器的 security-constraint 实施机制来简化实施 由 Servlet 注解必须在实施的效果上是等价的, 由容器从在本节中定义的映射产生 security-constraint 规格的列表 方法无关的约束应用到那些没有定义 HTTP 特定方法约束的所有 HTTP 方法 元素,@ServletSecurity 注解相当于包含一个 web-resource-collection 的单个 security-constraint 元素, 且 web-resource-collection 不包含 http-method 元素, 因此涉及到所有 HTTP 方法 注解表示为单个 security-constraint 元素 相关的 servlet(registration) 定义的 url-pattern 元素将被包含在 web-resource-collection 中, 任何包含的 auth-constraint 和 user-data-constraint 元素的存在和值, 将由定义在 页中 节的 为 XML 的值确定 代码示例

99 = "Role1")) <security-constraint> <web-resource-collection> <url-pattern>...</url-pattern> </web-resource-collection> <auth-constraint> <role-name>role1</role-name> </auth-constraint> </security-constraint> 元素, 方法无关的约束关联一个单个 security-constraint 元素, 其,web-resource-collection 包含了为每一个 HTTP 元素中的 http-method-omission 元素 不是, 包含 http-method-omission 元素的 security-constraint 必须不被创建 与另一种包含一个 web-resource-collection 的 security-constraint 关联,web-resource-collection 包含一个使用相应 HTTP 方法命名的 http-method 元素 注解为两种 security-constraint 元素 相应的 Servlet(registration) 定义的 url-pattern 元素将被包含在两种约束的 web-resource-collection 中, 且任何包含的 auth-constraint 和 user-data-constraint 元素的存在和值, 将由定义在 页中 节的 为 XML 的值确定 代码示例 13-9 的 = "Role1"), httpmethodconstraints = "TRACE", emptyrolesemantic = EmptyRoleSemantic.DENY)) <security-constraint> <web-resource-collection> <url-pattern>...</url-pattern> <http-method-omission>trace</http-method-omission> </web-resource-collection> <auth-constraint> <role-name>role1</role-name> </auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <url-pattern>...</url-pattern> <http-method>trace</http-method> </web-resource-collection> <auth-constraint/> </security-constraint> 99

100 为 XML 注解值 ( 中定义使用的 ) 为它们等价的 auth-constraint 和 user-data-constraint 表示, 这些注解共用一个通用模型用于表示用在便携式部署描述符中的 auth-constraint 和 user-data-constraint 元素的等价形式 该模型包括以下 3 种元素 : emptyrolesemantic 授权语义,PERMIT 或 DENY, 适用于在 rolesallowed 中没有指定的角色时 此元素的默认值为 PERMIT, 且 DENY 不支持与非空的 rolesallowed 列表结合使用 rolesallowed 一个包含授权角色的名字列表 当该列表为空时, 其含义取决于 emptyrolesemantic 的值 当角色名字 * 包含在允许的角色列表中时是没有特别的含义的 当特殊的角色名字 ** 出现在 rolesallowed 中时, 它表示用户认证, 不受约束的角色, 是必需的和足够的 该元素的默认值是一个空列表 transportguarantee 数据保护需求,NONE 或 CONFIDENTIAL, 在连接的请求到达时必须满足 该元素与一个包含一个使用相应值的 transport-guarantee 的 user-data-constraint 是等价的 该元素的默认值是 NONE 模型和 web.xml 中的 auth-constraint 和 user-data-constraint 元素之间的对应关系 代码示例 emptyrolesemantic=permit, rolesallowed={}, transportguarantee=none 无约束代码示例 emptyrolesemantic=permit, rolesallowed={}, transportguarantee=confidential <user-data-constraint> <transport-guarantee>confidential</transport-guarantee> </user-data-constraint> 代码示例 emptyrolesemantic=permit, rolesallowed={role1}, transportguarantee=none <auth-constraint> <security-role-name>role1</security-role-name> </auth-constraint> 代码示例 emptyrolesemantic=permit, rolesallowed={role1}, transportguarantee=confidential <auth-constraint> <security-role-name>role1</security-role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>confidential</transport-guarantee> 100 </user-data-constraint>

101 代码示例 emptyrolesemantic=deny, rolesallowed={}, transportguarantee=none <auth-constraint/> 代码示例 emptyrolesemantic=deny, rolesallowed={}, transportguarantee=confidential <auth-constraint/> <user-data-constraint> <transport-guarantee>confidential</transport-guarantee> </user-data-constraint> ServletRegistration.Dynamic 的 setservletsecurity ServletContextListener 内的 setservletsecurity 方法用于定义应用到 ServletRegistration 定义的映射的安全约束 Collection<String> setservletsecurity(servletsecurityelement arg); setservletsecurity 的 javax.servlet.servletsecurityelement 参数与 ServletSecurity 注解在结构和模型上是类似的 因此, 定义在 页 节的 为 security-constraint 的映射, 应用类似的包含 HttpConstraintElement 和 HttpMethodConstraintElement 值的 ServletSecurityElement 映射为其等价的 security-constraint 表示 setservletsecurity 方法返回一组 URL pattern( 可能空 ), 其已是便携式部署描述符中的 security-constraint 元素的精确目标 ( 因此, 调用是不影响的 ) 如果 ServletContext 中得到的 ServletRegistration 已经被初始化了, 该方法抛出 IllegalStateException 当便携式部署描述符中的 security-constraint 包含一个 url-pattern 其精确匹配 ServletRegistration 映射的 pattern, 调用 ServletRegistration 的 setservletsecurity 必须对 Servlet 容器对 pattern 实施的约束没有任何影响 除了上面列出的, 包括当 Servlet 当调用了 ServletRegistration 的 setservletsecurity, 它制定应用到 registration 的 url-pattern 的安全约束 13.5 角色 安全角色是由应用开发人员或装配人员定义的逻辑用户分组 当部署了应用, 由部署人员映射角色到运行时环境的 principal 或组 Servlet 容器根据 principal 的安全属性为与进入请求相关的 principal 实施声明式或编程式安全 这可能以如下任一方式发生 : 1. 部署人员已经映射一个安全角色到运行环境中的一个用户组 调用的 principal 所属的用户组取自其安全属性 仅当 principal 所属的用户组由部署人员已经映射了安全角色,principal 是在安全角色中 2. 部署人员已经映射安全角色到安全策略域中的 principal 名字 在这种情况下, 调用的 principal 的名字取 101

102 自其安全属性 仅当 principal 名字与安全角色已映射到的 principal 名字一样时,principal 是在安全角色 中 13.6 认证 web 客户端可以使用以下机制之一向 web 服务器认证用户身份 : HTTP 基本认证 (HTTP Basic Authentication) HTTP 摘要认证 (HTTP Digest Authentication) HTTPS 客户端认证 (HTTPS Client Authentication) 基于表单的认证 (Form Based Authentication) HTTP 基本认证 HTTP 基本认证基于用户名和密码, 是 HTTP/1.0 规范中定义的认证机制 Web 服务器请求 web 客户端认证用户 作为请求的一部分,web 服务器传递 realm( 字符串 ) 给要被认证的用户 Web 客户端获取用户的用户名和密码并传给 web 服务器 Web 服务器然后在指定的 realm 认证用户 基本认证是不安全的认证协议 用户密码以简单的 base64 编码发送, 且未认证目标服务器 额外的保护可以减少一些担忧 : 安全传输机制 (HTTPS), 或者网络层安全 ( 如 IPSEC 协议或 VPN 策略 ) 被应用到一些部署场景 HTTP 摘要认证 与 HTTP 基本认证类似,HTTP 摘要认证也是基于用户名和密码认证用户, 但不像 HTTP 基本认证,HTTP 摘要认证不在网络上发生用户密码 在 HTTP 摘要认证中, 客户端发送单向散列的密码 ( 和额外的数据 ) 尽管密码不在线路上发生,HTTP 摘要认证需要对认证容器可用的明文密码等价物 ( 密码等价物可以是这样的, 它们仅能在一个特定的 realm 用来认证用户 ), 以致容器可以通过计算预期的摘要验证接收到的认证者 Servlet 容器应支持 HTTP_DIGEST 身份认证 基于表单的认证 登录界面 的外观在使用 web 浏览器的内置的认证机制时不能被改变 本规范引入了所需的基于表单的认证机制, 允许开发人员控制登录界面的外观 Web 应用部署描述符包含登录表单和错误页面条目 登录界面必须包含用于输入用户名和密码的字段 这些字段必须分别命名为 j_username 和 j_password 当用户试图访问一个受保护的 web 资源, 容器坚持用户的认证 如果用户已经通过认证则具有访问资源的权限, 请求的 web 资源被激活并返回一个引用 如果用户未被认证, 发生所有如下步骤 : 1. 与安全约束关联的登录界面被发送到客户端, 且 URL 路径和 HTTP 协议方法触发容器存储的认证 2. 用户被要求填写表单, 包括用户名和密码字段 3. 客户端 post 表单到服务器 102

103 4. 容器尝试使用来自表单的信息认证用户 5. 如果认证失败, 使用 forward 或 redirect 返回错误页面, 且响应状态码设置为 200 错误页面包含失败信息 6. 如果授权成功, 客户端使用存储的 URL 路径重定向到资源 7. 当一个重定向的和已认证的请求到达容器, 容器恢复请求和 HTTP 协议方法, 且已认证的用户主体被检查看看是否它在已授权的允许访问资源的角色中 8. 如果用户已授权, 容器处理接受的请求 到达步骤 7 的重定向的请求的 HTTP 协议方法, 可以和触发认证的请求有不同的 HTTP 方法 同样地, 在第 6 步的重定向之后, 表单认证器必须处理重定向的请求, 即使对到达请求的 HTTP 方法的认证不是必需的 为了改善重定向的请求的 HTTP 方法的可预测性, 容器应该使用 303 状态码 (SC_SEE_OTHER) 重定向 ( 步骤 6), 除了与 HTTP 1.0 用户代理的协作之外的是必需的 ; 在这种情况应该使用 302 状态码 当进行一个不受保护的传输时, 基于表单的认证受制于一些与基本验证一样的相同的脆弱性 当触发认证的请求在一个安全传输之上到达, 或者登录页面受制于一个 CONFIDENTIAL user-data-constraint, 登录页面必须返回给用户, 并在安全传输之上提交到容器 登录页面受制于一个 CONFIDENTIAL user-data-constraint, 且一个 CONFIDENTIAL user-data-constraint 应该包含在每一个包含认证要求的 security-constraint 中 HttpServletRequest 接口的 login 方法提供另一种用于应用控制它的登录界面外观的手段 登录表单 基于表单的登录和基于 URL 的 session 跟踪可以通过编程实现 基于表单的登录应该仅被用在当 session 由 cookie 或 SSL session 信息维护时 为了进行适当的认证, 登录表单的 action 总是 j_security_check 该限制使得不管请求什么资源, 登录表单都能工作, 且避免了要求服务器指定输出表单的 action 字段 登录表单应该在密码表单字段上指定 autocomplete= off 下面的示例展示了如何把表单编码到 HTML 页中 : <form method= POST action= j_security_check > <input type= text name= j_username > <input type= password name= j_password > </form> 如果因为 HTTP 请求造成基于表单的登录被调用, 容器必须保存原始请求参数, 在成功认证时使用, 它重定向调用所请求的资源 如果用户已使用表单登录通过认证, 且已经创建一个 HTTP session, 该 session 的超时或失效将导致用户被注销, 在这种情况下, 随后的请求必须导致用户重新认证 注销与认证具有相同的作用域 : 例如, 如果容器支持单点登录, 如 JavaEE 技术兼容的 web 容器, 用户只需要与托管在 web 容器中的任何一个 web 应用重新认证即可 103

104 HTTPS 客户端认证 使用 HTTPS(HTTP over SSL) 认证最终用户是一种强认证机制 该机制需要客户端拥有 Public Key Certificate(PKC) 目前,PKCs 在电子商务应用中是很有用的, 也对浏览器中的单点登录很有用 其他容器认证机制 Servlet 容器应该提供公共接口, 可用于集成和配置其他的 HTTP 消息层的认证机制, 提供给代表已部署应用的容器使用 这些接口应该提供给参与者使用而不是容器供应商 ( 包括应用开发人员 系统管理人员和系统集成人员 ) 为了便于实现和集成其他容器认证机制, 建议为所有 Servlet 容器实现 Servlet 容器 Profile 的 Java tm 认证 SPI ( 即,JSR 196) SPI 可下载地址 : 服务器跟踪认证信息 下面的安全标识 ( 如用户和组 ) 在运行时环境中映射的角色是环境指定的而非应用指定的, 理想的是 : 1. 使登录机制和策略是 web 应用部署到的环境属性 2. 在同一个容器部署的所有应用能使用相同的认证信息来表示 principal, 且 3. 需要重新认证用户仅当已经越过了安全策略域边界 因此,servlet 容器需要在容器级别 ( 而不是在 web 应用级别 ) 跟踪认证信息 这允许在一个 web 应用已经通过认证的用户可以访问容器管理的以同样的安全标识许可的其他资源 13.8 指定安全约束 安全约束是一种定义 web 内容保护的声明式方式 安全约束关联授权和或在 web 资源上对 HTTP 操作的用户数据约束 安全约束, 在部署描述符中由 security-constraint 表示, 其包含以下元素 : web 资源集合 ( 部署描述符中的 web-resource-collection) 授权约束 ( 部署描述符中的 auth-constraint) 用户数据约束 ( 部署描述符中的 user-data-constraint) HTTP 操作和网络资源的安全约束应用 ( 即受限的请求 ) 根据一个或多个 web 资源集合识别 Web 资源集合包含以下元素 : URL 模式 ( 部署描述符中的 url-pattern) HTTP methods ( 部署描述符中的 http-method 或 http-method-omission 元素 ) 授权约束规定认证和命名执行受约束请求的被许可的授权角色的要求 用户必须至少是许可执行受约束请求的命名角色中的一个成员 特殊角色名 * 是定义在部署描述符中的所有角色名的一种简写 特殊的角色名 ** 是一种用于任何授权的用户不受约束的角色的速记法 它表示任何授权的用户, 不受约束的角色, 被授权允许执行约束的请求 没有指定角色的授权约束表示在任何情况下不允许访问受约束请求 授权约束包含以下元素 : 104

105 role name ( 部署描述符中的 role-name) 用户数据约束规定了在受保护的传输层连接之上接收受约束的请求的要求 需要保护的强度由传输保障的值定义 INTEGRAL 类型的传输保障用于规定内容完整性要求, 且传输保障 CONFIDENTIAL 用于规定保密性要求的 传输保障 NONE 表示当容器通过任何包括不受保护的连接接受到请求时, 必须接受此受约束的请求 容器可能在响应中强加一个受信的传输保障 (confidential transport guarantee) 为 INTEGRAL 值 用户数据约束包括如下元素 : transport guarantee ( 部署描述符中的 transport-guarantee) 如果没有授权约束应用到请求, 容器必须接受请求, 而不要求用户身份认证 如果没有用户数据约束应用到请求, 当容器通过任何包括不受保护的连接接收到请求时, 必须接受此请求 组合约束 为了组合约束,HTTP 方法可以说是存在于 web-resource-collection 中, 仅当没有在集合中指定 HTTP 方法, 或者集合在包含的 http-method 元素中具体指定了 HTTP 方法, 或者集合包含一个或多个 http-method-omission 元素, 但那些没有指定的 HTTP 方法 当 url-pattern 和 HTTP 方法以组合方式 ( 即, 在 web-resource-collection 中 ) 出现在多个安全约束中, 该约束 ( 在模式和方法上的 ) 是通过合并单个约束定义的 以相同的模式和方法出现的组合约束规则如下所示 : 授权约束组合, 其明确指定角色或通过 * 隐式指定角色, 可产生单个约束的合并的角色名称作为许可的角色 一个命名角色 ** 的授权约束将与授权约束命名的或隐式的角色组合以允许任何授权的用户不受约束的角色 不包含授权约束的安全约束将与明确指定角色的或隐式指定角色的允许未授权访问的安全约束合并 授权约束的一个特殊情况是其没有指定角色, 将与任何其他约束合并并覆盖它们的作用, 这导致访问被阻止 应用到常见的 url-pattern 和 http-method 的 user-data-constraint 组合, 可产生合并的单个约束接受的连接类型作为接受的连接类型 不包含 user-data-constraint 的安全约束, 将与其他 user-data-constraint 合并, 使不安全的连接类型是可接受的连接类型 示例 下面的示例演示了组合约束及它们翻译到的可应用的约束表格 假设部署描述符包含如下安全约束 <security-constraint> <web-resource-collection> <web-resource-name>precluded methods</web-resource-name> <url-pattern>/*</url-pattern> <url-pattern>/acme/wholesale/*</url-pattern> <url-pattern>/acme/retail/*</url-pattern> <http-method-omission>get</http-method-omission> <http-method-omission>post</http-method-omission> </web-resource-collection> <auth-constraint/> </security-constraint> 105

106 <security-constraint> <web-resource-collection> <web-resource-name>wholesale</web-resource-name> <url-pattern>/acme/wholesale/*</url-pattern> <http-method>get</http-method> <http-method>put</http-method> </web-resource-collection> <auth-constraint> <role-name>salesclerk</role-name> </auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>wholesale 2</web-resource-name> <url-pattern>/acme/wholesale/*</url-pattern> <http-method>get</http-method> <http-method>post</http-method> </web-resource-collection> <auth-constraint> <role-name>contractor</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>confidential</transport-guarantee> </user-data-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>retail</web-resource-name> <url-pattern>/acme/retail/*</url-pattern> <http-method>get</http-method> <http-method>post</http-method> </web-resource-collection> <auth-constraint> <role-name>contractor</role-name> <role-name>homeowner</role-name> </auth-constraint> </security-constraint> 翻译这个假定的部署描述符将产生定义在表 13-4 中的约束 表 13-4 安全约束表 url-pattern http-method 许可的角色支持的连接类型 106

107 /* 所有方法 除 GET,POST 阻止访问 不限制 /acme/wholesale/* 所有方法 阻止访问 不限制 除 GET,POST /acme/wholesale/* GET CONTRACTOR 不限制 SALESCLERK /acme/wholesale/* POST CONTRACTOR CONFIDENTIAL /acme/retail/* 所有方法 阻止访问 不限制 除 GET,POST /acme/retail/* GET CONTRACTOR 不限制 HOMEOWNER /acme/retail/* POST CONTRACTOR 不限制 HOMEOWNER 处理请求 当 servlet 容器接收到一个请求, 它将使用 119 页 使用 URL 路径 描述的规则来选择在请求 URI 最佳匹配的 url-pattern 上定义的约束 ( 如果有 ) 如果没有约束被选择, 容器将接受该请求 否则, 容器将确定在选择的模式上是否此请求的 HTTP 方法是受约束的 如果不是, 请求将被接受 否则, 请求必须满足在 urlpattern 应用到 HTTP 方法的约束 请求被接受和分派到相关的 servlet, 必须满足以下两个规则 1. 接收到的请求的连接特性必须满足至少一种由约束定义的支持的连接类型 如果该规则不满足, 容器将拒绝该请求并重定向到 HTTPS 端口 ( 作为一种优化, 容器将以拒绝该请求为 forbidden 并返回 403 (SC_FORBIDDEN) 状态码, 如果知道该访问将最终将被阻止 ( 通过没有指定角色的授权约束 )) 2. 请求的认证特性必须满足任何由约束定义的认证和角色要求 如果该规则不能满足是因为访问已经被阻止 ( 通过没有指定角色的授权约束 ), 则请求将被拒绝为 forbidden 并返回 403 (SC_FORBIDDEN) 状态码 如果访问是受限于许可的角色且请求还没有被认证, 则请求将被拒绝为 unauthorized 且 401(SC_UNAUTHORIZED) 状态码将被返回以导致身份认证 如果访问是受限于许可的角色且请求的认证身份不是这些角色中的成员, 则请求将被拒绝为 forbidden 且 403 状态码 (SC_FORBIDDEN) 将被返回到用户 未覆盖的 HTTP 协议方法 security-constraint schema 提供了枚举 ( 包括省略 ) 定义在 security-constraint 中的保护要求应用到哪一个 HTTP 方法的能力 当 HTTP 方法枚举在 security-constraint, 约束定义的保护仅应用到枚举建立的方法 我们把不是枚举建立的方法称为 未覆盖的 HTTP 方法 未覆盖的 HTTP 方法不保护所有 security-constraint 的 url-pattern 最匹配的请求的 URL 107

108 当 HTTP 方法没有枚举在一个 security-constraint 中时, 约束定义的保护应用到完整的 HTTP( 扩展 ) 方法集 在那种情况, 在那些 security-constraint 的 url-pattern 最佳匹配的所有请求的 URL, 没有未覆盖的 HTTP 方法 例子用三种方式描述了在哪些 HTTP 协议方法可能未覆盖 方法是否是未覆盖的是由在所有约束应用到一个 url-pattern 已经按照 页的 节, 组合约束 组合决定的 1. security-constraint 在 http-method 元素中命名一个或多个 HTTP 方法 除了那些明明在约束中的, 所有 HTTP 方法是未覆盖的 <security-constraint> <web-resource-collection> <web-resource-name>wholesale</web-resource-name> <url-pattern>/acme/wholesale/*</url-pattern> <http-method>get</http-method> </web-resource-collection> <auth-constraint> <role-name>salesclerk</role-name> </auth-constraint> </security-constraint> 除了 GET, 所以 HTTP 方法是未覆盖的 2. security-constriant 在 http-method-omission 元素中命名一个或多个 HTTP 方法 所有命名在约束中的 HTTP 方法是未覆盖的 <security-constraint> <web-resource-collection> <web-resource-name>wholesale</web-resource-name> <url-pattern>/acme/wholesale/*</url-pattern> <http-method-omission>get</http-method-omission> </web-resource-collection> <auth-constraint/> </security-constraint> GET 是未覆盖的 所有其他方法是被排除的 auth-constraint 覆盖的 3. 注解返回所有默认值, 除了那些命名在@HttpMethodConstraint 中的所有 HTTP 方法是被注解未覆盖的 这种情况是与情况 1 是类似的, 且等价于使用 ServletRegistration 接口的 setservletsecurity = = "GET", rolesallowed = = "POST", rolesallowed = "R1", transportguarantee = TransportGuarantee.CONFIDENTIAL) }) public class Example5 extends HttpServlet { } 108

109 除了 GET 和 POST 之外的所有 HTTP 方法是未覆盖的 安全约束配置规则 目的 : 确保在所有约束的 URL 模式上的所有 HTTP 方法有预期的安全保护 ( 即, 覆盖的 ) 1. 没有在约束中命名 HTTP 方法 ; 在这种情况下, 未 URL 模式定义的安全保护将应用到所有 HTTP 方法 2. 如果你不能遵循规则 #1, 添加 <deny-uncovered-http-methods> 和声明 ( 使用 <http-method> 元素, 或等价的注解 ) 所有在约束 URL 模式允许的 HTTP 方法 ( 有安全保护 ) 3. 如果你不能遵循规则 #2, 声明约束来覆盖每一个约束的 URL 模式的所有 HTTP 方法 使用 <http-method-omission> 元素或 HttpMethodConstraint 注解来表示除了被 <http-method> 或 HttpMethodConstraint 命名的那些之外的所有 HTTP 方法集 当使用注解时, 使用 HttpConstraint 定义应用到所有其他 HTTP 方法和配置 EmptyRoleSemantic=DENY 来导致所有其他 HTTP 方法被拒绝的安全语义 处理未覆盖的 HTTP 方法 在应用部署期间, 容器必须通知部署人员任何存在于从为应用定义的约束组合产生的应用安全约束配置中的未覆盖的 HTTP 方法 提供的信息必须标识未覆盖的 HTTP 协议方法, 和在 HTTP 方法未覆盖那些相关的 URL 模式 通知部署人员的要求可以通过记录必需的信息来满足 当 deny-uncovered-http-methods 标记在应用的 web.xml 中设置了, 容器必须拒绝任何 HTTP 协议方法, 当它用于一个其 HTTP 方法在应用到请求 URL 最佳匹配的 url-pattern 的组合安全约束请求 URL 是未覆盖的 拒绝的请求将被拒绝为 forbidden 并返回一个 403(SC_FORBIDDEN) 状态码 导致未覆盖的 HTTP 方法为拒绝, 部署系统将建立额外的排除 auth-constraint, 去覆盖这些在未覆盖的 HTTP 方法约束的 url-pattern 的 HTTP 方法 当应用的安全配置不包含未覆盖的方法,deny-uncovered-http-methods 标记在应用的有效的安全配置上必须没有效果 应用 deny-uncovered-http-methods 到一个应用, 其安全配置包含未覆盖的方法, 可能, 在一些情况下, 拒绝访问资源为了应用的功能必须是可访问的 这这种情况下, 应用的安全配置应该完成所有未覆盖的方法被相关约束配置覆盖 应用开发人员应该定义安全约束配置, 没有任何未覆盖的 HTTP 方法, 且他们应该设置 deny-uncovered-http-methods 标记确保他们的应用不会依赖于通过未覆盖的方法来得到可访问性 Servlet 容器可以提供一个配置选项来选择未覆盖方法的默认行为是 ALLOW 还是 DENY 这个选项可以配置在每容器粒度或更大 注意, 设置这个默认为 DENY 可能导致一些应用失败 13.9 默认策略 默认情况下, 身份认证并不需要访问资源 当安全约束 ( 如果有 ) 包含的 url-pattern 是请求 URI 的最佳匹配, 且结合了施加在请求的 HTTP 方法上的 auth-constraint( 指定的角色 ), 则身份认证是需要的 同样, 一个受保护的传输是不需要的, 除非应用到请求的安全约束结合了施加在请求的 HTTP 方法上的 user-data-constraint( 有一个受保护的 transport-guarantee) 109

110 13.10 登录和退出 容器在分派请求到 servlet 引擎之前建立调用者身份 在整个请求处理过程中或直到应用成功的在请求上调用身份认证 登录或退出, 调用者身份保持不变 对于异步请求, 调用者身份建立在初始分派时, 直到整个请求处理完成或直到应用成功的在请求上调用身份认证 登录或退出, 调用者身份保持不变 在处理请求时登录到一个应用, 精确地对应有一个有效的非空的与请求关联的调用者身份, 可以通过调用请求的 getremoteuser 或 getuserprincipal 确定 这些方法的任何一个返回 null 值表示调用者没有登录到处理请求的应用 容器可以创建 HTTP Session 对象用于跟踪登录状态 如果开发人员创建一个 session 而用户没有进行身份认证, 然后容器认证用户, 登录后, 对开发人员代码可见的 session 必须是相同的 session 对象, 该 session 是登录发生之前创建的, 以便不丢失 session 信息 110

111 部署描述文件 本章指定的 Java Servlet 规范 3.0 版要求 Web 容器支持部署描述文件 部署描述文件表达了应用开发人员 应用集成人员和 Web 应用部署人员之间的元素和配置信息 对于 Java Servlet 2.4 和以后的版本, 部署描述文件在 XML 模式文档中定义 为了向后兼容到 2.2 版本的 API 编写的应用程序,Web 容器也需要支持 2.2 版本的部署描述文件 为了向后兼容 2.3 版本的 API 编写的应用程序,Web 容器也需要支持 2.3 版本的部署描述文件 2.2 版本的部署描述文件可在此下载 : 版本的部署描述文件可在此下载 : 部署描述文件元素 所有 servlet 容器的 Web 应用程序部署描述文件需要支持以下类型的配置和部署信息 : ServletContext 初始化参数 Session 配置 Servlet 声明 Servlet 映射 应用程序生命周期监听器类 过滤器定义和过滤器映射 MIME 类型映射 欢迎文件列表 错误页面 语言环境和编码映射 安全配置, 包括 login-config,security-constraint,security-constraint,security-role-ref 和 run-as 14.2 部署描述符处理规则 本节列出了一些通用的规则,Web 容器和开发人员必须注意有关 Web 应用程序部署描述文件的处理 对于部署描述文件的文本节点元素内容,Web 容器必须删除所有前导和后置空格, 空格在 XML 1.0 ( 中被定义为 S(white space) 部署描述文件对模式来说必须是有效的 Web 容器和操作 Web 应用程序的工具对检查 WAR 文件的有效性有多种选择 包括检查 WAR 文件中部署描述文件的有效性 此外, 推荐 Web 容器和操作 Web 应用程序的工具提供一个级别的语义检查 例如, 应该检查安全约束中引用的角色和部署描述文件中定义的某个安全角色具有相同的名称 在 Web 应用程序不符合规范的情况下, 工具和容器应该用描述性的错误消息告知开发人员 鼓励高端应用 111

112 服务器提供商都提供这种有效性检查, 以工具的形式和容器分开 这个版本的规范中,web-aap 的子元素的顺序可以是任意的 由于 XML 模式的限制, 可分发元素多样性, session-config welcome-file-list jsp-config login-config 以及 locale-encoding-mapping-list, 从 可选的 变成 0 个或多个 当部署描述文件包含多个 session-config jsp-config 和 login-config 时, 容器必须用描述性的错误消息告知开发人员 当有多个事件时, 容器必须连接 welcome-file-list 和 locale-encoding-mapping-list 中的项目 多个可分发的事件必须与单个可分发的事件以同样的方式正确对待 假定部署描述符中指定的 URI 路径通过 URL 解码形式 ( 意思是已经对 URL 进行了转义 ) 当 URL 包含 CR(#xD)( 回车 ) 或 LF(#xA)( 换行 ) 时, 容器必须用描述性的错误消息告知开发人员 容器必须保存所有其他字符, 包括 URL 中的空格 容器必须尝试规范化部署描文件中的路径 例如,/a/../b 形式的路径必须解释为 /b 部署描述文件中以../ 开始的路径或解析成以../ 开始的路径都不是有效的路径 URI 路径指的是相对于 WAR 文件的根目录, 或相对于 WAR 文件的根目录的一个路径映射, 除非另有规定, 应以 / 开头 元素的值是一个枚举类型, 其值是区分大小写的 14.3 部署描述文件 这个版本规范的部署描述文件可在此下载 : 部署描述文件图解 本节举例说明部署描述文件中的元素 属性没有在图中显示 详细信息请参阅部署描述文件模式 1 web-app 元素 web-app 元素是一个 Web 应用程序的根部署描述符 此元素包含下列元素 这个元素有一个必需的属性 version 来指定部署描述符符合哪个版本的模式 此元素的所有子元素可以是任意的顺序 图 14-1 web-app 元素结构 112

113 2 description 元素 description 元素提供了父元素的文本描述 此元素不仅出现在 web-app 元素中, 其他很多元素中也有 它有 一个可选属性 xml:lang 指明描述中使用哪一种语言 该属性的默认值是英语 ( en ) 3 display-name 元素 display-name 元素包含一个简短的名称, 目的是通过工具显示 显示名称不必是唯一的 这个元素有一个可 选属性 xml:lang 用于指定语言 113

114 4 icon 元素 icon 元素包含 small-icon 和 large-icon 元素, 为大型和小型 GIF 或 JPEG 图标图片指定文件名, 用于在 GUI 工具中表示父元素 5 distributable 元素 distributable 元素表示设定该 Web 应用程序适合部署到一个分布式的 servlet 容器中 6 context-param 元素 context-param 元素包含了 Web 应用程序的 servlet 上下文初始化参数的声明 7 filter 元素 filter 元素声明了 Web 应用程序中的过滤器 该过滤器映射到一个 servlet 或 filter-mapping 元素中的一个 URL 模式, 使用 filter-name 的值来引用 过滤器在运行时可以通过 FilterConfig 接口访问部署描述文件中声明的初始化参数 filter-name 元素是过滤器的逻辑名称 它在 Web 应用程序中必须是唯一的 filter-name 元素的元素内容不能为空 filter-class 是过滤器的完全限定类名 init-param 元素包含的名值对作为此过滤器的初始化参数 当指定可选的 async-supported 元素时, 表示该过滤器支持异步请求处理 图 14-2 过滤器元素结构 114

115 8 filter-mapping 元素 容器使用 filter-mapping 决定哪个过滤器以什么样的顺序应用到请求 filter-name 的值必须是部署描述文件 中声明的过滤器中的一个 匹配的请求可以被指定为 url-pattern 或 servlet-name 图 14-3 filter-mapping 元素结构 115

116 9 listener 元素 listener 表示应用程序监听器 bean 的部署属性 子元素 listener-class 声明应用程序中的一个类必须注册为 Web 应用程序监听器 bean 它的值是监听器类的完全限定类名 图 14-4 listener 元素结构 10 servlet 元素 servlet 元素用于声明一个 servlet 它包含一个 servlet 的声明性数据 jsp-file 元素包含到以 / 开头的 Web 应用程序中一个 JSP 文件的完全路径 如果指定了 jsp-file 并且存在 load-on-start 元素, 那么 JSP 应该被预编译和加载 servlet-name 元素包含了 servlet 的规范名称 在 Web 应用程序中每个 servlet 的名称是唯一的 servlet-name 元素内容不能为空 servlet-class 包含了 servlet 的完全限定类名 run-as 元素指定用作一个组件执行的标识 它包含一个可选的 description, 和一个由 role-name 元素指定安全角色 load-on-startup 元素表示该 servlet 应该在 Web 应用程序启动时加载 ( 实例化并调用它的 init() 方法 ) 该元素的元素内容必须是一个整数, 表示 servlet 应该被加载的顺序 如果该值是一个负整数, 或不存在该元素, 容器自由选择什么时候加载这个 servlet 如果该值是一个正整数或 0, 当应用部署后容器必须加载和初始化这个 servlet 容器必须保证较小整数标记的 servlet 在较大整数标记的 servlet 之前加载 容器可以选择具有相同 load-on-startup 值的 servlet 的加载顺序 security-role-ref 元素声明组件中或部署组件的代码中的安全角色引用 它由一个可选的 description, 在代码中使用的安全角色名称 (role-name), 以及一个可选的到一个安全角色 (role-link) 的链接组成 如果没有指定安全角色, 部署器必须选择一个合适的安全角色 当指定了可选的 async-supported 元素, 指示的 servlet 可以支持异步请求处理 如果一个 servlet 支持文件上传功能和 mime-multipart 请求处理, 通过描述文件中的 multipart-config 元素能够提供相同的配置 multipart-config 元素可用于指定文件存储的位置, 上传文件大小的最大值, 最大请求大小和文件将写入磁盘之后的大小阈值 图 14-5 servlet 元素结构 116

117 11 servlet-mapping 元素 servlet-mapping 定义了 servlet 和 URL 模式之间的映射 图 14-6 servlet-mapping 元素结构 117

118 12 session-config 元素 session-config 元素定义了该 Web 应用程序的会话参数 子元素 session-timeout 定义了该 Web 应用程序中创建的所有会话的默认超时时间间隔 指定的超时时间必须使用分钟数表示 如果超时时间小于或等于 0, 容器将确保会话的默认行为永远不会超时 如果没有指定这个元素, 容器必须设置它的缺省超时期限 图 14-7 session-config 元素结构 13 mime-mapping 元素 mime-mapping 定义了扩展名和 MIME 类型之间的映射 extension 元素包含一个字符串描述的扩展名, 例如 txt 图 14-8 mime-mapping 元素结构 118

119 14 welcome-file-list 元素 welcome-file-list 包含了一个有序的欢迎文件列表 子元素 welcome-file 包含一个用作缺省欢迎文件的文件 名, 如 index.html 图 14-9 welcome-file-list 元素结构 15 error-page 元素 error-page 包含一个错误代码或异常类型到 Web 应用程序中资源的路径之间的映射 不过,error-code 或 exception-type 元素可以省略来指定一个默认的错误页面 子元素 exception-type 包含了一个 Java 异常类型的完全限定名称 子元素 location 包含了 web 应用程序中相对于 web 应用程序根目录的资源位置 location 的值必须以 '/' 开头 图 error-page 元素结构 16 jsp-config 元素 jsp-config 用来提供 Web 应用程序中的 JSP 文件的全局配置信息 它有两个子元素,taglib 和 jsp-property-group taglib 元素可用来为 Web 应用程序中的 JSP 页面使用的标签库提供信息 详细信息请参阅 JavaServer Pages 规范 2.1 版本 图 jsp-config 元素结构 119

120 17 security-constraint 元素 security-constraint 用于关联安全约束和一个或多个 Web 资源集合 子元素 web-resource-collection 确定安全约束应用到哪一些 Web 应用程序中资源的子集和这些资源的 HTTP 方法 auth-constraint 表示用户角色应该允许访问此资源集合 这里使用的 role-name 必须与该 Web 应用程序定义的其中一个 security-role 元素的 role-name 对应, 或者是指定的保留 role-name * 对应, 这是一个表示 web 应用程序中的所有角色的紧凑语法 如果 * 和角色名都出现了, 容器会将此解释为所有角色 如果没有定义角色, 不允许任何用户访问由包含 security-constraint 所描述的 Web 应用程序的部分 当容器确定访问时匹配角色名称是区分大小写的 user-data-constraint 表示客户端和容器之间的通信数据如何受到子元素 transport-guarantee 的保护 transport-guarantee 的合法值是 NONE,INTEGRAL 或 CONFIDENTIAL 之一 图 security-constraint 元素结构 120

121 18 login-config 元素 login-config 用于配置应该使用的验证方法, 可用于此应用程序的领域名, 以及表单登录机制所需要的属性 子元素 auth-method 为 Web 应用程序配置验证机制 该元素的内容必须是 BASIC DIGEST FORM CLIENT-CERT 或 vendor-specific 验证模式 realm-name 表示为 Web 应用程序选择用于验证模式的领域名 form-login-config 指定应该用于基于表单登录的登录和错误页面 如果不使用基于表单的登录方式, 这些元素将被忽略 图 login-config 元素结构 19 security-role 元素 security-role 定义了一个安全角色 子元素 role-name 指定安全角色的名称 该名称必须符合 NMTOKEN 的词法规则 图 security-role 元素结构 121

122 20 env-entry 元素 env-entry 声明了一个应用程序的环境入口 子元素 env-entry-name 包含部署组件环境入口的名称 这个名称是一个相对于 java:comp/env 上下文的 JNDI 名称 在部署组件中该名称必须是唯一的 env-entry-type 包含了应用程序代码所期望的环境入口值的 Java 类型完全限定名 子元素 env-entry-value 指定部署组件的环境入口值 该值必须是一个 String, 对指定的使用一个 String 或 java.lang.character 类型作为参数的构造器有效 可选的 injection-target 元素用来定义把指定的资源注入到字段或 JavaBean 属性 injection-target 指定了类中应该被注入资源的类和名称 injection-target-class 指定了注入目标的完全限定类名称 injection-target-name 指定了指定类中的目标 首先把查找目标作为一个 JavaBean 属性名称 如果没有找到, 则把查找目标作为一个字段名 在类初始化期间通过调用目标属性的 set 方法或给名称字段设置一个值将指定的资源注入到目标 如果环境入口指定了一个 injection-target, 那么 env-entry-type 可以省略或必须与注入目标的类型匹配 如果没有指定 injection-target, 那么需要指定 env-entry-type 图 env-entry 元素结构 122

123 21 ejb-ref 元素 ejb-ref 声明了一个对企业 bean 的 home 引用 ejb-ref-name 指定了引用企业 bean 的部署组件代码中使用的名称 ejb-ref-type 是引用的企业 bean 期望的类型, 它可以是 Entity 或 Session home 定义了引用的企业 bean 的 home 接口的完全限定名称 remote 定义了引用的企业 bean 的 remote 接口的完全限定名称 ejb-link 指定了连接到企业 bean 的一个 EJB 引用 更多详细信息请参阅 Java 平台企业版第 6 版 除了这些元素之外, injection-target 元素可以用于定义指定的企业 bean 注入到一个组件的字段或属性 图 ejb-ref 元素结构 123

124 22 ejb-local-ref 元素 ejb-local-ref 声明了对企业 bean 的本地 home 引用 local-home 定义了企业 bean 的本地 home 接口的完全限 定名称 local 定义了企业 bean 的本地接口的完全限定名称 图 ejb-local-ref 元素结构 124

125 23 service-ref 元素 service-ref 声明了一个对 Web service 的引用 service-ref-name 声明了用于查找 Web service 模块组件的逻辑名称 建议所有 service 的引用名称以 /service/ 开头 service-interface 定义了客户端依赖的 JAX-WS Service 接口的完全限定类名称 在大多数情况下, 这个值是 javax.xml.rpc.service 也可以指定一个 JAX-WS 生成的服务接口类 wsdl-file 元素包含了 WSDL 文件的 URI 位置 这个位置相对于模块根目录 jaxrpc-mapping-file 包含了描述应用程序使用的 Java 接口和 wsdl-file 中的 WSDL 描述之间的 JAX-WS 映射的文件名 这个文件名是一个模块文件中的相对路径 service-qname 元素声明了具体的被称为 WSDL 的服务元素 如果没有声明 wsdl-file, 则不需要指定 port-component-ref 元素声明了一个在容器中解析服务终端接口到一个 WSDL 端口的客户端依赖关系 它使用一个特别的端口组件选择性地关联服务终端接口 这仅被容器用于 Service.getPort(Class) 方法调用 handler 元素为端口组件声明处理器 处理程序可以使用 HandlerInfo 接口访问 init-param 名值对 如果未指定 port-name, 处理器将与 service 的所有端口关联 详细信息请参阅 JSR-109 规范 [ 不属于 Java EE 实现的容器不要求支持这个元素 图 service-ref 元素结构 125

126 24 resource-ref 元素 resource-ref 元素包含了部署组件对外部资源的引用声明 res-ref-name 指定了一个资源管理器连接工厂引用的名称 这个名称是一个相对于 java:com /env 上下文的 JNDI 名称 在部署文件中这个名称必须是唯一的 res-type 元素指定数据源的类型 该类型是一个希望由数据源实现的 Java 语言类或接口的完全限定名 res-auth 指定部署组件代码是否以编程方式注册到资源管理器, 或容器是否将代表的部署组件注册到资源管理器 如果是第二种情况, 容器使用部署器提供的信息 res-sharing-scope 指定了通过给定的资源管理器连接工厂引用获取的连接是否可以共享 如果指定了这个值, 它必须是 Shareable 或 Unshareable 可选的 injection-target 元素用于定义把指定的资源注入到字段或 JavaBean 属性 图 resource-ref 元素结构 126

127 25 resource-env-ref 元素 resource-env-ref 包含了部署组件和对部署组件环境中的资源有关的管理对象的引用 resource-env-ref-name 指定了资源环境引用的名称 它的值是部署组件代码中使用的环境入口名称, 它是一个相对于 java:comp/env 上下文的 JNDI 名称, 并且在部署组件中必须是唯一的 resource-env-ref-type 指定了资源环境引用的类型 它是一个 Java 语言类或接口的完全限定名 可选的 injection-target 元素用于定义把指定的资源注入到字段或 JavaBean 属性 必须提供 resource-env-ref-type 除非指定了注入目标, 在这种情况下, 将使用目标的类型 如果两者都指定, 该类型必须与注入目标的类型兼容 图 resource-env-ref 元素结构 127

128 26 message-destination-ref 元素 message-destination-ref 元素包含了部署组件和对部署组件环境中的资源有关的消息目标的引用声明 message-destination-ref-name 元素指定了一个消息目标引用的名称, 它的值是部署组件代码中使用的环境入口名称 这个名称是一个相对于 java:comp/env 上下文的 JNDI 名称, 并且在企业 bean 的 ejb-jar 中或其他部署文件中必须是唯一的 message-destination-type 指定了目标的类型 这个类型由希望目标实现的 Java 接口指定 message-destination-usage 指定了引用表示的消息目标的用法 这个值表示是使用目标信息中的消息, 还是产生目标消息, 亦或两者兼而有之 汇编器将使用此信息来连接目标的生产者与消费者 message-destination-link 把一个消息目标引用或消息驱动 bean 连接到一个消息目标 汇编器设置这个值来反映应用程序中的生产者和消费者消息流 这个值必须是同一个部署文件或同一个 Java EE 应用程序单元的另一个部署文件中的消息目标的 message-destination-name 或者, 这个值可以由一个路径名称组成, 使用目标添加的 message-destination-name 和通过 "#" 分隔路径名称说明一个部署文件包含引用的消息目标 这个路径名称是相对于部署文件, 包含引用消息目标的部署组件 这允许多个消息目标使用相同的名称作为唯一标识 可选的 injection-target 元素用于定义把指定的资源注入到字段或 JavaBean 属性 必须指定 message-destination-type 除非注入目标已经指定, 在这种情况下, 将使用目标的类型 如果两者都指定, 该类型必须与注入目标的类型兼容 示例 : <message-destination-ref> <message-destination-ref-name> jms/stockqueue </message-destination-ref-name> <message-destination-type> 128

129 javax.jms.queue </message-destination-type> <message-destination-usage> Consumes </message-destination-usage> <message-destination-link> CorporateStocks </message-destination-link> </message-destination-ref> 图 message-destination-ref 元素结构 27 message-destination 元素 message-destination 指定消息的目标 这个元素所描述的逻辑目标由部署器映射到物理目标 message-destination-name 元素指定了消息目标的名称 该名称在部署文件的消息目标名称中必须是唯一的 示例 : 129

130 <message-destination> <message-destination-name> CorporateStocks </message-destination-name> </message-destination> 图 message-destination 元素结构 28 locale-encoding-mapping-list 元素 locale-encoding-mapping-list 包含了语言环境和编码之间的映射 由子元素 locale-encoding-mapping 指定 示例 : <locale-encoding-mapping-list> <locale-encoding-mapping> <locale>ja</locale> <encoding>shift_jis</encoding> </locale-encoding-mapping> </locale-encoding-mapping-list> 图 locale-encoding-mapping-list 元素结构 130

131 14.5 实例 下面的例子说明了部署描述文件模式中列出的定义的用法 一个简单的例子 代码示例 14-1 基本部署描述文件示例 <?xml version="1.0" encoding="iso "?> <web-app xmlns=" xmlns:xsi=" xsi:schemalocation=" version= 2.5 > <display-name>a Simple Application</display-name> <context-param> <param-name>webmaster</param-name> </context-param> <servlet> <servlet-name> 目录 </ servlet 的名称 > <servlet-class>com.mycorp.catalogservlet </servlet-class> <init-param> <param-name>catalog</param-name> <param-value>spring</param-value> </init-param> </servlet> 131

本章学习目标 小风 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

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

D getinitparameternames() 9 下 列 选 项 中, 属 于 Servlet API 中 提 供 的 request 对 象 的 包 装 类 的 是 ( ) A HttpServletRequestWrapper B HttpServletRequest C HttpServ

D getinitparameternames() 9 下 列 选 项 中, 属 于 Servlet API 中 提 供 的 request 对 象 的 包 装 类 的 是 ( ) A HttpServletRequestWrapper B HttpServletRequest C HttpServ 第 四 章 Filter( 过 滤 器 ) 样 题 A 卷 一 选 择 题 ( 每 小 题 2 分, 共 20 分 ) 1 下 面 选 项 中, 用 于 实 现 初 始 化 过 滤 器 的 方 法 是 ( ) A init(filterconfig filterconfig) B dofilter(servletrequest req,servletresponse resp,filterchain

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

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

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

Guava学习之Resources

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

More information

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

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

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

(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

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

Slide 1

Slide 1 < 在此处插入图片 > JavaEE 6 Servlet 3.0 中的新特性 议题 易于开发和部署 < 在此处插入图片 > 模块化 web.xml 动态配置 异步 Servlet 2 Web Profile 用于 Web 应用程序的功能全面的中型 profile web profile 中的各种技术 Servlet 3.0 JSP 2.1 对其他语言的调试支持 EL 1.2 JSTL 1.2 JSF

More information

问 调 用 云 端 的 语 音 服 务 的 接 口 形 式, 对 规 范 语 音 识 别 服 务 提 供 方 式, 方 便 客 户 端 的 集 成 调 用, 从 而 促 进 语 音 交 互 应 用 的 推 广 发 展, 促 进 广 大 用 户 充 分 享 受 到 语 音 交 互 带 来 的 快 速

问 调 用 云 端 的 语 音 服 务 的 接 口 形 式, 对 规 范 语 音 识 别 服 务 提 供 方 式, 方 便 客 户 端 的 集 成 调 用, 从 而 促 进 语 音 交 互 应 用 的 推 广 发 展, 促 进 广 大 用 户 充 分 享 受 到 语 音 交 互 带 来 的 快 速 国 家 标 准 中 文 语 音 识 别 互 联 网 服 务 接 口 规 范 ( 征 求 意 见 稿 ) 编 制 说 明 一 工 作 简 况 1 任 务 来 源 按 照 国 家 标 准 化 管 理 委 员 会 2014 年 第 一 批 国 家 标 准 制 修 订 计 划 安 排, 国 家 标 准 制 定 项 目 中 文 语 音 识 别 互 联 网 服 务 接 口 规 范 ( 征 求 意 见 稿 ) 计

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

weblogic

weblogic Weblogic Allen Long allen@huihoo.com http://www.huihoo.com 2004-04 1 WebLogic, WLS WLS Domain 2 Weblogic6.1 Weblogic6.1 J2EE1.2,J2EE1.3 HTTP 1.1 J2EE Connector Architecture 1.0 J2EE EJB 2.0 J2EE JDBC 2.0

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

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

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

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

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

MASQUERADE # iptables -t nat -A POSTROUTING -s / o eth0 -j # sysctl net.ipv4.ip_forward=1 # iptables -P FORWARD DROP #

MASQUERADE # iptables -t nat -A POSTROUTING -s / o eth0 -j # sysctl net.ipv4.ip_forward=1 # iptables -P FORWARD DROP # iptables 默认安全规则脚本 一 #nat 路由器 ( 一 ) 允许路由 # iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT ( 二 ) DNAT 与端口转发 1 启用 DNAT 转发 # iptables -t nat -A PREROUTING -p tcp -d 192.168.102.37 dprot 422 -j DNAT to-destination

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

优迈科技教学大纲2009版本

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

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

2 Java 语 言 程 序 设 计 教 程 1.2.1 简 单 性 Java 语 言 的 语 法 与 C 语 言 和 C++ 语 言 很 接 近, 使 得 大 多 数 程 序 员 很 容 易 学 习 和 使 用 Java 另 一 方 面,Java 丢 弃 了 C++ 中 很 少 使 用 的 很 难

2 Java 语 言 程 序 设 计 教 程 1.2.1 简 单 性 Java 语 言 的 语 法 与 C 语 言 和 C++ 语 言 很 接 近, 使 得 大 多 数 程 序 员 很 容 易 学 习 和 使 用 Java 另 一 方 面,Java 丢 弃 了 C++ 中 很 少 使 用 的 很 难 第 1 章 Java 概 述 Java 的 诞 生 Java 的 特 点 Java 开 发 环 境 安 装 与 配 置 创 建 并 运 行 一 个 简 单 的 Java 程 序 Java 语 言 是 当 今 计 算 机 软 件 行 业 中 最 热 门 的 网 络 编 程 语 言, 以 Java 为 核 心 的 芯 片 技 术 编 译 技 术 数 据 库 连 接 技 术, 以 及 基 于 企 业 级

More information

無障礙網頁開發規範二版(草案)

無障礙網頁開發規範二版(草案) 國 家 通 訊 傳 播 委 員 會 無 障 礙 網 頁 開 發 規 範 2.0 版 ( 草 案 ) 委 辦 單 位 : 國 家 通 訊 傳 播 委 員 會 執 行 單 位 : 中 華 民 國 資 訊 軟 體 協 會 中 華 民 國 1 0 3 年 0 5 月 I II 目 錄 壹 前 言... 1 貳 適 用 範 圍... 2 參 用 語 釋 義... 3 肆 規 範 內 文... 14 一 規 範

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

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

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

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

Microsoft Word - 第4章 Servlet开发—教学设计.doc

Microsoft Word - 第4章 Servlet开发—教学设计.doc 传智播客 JavaWeb 程序开发入门 教学设计 课程名称 : JavaWeb 程序开发入门 授课年级 : 2014 年级 授课学期 : 2014 学年第一学期 教师姓名 : 某某老师 2014 年 09 月 09 日 课题名称内容分析教学目标及基本要求重点及措施 计划第 4 章 Servlet 技术 6 课时学时随着 Web 应用业务需求的增多, 动态 Web 资源的开发变得越来越重要, 为此 Sun

More information

Java 1 Java String Date

Java 1 Java String Date JAVA SCJP Java 1 Java String Date 1Java 01 Java Java 1995 Java Java 21 Java Java 5 1-1 Java Java 1990 12 Patrick Naughton C++ C (Application Programming Interface API Library) Patrick Naughton NeXT Stealth

More information

拦截器(Interceptor)的学习

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

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

iGENUS爱琴思邮件系统技术白皮书

iGENUS爱琴思邮件系统技术白皮书 igenus 爱 琴 思 邮 件 系 统 技 术 白 皮 书 Http://www.iGENUS.cn 版 权 信 息 igenus 爱 琴 思 邮 件 系 统 版 权 所 有 2009 爱 琴 思 科 技 ( 成 都 ) 有 限 公 司 igenus information technologies Inc.,Chengdu 文 档 保 证 声 明 本 文 档 以 提 供 信 息 为 目 的, 所

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

1

1 PRIMETON TECHNOLOGIES, LTD. EOS EOS Manager No part of this document may be reproduced, stored in any electronic retrieval system, or transmitted in any form or by any means, mechanical, photocopying,

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

Microsoft Word - SCWCD-CH01.doc

Microsoft Word - SCWCD-CH01.doc Java SCWCD 5(Sun Certified Web Component Developer) 全 名 為, 屬 於 專 業 級 這 項 主 要 是 確 保 開 發 工 程 師 具 備 能 使 用 JavaServer Pages Servlet 技 術 所 提 供 Web 服 務 動 態 Web 內 容 的 能 力 對 於 想 要 開 發 Web 應 用 程 的 開 發 人 員 來 說,

More information

Marketing_WhitePaper.PDF

Marketing_WhitePaper.PDF Turbolinux PowerMonitor Enterprise 1. 1994 WWW WEB 1 Web 1: Web Web web web web web web Web HTML 2 DNS Web DB LDAP Shipping Agencies 2 2 CGI Servlets JSP ASP XSL JDBC Web 2. HP OpenView CA Unicenter Tivoli

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

( Version 0.4 ) 1

( Version 0.4 ) 1 ( Version 0.4 ) 1 3 3.... 3 3 5.... 9 10 12 Entities-Relationship Model. 13 14 15.. 17 2 ( ) version 0.3 Int TextVarchar byte byte byte 3 Id Int 20 Name Surname Varchar 20 Forename Varchar 20 Alternate

More information

epub 61-2

epub 61-2 2 Web Dreamweaver UltraDev Dreamweaver 3 We b We b We Dreamweaver UltraDev We b Dreamweaver UltraDev We b We b 2.1 Web We b We b D r e a m w e a v e r J a v a S c r i p t We b We b 2.1.1 Web We b C C +

More information

WebSphere Studio Application Developer IBM Portal Toolkit... 2/21 1. WebSphere Portal Portal WebSphere Application Server stopserver.bat -configfile..

WebSphere Studio Application Developer IBM Portal Toolkit... 2/21 1. WebSphere Portal Portal WebSphere Application Server stopserver.bat -configfile.. WebSphere Studio Application Developer IBM Portal Toolkit... 1/21 WebSphere Studio Application Developer IBM Portal Toolkit Portlet Doug Phillips (dougep@us.ibm.com),, IBM Developer Technical Support Center

More information

PowerPoint Presentation

PowerPoint Presentation 数 字 化 校 园 信 息 平 台 解 决 方 案 杭 州 正 方 电 子 工 程 有 限 公 司 2007.10 杭 州 正 方 电 子 工 程 有 限 公 司 简 介 正 方 公 司 成 立 于 1999 年 1 月 份, 现 有 员 工 170 多 名, 是 经 相 关 机 构 认 定 的 高 新 技 术 企 业 软 杭 件 企 州 业 正, 取 方 得 电 计 算 子 机 工 软 件 程 著

More information

untitled

untitled rxli@public.wh.hb.cn http://idc.hust.edu.cn/~rxli/ 2 3 ( ) (Distributed System) Integrated System () 4 5 6 System Integration 7 8 Integrated System 9 1.1 CIMS IDEF CSCW STEP MIS MRPII ERP CRM SCM MIS:

More information

Chapter #

Chapter # 第三章 TCP/IP 协议栈 本章目标 通过本章的学习, 您应该掌握以下内容 : 掌握 TCP/IP 分层模型 掌握 IP 协议原理 理解 OSI 和 TCP/IP 模型的区别和联系 TCP/IP 介绍 主机 主机 Internet TCP/IP 早期的协议族 全球范围 TCP/IP 协议栈 7 6 5 4 3 应用层表示层会话层传输层网络层 应用层 主机到主机层 Internet 层 2 1 数据链路层

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

「人名權威檔」資料庫欄位建置表

「人名權威檔」資料庫欄位建置表 ( version 0.2) 1 3 3 3 3 5 6 9.... 11 Entities - Relationship Model..... 12 13 14 16 2 ( ) Int Varchar Text byte byte byte Id Int 20 Name Surname Varchar 20 Forename Varchar 20 Alternate Type Varchar 10

More information

Stateless Session Beans(无状态bean)的学习

Stateless Session Beans(无状态bean)的学习 一 Stateless Session Beans( 无状态 bean) 的学习 第一步 : 要定义一个会话 Bean, 首先需要定义一个包含他所有业务方法的接口 这个接口不需要任何注释, 就像普通的 java 接口那样定义 调用 EJB 的客户端通过使用这个接口引用从 EJB 容器得到的会话 Bean 对象 stub 接口的定义如下: HelloWorld.java package com.foshanshop.ejb3;

More information

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

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

More information

Microsoft Word - 01.DOC

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

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 - Broker.doc

Microsoft Word - Broker.doc Broker 模式 采用 broker 模式对分布式计算进行简单模拟 系统在一个进程内模拟分布式环境, 因此不涉及网络编程和进程间通信,Broker 通过本地函数调用的方式实现 request 和 response 的转发 采用 broker 模式对分布式计算进行简单的模拟, 要求如下 : 设计四个 server, 一个 server 接收两个整数, 求和并返回结果, 一个 server 接收两个整数,

More information

<4D6963726F736F667420576F7264202D20312D3120B9ABBFAAD7AAC8C3CBB5C3F7CAE9A3A8C9EAB1A8B8E5A3A92E646F63>

<4D6963726F736F667420576F7264202D20312D3120B9ABBFAAD7AAC8C3CBB5C3F7CAE9A3A8C9EAB1A8B8E5A3A92E646F63> 广 西 新 豪 智 云 技 术 股 份 有 限 公 司 ( 申 报 稿 ) 推 荐 主 办 券 商 二 〇 一 六 年 一 月 声 明 本 公 司 及 全 体 董 事 监 事 高 级 管 理 人 员 承 诺 不 存 在 虚 假 记 载 误 导 性 陈 述 或 重 大 遗 漏, 并 对 其 真 实 性 准 确 性 完 整 性 承 担 个 别 和 连 带 的 法 律 责 任 本 公 司 负 责 人 和

More information

RxJava

RxJava RxJava By 侦跃 & @hi 头 hi RxJava 扩展的观察者模式 处 观察者模式 Observable 发出事件 Subscriber 订阅事件 bus.post(new AnswerEvent(42)); @Subscribe public void onanswer(answerevent event) {! }! Observable observable = Observable.create(new

More information

VIDEOJET connect 7000 VJC-7000-90 zh- CHS Operation Manual VIDEOJET connect 7000 zh-chs 3 目 录 1 浏 览 器 连 接 7 1.1 系 统 要 求 7 1.2 建 立 连 接 7 1.2.1 摄 像 机 中 的 密 码 保 护 7 1.3 受 保 护 的 网 络 7 2 系 统 概 述 8 2.1 实 况

More information

詞 彙 表 編 號 詞 彙 描 述 1 預 約 人 資 料 中 文 姓 名 英 文 姓 名 身 份 證 字 號 預 約 人 電 話 性 別 2 付 款 資 料 信 用 卡 別 信 用 卡 號 信 用 卡 有 效 日 期 3 住 房 條 件 入 住 日 期 退 房 日 期 人 數 房 間 數 量 入

詞 彙 表 編 號 詞 彙 描 述 1 預 約 人 資 料 中 文 姓 名 英 文 姓 名 身 份 證 字 號 預 約 人 電 話 性 別 2 付 款 資 料 信 用 卡 別 信 用 卡 號 信 用 卡 有 效 日 期 3 住 房 條 件 入 住 日 期 退 房 日 期 人 數 房 間 數 量 入 100 年 特 種 考 試 地 方 政 府 公 務 人 員 考 試 試 題 等 別 : 三 等 考 試 類 科 : 資 訊 處 理 科 目 : 系 統 分 析 與 設 計 一 請 參 考 下 列 旅 館 管 理 系 統 的 使 用 案 例 圖 (Use Case Diagram) 撰 寫 預 約 房 間 的 使 用 案 例 規 格 書 (Use Case Specification), 繪 出 入

More information

epub83-1

epub83-1 C++Builder 1 C + + B u i l d e r C + + B u i l d e r C + + B u i l d e r C + + B u i l d e r 1.1 1.1.1 1-1 1. 1-1 1 2. 1-1 2 A c c e s s P a r a d o x Visual FoxPro 3. / C / S 2 C + + B u i l d e r / C

More information

untitled

untitled ArcGIS Server Web services Web services Application Web services Web Catalog ArcGIS Server Web services 6-2 Web services? Internet (SOAP) :, : Credit card authentication, shopping carts GIS:, locator services,

More information

SiteView技术白皮书

SiteView技术白皮书 SiteView ECC V6.2 技 术 白 皮 书 游 龙 网 络 科 技 ( 中 国 ) 有 限 公 司 DragonFlow Networks(China),Inc. 目 录 第 一 章 产 品 概 述... 3 第 二 章 系 统 结 构... 6 一 系 统 架 构... 7 1 用 户 管 理 模 块... 7 2 Web Server... 8 3 存 储 加 密 模 块... 8

More information

设计模式 Design Patterns

设计模式 Design Patterns 丁勇 Email:18442056@QQ.com 学习目标 网络程序设计的基本概念 Servlet 基础 Servlet 的生命周期 网络程序设计的基本概念 Servlet 基础 Servlet 的生命周期 1 网络程序设计的基本概念 网络将世界联系在一起, 使世界变得更加丰富多彩 同时网络互连是一个内容丰富而复杂的主题, 所以这方面的程序设计涉及面很广且不易掌握 与其他语言相比, 语言在网络应用程序方面具有一定的优势

More information

云数据库 RDS SDK

云数据库 RDS SDK 云数据库 RDS SDK SDK SDK 下载 SDK 下载 最新版本 java_sdk.zip python_sdk.zip php_sdk.zip c#_sdk.zip 历史版本 2015-11-3 java_sdk.zip python_sdk.zip php_sdk.zip c#_sdk.zip JAVA 教程 JAVA 创建 Access Key 登陆阿里云账号 打开 我的 Access

More information

http://panweizeng.com http://meituan.com http://meituan.com hosts http://meituan.com hosts localhost 127.0.0.1 /etc/nsswitch.conf /etc/hosts /etc/resolv.conf Mail Client Web Browser cache 1-30mins Clients

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

D C 93 2

D C 93 2 D9223468 3C 93 2 Java Java -- Java UML Java API UML MVC Eclipse API JavadocUML Omendo PSPPersonal Software Programming [6] 56 8 2587 56% Java 1 epaper(2005 ) Java C C (function) C (reusability) eat(chess1,

More information

<4D6963726F736F667420576F7264202D20383439342D352DBED6D3F2CDF8D7E9BDA8D3EBB9DCC0EDCFEEC4BFBDCCB3CCD5FDCEC42E646F63>

<4D6963726F736F667420576F7264202D20383439342D352DBED6D3F2CDF8D7E9BDA8D3EBB9DCC0EDCFEEC4BFBDCCB3CCD5FDCEC42E646F63> 第 4 单 元 搭 建 自 己 的 Web 站 点 本 单 元 通 过 学 习 架 构 Web 服 务 器, 实 现 Web 服 务, 管 理 Web 站 点, 了 解 Web 站 点 服 务 器 的 架 构 个 人 空 间 和 虚 拟 主 机 的 概 念, 掌 握 IIS 组 件 的 安 装 Web 站 点 的 创 建 管 理 站 点 属 性 选 项 卡 的 配 置 管 理 等 知 识,Web 网

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

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

提纲 1 2 OS Examples for 3

提纲 1 2 OS Examples for 3 第 4 章 Threads2( 线程 2) 中国科学技术大学计算机学院 October 28, 2009 提纲 1 2 OS Examples for 3 Outline 1 2 OS Examples for 3 Windows XP Threads I An Windows XP application runs as a seperate process, and each process may

More information

Symantec™ Sygate Enterprise Protection 防护代理安装使用指南

Symantec™ Sygate Enterprise Protection 防护代理安装使用指南 Symantec Sygate Enterprise Protection 防 护 代 理 安 装 使 用 指 南 5.1 版 版 权 信 息 Copyright 2005 Symantec Corporation. 2005 年 Symantec Corporation 版 权 所 有 All rights reserved. 保 留 所 有 权 利 Symantec Symantec 徽 标 Sygate

More information

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

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

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



 服 务 类 采 购 公 开 招 标 文 件 项 目 名 称 : 广 东 环 境 保 护 工 程 职 业 学 院 教 育 信 息 系 统 软 件 采 购 项 目 广 东 环 境 保 护 工 程 职 业 学 院 发 布 日 期 :2015 年 8 月 28 日 目 录 第 一 部 分 投 标 邀 请 函...3 第 二 部 分 采 购 项 目 内 容...7 第 三 部 分 投 标 人 须 知...26

More information

<4D6963726F736F667420576F7264202D20BBF9D3DA416E64726F6964C6BDCCA8B5C4B5E7D7D3C5C4C2F4CFB5CDB32E646F63>

<4D6963726F736F667420576F7264202D20BBF9D3DA416E64726F6964C6BDCCA8B5C4B5E7D7D3C5C4C2F4CFB5CDB32E646F63> 基 于 Android 平 台 的 电 子 拍 卖 系 统 摘 要 本 电 子 拍 卖 系 统 其 实 就 是 一 个 电 子 商 务 平 台, 只 要 将 该 系 统 部 署 到 互 联 网 上, 客 户 都 可 以 在 该 系 统 上 发 布 想 出 售 的 商 品, 也 可 以 对 拍 卖 中 的 商 品 参 与 竞 价 整 个 过 程 无 须 人 工 干 预, 由 系 统 自 动 完 成 本

More information

<4D6963726F736F667420576F7264202D2031A3AD4A617661BCBCCAF5CAC6CDB7D5FDBEA22E646F63>

<4D6963726F736F667420576F7264202D2031A3AD4A617661BCBCCAF5CAC6CDB7D5FDBEA22E646F63> Java 技 术 的 势 头 正 劲 清 华 大 学 计 算 机 科 学 与 技 术 系 李 涓 子 徐 鹏 王 克 宏 Java 技 术 已 经 遍 布 世 界 各 个 角 落, 从 智 能 卡 Java 手 机 和 电 话, 到 汽 车 生 产 以 至 于 控 制 火 星 漫 游 者 号 的 临 界 任 务 系 统 都 能 看 到 它 的 作 用,Java 已 经 成 为 一 种 普 遍 深 入

More information

FileMaker 16 ODBC 和 JDBC 指南

FileMaker 16 ODBC 和 JDBC 指南 FileMaker 16 ODBC JDBC 2004-2017 FileMaker, Inc. FileMaker, Inc. 5201 Patrick Henry Drive Santa Clara, California 95054 FileMaker FileMaker Go FileMaker, Inc. FileMaker WebDirect FileMaker Cloud FileMaker,

More information

通过Hive将数据写入到ElasticSearch

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

More information

網站安全

網站安全 2 3 4 5 6 7 8 9 : 10 ( ) E-mail rdec@rdec.gov.tw 11 (PATCH) 12 ( ) 13 cookie 14 1. 2. 3. 4. 15 cookie Cookie Netscape IE Internet cookie cookie cookie cookie 16 MS Internet Explorer 6.x-> -> 17 cookie

More information

XXXXXXXX http://cdls.nstl.gov.cn 2 26

XXXXXXXX http://cdls.nstl.gov.cn 2 26 [ ] [ ] 2003-7-18 1 26 XXXXXXXX http://cdls.nstl.gov.cn 2 26 (2003-7-18) 1...5 1.1...5 1.2...5 1.3...5 2...6 2.1...6 2.2...6 2.3...6 3...7 3.1...7 3.1.1...7 3.1.2...7 3.1.2.1...7 3.1.2.1.1...8 3.1.2.1.2...10

More information

RunPC2_.doc

RunPC2_.doc PowerBuilder 8 (5) PowerBuilder Client/Server Jaguar Server Jaguar Server Connection Cache Thin Client Internet Connection Pooling EAServer Connection Cache Connection Cache Connection Cache Connection

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

使用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

水晶分析师

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

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

执 行 引 擎 JSP : java 嵌 入 进 HTML 中 在 server 端 运 行 时 把 整 个.jsp 文 件 翻 译 成 Servlet 格 式 用 户 不 用 手 动 把 <html> 改 为 java 语 言 打 印 jsp 替 用 户 完 成 jsp --> jasper --

执 行 引 擎 JSP : java 嵌 入 进 HTML 中 在 server 端 运 行 时 把 整 个.jsp 文 件 翻 译 成 Servlet 格 式 用 户 不 用 手 动 把 <html> 改 为 java 语 言 打 印 jsp 替 用 户 完 成 jsp --> jasper -- Tomcat 基 础 java 基 础 概 念 : 特 性 : 面 向 对 象 多 线 程 结 构 化 错 误 处 理 垃 圾 收 集 动 态 链 接 动 态 扩 展 JDK : Java Development Kit ( java 开 发 工 具 包 ) 包 含 了 一 个 jvm JVM : Java 虚 拟 机 JAR 文 档 格 式 JDBC : JAVA 连 接 数 据 库 j2se :

More information

A API Application Programming Interface 见 应 用 程 序 编 程 接 口 ARP Address Resolution Protocol 地 址 解 析 协 议 为 IP 地 址 到 对 应 的 硬 件 地 址 之 间 提 供 动 态 映 射 阿 里 云 内

A API Application Programming Interface 见 应 用 程 序 编 程 接 口 ARP Address Resolution Protocol 地 址 解 析 协 议 为 IP 地 址 到 对 应 的 硬 件 地 址 之 间 提 供 动 态 映 射 阿 里 云 内 A API Application Programming Interface 见 应 用 程 序 编 程 接 口 ARP Address Resolution Protocol 地 址 解 析 协 议 为 IP 地 址 到 对 应 的 硬 件 地 址 之 间 提 供 动 态 映 射 阿 里 云 内 容 分 发 网 络 Alibaba Cloud Content Delivery Network 一

More information

Servlet 134 Filter Listener Directive 16 Action 26 Scripting 3 Implicit Object 95 Core Tag Library SQL SQL Tag Lib

Servlet 134 Filter Listener Directive 16 Action 26 Scripting 3 Implicit Object 95 Core Tag Library SQL SQL Tag Lib JSP JSP 978-7-115-16111-6 62 185 260 1/16 35.75 570 1CD 2007 5 41 50 9 268 6 274 181 Servlet 134 Filter Listener 229 509 Directive 16 Action 26 Scripting 3 Implicit Object 95 Core Tag Library 38 45 SQL

More information

1 Par t IBM 7 Par t 2 I BM IBM Par t Q & A

1 Par t IBM 7 Par t 2 I BM IBM Par t Q & A IBM 1 Par t 1 12 2 3 1 3 3 3 1 4 4 4 5 5 5 2 5 6 6 IBM 7 Par t 2 I BM IBM 1 0 1 1 2 2 1 6 3 1 8 Par t 3 2 0 Q & A 2 9 2 2 Pa r t 1 12 4 27 1 2 3 2,3 0 0 2 1990 9 1992 6 1995 4 1995 7 12 1995 8 11 1995

More information

Slide 1

Slide 1 了解 Java EE 6 和 WebLogic Arun Gupta,Java EE 和 GlassFish 专家 blogs.sun.com/arungupta, @arungupta 以下内容旨在概述产品的总体发展方向 该内容仅供参考, 不可纳入任何合同 该内容不构成提供任何材料 代码或功能的承诺, 并且不应该作为制定购买决策的依据 此处所述有关 Oracle 产品的任何特性或功能的开发 发布以及相应的日程安排均由

More information

目录

目录 目 录 1 系 统 概 述... 1 1.1 主 要 功 能... 1 1.2 工 作 环 境 要 求... 2 1.2.1 硬 件 环 境... 2 1.2.2 操 作 系 统... 2 1.2.3 数 据 库... 2 1.2.4 浏 览 器... 2 2 安 装 卸 载... 3 2.1 安 装 步 骤... 3 2.2 使 用 加 密 狗... 5 2.3 卸 载 步 骤... 6 3 新

More information

final

final 行 政 院 研 究 發 展 考 核 委 員 會 政 府 網 站 建 置 及 營 運 作 業 參 考 指 引 中 華 民 國 99 年 2 月 政 府 網 站 建 置 及 營 運 作 業 參 考 指 引 目 次 前 言 與 導 讀... 1 一. 緣 由... 1 二. 現 行 規 範 應 用 的 運 作 與 問 題... 1 三. 政 府 網 站 建 置 與 營 運 作 業 參 考 指 引 之 規

More information

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas 目录 1 IPv6 快速转发 1-1 1.1 IPv6 快速转发配置命令 1-1 1.1.1 display ipv6 fast-forwarding aging-time 1-1 1.1.2 display ipv6 fast-forwarding cache 1-1 1.1.3 ipv6 fast-forwarding aging-time 1-3 1.1.4 ipv6 fast-forwarding

More information

册子0906

册子0906 IBM SelectStack ( PMC v2.0 ) 模块化私有云管理平台 是跨主流虚拟化技术的统一资源云管理平台 01 亮点 : 快速可靠地实现集成化 私有云管理平台 02/03 丰富的功能支持企业数据中心云计算 扩展性强 : 简单易用 : 04/05 功能丰富 : 06/07 为什么选择 IBM SelectStack (PMC v2.0)? 快速实现价值 提高创新能力 降低 IT 成本 降低复杂度和风险

More information

PowerPoint Presentation

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

More information

静态分析 投放文件 行为分析 互斥量 (Mutexes) 执行的命令 创建的服务 启动的服务 进程 cmd.exe PID: 2520, 上一级进程 PID: 2556 cmd.exe PID: 2604, 上一级进程 PID: 2520 访问的文件 C:\Users\test\AppData\Lo

静态分析 投放文件 行为分析 互斥量 (Mutexes) 执行的命令 创建的服务 启动的服务 进程 cmd.exe PID: 2520, 上一级进程 PID: 2556 cmd.exe PID: 2604, 上一级进程 PID: 2520 访问的文件 C:\Users\test\AppData\Lo 魔盾安全分析报告 分析类型 开始时间 结束时间 持续时间 分析引擎版本 FILE 2016-11-25 00:20:03 2016-11-25 00:22:18 135 秒 1.4-Maldun 虚拟机机器名 标签 虚拟机管理 开机时间 关机时间 win7-sp1-x64 win7-sp1-x64 KVM 2016-11-25 00:20:03 2016-11-25 00:22:18 魔盾分数 0.0

More information

untitled

untitled . Version 1.0 2015 7 1. IT 1.. IBM IBM IBM WBI IBM WBI Jasdaq 3G 9 Java Hitachi Suntory Panansonic 2. IT . 10 Java Software AG (Dachieve) (Angel Engineers Inc.) 360,, Software AG XML,.,,,,.. CRM TOLO 3G

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

二 Synchronized 1. Java 语 言 的 关 键 字, 当 它 用 来 修 饰 一 个 方 法 或 者 一 个 代 码 块 的 时 候, 能 够 保 证 在 同 一 时 刻 最 多 只 有 一 个 线 程 执 行 该 段 代 码 2. 当 两 个 并 发 线 程 访 问 同 一 个

二 Synchronized 1. Java 语 言 的 关 键 字, 当 它 用 来 修 饰 一 个 方 法 或 者 一 个 代 码 块 的 时 候, 能 够 保 证 在 同 一 时 刻 最 多 只 有 一 个 线 程 执 行 该 段 代 码 2. 当 两 个 并 发 线 程 访 问 同 一 个 Java 基 础 包 括 多 线 程 (Thread 和 Runable 的 区 别 ) 同 步 异 步 (Synchronized) 线 程 池 集 合 序 列 化 反 射 实 例 化 过 程 JDBC 常 用 类 IBatis Java 类 生 命 周 期 Java Web 生 命 周 期 Tomcat 出 去 Http 请 求 过 程 Java 垃 圾 回 收 机 制 Java 性 能 优 化

More information

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

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

More information