javaweb之cookie、session、filter、listener

会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话。

在客户端与服务器端交互的过程中,会产生一些数据。为了保存会话过程中产生的数据,在Servlet技术中,提供了两个用于保存会话数据的对象,分别是Cookie和Session

一个网站怎么证明你来过?

  1. 服务端给客户端一个信件(cookie),客户端下次访问服务端带上信件就可以了

  2. 服务器登记你来过了,下次你来的时候我来匹配你(session)

  • cookie,客户端技术
  • session,服务器技术,我们可以把信息或者数据放在session中

cookie

浏览器端的会话技术,它通过在浏览器中记录一些服务器传递过来的数据,解决会话从什么时候开始,到什么时候结束。

就是在浏览器上记录会话过程中产生的临时数据。

HTTP协议是无状态协议,只定义规则,不保存数据,就有了cookie的产生。

cookie的应用场景

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 上一次访问时间
  • 购物车

cookie api

package com.lx.servlet.cookiesession;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/cookieSessionDemo")
public class CookieSessionDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("demoUserName","jayChou");

        // cookie路径
        // 服务器是根据路径获取cookie的,cookie默认路径是 请求路径的上一级
        // 如果默认路径为多级的话,就拿不到本网站所有的cookie
        // 所以一般我们设置项目路径为cookie的路径
        cookie.setPath(req.getContextPath());

        // cookie默认是会话级别,存储在内存中
        // 也可以设置为持久化级别,存储在硬盘
        // 单位为秒,正整数为持久化的时间,
        // 负整数,代表会话级别
        // 0 代表删除
        // 删除cookie,同名同路径,setMaxAge 为 0
        // 就是说如果不设置持久化的话,cookie就是会话级别,
        // 一旦持久化,关闭浏览器再开启cookie依然存在,但是不安全
        cookie.setMaxAge(60*60*24*7);
        // 解决cookie跨域,一般设置为顶级域名,这里实际上设置的是前端的域名
        cookie.setDomain("itlx.com");

        // 向浏览器添加cookie
        resp.addCookie(cookie);


        Cookie[] cookies = req.getCookies();

        // 这个获取所有cookie只是获取本网站的cookie,而不是浏览器的所有cookie
        if (cookies!=null && cookies.length > 0){
            for (Cookie cookieObj : cookies) {
                System.out.println(cookieObj.getName() + ":" +cookieObj.getValue());
            }
        }


    }

cookie注意事项

  • 不支持中文,不能跨浏览器
  • 有大小限制,4kb
  • 对于一个网站,最多20个cookie,浏览器的上限是200个cookie

session

  • 服务器会给每一个用户(浏览器)创建一个session对象
package com.lx.servlet.cookiesession;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet("/cookieSessionDemo")
public class CookieSessionDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 如果浏览器第一次访问服务器,就会创建一个session对象
        // 服务器会自动创建一个cookie 名字是 JSESSIONID
        HttpSession session = req.getSession();

        session.setAttribute("sessionUserName","jay");

        // 服务器创建session后会有一个随机的id
        String id = session.getId();

        Cookie cookie = new Cookie("JSESSIONID", id);

        // 将session设置失效时间为7天
        cookie.setMaxAge(60*60*24*7);
        cookie.setPath(req.getContextPath());

        resp.addCookie(cookie);


        resp.setContentType("text/html;charset=utf-8");

        String sessionUserName = (String) session.getAttribute("sessionUserName");
        resp.getWriter().write("名字是:" + sessionUserName);


		// session.isNew() 判断session是不是新创建的
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

session应用场景
Session 代表着服务器和客户端一次会话的过程。

Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当客户端关闭会话,或者 Session 超时失效时会话结束。

cookie与session的面试问题

cookie和session的区别

  1. 存储位置不同
  • cookie的数据信息存放在客户端浏览器上
  • session的数据信息存放在服务器上
  1. 存储容量不同
  • 单个cookie保存的数据<=4KB,一个站点最多保存20个Cookie
  • 对于session来说并没有上限,但出于对服务器端的性能考虑,session内不要存放过多的东西
  1. 隐私策略不同
  • cookie对客户端是可见的,别有用心的人可以分析存放在本地的cookie并进行cookie欺骗,所以它是不安全的
  • session存储在服务器上,对客户端是透明对,不存在敏感信息泄漏的风险
  1. 性能使用不同
  • session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。

cookie与session生命周期

cookie默认的生命周期为会话级别,可以手动设置为持久化。

Tomcat中默认是30分钟, 在tomcat的conf/web.xml中有如下配置,也可以直接在java项目的web.xml中配置

<session-config>  
        <session-timeout>30</session-timeout>  
</session-config>  

这个30分钟是指距最后一次访问30分钟

服务端是根据 Cookie 中的信息判断用户是否登录,那么如果浏览器中禁止了 Cookie,如何保障整个机制的正常运转

默认情况下禁用 Cookie 后,Session 是无法正常使用的。

这是因为大多数 Web 服务器都是依赖于 Cookie 来传递 Session 的会话 ID 的。客户端浏览器禁用 Cookie 时,服务器将无法把会话 ID 发送给客户端,客户端也无法在后续请求中携带会话 ID 返回给服务器,从而导致服务器无法识别用户会话。

解决方案

  1. URL 中携带 SessionID(URL重写):可以通过 URL 重写的方式将 Session ID 添加到所有的 URL 中。服务器生成 Session ID 后,将其作为 URL 的一部分传递给客户端,客户端在后续的请求中将 Session ID 带在 URL 中。服务器端需要相应地解析 URL 来获取 Session ID,并维护用户的会话状态。
    第一种方案,每次请求中都携带一个 SessionID 的参数,也可以 Post 的方式提交,也可以在请求的地址后面拼接xxx?SessionID=123456…。

  2. 第二种方案,Token 机制。Token 机制多用于 App 客户端和服务器交互的模式,也可以用于 Web 端做用户状态管理。
    Token 的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。Token 机制和 Cookie 和Session的使用机制比较类似。
    当用户第一次登录后,服务器根据提交的用户信息生成一个 Token,响应时将 Token 返回给客户端,以后客户端只需带上这个 Token前来请求数据即可,无需再次登录验证

  3. 隐藏表单字段传递 SessionID:将 Session ID 添加到 HTML 表单的隐藏字段中。在每个表单中添加一个隐藏的字段,保存 Session ID,客户端提交表单时会将 Session ID 随表单数据一起发送到服务器,服务器通过解析表单数据中的 Session ID 来获取用户的会话状态。

web三大组件

  • servlet 处理请求并给与响应
  • filter 过滤器
  • listener 监听器

filter

filter的目的是,在请求和响应之间拦截检查请求和响应的内容,主要是针对请求和响应做相应的处理。

javax.servlet.Filter接口,定义过滤器必须具备筛选功能,具体的筛选逻辑由实现类去实现。

filter主要用于对用户请求进行预处理

Filter 可以认为是 Servlet 的一种”加强版”。它主要用于对用户请求进行预处理,也可以对 HttpServletResponse 进行后处理,是个典型的处理链;

Filter 可以对用户请求生成响应,和 Servlet 相同;

处理流程:用户请求 -> Filter 预处理 -> Servlet 处理请求生成响应 -> Filter 对响应进行后处理。

用处

  • 在 HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest;

根据需要检查 HttpServletRequest,也可以修改 HttpServletRequest 头和数据;

  • 在 HttpServletResponse 到达客户端之前,拦截 HttpServletResponse;

根据需要检查 HttpServletResponse,也可以修改 HttpServletResponse头和数据。

应用场景

所谓过滤器顾名思义是用来过滤的。在 Java Web中,传入的 request、response 提前过滤掉一些信息,或者提前设置一些参数;然后再传入 Servlet 或者 Struts 的 action 进行业务逻辑。比如,过滤掉非法 URL(不是 login.do 的地址请求,如果用户没有登陆都过滤掉),或者在传入 Servlet 或者 Struts 的 action 前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。

  1. 登录、权限检查
  2. 过滤敏感词汇
  3. 全站编码

生命周期

  • init 初始化
  • doFilter 执行过滤操作
  • destory 销毁
  1. 创建
    服务器启动的时候创建,在servlet之前。

  2. 过滤
    每当被过滤的请求被请求时,就会执行一次doFilter方法。

    如果不放行,到达不了servlet的service方法中。

  3. 销毁
    关闭服务器的时候,在servlet之后。

过滤器执行顺序

在这里插入图片描述
一个请求路径上可以有多个过滤器进行拦截,并且他们的执行是有顺序的,

  • 如果采用的是注解方式的话,跟过滤器的名字有关系,自然顺序(abcde)。

  • 如果采用的是web.xml方式的话,顺序是配置filter的顺序。

注解配置方式

<%-- index.jsp
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2022/5/4
  Time: 20:33
  To change this template use File | Settings | File Templates.
--%>
<%-- 这是一个指定 代表当前页面的解析方式--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>使用filter处理全站乱码问题</title>
  </head>
  <body>

    <form action="${pageContext.request.contextPath}/encoding" method="post">
      <input type="text" name="name">
      <input type="submit" value="提交">
    </form>

  </body>
</html>

package com.lx.servlet.filter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/encoding")
public class FilterDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name" );
        resp.getWriter().write(name);
    }
}

package com.lx.servlet.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 配置过滤路径,注解配置 和 web.xml 配置
 *
 * url-pattern
 *      精确匹配    /servlet完整请求路径
 *      目录匹配    / 中间自定义 *  例如:/abc/*
 *      后缀名匹配  *.jsp *.action
 *
 */
@WebFilter("/*")
public class FilterDemo implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    // 过滤筛选方法
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        // servletRequest 没有对get post进行区分,需要向下转型到HttpServletRequest
        //
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;

        // 全站编码
        if (httpServletRequest.getMethod().equalsIgnoreCase("post")){
            httpServletRequest.setCharacterEncoding("utf-8");
        }

        // 设置响应对象 缓冲区的 编码
        servletResponse.setContentType("text/html;charset=utf-8");

        System.out.println("进入:doFilter");

        // 放行,就是可以访问原本访问的servlet
        // 如果不写,程序到这里就被拦截停止
        filterChain.doFilter(servletRequest,servletResponse);

        // 执行完servlet还能进入到过滤器
        System.out.println("执行完servlet还能进入到过滤器");
    }
}

xml配置方式

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    

    <!--
        配置拦截器name 和 路径
    -->
    <filter>
        <filter-name>filterDemo2</filter-name>
        <filter-class>com.lx.servlet.filter.FilterDemo2</filter-class>
    </filter>

    <!-- 配置要拦截的路径-->
    <filter-mapping>
        <filter-name>filterDemo2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <filter>
        <filter-name>filterDemo</filter-name>
        <filter-class>com.lx.servlet.filter.FilterDemo</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>filterDemo</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>






</web-app>

拦截方式的介绍

package com.lx.servlet.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;


/**
 * 默认情况下,对请求转发没有进行拦截操作
 *
 * <dispatcher></dispatcher>
 *      作用:指定哪一种的访问方式会被拦截。
 *
 *      REQUEST     默认的请求类型,就是直接从浏览器发送的请求
 *      FORWARD    请求转发的时候会进行拦截
 *      ERROR       拦截跳转到错误页面
 *      INCLUDE     拦截一个页面中包含另外一个页面
 */
@WebFilter(urlPatterns = "/*",dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST})
public class FilterDemo implements Filter {


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filterDemo");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

listener

监听器实际应用中不多。

监听web服务器的运行,当发生特定事件的时候,采取预先设定的处理方案。

主要监听域对象

  • Request 一次请求
  • Session 一次会话
  • ServletContext 整个web项目

主要监听这三个对象的状态变化,创建与销毁。

监听器常见的有8个,这里只说3个。

  1. 监听三个域对象的生命周期
  2. 监听三个域对象中属性的变化
  3. 监听javabean在session的变化

生命周期

  • ServletContext
    创建:服务器启动的时候创建,一个web项目只有一个ServletContext对象
    销毁:服务器关闭的时候,或者重新发布项目的时候

  • HttpSesion
    创建:一次会话开始的时候,也就是第一次访问
    销毁:session对象,在未操作的状态30分钟,要么调用手动销毁方法。

应用场景

  1. 统计在线人数或者统计网站的访问量
  2. 加载一些web初始化信息

ServletContextListener

监听域对象的创建和销毁

package com.lx.servlet.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * ServletContextListener   监听web项目启动 和 销毁
 */
@WebListener
public class ServletContextListenerDemo implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {

        System.out.println("web项目启动");

        // 获取项目对象
        Object source = servletContextEvent.getSource();
        System.out.println(source);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("web项目销毁");
    }
}

也可以配置xml

<listener>
	<listener-class>com.lx.servlet.listener.ServletContextListenerDemo</listener-class>
</listener>

HttpSessionListener

  • 访问HTML是否创建session:不会
  • 访问JSP是否创建session:会
  • 访问servlet是否创建session:不会(默认没有调用getSession方法)
package com.lx.servlet.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * ServletContextListener   监听web项目启动 和 销毁
 * HttpSessionListener      监听一次会话的创建 和 销毁
 */
@WebListener
public class ServletContextListenerDemo implements ServletContextListener,HttpSessionListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {

        System.out.println("web项目启动");

        // 获取项目对象
        Object source = servletContextEvent.getSource();
        System.out.println(source);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("web项目销毁");
    }

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("一个session对象创建了");
        HttpSession session = httpSessionEvent.getSession();
        System.out.println(session.getId() + ":上线了");
    }

    /**
     * 何时销毁
     *
     * 非正常关闭服务器
     * session过期(tomcat默认过期时间30分钟)
     * 手动调用session.invalidate()
     * @param httpSessionEvent
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("一个session对象销毁了");
        HttpSession session = httpSessionEvent.getSession();
        System.out.println(session.getId() + ":下线了");
    }
}

拦截器与过滤器的区别

过滤器(Filter)

过滤器,是在java web中将你传入的request、response提前过滤掉一些信息,或者提前设置一些参数。然后再传入Servlet或Struts2的 action进行业务逻辑处理。比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入Servlet或Struts2的action前统一设置字符集,或者去除掉一些非法字符。

拦截器(Interceptor)

拦截器,是面向切面编程(AOP,Aspect Oriented Program)的。就是在你的Service或者一个方法前调用一个方法,或者在方法后调用一个方法。比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

拦截器与过滤器的区别

Spring 的 Interceptor(拦截器)与 Servlet 的 Filter 有相似之处,比如二者都是 AOP 编程思想的体现,都能实现权限检查、日志记录等。

不同之处总结如下:

1、拦截器是基于java的反射机制的,而过滤器是基于函数回调。

2、拦截器是属于springmvc的,过滤器是属于servlet的。

3、filter只在servlet前后起作用,拦截器能够深入到方法前后、异常抛出前后等,具有更大的弹性。
在spring中,优先使用拦截器,它几乎可以实现过滤器的所有功能。

使用场景

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

拦截器:

1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

过滤器应用场景:

1)过滤敏感词汇(防止sql注入)

2)这是字符编码

3)URL级别的权限访问控制

4)压缩响应信息

部分知识转载自:
https://www.bilibili.com/video/BV12J411M7Sj?p=17&spm_id_from=pageDriver&vd_source=64c73c596c59837e620fed47fa27ada7
https://www.iteye.com/blog/18810098265-2002428
https://www.cnblogs.com/jirglt/archive/2012/10/20/2732255.html
https://blog.csdn.net/wz2292667460/article/details/79366493
https://blog.51cto.com/u_15989526/6288855
https://blog.csdn.net/weixin_37264997/article/details/90693525
https://blog.csdn.net/u013938578/article/details/136189698

第一,科学家的类别可以不一样,有些是架构型的科学家,有些是阐述型科学家,有些是突破型的科学家,有些是工匠型的科学家……。年龄大的科学家,他们人生阅历很丰富,对系统架构的认识很清晰;他们向青年人阐述架构模型,年轻人有奇思怪想就容易突破,这个架构里的缺陷就容易被修复了;有些人深入实践,在工程实现方面积累了丰富的Know-How经验,善于解决复杂的工程问题,我们也称之为工匠科学家。最有创造力的是年轻人,但最有架构能力的还是有经验的老专家、老教授,他们对整个架构有很清晰的认识。所以,要将老、中、青结合起来,国家才能够攻克大的难关。

https://baijiahao.baidu.com/s?id=1760664270073856317&wfr=spider&for=pc
擦亮花火、共创未来——任正非在“难题揭榜”花火奖座谈会上的讲话
任正非

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值