Servlet 3.0 规范摘要
目录
# Tomcat 版本
# Servlet
# ServletRequest
# 异步处理
# Servlet Context
# ServletResponse
# 过滤器
# Session
# Annotation
# Web fragment
# RequestDispatcher
# Web App
# 错误处理
# 欢迎页面
# Tomcat 版本
Tomcat 7.x:JDK 7/Servlet 3.0/JSP 2.2/EL 2.2
Tomcat 6.x:JDK 6/Servlet 2.5/JSP 2.1
# Servlet
Servlet接口2个类:GenericServlet,HttpServlet
一般,容器只创建一个Servlet实例,并发的请求使用同一个实例进行处理,因此,Servlet 不是线程安全的
Servlet 若实现 SingleThreadModel,则容器会创建多个实例,确保每个实例同时只在一个线程内运行。但是,规范不推荐使用 SingleThreadModel
两个生命周期回调方法:init() 和 destroy()
o 路径映射
路径格式:
- 以 / 开头,以/* 结尾的,用最长匹配
- 以 * 开头的,用扩展名匹配
- 空串(""),匹配Context Path
- 仅/字符,匹配默认Servlet
- 所有其他的,严格匹配
如果某URL出现多个匹配,优先顺序:
- 严格匹配
- 最长匹配
- 扩展名匹配
# ServletRequest
接口 ServletRequest,HttpServletRequest
类 HttpServletRequestWrapper
o 生命周期:请求对象失效后,被容器回收后可能被重用,应用程序不应该依赖于超出有效范围的请求对象
o 请求参数
客户端提交的请求参数,通过 HttpServletRequest.getParameterXxx() 方法读取
表单数据如果是POST方法提交,则编码类型必须是 application/x-www-form-urlencoded ,表单数据才作为参数,否则,表单数据在 HTTP 请求 body 内,只能通过 InputStream 读取
文件上传(File upload)须使用 multipart/form-data 表单类型,且Servlet 添加 @MultipartConfig 标记
文件上传数据的读取:getPart(),getParts()
o 属性
属性(Attribute)是容器设置,或应用程序设置,方法:setAttribute(),getAttributeXxx()
以 java,javax,sun开头的属性名称保留
SSL有关的属性,容器以属性的形式提供
判断是否SSL:isSecure()
o HTTP 头:getHeaderXxx(),getXxxHeader()
o 请求路径
请求路径包含3部分
- Context Path:Web 应用的根路径,如果Web应用为默认应用,则为"",getContextPath()
- Servlet Path:Context Path 后面,Servlet 映射路径
- Path Info:如果Servlet映射路径使用了通配符,Servlet Path 后面的部分为 Path Info
如,主机为www.the.com,Web应用为 some.war,某一Servlet 映射路径为 /oneServlet/*,客户端请求 http://www.the.com/some/oneServlet/any/file,则
- Context Path = /some
- Servlet Path = /oneServlet
- Path Info = /any/file
忽略URL编码,requestURI = contextPath + servletPath + pathInfo
o 获取本地路径
可将请求路径转换为服务器本地文件系统路径
- ServletContext.getRealPath():将相对于 Context Path 的路径转换为本地物理路径
- HttpServletRequest.getPathTranslated() :将该请求的 Path Info 转换为本地物理路径
o getCookies() 获取 Cookie
o I18N
HTTP请求中 Accept-Language 头,可通过以下方法读取:getLocale(),getLocales()
o 请求的字符编码
getCharacterEncoding(),如果客户端未指定(Content-Type头),则返回 null,容器默认使用 ISO-8859-1
setCharacterEncoding() 覆盖客户端提交的字符编码
# 异步处理
如果 Servlet.service() 方法内需要等待另一资源可用,如数据库连接,会导致线程等待,降低了容器的线程利用率
异步处理的基本思路是,应用程序起一个子线程,在子线程内执行导致线程等待的工作,让 service() 尽快返回
ServletRequest.startAsync() 使请求进入异步模式,在异步模式下,退出service() 不会提交Response 到客户端,而是要等到
- 异步处理完成。通过调用 AsyncContext.complete() 通知容器,AsyncContext 由 startAsync() 返回
- 异步处理超时
(对于在Web容器内起应用程序线程,个人持保留态度)
# Servlet Context
ServletContext 是Web app的访问接口
Web app 在服务器上的路径为 http://host:port/contentRoot
每个 Web app 只有一个 ServletContext 实例
o 初始化参数
设置:通过 web.xml
读取:getInitParameterXxx()
o 编程增加Servlet,Filter和Listener
ServletContext 提供方法,可在Web app 初始化时创建、配置 Servlet、Filter 和 Listener,如同在 web.xml 中声明一样
- addServlet/Filter/Listener()
- createServlet/Filter/Listener()
- getServlet/Filter/ListenerRegistration()
- getServlet/Filter/ListenerRegistrations()
o 属性
ServletContext 的属性对象可以被Web app 内任意组件访问
- setAttribute()
- getAttribute()
- getAttributeNames()
- removeAttribute()
o 读取资源
可读取 Web app 内的静态资源文件,如:HTML
- getResource()
- getResourceAsStream()
o 临时文件夹
容器要为每个Webapp 提供一个临时文件夹
File dir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
# ServletResponse
HttpServletResponse 表示给客户端的HTTP响应
ServletResponse 对象应该只在其有效范围(Servlet.service())内使用
o 缓冲
返回客户端的数据,可以通过 OutputStream 或 PrintWriter 写出去,也可以先写入缓冲区,再提交到客户端
ServletResponse 提供以下方法
- getBufferSize()
- setBufferSize()
- reset()
- resetBuffer()
- flushBuffer()
- isCommitted()
o HTTP 头
setHeader()
addHeader()
setXxxHeader()
addXxxHeader()
o 便利方法
- sendRedirect() 重定向
- sendError() 返回HTTP错误页面
o I18N
- setLocale()
- setContentType()
- setCharacterEncoding()
# 过滤器
接口 Filter
过滤器可在请求到达Servlet前对 Request 和 Response 对象进行修改
也可在Servlet 处理之后、发送给客户端之前,对 Response 进行修改
过滤器可通过包装(Wrap)的方式修改 Request或Response 头
生命周期:init(),doFilter(),destroy()
init() 时,容器提供 FilterConfig 参数,通过FilterConfig,Filter 可
- 获取初始化参数:getInitParameterXxx()
- 获取 ServletContext:getServletContext()
doFilter() 接收 FilterChain 参数,须显式调用其 doFilter() 方法以调用下一个过滤器
下一个 Filter.doFilter() 执行之后,可修改 Response 对象
FilterChain 中的 Filter.doFilter() 形成一个函数调用栈,因此,程序流程是沿着FilterChain的一次往复过程,先从头至尾经过每一个Filter,再按相反顺序回到第一个Filter
o Filter 的配置
首先在 web.xml 中配置 Filter
<filter> <filter-name>...</filter-name> <filter-class>...</filter-class> <init-params>... </init-params> </filter>
然后设置Filter 映射,有两种方式:
<filter-mapping> <filter-name>...</filter-name> <servlet-name>...</servlet-name> </filter-mapping> 或 <filter-mapping> <filter-name>...</filter-name> <url-pattern>...</url-pattern> </filter-mapping>
<filter-mapping> 下,<servlet-name> 和 <url-pattern> 可出现多个,并且可以两者都出现,如:
<filter-mapping> <filter-name>...</filter-name> <servlet-name>...</servlet-name> <servlet-name>...</servlet-name> <url-pattern>...</url-pattern> <servlet-name>...</servlet-name> </filter-mapping>
和某一个Servlet或其它Web资源(如JSP、HTML)关联的FilterChain的顺序为
- 首先是通过<url-pattern> 映射的Filter,如果有多个,按照映射的声明先后
- 然后是通过<servlet-name> 映射的Filter,如果有多个,按照映射的声明先后
<filter-mapping> 下可包含 <dispatcher> 子元素,如
<filter-mapping> ... <dispatcher>REQUEST</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
<dispatcher>值有
- REQUEST:此Filter 应用于来自客户端的请求时
- FORWARD:此Filter 应用于 ForwardDispatcher.forward()
- INCLUDE:此Filter应用于 ForwardDispatcher.include()
- ERROR:此Filter 应用于错误页面
- ASYNC:此Filter 应用于异步派遣(Async context dispatch)
如果没有 <dispatcher> 则等同有一个 REQUEST
# Session
Web 容器通过以下方法自动维护Session
- Cookie:Cookie 名称为 JSESSIONID
- SSL Session:HTTPS 时,SSL 已经有了Session
- URL 重写:在 URL后附加 ;jsessionid=xxx
如果浏览器禁用Cookie,则容器会认为每个请求都是一个新的Session
Session.isNew()
应用程序可在Session中以属性(Attribute)存储自定义对象:setAttribute(),getAttribute()
属性对象的变化可以使用HttpSessionBindingListener 进行监听
Session 超时:setMaxInactiveInterval(),getMaxInactiveInterval(),-1表示永不超时
getLastAccessedTime() 获取最后一次被访问的时间
o URL重写
使用URL 重写技术时,容器提供的服务是,从请求URL中提取出Session ID,这一点不需要应用程序处理。但应用程序要为所有页面动态地为所有URL附加 ;jsessionid=xxx
URL 重写可用于GET和POST方法
# Annotation
web.xml 描述文件根元素 <web-app> metadata-complete 属性指定是否只使用 web.xml
如果 metadata-complete="false" 则容器会搜索 Annotation
- @WebServlet 用于 Servlet
- @WebFilter 用于 Filter
- @WebInitParam 用于Servlet和Filter
- @WebListrener 用于 各种监听器
- @MultipartConfig 用于Servlet,需要支持表单文件上传的Servlet 必须使用此Annotation
# Web fragment
可将 WebApp 中的组件(类)分别打包为不同的 jar 包,在 jar 包 /META-INF/web-fragment.xml 中类似于 web.xml 一样对包内组件进行声明和配置
这样的 jar 包称为 Web fragment
web-fragment.xml 根元素为 <web-fragment>
web.xml 中 <web-app metadata-complete="true"> 时,web-fragment.xml 无效(同 Annotation 一样)
名称(如 <servlet-name>)的唯一性,必须在 web.xml 和所有 Web fragment 中保证,不同的 Web fragment 以及与 web.xml 之间不允许出现相同的名称
# RequestDispatcher
获得 RequestDispatcher
- ServletContext.getRequestDispatcher()
- ServletContext.getNamedReuquestDispatcher()
- HttpServletRequest.getRequestDispatcher()
参数URL中附加查询字符串(Query string)
include()
forward()
- 被包含的Servlet不允许修改Response 对象的HTTP 头
- forward() 之前,容器会将 Response 内容清空,forward() 之后,容器会将 Response 内容发送给客户端并关闭
# Web App
o 目录结构
客户端请求URL中Context Path 之后的称为虚拟路径(Virtual path)
虚拟路径可相对于:
- Web app(*.war)根,记作/
- /WEB-INF/lib/ 下的 jar 包的 /META-INF/resources/
前者优先
/WEB-INF 下的所有资源都不可以被客户端公开访问,但是可以被Servlet读取,或者通过 RequestDispatcher 访问
例外:/WEB-INF/lib 下的 jar 包 /META-INF/resources/ 下的资源可以被客户端公开访问
# 错误处理
当 HttpServletResponse.sendError() 或者 某个Servlet/Filter 抛出异常最终被容器捕获,可根据HTTP状态代码或者异常类型,向客户端返回不同的错误页面
HTTP状态代码和异常类型与错误页面之间的映射,在 web.xml 中配置
<error-page> <location>/some/page.jsp</location> <error-code>404</error-code> <exception-type>java.io.IOException</exception-type> </error-page>
# 欢迎页面
客户端请求URL指定资源不存在时,依次在URL后附加欢迎页面,如果存在欢迎页面则返回给客户端
<welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list>
欢迎页面可以指定包含子目录,但是,不得以/开头或结尾
容器在匹配欢迎页面时,优先匹配静态资源,然后再匹配 Servlet 路径映射