Servlet高级
Servlet会话技术Cookie和Session
Servlet三大作用域
Servlet有三大作用域request请求域、session会话域和application应用域.分别对应HttpServletRequest,HttpSession和ServletContext三个接口的实现。
-
ServletContext:应用域,针对一个WEB应用,一个WEB应用只有一个ServletContext对象,使用该对象保存的数据在整个web应用中都有效。
生命周期:
- 创建: 服务器启动时,会为每一个项目创建一 个ServletContext对象
- 销毁:服务器关闭时或项目从服务器上移除
- 作用范围: 整个WEB应用
作用:
- 获取文件mime类型
- 获取资源在服务器上的完整路径
- 存放共享的数据
-
HTTPSession: 会话域,针对一次会话。使用该对象保存数据,一次会话(多次请求)内数据有效
生命周期:
- 创建: 调用request.getSession()时
- 销毁:服务器非正常关闭;Session超时;手动销毁:调用invalidate方法
- 作用范围:一次会话
作用:
- 存放私有的数据
-
HttpServletRequest:针对一次请求。使用该对象保存数据,一次请求(一个页面,如果是请求转发则多个页面)内数据有效。
生命周期:
- 创建:请求来的时候,即客户端向服务器发出请求时创建
- 销毁:响应生成的时候,即服务器为该请求做出响应后销毁
- 作用范围:一次请求链中
作用:
- 存放一次请求串中的数据
什么是会话?
Web应用中的会话过程类似于生活中的打电话过程,它指的是一个客户端(浏览器)与Web服务器之间连续发生的一系列请求和响应过程,例如:一个用户在某网站上的整个购物过程就是一个会话。
客户端与服务器交互的过程中会产生一些数据,这些数据都需要进行存储。之前我们所讲过的HttpServletRequest对象和ServletContext对象都可以对数据进行保存,但是这两个对象都不能用来保存会话数据。具体原因如下:
-
HttpServletRequest域不适合保存用户个人信息:客户端请求Web服务器时,针对每一次HTTP请求,都会创建一个HttpServletRequest对象,该对象只能保存本次请求所传递的数据。由于购买和结账是两个不同的请求,因此,当用户在完成结账请求时,之前购买的请求中的数据将会丢失。
-
ServletContext域也不适合保存用户个人信息:使用ServletContext对象保存数据时,由于同一个Web应用共享的是同一个ServletContext对象,因此,当用户在完成结账请求时,由于无法区分哪些商品是哪个用户所购买的,而会将该购物网站中所有用户购买的商品进行结算,这显然也是不可行的。
-
Cookie和Session技术:为了保存某个会话过程中产生的数据,在Servlet规范中,提供了两种用于保存会话数据的技术,分别是Cookie和Session。Cookie是客户端技术,Session是服务器端技术,Session技术依赖于Cookie技术。
什么是Cookie?
Cookie是存储在客户端浏览器的文本数据。它相当于我们生活中的会员卡,记录了顾客消费的详细信息。在Web应用中,当用户通过浏览器访问Web服务器时,服务器会给客户端发送一些信息,这些信息都保存在Cookie中。这样当浏览器再次访问服务器的资源时,都会在请求头中将Cookie发送给服务器,方便服务器对浏览器做出正确的响应。
服务器向客户端发送Cookie时会在Http响应头字段中增加Set-Cookie响应头字段。
需要注意的是Cookie必须以键值对的形式存在,其属性可以有多个,但这些属性之间必须用分号;和空格分隔。在cookie 的名或值中不能使用分号(;)、逗号(,)、等号(=)以及空格这是cookie的赋值规则。
当用户第一次访问服务器时,服务器会在响应消息中增加Set-Cookie头字段,将用户信息以Cookie的形式发送给浏览器。一旦用户浏览器接受了服务器发送的Cookie信息,就会将它保存在浏览器的缓冲区中,这样,当浏览器后续访问该服务器时,都会在请求消息中将用户信息以Cookie形式发送给Web服务器,从而使服务器端分辨出当前请求是哪个用户发出的。
Cookie的基本使用
-
创建Cookie:构造方法: Cookie(String name ,String value)
cookie没有无参构造方法 , 在创建时就得制定好cookie的名字和值
-
将cookie发送给浏览器: response.addCookie 向响应中添加cookie
-
接收浏览器携带的所有cookie: request.getCookies() : 从请求中获取所有的cookie
Cookie对象相关的API如下表所示:
方法名 | 描述 |
---|---|
getName() | 获取 cookie 名称 |
getValue() | 获取 cookie 的值 |
setMaxAge(int expiry) | 设置 cookie 的有效时间。若未设置,cookie 仅缓存于浏览器缓存中,浏览器关闭即删除;若设置了有效时间,在该时间范围内,cookie 被写入浏览器端,关闭浏览器下次访问仍可获取,直至过期 |
setPath(java.lang.String uri) | 设置 cookie 允许被访问的路径。所设置路径及其子路径都允许访问。如 setPath ("/web/a/b"); ,http://localhost:8080/web/a/b/oneServlet(当前路径)和http://localhost:8080/web/a/b/c/oneServlet(子路径)可访问,http://localhost:8080/web/a/c/oneServlet(无关路径)不允许访问。常见设置 setPath ("/"),当前 tomcat 下所有 web 项目都可访问 |
Cookie的使用细节总结
- 一个Cookie只用标识一种信息,至少含有一个标识该信息的名称和值。
- 一个web站点可以给一个浏览器发送多个Cookie。一个web浏览器可以存储多个web站点的Cookie。
- 浏览器存放的Cookie的大小和个数是有限制的: 浏览器一般只允许存放300个Cookie,每个站点最多可以存放20个Cookie,每个Cookie的大小限制为4KB(老版本浏览器)。
- 如果创建了一个Cookie,并发送到浏览器,默认情况下它是一个会话级别的Cookie。用户退出浏览器就被删除。如果希望将这个Cookie存到磁盘上,需要设置有效时长调用setMaxAge(int maxAge)方法,以秒为单位的。
- 需要手动删除持久性Cookie,可以将Cookie的有效时长设置为0. 必须注意:删除Cookie时候,path必须一致,否则无法删除。
什么是Session?
Session是在无状态的HTTP协议下,服务端记录用户状态时用于标识具体用户的机制。它是在服务端保存的用来跟踪用户的状态的数据结构,可以保存在文件、数据库或者集群中。在浏览器关闭后这次的Session就消失了,下次打开就不再拥有这个Session。其实并不是Session消失了,而是Session ID变了,服务器端可能还是存着你上次的Session ID及其Session 信息,只是他们是无主状态,也许一段时间后会被删除。
当浏览器访问Web服务器时,Servlet容器就会创建一个session对象和ID属性,其中Session对象就相当于病历档案,ID就相当于就诊卡号。当客户端后续访问服务器时,只要将标识号传递给服务器,服务器就能判断出该请求是哪个客户端发送的,从而选择与之对应的Session对象为其服务。
要注意的是,由于客户端要接收,记录和回送Session对象的ID,因此,通常情况下,Session是借助Cookie技术来传递ID属性的。
有了Cookie为什么还要Session?
- Cookie是有大小和个数的限制的,Session没有大小和个数的限制。
- Cookie相对于Session来讲不安全,因为Cookie是保存在客户端的,Session是保存到服务器端的数据相对的安全性要好一些;
Session的使用
需要注意的是:一个session的概念需要包括特定的客户端,特定的服务器端以及不中断的操作时间。A用户和C服务器建立连接时所处的session同B用户和C服务器建立连接时所处的Session是两个不同的session。
Session的生命周期:
-
session对象的创建:
- 当一个session第一被启动时,一个唯一的标识(32位的ID号)被存储与本地的cookie中;
- 首先使用session_start()函数,从session仓库中加载已经存储的session变量。
Session是与每个请求消息紧密相关的,为此,HttpServletRequest定义了用于获取Session对象的getSession()方法,该方法有两种重载方式,具体如下:
- getSession()
- getSession(boolen isNew)
这样,前者会检测当前时候是否有session存在,如果不存在则创建一个,如果存在就返回当前的。
getSession()相当于getSession(true);
- 参数为true时,若存在会话,则返回该会话,否则新建一个会话;
- 参数为false时,如存在会话,则返回该会话,否则返回NULL;
-
session对象的销毁:
session有三种销毁方式:
-
自杀: 可以通过明确调用session.invalidate()方法立即杀死当前session 。
-
寿终正寝 : session默认发呆时间为30分钟 , 如果超过30分钟没有用户使用这个session , 则服务器会认为这个session超时 , 杀死会话对应的session 。
-
意外身亡 : 当web应用销毁时 , session也随之销毁 。浏览器关闭,session也随之销毁。
-
-
session对象的作用范围:在整个会话范围内有效
-
session对象的主要作用:在整个会话范围内共享数据
HttpSession接口中常用的方法
方法声明 | 功能描述 |
---|---|
String getId() | 返回与当前 HttpSession 对象关联的会话标识号 |
long getCreationTime() | 返回 Session 创建的时间,为创建 Session 的时间与 1970 年 1 月 1 日 00:00:00 之间时间差的毫秒表示形式 |
long getLastAccessedTime() | 返回客户端最后一次发送与 Session 相关请求的时间,是发送请求的时间与 1970 年 1 月 1 日 00:00:00 之间时间差的毫秒表示形式 |
void setMaxInactiveInterval(int interval) | 设置当前 HttpSession 对象可空闲的以秒为单位的最长时间,即修改当前会话的默认超时间隔 |
boolean isNew() | 判断当前 HttpSession 对象是否是新创建的 |
void invalidate() | 强制使 Session 对象无效 |
ServletContext getServletContext() | 返回当前 HttpSession 对象所属于的 WEB 应用程序对象,即代表当前 WEB 应用程序的 ServletContext 对象 |
void setAttribute(String name, Object value) | 将一个对象与一个名称关联后存储到当前的 HttpSession 对象中 |
String getAttribute() | 从当前 HttpSession 对象中返回指定名称的属性对象 |
void removeAttribute(String name) | 从当前 HttpSession 对象中删除指定名称的属性 |
过滤器
过滤器的概念
过滤器位于客户端和web应用程序之间,用于检查和修改两者之间流过的请求和响应。在请求到达Servlet/JSP之前,过滤器截获请求。在响应送给客户端之前,过滤器截获响应。我们可以将多个Servlet之中的重复代码写到过滤器之中。
多个过滤器会形成一个过滤器链,过滤器链中不同过滤器的先后顺序由部署文件web.xml中过滤器映射
如何使用过滤器?
在Web应用中使用过滤器需要以下两个步骤:
- 创建过滤器:实现javax.servlet.Filter接口,实现Filter接口中所定义的方法;
- 配置过滤器:在web.xml中配置过滤器或者使用注解配置。
-
创建过滤器:实现Filter接口,具体格式如下:
Filter接口 :
-
public void init(FilterConfig config) :web容器调用本方法,说明过滤器正被加载到web容器中去。容器只有在实例化过滤器时才会调用该方法一次。容器为这个方法传递一个FilterConfig对象,其中包含与Filter相关的配置信息。
-
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) :每当请求和响应经过过滤器链时,容器都要调用一次该方法。需要注意的是过滤器的一个实例可以同时服务于多个请求,特别需要注意线程同步问题,尽量不用或少用实例变量。在过滤器的doFilter()方法实现中,任何出现在FilterChain的doFilter方法之前地方,request是可用的;在doFilter()方法之后response是可用的。
-
public void destroy() :容器调用destroy()方法指出将从服务中删除该过滤器。如果过滤器使用了其他资源,需要在这个方法中释放这些资源。
public class MyFilter implements Filter { public void init(FilterConfig fc) { //过滤器初始化代码 } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { //在这里可以对客户端请求进行检查 //沿过滤器链将请求传递到下一个过滤器。 chain.doFilter(request, response); //在这里可以对响应进行处理 } public void destroy( ) { //过滤器被销毁时执行的代码 } }
-
-
过滤器的配置
-
在Web.xml配置文件中配置过滤器:
在Web应用的WEB-INF目录下,找到web.xml文件,在其中添加如下代码来声明Filter。
<filter> <filter-name>MyFilter</filter-name> <filter-class> cn.edu.uibe.webdev.MyFilter </filter-class> <init-param> <param-name>developer</param-name> <param-value>TongQiang</param-value> </init-param> </filter>
-
针对一个Servlet做过滤
<filter-mapping> <filter-name>MyFilter</filter-name> <servlet-name>MyServlet</servlet-name> </filter-mapping>
-
针对URL Pattern做过滤
<filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/book/*</url-pattern> </filter-mapping> <filter-mapping>
标记是有先后顺序的,它的声明顺序说明容器是如何形成过滤器链的。过滤器应当设计为在部署时很容易配置的形式。通过认真计划和使用初始化参数,可以得到复用性很高的过滤器。 过滤器逻辑与Servlet逻辑不同,它不依赖于任何用户状态信息,因为一个过滤器实例可能同时处理多个完全不同的请求。
-
使用@WebFilter注解配置过滤器
Servlet3.0以后的规范中也可以使用@WebFilter注解对过滤器进行相应的配置,该注解的属性如下:
属性名 类型 描述 filterName String 指定过滤器的 name 属性,等价于 <filter - name> value String[] 该属性等价于 urlPatterns 属性,但两者不应同时使用 urlPatterns String[] 指定一组过滤器的 URL 匹配模式,等价于 <url - pattern> 标签 servletNames String[] 指定过滤器将应用于哪些 Servlet,取值是 @WebServlet 中的 name 属性取值,或者是 web.xml 中 <servlet - name> 的取值 dispatcherTypes DispatcherType 指定过滤器的转发模式,具体取值包括 ASYNC、ERROR、FORWARD、INCLUDE、REQUEST initParams WebInitParam[] 指定一组过滤器初始化参数,等价于 <init - param> 标签 asyncSupported boolean 声明过滤器是否支持异步操作模式,等价于 <async - supported> 标签 description String 该过滤器的描述信息,等价于 标签 displayName String 该过滤器的显示名,通常配合工具使用,等价于 <display - name> 标签 使用注解的方式配置过滤器的这种情况下,想要控制filer的执行顺序可以通过控制filter的文件名来控制,即Servlet@WebFilter注解方式——过滤器链的执行顺序和类名字符排序有关!
如:Filter1.java 和 Filter2.java
则先执行Filter1.java后执行Filter2.java.
@WebFilter注解最常见的两个属性就是filterName和urlPatterns,filterName属性对应于Web.xml配置文件中的
标签,urlPatterns属性对应着 标签。
-
常见过滤器的实现
-
字符过滤器
下面是最简单的字符过滤器,在Tomcat8.0以后的版本中不需要额外对客户端发出的get请求做特殊处理,只需要对post方式的请求数据及响应的MIME类型进行设置就可以了
//该字符过滤器对本应用中的所有资源进行过滤 @WebFilter(filterName = "ACharFilter", urlPatterns = "/*") public class ACharFilter_zuoyabing70204 implements Filter { public void init(FilterConfig config) throws ServletException { } public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(request, response); } }
-
使用过滤器实现网页登录验证及自动登录功能案例
监听器
Servlet监听器的概念
Listener是Servlet的监听器,其主要的功能就是监听Web的各种操作,当相关的操作触发后将产生的事件,并对此事件进行处理;Listener可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时,就激发sessionCreated(HttpSessionEvent se)方法,这样就可以给在线人数加1。
监听器的具体内容见下图:
Servlet监听器的分类及介绍
-
ServletContextListener:用于监听WEB应用启动和销毁的事件,即ServletContext的生命周期。监听器类需要实现javax.servlet.ServletContextListener 接口。
- 初始化:contextInitialized
- 销毁:contextDestoryed
-
ServletContextAttributeListener:用于监听WEB应用属性改变的事件,即ServletContex属性的变化 。包括:增加属性、删除属性、修改属性,监听器类需要实现javax.servlet.ServletContextAttributeListener接口。
- attributeAdded:监听属性增加
- attributeReplaced:监听属性修改
- attributeRemoved:监听属性删除
-
HttpSessionListener:用于监听Session对象的创建和销毁,即Session的生命周期。监听器类需要实现 javax.servlet.http.HttpSessionListener接口或者javax.servlet.http.HttpSessionActivationListener接口,或者两个都实现。
- sessionCreated: 监听Session对象的创建
- sessionDestoryed: 监听Session对象的销毁
/** 会话监听器 */ public class SessionListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent arg0) { } public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); User user = (BrsSession) session.getAttribute("currUser"); if (user != null) { //TODO something } } }
-
HttpSessionActivationListener:用于监听Session对象的钝化/活化事件,监听器类需要实现javax.servlet.http.HttpSessionListener接口或者javax.servlet.http.HttpSessionActivationListener接口,或者两个都实现。
- sessionWillPassivate: 监听Session内部存储对象的钝化-----存储
- sessionDidActive:监听Session内部存储对象的活化-----读取
- 对应类要实现序列化接口Serializable
-
HttpSessionAttributeListener:用于监听Session对象属性的改变事件,监听器类需要实现javax.servlet.http.HttpSessionAttributeListener接口。
- attributeAdded:监听属性增加
- attributeReplaced:监听属性修改
- attributeRemoved:监听属性删除
-
HttpSessionBindingListener: 监听Session中对象的添加和移除(针对某个对象)
- valueBound: 监听对象的绑定
- valueUnBound: 监听对象的解除绑定
-
HttpSessionIdListener : 监听HttpSession的id变化
- sessionIdChanged: 监听HttpSession的id变化
Servlet监听器的布署
监听器的部署在web.xml文件中配置,在配置文件中,它的位置应该在过滤器的后面Servlet的前面。
-
web.xml配置文件
<!-- Quartz监听器 --> <listener> <listener-class> com.flyer.lisenter.QuartzListener </listener-class> </listener>
-
使用注解@WebListener进行配置
Servlet3.0以后的规范中可以使用@WebListener注解对监听器进行相应的配置,只需把此注解添加在相应的监听器类声明的上方就可以了。