Cookie,Session Filter,Listener详解

HTTP请求的无状态性

HTTP的无状态性是其一个重要的特征,指的是HTTP协议本身并不保留客户端与服务器交互的历史信息,换而言之,即每次的HTTP请求都是独立的,服务器在处理每一个请求时都不会记住前一个请求的状态

无状态的含义

  • 独立性: 每次的HTTP请求都是独立的,不依赖于之前的请求,即服务器处理每次请求时都会从头开始,不会参照之前的状态

**E.g:**假设A用户在一个Web超市添加的一个商品到购物车中,等到再次购买时,服务器已经无法分别判断购买行为是属于用户A还是其他用户

就是由于HTTP请求的无状态性,服务器无法识别其请求的上文状态,因此人们就开发了新的技术来解决HTTP无状态性带来的状态丢失问题,也就是我们接下来要讲解的CookieSession 也借鉴了创造者@测试开发喵

Cookie

Cookie原意为"饼干",是由W3C组织提出的.目前的主流浏览器IE,Google,Edge,Firefox等等都支持了Cookie技术

Cookie的原理机制

鉴于HTTP请求协议是一个无状态的请求协议,服务器单从网络连接上无法得知客户的身份.于是前辈们就想出了一个方法:给客户端们都颁发一个通行证,这样每次发起请求后都要携带自己的通行证.于是乎服务器就可以从通行证上确认用户的身份了

Cookie的本质

  • Cookie实际 上是一小串文字信息.当客户端请求服务器时,若服务器要记录该用户的状态,则使用response 向客户端浏览器发送一个Cookie.客户端的浏览器会把Cookie保存→当此浏览器再次申请服务器时,浏览器会将请求的网站连同Cookie一起提交给服务器→浏览器会检查该Cookie,以此来辨别用户的状态,服务器也可以根据需求修改Cookie中的内容

Cookie的类型

  • 持久型cookie
    • 以文件方式存放在硬盘空间上的永久性cookie. 持久cookie是值存放在客户端硬盘中的cookie信息(被设置了一段有效期)
      • 当用户访问网站时,浏览器会在本地硬盘上查找与该网站相关联的cookie.若该cookie存在,则浏览器会将其和页面请求一起发送到用户所在的站点,之后服务器会比对cookie中相应的属性值与存放在服务器中的信息是否一致,以此判断"新用户"和老用户
  • 会话型cookie
    • **停留在浏览器内存中的临时cookie.**会话型cookie.仅在会话期间存在,浏览器一旦关闭,会话型cookie就会被销毁

Cookie中的属性

  • **Domain:**指定Cookie会被哪些域名下的页面访问
  • **Path:**指定Cookie可以被哪些路径下的页面访问
  • **Secure:**若设置为true,则只有在HTTPS连接下才会发送Cookies,增加了安全性
  • HttpOnly: 若设置为true,则Cookie不能被JavaScript访问,有利于防止跨站脚本攻击
  • **SameSite:**设置Cookie是否随着第三方请求一起发送,有助于防止跨站伪造攻击

JavaWeb对Cookie的操作

Java中将Cookie操作封装到javax.servlet.http.Cookie类中,

Cookie对象的创建

  • new Cookie(String name, String value):设置Cookie的名称与值
    • name:是Cookie的唯一标识,通过name可以区分不同的Cookie对象,一个网站可能有多个Cookie如username,language,等等
    • value:用于存储实际的数据,通过cookie值可以跟踪用户状态

Java中常用的Cookie的属性

属 性 名 描 述
String name 该Cookie的名称。Cookie一旦创建,名称便不可更改
String value 该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码
int maxAge 该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为--1
boolean secure 该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false
String path 该Cookie的使用路径。如果设置为"/sessionWeb/",则只有contextPath为"/sessionWeb"的程序可以访问该Cookie。如果设置为"/",则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为"/"
String domain 可以访问该Cookie的域名。如果设置为".google.com",则所有以"google.com"结尾的域名都可以访问该Cookie。注意第一个字符必须为"."
String comment 该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明
int version 该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

Cookie的有效期

Cookie的maxAge决定着Cookie的有效期,单位为秒(second),Cookie中的getMaxAge()setMaxAge(int maxAge)可以用来读写maxAge属性

  • maxAge为正数,**则表示该Cookie会在maxAge秒后失效,**浏览器会将maxAge为正数的Cookie持久化,即写入到对应的Cookie文件中.无论客户关闭了浏览器还是电脑,只要在maxAge之内,访问相应的网站仍然有效,
java 复制代码
 Cookie cookie = new Cookie("username","张三");//新建cookie
        cookie.setMaxAge(Integer.MAX_VALUE);//设置生命时间为无限
        resp.addCookie(cookie);//响应到客户端
					//此方法添加的cookie信息永远生效
  • maxAge为负数时则表示此cookie只在该浏览器窗口以及期子窗口生效 ,关闭浏览器即失效,maxAge为负数的Cookie为临时Cookie,不会被持久化,即不会被写入到文件中,Cookie信息只保留在浏览器的内存中,Cookie的默认值为-1,即默认为会话Cookie
  • maxAge为0时则表示,删除该Cookie.Cookie的机制没有提供删除Cookie的方法,因此可以提供设置maxAge为0的方法即时失效,实现删除Cookie的效果,失效的Cookie会被浏览器从文件或内存中清除
java 复制代码
  Cookie cookie = new Cookie("username","李四");//创建cookie
        cookie.setMaxAge(0);//设置为0,即时失效
        resp.addCookie(cookie);//相应到客户端

Cookie的修改

  • Cookie本身并不提供修改的操作,若要修改一个Cookie,则需要新建一个同名的Cookie,添加到response中将原本的Cookie覆盖
    • 注意点:修改时新建的Cookie除了value,maxAge之外的属性,例如name,path,domian等等都要和原先的Cookie一致才能完成修改

Cookie的不可跨域名性

Cookie的不可跨域名性表示的是**:Cookie通常只能由创建它的域名所访问**,这意味着一个域名下的Cookie不能被另一个域名下的Cookie访问

  • 提供设置Domain属性是实现不可跨域名性:

    • 例如当把Domian设置为:.example.com 时,则该Cookie不仅可以在example.com域名上被访问,也可以在sub.example上被访问
    java 复制代码
     @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Cookie cookie = new Cookie("username","李四");//创建cookie
            cookie.setMaxAge(Integer.MAX_VALUE);
    
            cookie.setHttpOnly(true);//不可被JavaScript访问
            cookie.setSecure(true);//设置只能提供Http发送
            cookie.setDomain(".example.com");//cookie可以被example.com及其子域名访问
            resp.addCookie(cookie);//相应到客户端
        }

Session

Session也是一种解决HTTP请求无状态性的技术,Session是服务器使用的一种记录客户端状态的机制, 相比Cookie来说,Session更加简单,但增加了服务器的存储压力

Session的原理机制

Session是一种服务器端的机制,服务器使用一种哈希表的结构存储Session信息

Session的行为

  • Session是依赖于Cookie的,用户客户端请求申请创建一个session→服务器首先检查客户端请求中是否包含了一个session的标识---session id 若包含一个session id 则说明已经为该客户端创建过session,服务器会按照session id检索出来直接使用,若检索不到则新建一个;若不包含 session id,则为此客户端新建一个session id并生成相应的session id→新建的session id会包含在cookie中随响应一起返回到客户端中保存
  • 简单来说:如果是cookie是检查客户端携带的"通行证",来确认客户.那么session就是通过检查服务器上的"客户端明细表"来确认客户端身份,session相对于在服务器上建立了一份客户档案.

Session的属性

与Cookie一致的是 Session的值也是以key-value的形式存在的,Java中把将Session的操作封装到javax.servlet.http.Session类中

获取Session

  • 使用 request中的HttpSession getSession()方法可以获取当前用户的Session,若该用户的Session不存在则返回null
    • 进而衍生出了另一种传参的getSession()方法 HttpSession getSession(boolean create); 当create为true时,该方法会新建一个Session,再讲Session返回
java 复制代码
public class myServletTest extends HttpServlet {
	
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        HttpSession session1 = req.getSession(true);
    }
}

Session中常用的方法

方 法 名 描 述
void setAttribute(String attribute, Object value) 设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大
String getAttribute(String attribute) 返回Session属性
Enumeration getAttributeNames() 返回Session中存在的属性名
void removeAttribute(String attribute) 移除Session属性
String getId() 返回Session的ID。该ID由服务器自动创建,不会重复
long getCreationTime() 返回Session的创建日期。返回类型为long,常被转化为Date类型,例如:Date createTime = new Date(session.get CreationTime())
long getLastAccessedTime() 返回Session的最后活跃时间。返回类型为long
int getMaxInactiveInterval() 返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效
void setMaxInactiveInterval(int second) 设置Session的超时时间。单位为秒
void putValue(String attribute, Object value) 不推荐的方法。已经被setAttribute(String attribute, Object Value)替代
Object getValue(String attribute) 不被推荐的方法。已经被getAttribute(String attr)替代
boolean isNew() 返回该Session是否是新创建的
void invalidate() 使该Session失效

Session与Cookie的关系

  • Session实现的原理与Cookie有关

    • 当服务器创建了Session对象后,首先将其存入服务器内存,并把Session的唯一标识session id以Cookie的形式写回客户端本地文件中(键名为JSESSIONID,值为该session的id)

      java 复制代码
       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      
              HttpSession session = req.getSession();
              Cookie cookie = new Cookie("JSESSIONID",session.getId());
              cookie.setMaxAge(60*60);
              resp.addCookie(cookie);
          }
  • Session的存储结构

    Session是以Map数据结构存储的key值为session id;value值为Session对象

    java 复制代码
    protected Map<String, Session> sessions = new ConcurrentHashMap<>();
  • Session与Cookie的区别

    • 安全性:
      • Session:存储在服务器中,更加安全
      • Cookie :存储在客户端,更容易受到攻击,可以设置HttpOnly,和Secure属性来提高安全性
    • 数据量:
      • **Session:**可以存储较大的数据量,没有严格的大小限制
      • **Cookie:**提出限制在4kb左右
    • 应用场景:
      • **Session:**用于跟踪用户状态,适合存储敏感信息,如身份验证等等
      • **Cookie:**用于存储非敏感信息,适合短期保存数据

Filter过滤器

Filter过滤器是Servlet技术中最实用的部分,Web开发人员通过Filter技术管理Web服务器的所有资源,如**JSP,Servlet,HTML**等等,主要用于对客户请求进行预处理

Filter的主要功能

  • 编码转换: 在请求资源到达资源之前转换字符编码**,确保字符编码的一致性**
  • **日志记录:**在请求和响应中记录相关信息
  • 预处理和后处理认任务:
    • 修改请求头或响应头
    • 添加缓存控制头
    • 进行安全检查

Filter的配置

Filter有两种配置方法,一种是在web.xml文件中配置,第二种是使用注释的方法配置(Java Servlet 3.0 及以上版本)

web.xml配置

借鉴作者@coderland

java 复制代码
 <filter>
       <filter-name>myFilter01</filter-name>//设置filter名称
       <filter-class>com.mashang.web.myFilter01</filter-class>
   //指定用于指定过滤器的完整类路径
   </filter>

    <filter-mapping>//设置Filter负责拦截的资源
        <filter-name>myFilter01</filter-name>//需和filter-name一致
        <url-pattern>/ *</url-pattern>//设置filter拦截的路径 URL结构
    </filter-mapping>

注释配置

@WebFilter()

  • Filter实现类,顶部使用@WebFilter()进行注释
  • @WebFilter()中的属性
    • String filterName() default "";:指定Filter名称
    • String[] urlPatterns() default {};:指定Filter拦截的URL,使用/*表示所有URL都会经过此Filter
      • 由于urlPatterns以字符串数组存在,因此可以一次配置多条路径,例如

        java 复制代码
        @WebFilter(filterName = "MyFilter", urlPatterns = {"/secure/*", "/admin/*"})

@WebInitParam()

@WebInitParam注释可用于在@WebFilter中配置参数初始值

  • WebInitParam[] initParams() default {};:是@WebFilter中的参数类别,默认为空值,表示没有被初始化
    • 其有两个参数:name:参数名称;value:参数值
java 复制代码
@WebFilter(filterName = "myFilter01",urlPatterns = "/*",
        initParams ={
        @WebInitParam(name = "encoding",value = "UTF-8")
       //将其中的encoding 属性配置为UTF-8,来实现编码统一
        }
)
public class myFilter01 implements Filter { }

Filter的生命周期

Filter是Java的一个接口,其有一个简单的生命周期,

  • void init(FilterConfig config)
    • 与Servlet程序一致,Filter的创建和销毁都是由Web服务器操作的,Web服务器启动时创建Filter对象,并调用init()方法完成初始化工作,读取web.xml文件,Filter对象只会创建一次,因此init()方法只会执行一次,
    • FilterConfig 是 Java Servlet API 中的一个接口,它提供了获取 Filter 配置信息的方法,在下文我们会展开讲解
  • **void doFilter(ServletRequest serReq, ServletResponse** **serResp, FilterChain filterChain)**
    • 完成实际过滤操作的方法.Web服务器会在每次屌用service()方法之前调用Filter的doFilter()方法
    • FilterChain:Filter链,在开发中会编写多个Filter,FilterChain是Filter的集合,如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源
  • void destroy()
    • Filter对象创建后会驻留在Web内存中,当Web用于结束服务器停止时,Web服务器销毁之前的对象
    • 与init()一致的是destroy()也只调用一次

FilterConfig接口

当Filter被初始化时,FilterConfig对象会被传递给init()方法,在init()中通过FilterConfig,可以回去Filter的名称,初始化参数,及相关的ServletContext

FilterConfig主要方法

  • String getFilterName(): 返回Filter的名称

  • String getIntiParameter(String name):获取指定名称的初始参数的值,若没找到对应的初始化参数则返回null

  • Enumeration<String> getInitParameterNames():返回所有初始化参数名称,

  • ServletContext getServletContext():返回与Filter关联的ServletContext对象,ServletContext对象提供了整个Web应用程序的访问

    java 复制代码
       public void init(FilterConfig filterConfig) throws ServletException {
            //获取FilterConfig中的所有参数名
            Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
            while (initParameterNames.hasMoreElements())
            {
                String name = initParameterNames.nextElement();
                System.out.println("param"+":"+name);
            }
            ServletContext servletContext = filterConfig.getServletContext();
            servletContext.setAttribute("name","value");
        }

用Filter实现编码统一

java 复制代码
@WebFilter(urlPatterns = "/*")
public class myFilter01 implements Filter {
    private String characterEncoding=null;
    @Override
    public void init(FilterConfig fC) throws ServletException {
        //在初始定义中获取characterEncoding
        //若为非空,encoding也是非空 则直接获取 encoding的值
        if (fC != null && fC.getInitParameter("encoding") !=null
        && ! fC.getInitParameter("encoding").equals(""))
        {
            characterEncoding=fC.getInitParameter("encoding");
        }
        else{
            characterEncoding="UTF-8";//否则置为utf8
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //将Servlet转换为HttpServlet用于处理HTTP请求响应
        HttpServletRequest req  = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        //拦截所有请求进行统一编号
        //指定request和response的编号
        req.setCharacterEncoding(characterEncoding);
        //将response数据响应为utf8
        resp.setCharacterEncoding(characterEncoding);
        //告诉浏览器输出内容为HTML格式,
        resp.setContentType("text/html;charset="+characterEncoding);
        filterChain.doFilter(req,resp);//将请求和响应传递给下一个 Filter 或目标资源
    }

Listener

Listener 监听器与Servlet 程序,Filter 过滤器共称JavaWeb的三大组件 ,Listener作用application,session,request三个对象中**,Listener用于监听特点的时事件,然后回调函数,并做出相应的反应** ,Listner主要分为三个大类:ServletContext 监听,Session监听,Request 监听**;Listener本质是个接口**

Listener的分类及使用

ServletContext监听

ServletContext监听是由ServletContextListenerServletContextAttributeListener接口实现的,

ServletContextListener方法

对整个Servlet上下文进行监听(创建或销毁)

  • public void contextInitialized(ServletContextEvent sce);:执行初始化任务,如加载缓存等等
  • public void contextDestroyed(ServletContextEvent sce);:停止时执行清除任务,释放资源,关闭连接等等
  • ServletContextEvent对象的操作:
    • public ServletContext getServletContext();:取得一个ServletContext(application)对象

ServletContextAttributeListener方法

对Servlet上下文属性的监听(增删改属性)

  • public void attributeAdded(ServletContextAttributeEvent scab);:向ServletContext中添加属性
  • public void attributeRemoved(ServletContextAttributeEvent scab);:删除ServletContext中的属性
  • public void attributeRepalced(ServletContextAttributeEvent scab);:替换SevletContext中的属性,(重复设置无效果)
  • ServletContextAttributeEvent对象的操作:能获取属性名于值
    • public String getName();:获取属性名
    • public Object getValue();:获取属性的值

Session监听

ServletContext类似,Session也分为两种接口,分别为HttpSessionListenerHttpSessionAttributeListener

HttpSessionListener方法

对Session整体状态的监听

  • public void sessionCreated(HttpSessionEvent se);:创建Session
  • public void sessionDestroyed(HttpSessionEvent se);:销毁Session
  • HttpSessionEvent对象的操作:
    • public HttpSession getSession();:取得当前操作的session

HttpSessionAttributeListener方法

对Session属性的监听

  • public void attributeAdded(HttpSessionBindingEvent se);:添加属性到HttpSession
  • public void attributeRemoved(HttpSessionBindingEvent se);:将一个属性从HttpSession中删除
  • public void attributeReplaced(HttpSessionBindingEvent se);:替换HttpSession中的属性
  • HttpSessionBindingEvent对象的操作
    • public String getName();:取得属性的名
    • public Object getValue();:取得属性的值
    • public HttpSession getSession();:取得当前的session

Request监听

Request监听分为ServletRequestListenerServletRequestAttributeListener

ServletRequestListener方法

  • public void requestInitialized(ServletRequestEvent sre);:request初始化
  • public void requestDestroyed(ServletRequestEvent sre);:request销毁
  • ServletRequestEvent对象的操作
    • public ServletRequest getServletRequest();:取得一个ServletRequest对象
    • public ServletContext getServletContext();:取得一个ServletContext(application)对象

ServletRequestAttributeListener方法

  • public void attributeAdded(ServletRequestAttributeEvent srae);:往当前ServletRequest对象中增加属性
  • public void attributeRemoved(ServletRequestAttributeEvent srae);往当前ServletRequest对象中删除属性
  • public void attributeReplaced(ServletRequestAttributeEvent srae);属性替换(第二次设置同一属性)
  • ServletRequestAttributeEvent对象操作
    • public String getName();:得到属性名称
    • public Object getValue();:取得属性的值

Listener的配置

  • web.xm配置

    原理于Servlet,Filter大同小异,不展开讲解

    java 复制代码
    <listener>
        <listener-class>com.listener.class</listener-class>
    </listener>
  • 注释@WebListener

    • 往Listener实现类顶部加上@WebListener注释即可
    java 复制代码
    @WebListener
    public class myListener01 implements HttpSessionAttributeListener {}

Listener的实例应用

使用HttpSessionListener统计最大在线人数

java 复制代码
@WebListener
public class myListener01 implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent event) {
        //使用Session获取ServletContext对象
        ServletContext app = event.getSession().getServletContext();
        //获取Servlet中的count属性
        int count = (int) app.getAttribute("onLineCount");
        count++;//每次创建一个Session Count就会+1 用来计数
        app.setAttribute("onLineCount",count);
        int maxOnLineCount= (int) app.getAttribute("maxOnLineCount");
        //若count>maxOnLineCount 则将maxOnLineCount更新为count的值
        if (count>maxOnLineCount)
        {
            app.setAttribute("maxOnLineCount",count);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            app.setAttribute("date",sdf.format(new Date()));
        }
    }
         
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        //结束会话后会删除Session 即减少一位客户 count--
        ServletContext app = event.getSession().getServletContext();
        int count = (int)app.getAttribute("count");
        count--;
        app.setAttribute("count", count);
    }
}
相关推荐
ihav2carryon2 个月前
JDBC,SQL注入,事务,C3P0于Druid连接池(最详细解析)
#java开发#java开发#javaweb#tomca#sevlet#底层原理·#jdbc·#后端开发·#sql注入·#连接池·#druid
ihav2carryon3 个月前
JavaWeb中的Tomcat,Servlet详解
#java开发#java开发#javaweb#tomca#sevlet#底层原理