Cookie概述
Cookie是由服务器端生成并储存在浏览器客户端上的数据,只要Cookie清除或者Cookie失效,这个会话状态就没有了。当然,Cookie也可以保存在浏览器的缓存中,浏览器关闭Cookie消失。
在javaweb开发中Cookie被当做java对象在web服务器端创建,并由web服务器发送给特定浏览器客户端,并且WEB服务器可以向同一个浏览器客户端上同时发送多个Cookie,每一个Cookie对象都由name和value组成,name和value只能是字符串类型,浏览器接收到来自服务器的Cookie数据之后默认将其保存在浏览器缓存中(如果浏览器关闭,缓存消失,Cookie数据消失),只要浏览器不关闭,当我们下一次发送“特定”请求的时候,浏览器负责将Cookie数据发送给WEB服务器。我们还可以使用特殊的方法,将Cookie保存在客户端的硬盘上。永久性保存。这样关闭浏览器Cookie还是存在的,不会消失,比如:实现两周内自动登录。
Cookie不止在javaweb中存在,只要是web开发,只要是B/S架构的系统,只要是基于HTTP协议,就有Cookie的存在,Cookie这种机制是HTTP协议规定的。
Cookie在现实生活中对应的场景
Cookie在客户端的保存形式和有效时间
服务器端默认创建的Cookie,发送到浏览器之后,浏览器默认将其保存在缓存中,当浏览器关闭之后Cookie消失,。在java程序中创建Cookie
Cookie cookie = new Cookie(String cookieName, String cookieValue);
在浏览器客户端无论是硬盘文件中还是缓存中保存的Cookie,什么时候会再次发送给服务器呢?
- 浏览器会不会提交发送这些Cookie给服务器,和请求路径有关系。
- 请求路径和Cookie是紧密关联的。
- 不同的请求路径会发送提交不同的Cookie
默认情况下Cookie会和哪些路径绑定在一起?
若是项目中部署的路径
- /prj-servlet-18/test/createAndSendCookieToBrowser 请求服务器,服务器生成Cookie,并将Cookie发送给浏览器客户端,这个浏览器中的Cookie会默认和“test/”这个路径绑定在一起。也就是说,以后只要发送“test/”请求,Cookie一定会提交给服务器。
若存在servlet中的路径
- /prj-servlet-18/a 请求服务器,服务器生成Cookie,并将Cookie发送给浏览器客户端,这个浏览器中的Cookie会默认和“prj-servlet-18/”这个路径绑定在一起。也就是说,以后只要发送“prj-servlet-18/”请求,Cookie一定会提交给服务器。
其实路径是可以指定的,可以通过java程序进行设置,保证Cookie和某个特定的路径绑定在一起。假设,执行了这样的程序:cookie.setPath("/prj-servlet-18/king"); 那么:Cookie将和"/prj-servlet-18/king"路径绑定在一起,只有发送“/prj-servlet-18/king”请求路径,浏览器才会提交Cookie给服务器。
服务器创建Cookie对象之后,调用setMaxAge方法设置Cookie的有效时间。默认情况下,没有设置Cookie的有效时长,该Cookie被默认保存在浏览器的缓存当中,只要浏览器不关闭Cookie存在,只要关闭浏览器Cookie消失,我们可以通过设置Cookie的有效时长,以保证Cookie保存在硬盘文件当中。但是这个有效时长必须是>0的。换句话说,只要设置Cookie的有效时长大于0,则该Cookie会被保存在客户端硬盘文件当中。有效时长过去之后,则硬盘文件当中的Cookie失效。
- 如果这个有效时间 >0,则该Cookie对象发送给浏览器之后浏览器将其保存到硬盘文件中。
- 如果这个有效时间 <0,则该Cookie对象也是被保存在浏览器缓存中,待浏览器关闭Cookie消失。
- 如果这个有效时间 =0,则该Cookie从服务器端发过来的时候就已经是一个已过时的Cookie。
cookie.setMaxAge(60 * 60); //1小时有效,参数以second为单位
浏览器提交Cookie给服务器,服务器怎么接收Cookie?
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
System.out.println(cookieName + "=" + cookieValue);
}
}
Cookie和请求路径之间的关系
每一个Cookie和请求路径是绑定在一起的,只有特定的路径才可以发送特定的Cookie。实际上浏览器是这样做的:浏览器在向web服务器发送请求的时候先去对应的请求路径下搜索是否有对应的Cookie,如果有Cookie,并且Cookie没有失效,则发送该Cookie或者多个Cookie到服务器端。请求路径和Cookie的关系是这样对应的:
假如获取Cookie时的路径是 :http://127.0.0.1:8080/PrjCookies/getCookie
将来发送Cookie的路径包括如下路径 :
- http://127.0.0.1:8080/PrjCookies/getCookie(相同路径)
- http://127.0.0.1:8080/PrjCookies/xxxx(同目录)
- http://127.0.0.1:8080/PrjCookies/xxxx/xxxx/xxx(子目录)
假如获取Cookie时的路径是 :http://127.0.0.1:8080/PrjCookies/servlet/getCookie
将来发送Cookie的路径包括如下路径 :
- http://127.0.0.1:8080/PrjCookies/servlet/getCookie(相同路径)
- http://127.0.0.1:8080/PrjCookies/servlet/xxxxx(同目录)
- http://127.0.0.1:8080/PrjCookies/servlet/xxxxx/xxxx(子目录)
不过我们也可以在创建Cookie对象的时候设置Cookie的关联路径,例如:cookie.setPath(“/PrjCookies/system/login”);那么如下的请求路径浏览器会发送该Cookie:
- http://127.0.0.1:8080/PrjCookies/system/login(相同路径)
- http://127.0.0.1:8080/PrjCookies/system/xxx(同一目录)
- http://127.0.0.1:8080/PrjCookies/system/xxx/xxx(子目录)
浏览器禁用Cookie
浏览器是可以禁用Cookie,表示服务器发送过来的Cookie,我浏览器不要,不接收。服务器还是会发送Cookie的,只不过浏览器不再接收。
IE浏览器禁用Cookie。
当浏览器禁用Cookie之后,服务器还是仍然会将Cookie发送给浏览器,只不过这次浏览器选择了不接收。现在有很多网站的使用都是需要开启接收Cookie的。例如126邮箱。
Cookie实现“两周内自动登录”
附:
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>isLogin</welcome-file> </welcome-file-list> <servlet> <servlet-name>login</servlet-name> <servlet-class>myweb.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> <servlet> <servlet-name>isLogin</servlet-name> <servlet-class>myweb.CheckLoginStatusServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>isLogin</servlet-name> <url-pattern>/isLogin</url-pattern> </servlet-mapping> </web-app>
login.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <html> <head> <title>登录页面</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> </head> <body> <form action="/Servlet-11/login" method="post"> 用户名 <input type="text" name="username" > <br> 密码 <input type="password" name="password"> <br> <input type="checkbox" name="tenDayAutoLoginFlag" value="ok">十天内免登录<br> <input type="submit" value="登录"> </form> </body> </html>
login-error.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <html> <head> <title>登录失败</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> </head> <body> 登录失败,用户名不存在或者密码错误,请<a href="/Servlet-11/login.html">重新登录</a> </body> </html>
CheckLoginStatusServlet.java
package myweb; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CheckLoginStatusServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //从request中获取所有的Cookie Cookie[] cookies = request.getCookies(); String username = null; String password = null; if(cookies != null){ //遍历Cookie for(Cookie cookie : cookies){ String cookieName = cookie.getName(); String cookieValue = cookie.getValue(); if("username".equals(cookieName)){ username = cookieValue; }else if("password".equals(cookieName)){ password = cookieValue; } } } if(username != null && password != null){ //连接数据库JDBC验证用户名和密码 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; boolean loginSuccess = false; String realName = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/MySQL", "root", "root"); String sql = "select id,username,password,realname from login.t_user where username=? and password=?"; ps = conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); rs = ps.executeQuery(); if(rs.next()){ loginSuccess = true; realName = rs.getString("realname"); } } catch (Exception e) { e.printStackTrace(); } finally{ if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(ps != null){ try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } if(loginSuccess){ //登录成功跳转到成功页面 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print("<html>"); out.print("<head>"); out.print("<title>欢迎页面</title>"); out.print("</head>"); out.print("<body>"); out.print("欢迎"); out.print(realName); out.print("访问"); out.print("</body>"); out.print("</html>"); }else{ //登录失败跳转到失败页面 response.sendRedirect(request.getContextPath() + "/login-error.html"); } }else{ //跳转到登录页面 response.sendRedirect(request.getContextPath() + "/login.html"); } } }
LoginServlet.java
package myweb; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取用户名和密码 request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); //JDBC连接数据库验证用户名和密码 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; boolean loginSuccess = false; String realName = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/MySQL", "root", "root"); String sql = "select id,username,password,realname from login.t_user where username=? and password=?"; ps = conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); rs = ps.executeQuery(); if(rs.next()){ loginSuccess = true; realName = rs.getString("realname"); } } catch (Exception e) { e.printStackTrace(); } finally{ if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(ps != null){ try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } if(loginSuccess){ //登录成功之后,获取用户是否选择了十天内免登录 String tenDayAutoLoginFlag = request.getParameter("tenDayAutoLoginFlag"); if("ok".equals(tenDayAutoLoginFlag)){ //创建Cookie对象 Cookie cookie1 = new Cookie("username",username); Cookie cookie2 = new Cookie("password",password); //设置有效时间 cookie1.setMaxAge(60 * 60 * 24 * 10); cookie2.setMaxAge(60 * 60 * 24 * 10); //设置关联路径 cookie1.setPath(request.getContextPath()); cookie2.setPath(request.getContextPath()); //发送Cookie给浏览器 response.addCookie(cookie1); response.addCookie(cookie2); } //登录成功跳转到成功页面 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.print("<html>"); out.print("<head>"); out.print("<title>欢迎页面</title>"); out.print("</head>"); out.print("<body>"); out.print("欢迎"); out.print(realName); out.print("访问"); out.print("</body>"); out.print("</html>"); }else{ //登录失败跳转到失败页面 response.sendRedirect(request.getContextPath() + "/login-error.html"); } } }
use login; drop table if exists t_user; create table t_user( id int(10) primary key auto_increment, username varchar(32) not null unique, password varchar(32) not null, realname varchar(128) ); insert into t_user(username,password,realname) values('admin','123','管理员'); insert into t_user(username,password,realname) values('zhangsan','123','张三'); commit; select * from t_user;