文章目录
4.3 cookie-session
学习目标:
-
什么是Cookie和Session
-
Cookie对象和Session对象的使用
-
购物车和用户登录的流程
-
会话概述
案例:两个人打电话,你问我答。
Web应用会话:一个用户在某网站上的整个购物过程就是一个会话
- 一个客户端(浏览器)与Web服务器之间连续发生的一系列请求和响应过程。
- Servlet技术中,提供了两个用于保存会话数据的对象,分别是Cookie和Session
2.1 什么是Cookie
Cookie的功能类似于会员卡,通过会员卡可以看到用户信息,用户的消费会累积到会员卡
Cookie在浏览器和服务器之间的传输:
- 第一次访问服务器,服务器增加SetCookie头字段,将Cookie信息发送给浏览器,并保存在客户端。
- 在后续访问服务器时,会在请求消息中将Cookie数据发送给服务器,从而使服务器分辨出当前请求是哪个用户发出的。
2.2 Cookie API
- 构造方法 Cookie(String name, String value)
- Cookie类的常用方法
4.3.1 响应消息中添加Cookie
目标
服务端通过response.addCookie(),浏览器端能看到(开发者工具:网络,应用,控制台)
目标:要能够在响应标头中看到Set-Cookie,第二次请求时,要在请求标头中看到Cookie,在应用中能看到Cookie具体属性
步骤:
- 创建setServletCookie.java文件,继承自HttpServlet
- 创建一个Cookie对象,参数为user、zhang3
- 配置URL,启动程序,打开对应网页
代码:
@WebServlet("/SetCookieServlet")
public class setCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("user","zhang3");
resp.addCookie(cookie);
resp.getWriter().append("Served at: ").append(req.getContextPath());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
创建Cookie对象后,打开网址,响应标头中多了set-Cookie:user=zhang3,请求标头中也多了Cookie
在这里也可以看到Cookie的一些值
4.3.2 读取请求消息中的Cookie
目标:
服务端读取浏览器请求中的cookie并输出到控制台
第二次访问时,请求标头中有Cookie信息,要在服务器端把它获取出来,并且输出在页面上,或打印在控制台上
代码:
@WebServlet("/ReadCookiesServlet")
public class ReadCookiesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//getCookies会返回一个Cookie数组
Cookie[] cookies = req.getCookies();
//通过循环遍历,把这些信息输出在控制台上
if(cookies != null){
for (Cookie cookie : cookies) {
System.out.println(cookie.getName() + "--->" + cookie.getValue());
}
}
resp.getWriter().append("Served at: ").append(req.getContextPath());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
第二次请求时,浏览器把Cookie发送到了服务端,服务端收到了并输出
4.3.3 删除Cookie
目标
清除cookie
步骤:
- 在浏览器—检查元素—控制台处再添加一个cookie
- 新写一个ClearCookiesServlet.java,用来删掉cookie
- 打开ReadCookiesServlet网页,可以看到idea的控制台输出了当前cookie
- 打开ClearCookiesServlet网页,删除cookie
- 打开检查元素,在cookie中已经看不到user和pwd两个cookie的信息了
代码:
@WebServlet("/ClearCookiesServlet")
public class ClearCookiesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
cookie.setMaxAge(0); //删掉cookie
resp.addCookie(cookie); //响应给浏览器
System.out.println(cookie.getName() + "-->" + cookie.getValue());
}
resp.getWriter().append("Served at: ").append(req.getContextPath());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
在控制台处添加cookie
两个cookie都有了
控制台端也已输出两个cookie
打开ClearCookiesServlet网页,删除cookie
问题及解决办法:
问题:不会删除cookie
解决办法:
首先使用req.getCookies()
方法拿到浏览器内的Cookie数组
再遍历Cookie
数组,依次使用cookie.setMaxAge(0)
删掉cookie
和resp.addCookie(cookie)
响应给浏览器
4.3.4. cookie案例-显示上次访问时间
目标:
学会如何使用Cookie技术实现显示用户上次的访问时间的功能
步骤:
- 创建Servlet,通过Date输出当前系统时间
- 要显示上次访问时间,就把这个date放到浏览器端,让浏览器保存,下次请求时再把时间给带过来
- 要在浏览器端保存,就需要浏览器去更新cookie,把当前这次访问的时间记录到cookie当中,在下次请求时发过来。
- 配置映射信息,查看运行效果
- 解决空格乱码
代码
@WebServlet("/LastAccessServlet")
public class LastAccessServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//正确拿到浏览器中的cookies数组
Cookie[] cookies = req.getCookies();
String cookieName = "lastAccess";
String lastTime = null;
String returnMsg;
//如果cookies数组中有cookie的name参数 = “lastAccess”
//那么就用lastTime字符串获取它的值,即上次访问时间
if(cookies != null){
for (Cookie cookie : cookies) {
if(cookieName.equals(cookie.getName())){ //如果有上次访问时间
lastTime = cookie.getValue();
lastTime = URLDecoder.decode(lastTime);
}
}
}
//如果lastTime不为空,就输出上次访问时间
//如果lastTime为空,就要告诉浏览器,这是你的首次访问
if(lastTime == null){
returnMsg = "first Access!";
} else {
returnMsg = "last Access at : " + lastTime;
}
//通过Date获得当前系统时间,使用字符串str接收时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String str = sdf.format(new Date());
//告诉浏览器更新访问时间
Cookie cookie = new Cookie(cookieName, URLEncoder.encode(str));
resp.addCookie(cookie);
resp.getWriter().append(returnMsg);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
第一次访问,请求标头中没有cookie,响应中有
第二次访问,显示了上次访问的时间,请求中也有了cookie
解决了空格报异常的问题:
问题及解决办法
问题:Cookie中存在无效字符
解决办法:空格 改为 #
解决办法2:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd#HH:mm:ss");
//告诉浏览器更新访问时间
Cookie cookie = new Cookie(cookieName, sdf.format(new Date()));
改为:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String str = sdf.format(new Date());
//告诉浏览器更新访问时间
Cookie cookie = new Cookie(cookieName, URLEncoder.encode(str));
给lastTime增加一个解码的lastTime = URLDecoder.decode(lastTime);
4.3.5.创建session-浏览器查看对应cookie-JSESSIONID
Seesion对象(讲解)
- 什么是Session?
- Session技术就好比医院发放给病人的就医卡和医院为每个病人保留病历档案的过程。
医生通过就医卡可以查到病人的就诊信息。 - 当浏览器访问Web服务器时,Seevlet容器就会创建一个Session对象和ID属性。Sesiion对象就相当于病历档案,ID就相当于就医卡号。
通常,Session借助Cookie技术来传递ID属性的。
(Cookie数据保存在浏览器上,Session数据保存在服务器上)
- HttpSession API
- Session超时管理
在一定时间内,如果某个客户端一直没有请求访问,那么,Web服务器会认为客户端已经结束请求,将对应的Session对象变成垃圾对象,并进行清除。反之,Web服务器会创建一个新的Session对象,并分配一个新的ID属性。
会话时间在web.xml文件中设置。
目标:
生成一个Session对象,把数据在页面上呈现出来,在浏览器这端能看到cookie信息
代码:
@WebServlet("/SessionInfoServlet")
public class SessionInfoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
HttpSession session = req.getSession(true);
if(session == null){
writer.println("没有get到session对象");
return;
}
writer.println("session id: " + session.getId());
writer.println("session created at: " + session.getCreationTime());
writer.println("session LastAccessedTime at: " + session.getLastAccessedTime());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
服务器在创建session时,每个session都有编号,服务器把session id以cookie的形式发给浏览器,浏览器收到后就保存起来。下次请求时,浏览器就把JSession id发给服务器。
创建时间created at,上次访问时间LastAccessedTime,每次刷新,创建时间不变,上次访问时间改变。
问题及解决办法
第一次访问时,中文乱码
解决中文乱码:
在doGet方法的最开始加一个句resp.setContentType("text/html;charset=utf-8");
4.3.6.给session添加数据-attribute
步骤:
- 在代码中写一个session
- 通过setAttribute方法,添加了两个数据
- 在另一个Servlet中,先获取这个session,然后再getAttribute方法读这两个数据
- 如果浏览器关掉,cookie就没有了,所以两个数据都为null了
代码:
@WebServlet("/SessionSetAttributeServlet")
public class SessionSetAttributeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
HttpSession session = req.getSession(true);
session.setAttribute("user","zhang3");
session.setAttribute("age","20");
writer.println("session id: " + session.getId());
writer.println("数据已设置");
writer.append("Served at: ").append(req.getContextPath());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
@WebServlet("/SessionGetAttributeServlet")
public class SessionGetAttributeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
HttpSession session = req.getSession(true);
writer.println("session id: " + session.getId());
writer.println("session user: " + session.getAttribute("user"));
writer.println("session age: " + session.getAttribute("age"));
writer.append("Served at: ").append(req.getContextPath());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
4.3.7.基于session的能保存状态的用户登陆案例
1. 目标与流程分析
- 用户通过浏览器,先请求一个静态资源:
/login.html
,这个页面呈现的就是账号框、密码框、提交按钮。 - 用户填写好后,点击提交,这个提交的
action
会提交到另外一个servlet
:/login
,它负责验证账号密码。 - 如果登录成功,让它重定向到:
/home
,在这个页面要展示已登录账号的用户名、退出登录按钮。 - 如果验证失败,就重定向到表单:
/login.html
,去重新填写账号密码 - 如果用户没有登录,直接在浏览器中输入
/home
来访问,就要在servlet
中查询当前用户登录的状态,如果是登录的就展示用户信息,如果没登录,告诉浏览器让它重定向到:/login.html
中 - 如果在
/home
页面点击了退出登录,浏览器发送退出登录请求:/logout
总结:一个可登录的页面:/login.html
,/login
负责验证,登录成功转到/home
,当用户点击退出按钮,就访问servlet
:/logout
,把登录信息删掉。
登录状态用session
来保存,在session
中添加一个user
数据,如果有这个user
数据,我们就认为当前是登录状态,如果没有user
数据,就认为它是非登录状态。
代码
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String pwd = req.getParameter("pwd");
if ("123".equals(pwd)) {
req.getSession().setAttribute("user", username);
//如果登录成功,重定向跳转
resp.sendRedirect("/ch0407_war_exploded/home");
} else {
//如果验证失败,重定向跳转到login.html
resp.sendRedirect("/ch0407_war_exploded/login.html");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码方式
resp.setContentType("text/html;charset=utf-8");
//判断用户是否在登录状态,如果不在登录状态,要重定向到login.html
HttpSession session = req.getSession();
//如果有session对象,并且session对象当中已经保存了user
if (session != null && session.getAttribute("user") != null) {
//展示信息
resp.getWriter().append("<!DOCTYPE html>")
.append("<html lang=\"en\">")
.append("<head>")
.append("<meta charset=\"UTF-8\">")
.append("<title>Title</title>")
.append("</head>")
.append("<body>")
.append("<h1>管理首页</h1>")
.append("<h4>登录用户:" + session.getAttribute("user") + "</h4>")
.append("<a href='logout'>退出登录</a><br/>")
.append("添加成绩<br/>")
.append("修改成绩<br/>")
.append("....<br/>")
.append("</body>")
.append("</html>");
} else {
//重定向
resp.sendRedirect("/ch0407_war_exploded/login.html");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//删除session中的数据
if (req.getSession() != null) {
req.getSession().removeAttribute("user");
}
//重定向到login.html
resp.sendRedirect("/ch0407_war_exploded/login.html");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
访问home,重定向到login.html
两次请求,第一次请求home,它的响应是302、location
输入账号密码,如果密码错误,会重定向到login.html
登录成功后,跳转到home页面,显示用户信息
点击退出登录后,跳转到login.html,同时数据被删除。此时直接进home页面会重定向到login.html
问题及解决办法
用户名为中文时,home页面显示乱码
解决办法:
告诉tomcat,对方发过来的数据是utf-8的。req.setCharacterEncoding("utf-8");