Servlet高级

Servlet会话技术Cookie和Session

Servlet三大作用域

Servlet有三大作用域request请求域、session会话域和application应用域.分别对应HttpServletRequest,HttpSession和ServletContext三个接口的实现。

  1. ServletContext:应用域,针对一个WEB应用,一个WEB应用只有一个ServletContext对象,使用该对象保存的数据在整个web应用中都有效。

    生命周期:

    • 创建: 服务器启动时,会为每一个项目创建一 个ServletContext对象
    • 销毁:服务器关闭时或项目从服务器上移除
    • 作用范围: 整个WEB应用

    作用:

    • 获取文件mime类型
    • 获取资源在服务器上的完整路径
    • 存放共享的数据
  2. HTTPSession: 会话域,针对一次会话。使用该对象保存数据,一次会话(多次请求)内数据有效

    生命周期:

    • 创建: 调用request.getSession()时
    • 销毁:服务器非正常关闭;Session超时;手动销毁:调用invalidate方法
    • 作用范围:一次会话

    作用:

    • 存放私有的数据
  3. HttpServletRequest:针对一次请求。使用该对象保存数据,一次请求(一个页面,如果是请求转发则多个页面)内数据有效。

    生命周期:

    • 创建:请求来的时候,即客户端向服务器发出请求时创建
    • 销毁:响应生成的时候,即服务器为该请求做出响应后销毁
    • 作用范围:一次请求链中

    作用:

    • 存放一次请求串中的数据

什么是会话?

​ Web应用中的会话过程类似于生活中的打电话过程,它指的是一个客户端(浏览器)与Web服务器之间连续发生的一系列请求和响应过程,例如:一个用户在某网站上的整个购物过程就是一个会话。

​ 客户端与服务器交互的过程中会产生一些数据,这些数据都需要进行存储。之前我们所讲过的HttpServletRequest对象和ServletContext对象都可以对数据进行保存,但是这两个对象都不能用来保存会话数据。具体原因如下:

  1. HttpServletRequest域不适合保存用户个人信息:客户端请求Web服务器时,针对每一次HTTP请求,都会创建一个HttpServletRequest对象,该对象只能保存本次请求所传递的数据。由于购买和结账是两个不同的请求,因此,当用户在完成结账请求时,之前购买的请求中的数据将会丢失。

  2. ServletContext域也不适合保存用户个人信息:使用ServletContext对象保存数据时,由于同一个Web应用共享的是同一个ServletContext对象,因此,当用户在完成结账请求时,由于无法区分哪些商品是哪个用户所购买的,而会将该购物网站中所有用户购买的商品进行结算,这显然也是不可行的。

  3. 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中过滤器映射的顺序决定。最先截获客户端请求的过滤器将最后截获Servlet/JSP的响应信息。过滤器的链式结构可以为一个Web应用组件部署多个过滤器,这些过滤器组成一个过滤器链,每个过滤器只执行某个特定的操作或者检查。这样请求在到达被访问的目标之前,需要经过这个过滤器链。

image

如何使用过滤器?

在Web应用中使用过滤器需要以下两个步骤:

  • 创建过滤器:实现javax.servlet.Filter接口,实现Filter接口中所定义的方法;
  • 配置过滤器:在web.xml中配置过滤器或者使用注解配置。
  1. 创建过滤器:实现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( ) { 
    
    		//过滤器被销毁时执行的代码 
    	} 
    } 
    
  2. 过滤器的配置

    • 在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属性对应着标签。

常见过滤器的实现

  1. 字符过滤器

    下面是最简单的字符过滤器,在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);
        }
    }
    
  2. 使用过滤器实现网页登录验证及自动登录功能案例

监听器

Servlet监听器的概念

Listener是Servlet的监听器,其主要的功能就是监听Web的各种操作,当相关的操作触发后将产生的事件,并对此事件进行处理;Listener可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时,就激发sessionCreated(HttpSessionEvent se)方法,这样就可以给在线人数加1。

监听器的具体内容见下图:

image

Servlet监听器的分类及介绍

  1. ServletContextListener:用于监听WEB应用启动和销毁的事件,即ServletContext的生命周期。监听器类需要实现javax.servlet.ServletContextListener 接口。

    • 初始化:contextInitialized
    • 销毁:contextDestoryed
  2. ServletContextAttributeListener:用于监听WEB应用属性改变的事件,即ServletContex属性的变化 。包括:增加属性、删除属性、修改属性,监听器类需要实现javax.servlet.ServletContextAttributeListener接口。

    • attributeAdded:监听属性增加
    • attributeReplaced:监听属性修改
    • attributeRemoved:监听属性删除
  3. 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
           }
       }
    }
    
  4. HttpSessionActivationListener:用于监听Session对象的钝化/活化事件,监听器类需要实现javax.servlet.http.HttpSessionListener接口或者javax.servlet.http.HttpSessionActivationListener接口,或者两个都实现。

    • sessionWillPassivate: 监听Session内部存储对象的钝化-----存储
    • sessionDidActive:监听Session内部存储对象的活化-----读取
    • 对应类要实现序列化接口Serializable
  5. HttpSessionAttributeListener:用于监听Session对象属性的改变事件,监听器类需要实现javax.servlet.http.HttpSessionAttributeListener接口。

    • attributeAdded:监听属性增加
    • attributeReplaced:监听属性修改
    • attributeRemoved:监听属性删除
  6. HttpSessionBindingListener: 监听Session中对象的添加和移除(针对某个对象)

    • valueBound: 监听对象的绑定
    • valueUnBound: 监听对象的解除绑定
  7. HttpSessionIdListener : 监听HttpSession的id变化

    • sessionIdChanged: 监听HttpSession的id变化

Servlet监听器的布署

监听器的部署在web.xml文件中配置,在配置文件中,它的位置应该在过滤器的后面Servlet的前面

  1. web.xml配置文件

    <!-- Quartz监听器 -->
    <listener>
    
            <listener-class>
    
               com.flyer.lisenter.QuartzListener
    
            </listener-class>
    
    </listener>
    
  2. 使用注解@WebListener进行配置

    Servlet3.0以后的规范中可以使用@WebListener注解对监听器进行相应的配置,只需把此注解添加在相应的监听器类声明的上方就可以了。

posted @ 2025-02-05 23:41  韩熙隐ario  阅读(42)  评论(0)    收藏  举报