项目中存在的问题:
1、登录时是否可以做一个记住密码这样一个功能。
2、登录成功以后右上角admin 是写死的,能不能登录成功以后,每个页面都显示登录的用户名呢?
3、验证码功能
今天的内容—会话技术

一、Cookie—小甜点

  1. Cookie数据存放在浏览器中。<br />常用的API:
Cookie cookie = new Cookie("name", "zhangsan");
        resp.addCookie(cookie);
        resp.getWriter().write("cookie数据已经返回给浏览器");
   通过浏览器访问servlet,servlet就会创建cookie,并且把cookie传递给页面,页面将信息进行保存。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/22131196/1631324315285-44b632e7-1073-4503-9790-b94b70d3367e.png#clientId=u46b5671f-0957-4&from=paste&height=404&id=ua7ec0398&margin=%5Bobject%20Object%5D&name=image.png&originHeight=404&originWidth=696&originalType=binary&ratio=1&size=27384&status=done&style=none&taskId=ue0a4ba34-203f-4230-8424-5ac2cc45376&width=696)<br />问题<br />1、服务器端一次可不可以发送多个cookie 呢?<br />     可以,创建多个Cookie对象,通过resp对象传递即可。
Cookie cookie = new Cookie("name", "zhangsan");
        Cookie cookie2 = new Cookie("age", "19");
        resp.addCookie(cookie);
        resp.addCookie(cookie2);

2、cookie数据在浏览器中可以保存多久才失效呢?
1)默认情况下,当浏览器关闭以后,Cookie数据就被销毁了
2)持久化存储:
setMaxAge(int seconds)
1、正数:Cookie数据会存储在硬盘上,持久化。直到我们指定的时间到了为止,cookie数据才失效
2、负数:默认情况
3、零 : 删除cookie中的数据
3、cookie可不可以存放中文呢?
在tomcat8之前,是不能存放中文的。
需要将中文数据转换—一般采用url编码。
tomcat8虽然现在可以存放中文,但是一些特殊的字符还是不支持,比如说空格。如果想解决也是使用url编码。(%E3%D4%)
关于URL编码:
java.net.URLEncoder.encode(str, “UTF-8”);
URL解码:
java.net.URLDecoder.decode(str, “UTF-8”);

如果不编码,出现异常:

java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
    org.apache.tomcat.util.http.Rfc6265CookieProcessor.validateCookieValue(Rfc6265CookieProcessor.java:182)
    org.apache.tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.java:115)
    org.apache.catalina.connector.Response.generateCookieString(Response.java:1019)
    org.apache.catalina.connector.Response.addCookie(Response.java:967)
    org.apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.java:386)
    com.qfedu.servlet.CookieServlet.doGet(CookieServlet.java:22)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

总结:Cookie
Cookie就是一个存储在浏览器端的数据的一个小技术。一般存放一些不敏感的数据,浏览器端存放的数据都是不安全。浏览器端存放单个Cookie的数据有大小限制(4kb),一个域名下不能存放很多Cookie,一般一个域名下最多存放20个Cookie数据。

二、Cookie实战

通过Cookie制作一个记住账号密码的功能。
第一步:需要在登录页面,有一个记住密码的选项

<p style="position: relative;text-align:left;margin-left:36px;margin-top: 5px;">
        <input type="checkbox" name="isJiZhu" id="isJiZhu" />记住密码
        <span id="msg" style="color:red"></span>
    </p>

第二步:登录时带上用户是否使用了该选项,如果选择了该选项,就把正确的用户名和密码通过Cookie返回给浏览器
并且加上一个过期时间。

var username=$("#username").val();
            var password=$("#password").val();
            // 想到 js 通过checked 获取checkbox是否被选中的
            // 需要将 jquery对象转换为 js对象 $("#isJiZhu")[0]
            var isJiZhu =$("#isJiZhu")[0].checked;// js   得到一个checkbox  .checked
            console.log(isJiZhu);
            $.get("${pageContext.request.contextPath}/loginAjax?username="+username+"&password="+password+"&isJiZhu="+isJiZhu,function (data) {
                if(data=='1'){
                    location.href="${pageContext.request.contextPath}/customer/show";
                }else{
                    $("#msg").text("登录失败,请检查账号密码是否正确");
                    //alert();
                }
            });
            return false;// 阻止默认提交行为

Java代码:

String username = req.getParameter("username");
        String password = req.getParameter("password");
        String isJiZhu = req.getParameter("isJiZhu");
        System.out.println(username+","+password+","+isJiZhu);

        boolean result = adminService.validateLogin(username,password);
        if(result){
            Cookie usernameCookie = new Cookie("username", username);
            Cookie passwordCookie = new Cookie("password", password);

            if(isJiZhu.equals("true")){
                // 设置7天过期
                usernameCookie.setMaxAge(7*3600*24);
                passwordCookie.setMaxAge(7*3600*24);
            }else{
                usernameCookie.setMaxAge(0);
                passwordCookie.setMaxAge(0);
            }
            resp.addCookie(usernameCookie);
            resp.addCookie(passwordCookie);

            resp.getWriter().write("1");
        }else{
            resp.getWriter().write("0");
        }

第三步:下一次在登录的时候,通过js从cookie中获取数据,填充到登录框内。
为了更加方便的从cookie中获取数据,我们使用了一个jquery的插件 jquery.cookie.js
<script src=”js/jquery.cookie.js”></script>

$(function(){
            //页面加载完毕之后,通过js将浏览器中的cookie获取出来,填充到账号和密码的地方
            console.log(document.cookie);// 通过原生的js可以获取cookie,但是是所有的cookie数据都存放到了一个字符串中,需要截取
            // 可以通过插件的方式快速获取cookie
            var userName = $.cookie("username");
            var password = $.cookie("password");
            $("#username").val(userName);
            $("#password").val(password);
            if((userName!= null && userName!="") && (password!=null&&password!="") ){
                $("#isJiZhu").prop("checked",true);
            }else{
                $("#isJiZhu").prop("checked",false);
            }
        });

记住密码的功能。

三、Session—会话

   Session数据是存放在服务器端的。<br />      张三                             我<br />             --------------> 吃了没?<br />             <--------------吃过了     一次请求与响应。<br />             ----------------->吃的啥?<br />            <---------------- 吃的盖浇饭    又一次请求与响应<br />  聊天的过程就叫做一次会话。谈话会在其中一方的离开作为结束。<br />Session其实是一个浏览器与服务器的谈话,该谈话包含多次的请求与响应。Session中的数据是共享的。<br />Session是四个域对象之一,域对象都可以存放数据。<br />request和session是用的最多的域对象。session中的数据的作用范围要比request大。

常用的API:

//如何获取session== 通过req对象获取session
        HttpSession session = req.getSession();
        session.setAttribute("subject","Java");
        //session.removeAttribute("subject");

jsp想获取数据:

获取到的session数据是:${sessionScope.subject}

提出几个疑问?

1、当浏览器关闭之后,服务器端不关闭,两次获取到的session是不是同一个?
通过两次请求打印的session对象地址来看,是不一样的。
org.apache.catalina.session.StandardSessionFacade@197c9162
org.apache.catalina.session.StandardSessionFacade@1255de1a
一次对话的标准是以其中一个对象的离开作为结束标准的。
期间浏览器关闭,也就意味着本次会话结束了。再打开一个新的,跟服务器端通信,那是另一次会话。
以上都是默认情况下。
如果你想关闭浏览器,再打开还接着上一次的会话继续聊,需要做如下事情:
image.png
服务器端就是靠着JSESSIONID是否相同来判断哪些请求和响应是同一个会话的,Session技术是依赖于Cookie。
org.apache.catalina.session.StandardSessionFacade@7dbf463c
org.apache.catalina.session.StandardSessionFacade@7dbf463c
代码如下:

//如何获取session== 通过req对象获取session
        HttpSession session = req.getSession();
        Cookie cookie = new Cookie("JSESSIONID",session.getId());
        cookie.setMaxAge(60*60);
        System.out.println(session);
        session.setAttribute("subject","Java");
        //session.removeAttribute("subject");

        resp.addCookie(cookie);
        // 重定向,记得前面+虚拟路径名
        resp.sendRedirect(req.getContextPath()+"/demo.jsp");

2、客户端不关闭,服务器端重启,两次获取到的session是不是还是同一个?

默认不是同一个,一次会话,其中一方走了,会话就结束了,即使回来,也不是同一个对象了。
session对象虽然不是同一个,但是数据却可以正常的获取,因为数据没有丢失。
如果服务器端是tomcat的话,启动后tomcat中的session数据不会丢失。
tomcat在进行关闭的时候:
session的钝化:在服务器正常关闭之前,会将session数据序列化到磁盘上。
tomcat正常启动后:
session的活化:重新加载钝化的数据。 钝化的数据会保存在work目录下,Session.ser

3、Session什么时候销毁?
1)服务器端关闭
2)Session对象调用了session.invalidate();
3) session失效: 30分钟失效
在tomcat的web.xml中可以设置过期时间

30

总结:
Session是一个将数据保存在服务器端的会话技术,可以保存数据,多次请求与响应可以共享该数据。
可以存储任意的数据类型,也没有大小限制。session相对于cookie来讲数据比较安全。

四、Session实战

项目中登录一个用户后,将用户的名字展示在各个页面上。<br />思路:<br />第一步:登录成功以后,将用户的名字保存在session域对象中
// 将用户名保存在session中便于页面获取数据
            HttpSession session = req.getSession();
            session.setAttribute("USERNAME",username);

第二步:找到需要展示的页面,在页面中获取session中的用户名
为什么不把用户名放在request中呢?因为request的数据只在一次请求中有效,多个页面就是多次请求,必须使用范围更大的session对象。
<li><a href=”#”>${sessionScope.USERNAME}</a></li>

第三步:当用户退出时,需要将session中的用户名数据删除。

@WebServlet("/loginOut")
public class LoginOutServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getSession().removeAttribute("USERNAME");
        resp.sendRedirect(req.getContextPath()+"/login.jsp");
    }
}