JavaWeb之cookie&session

一、会话概述

日常生活中:从拨通电话到挂断电话之间的一连串你问我答的过程就是一个会话。

B/S架构中 : 从浏览器第一次给服务器发送请求时,建立会话;直到有一方断开,会话结束。

一次会话:包含多次请求响应。

会话中出现的问题:由于Http是一个无状态协议,不会记录每次请求的状态,这就造成了同一个会话的两请求之间相互独立,彼此没有联系。

此时就需要一种技术在客户端或者服务端,记录会话过程中产生的一些数据,这就是会话管理技术。

两种会话管理技术:

  • cookie:在一次会话的多次请求响应之间共享数据,将数据保存到客户端(浏览器)
  • session:在一次会话的多次请求之间共享数据,它将数据保存到服务器

二、cookie

cookie:利用客户端保存共享信息实现多次请求的数据共享。

使用cookie需要导入javax.servlet.http.Cookie

2.1 cookie的属性

  • name cookie的名称
  • value cookie的值
  • domain cookie的域名,默认值是访问服务的主机名称
  • path cookie的路径,默认值是应用的发布URI(发布名称/发布路径)
  • maxAge cookie的存活时间,0表示立即销毁
  • comment 描述信息 (无关紧要的属性)
  • version 版本号 (无关紧要的属性)

2.2 cookie相关API

方法名作用
Cookie cookie = new Cookie(name,value)创建Cookie对象
response.addCookie(Cookie c)将cookie写回浏览器
cookie.getName()获取cookie名
cookie.getValue()获取cookie的值
Cookie [] cookis = request.getCookies()获取cookie数组
cookie.setMaxAge(秒)设置cookie的有效时间
cookie.setPath("/path")设置cookie再次访问服务器时,自动携带cookie的依据

客户端带cookie到服务器机制:
请求资源URI去掉资源的部分之后和Cookie的Path进行比较,请求资源URI去掉资源的部分.startWith(cookiePath),结果为true,客户端就会带着cookie访问浏览器;如果为false,客户端访问浏览器就不会带cookie。

coolkiePath   /cookieandsession/servlet
PathQuestionDemo2     访问URI:     /cookieandsession/PathQuestionDemo2		
			URI去掉资源的部分:      /cookieandsession
PathQuestionDemo3     访问URI:     /cookieandsession/servlet/PathQuestionDemo3	
             URI去掉资源的部分:     /cookieandsession/servlet             

在上面的案例中,只有PathQuestionDemo3访问服务器会带着cookie

2.3 cookie的一些细节

  1. 一个服务器在浏览器端最多支持20个Cookie
  2. 所有服务器在浏览器端最多可以写300个Cookie
  3. 每个Cookie的大小不能超过4KB
  4. 定位一个cookie,domain+path+name

2.4 使用cookie完成购物车案例

xml配置:

<servlet>
        <servlet-name>CartServlet</servlet-name>
        <servlet-class>com.itcast.cart.CartServlet</servlet-class>
</servlet>
<servlet-mapping>
        <servlet-name>CartServlet</servlet-name>
        <url-pattern>/cart</url-pattern>
</servlet-mapping>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>购物车</title>
</head>
<body>
<a href="/cookieandsession/cart?action=showProductList">查看商品列表</a>
<hr/>
<a href="/cookieandsession/cart?action=showCartInfo">查看购物车</a>
</body>
</html>
public class CartServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求正文字符集
        req.setCharacterEncoding("UTF-8");
        //设置响应正文的MIME类型和字符集
        resp.setContentType("text/html;charset=UTF-8");
        //获取请求参数
        String action = req.getParameter("action");
        if ("showProductList".equals(action)){
            showProductList(req,resp);
        }else if ("showCartInfo".equals(action)){
            showCartInfo(req,resp);
        }else {
            System.out.println("无信息");
        }
        //获取请求参数
        String productName = req.getParameter("productName");
        if (productName != null){
            addCart(req,resp,productName);
        }

    }

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

    private void showProductList(HttpServletRequest req, HttpServletResponse resp){
        PrintWriter out = null;
        try {
            //获取输出流
            out = resp.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //输出商品列表
        out.write("01.Xiaomi&nbsp;&nbsp;&nbsp;<a href='"+req.getContextPath()+"/cart?action=showProductList&productName=Xiaomi'>添加购物车</a><br/>");
        out.write("02.Huawei&nbsp;&nbsp;&nbsp;<a href='"+req.getContextPath()+"/cart?action=showProductList&productName=Huawei'>添加购物车</a><br/>");
        out.write("03.Lianxiang&nbsp;&nbsp;&nbsp;<a href='"+req.getContextPath()+"/cart?action=showProductList&productName=Lianxiang'>添加购物车</a><br/>");
    }

    private void showCartInfo(HttpServletRequest req, HttpServletResponse resp){
        PrintWriter out = null;
        try {
            //获取输出流
            out = resp.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        out.write("<h1>购物车的详情:</h1>");
        //获取Cookie
        Cookie[] cookies = req.getCookies();
        //4.判断
        if(cookies == null || cookies.length == 0){
            out.write("您还没有添加商品到购物车");
        }else {
            for (Cookie cookie : cookies){
                //判断
                if("CartInfo".equals(cookie.getName())){
                    //找到了我们想要的cookie
                    String value = cookie.getValue();//Xiaomi-Xiaomi-Lianxiang
                    //分隔
                    String[] productNames = value.split("-");
                    //遍历名称
                    for(String productName : productNames){
                        out.write(productName+"<br/>");
                    }
                }
            }
        }
    }

    private void addCart(HttpServletRequest req, HttpServletResponse resp,String productName){
        PrintWriter out = null;
        try {
            //取出输出流
            out = resp.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //取出Cookie
        Cookie[] cookies = req.getCookies();
        //定义要写到客户端的Cookie
        Cookie cookie = null;
        //判断,如果没有Cookies就是第一次
        if(cookies == null || cookies.length == 0){
            cookie = new Cookie("CartInfo",productName);
        }else {
            //遍历
            for(Cookie c : cookies){
                //判断名称
                if("CartInfo".equals(c.getName())){
                    cookie = c;
                    break;
                }
            }
            //给cookie拼值,就是在原来的value上,再加上新的value(productName)
            String value = cookie.getValue()+"-"+productName;
            cookie.setValue(value);
        }
        //设置最大存活时间
        cookie.setMaxAge(Integer.MAX_VALUE);
        //把cookie写到浏览器
        resp.addCookie(cookie);
        //提示
        out.write("<hr size='7px' color='orange'>");
        out.write("添加成功。<a href='"+req.getContextPath()+"/cart?action=showCartInfo'>查看购物车</a>");
    }
}

三、session

3.1 session概述

session:在一次会话的多次请求之间共享数据,将数据保存到服务器端

在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。

Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。

使用session需要导入javax.servlet.http.HttpSession

3.2 session的基本使用

3.2.1 获取session的方法

  • HttpSession session = request.getSession(); 无论之前有还是没有session,都会有返回一个session,若之前的找到了就使用之前的session;若之前的session没有找到,就创建一个session
  • HttpSession session = request.getSession(boolean create);当create为true时,与request.getSession()使用情况一致;当create为false时,若之前的找到了就使用之前的session;若之前的session没有找到,就返回null

3.2.2 会话域

HttpSession也是一个域对象,它表示的是会话域,作用范围是一次会话之中(包含多次请求)。

域对象常用api:

  • getAttribute(String name) 通过属性名获取域对象的属性
  • setAttibute(String name , Object obj) 设置域对象的属性
  • removeAttribtue(String name) 通过属性名移除域对象的属性

session生命周期:

  • 创建:第一次调用request.getSession() 创建session对象
  • 销毁:
1.关闭浏览器,会话结束;
2.超过一定时间没有对网站有任何操作时,会话超时结束,默认时间是30分钟;
3.手动调用 session.invalidate() 销毁session对象;
4.服务器非正常关闭销毁对象(关机 死机 蓝屏等)

正常关闭服务器将session保存到本地:
在这里插入图片描述
正常关闭session没有销毁 而是保存到本地 , 再次启动服务器时会加载本地文件到内存中。

3.2.3 HttpSession原理

HttpSession是利用了Cookie实现的,其本质是一个特殊的Cookie。

Cookie名称是固定的:JSESSIONID ,Cookie的值就是HttpSession的唯一标识。

在这里插入图片描述

3.2.4 cookie和session的区别

  • cookie : 存入浏览器 cookie的值存储是有限制 不安全
  • session: 存入服务器 session存储没有限制 相对安全

如果cookie被清除了,session还在,只不过无法直接找到session, 可以通过url重写地址栏可以找回来的。

如果浏览器禁用cookie,session还可以使用,session的底层基于cookie 但不完全依赖cookie 有其他的方式可以替代。

session是一个域对象 , 为什么cookie不是域对象?因为域对象指的是服务器端的技术,而cookie是浏览器端的技术。

3.2.5 持久化级别session

通过创建cookie,可以持久化保存session

 //创建session对象
HttpSession session = request.getSession();

 //自己创建cookie
Cookie cookie = new Cookie("JSESSIONID" , session.getId());
        
cookie.setMaxAge(60*60*7);
response.addCookie(cookie);

System.out.println("session地址值:" + session);
System.out.println("session的id为:" + session.getId());
System.out.println("session是否为新创建的:" + session.isNew());

3.2.6 session的使用细节

session的活化与钝化:

  • 钝化:当应用停止服务时,服务器会把Session域中内容序列化到磁盘上
  • 当应用再次启动时,服务器会把磁盘上的.ser文件内容加载回内存中

前提:

  1. 正常关闭
  2. 存入的是对象必须实现序列化接口

客户端禁用Cookie的会话保持:
3. 文字提示,请不要禁用您的Cookie
4. URL重写,在访问地址后面拼接一个JSESSIONID(不推荐使用)

  • encodeUrl(url):其他的连接使用此方法
  • endcodeRedirectUrl(url):重定向的连接就使用此方法
 //获取session
HttpSession session = request.getSession();

session.setAttribute("username","url重写");

String url=request.getContextPath();
System.out.println(response.encodeRedirectURL(url));

response.setContentType("text/html;charset=utf-8");
response.getWriter().print("<a href='"+url+"'>返回首页</a><br>");

String url2 = request.getContextPath()+"/demo2";
url2=response.encodeURL(url2);
System.out.println(url2);
response.getWriter().print("<a href='"+url2+"'>获取数据</a>");

3.3 表单重复提交问题解决

当网络延迟高或者刷新网页可能会导致表单重复提交问题,这时候就要使用令牌思想,即在表单页面,生成一个令牌token,同时放入会话域和表单参数,当第一次表单提交时,判断会话域中的token和表单中的checkToken是否相等,相等就执行表单之后的操作,然后移除token

FormUI:

public class FormUI extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置响应正文的MIME类型和字符集
        resp.setContentType("text/html;charset=UTF-8");
        //2.获取输出流
        PrintWriter out = resp.getWriter();

        //生成一个令牌:
        String token = UUID.randomUUID().toString();//它是一个唯一标识符。是由32个16进制的数组成的一个128位的数    xxxxxxxx-xxxxxxxxxxxx-xxxx-xxxx-xxxx
        System.out.println(token);
        token = token.replace("-","").toUpperCase();

        //把令牌存入会话域中
        HttpSession session = req.getSession();
        session.setAttribute("token",token);

        //3.输出一个表单
        out.write("<html>");
        out.write("<head>");
        out.write("<title>转账操作</title><meta charset='UTF-8'></meta>");
        out.write("</head>");
        out.write("<body>");
        out.write("<form action='"+req.getContextPath()+"/TransferServlet' method='post'>");
        out.write("转账金额:<input type='text' name='money' value=''><br/>");
        out.write("<input type='hidden' name='checkToken' value='"+token+"'><br/>");
        out.write("<input type='submit' value='转账'>");
        out.write("</form>");
        out.write("</body>");
        out.write("</html>");
    }

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

TransferServlet

@WebSevlet("/TransferServlet")
public class TransferServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置响应正文的MIME类型和字符集
        resp.setContentType("text/html;charset=UTF-8");
        //2.获取输出流
        PrintWriter out = resp.getWriter();

        //模拟网络慢
        try{
            Thread.sleep(5000);
        }catch (Exception e){
            e.printStackTrace();
        }



        //校验
        //取出表单中的checkToken
        String checkToken = req.getParameter("checkToken");
        //取出会话域中token
        HttpSession session = req.getSession();
        String token = (String)session.getAttribute("token");

        if(checkToken.equals(token)){
            //3.获取请求参数
            String money = req.getParameter("money");
            System.out.println(money);
            //4.输出
            out.write("转账成功!");
            //非常重要的事,移除会话域中的令牌
            session.removeAttribute("token");
        }else {
            out.write("请不要重复提交!");
        }



    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值