项目第六天-Cookie&Session

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

一、Cookie

Cookie数据存放在浏览器中。
常用的API:

  1. Cookie cookie = new Cookie("name", "zhangsan");
  2. resp.addCookie(cookie);
  3. resp.getWriter().write("cookie数据已经返回给浏览器");

通过浏览器访问servlet,servlet就会创建cookie,并且把cookie传递给页面,页面将信息进行保存。
项目第6天 - 图1
问题
1、服务器端一次可不可以发送多个cookie 呢?
可以,创建多个Cookie对象,通过resp对象传递即可。

  1. Cookie cookie = new Cookie("name", "zhangsan");
  2. Cookie cookie2 = new Cookie("age", "19");
  3. resp.addCookie(cookie);
  4. 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”);
如果不编码,出现异常:

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

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

二、Cookie实战

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

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

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

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

Java代码:

  1. String username = req.getParameter("username");
  2. String password = req.getParameter("password");
  3. String isJiZhu = req.getParameter("isJiZhu");
  4. System.out.println(username+","+password+","+isJiZhu);
  5. boolean result = adminService.validateLogin(username,password);
  6. if(result){
  7. Cookie usernameCookie = new Cookie("username", username);
  8. Cookie passwordCookie = new Cookie("password", password);
  9. if(isJiZhu.equals("true")){
  10. // 设置7天过期
  11. usernameCookie.setMaxAge(7*3600*24);
  12. passwordCookie.setMaxAge(7*3600*24);
  13. }else{
  14. usernameCookie.setMaxAge(0);
  15. passwordCookie.setMaxAge(0);
  16. }
  17. resp.addCookie(usernameCookie);
  18. resp.addCookie(passwordCookie);
  19. resp.getWriter().write("1");
  20. }else{
  21. resp.getWriter().write("0");
  22. }

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

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

记住密码的功能。

三、Session—会话

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

常用的API:

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

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

提出几个疑问?

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

  1. //如何获取session== 通过req对象获取session
  2. HttpSession session = req.getSession();
  3. Cookie cookie = new Cookie("JSESSIONID",session.getId());
  4. cookie.setMaxAge(60*60);
  5. System.out.println(session);
  6. session.setAttribute("subject","Java");
  7. //session.removeAttribute("subject");
  8. resp.addCookie(cookie);
  9. // 重定向,记得前面+虚拟路径名
  10. 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实战

项目中登录一个用户后,将用户的名字展示在各个页面上。
思路:
第一步:登录成功以后,将用户的名字保存在session域对象中

  1. // 将用户名保存在session中便于页面获取数据
  2. HttpSession session = req.getSession();
  3. session.setAttribute("USERNAME",username);

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

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

  1. @WebServlet("/loginOut")
  2. public class LoginOutServlet extends HttpServlet {
  3. @Override
  4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  5. req.getSession().removeAttribute("USERNAME");
  6. resp.sendRedirect(req.getContextPath()+"/login.jsp");
  7. }
  8. }