触点数字孪生,揭秘它的独特魅力
642
2022-10-17
Servlet笔记三(会话及其会话技术)
文章目录
Cookie 对象
Cookie API 构造方法 Cookie 类的常用方法实例
Session对象
HttpSession APIHttpSession 接口中的常用方法Session超时管理Session 对象的两个应用实例
实现购物车
1. 用于创建封装图书信息类2. 创建数据库模拟类3. 创建Servlet
实现用户登录
1. 创建封装用户的信息类2. 创建Servlet3. 创建登录页面4. 启动项目,查看结果
利用 Session 实现一次性验证码
当用户通过浏览器访问Web应用时,通常情况下,服务器需要对用户的状态进行跟踪,例如:用户在网站结算商品时,Web服务器必须根据请求用户的身份,找到该用户所购买的商品。在Web开发中,服务器跟踪用户信息的技术称为会话技术。为了保存会话过程中产生的数据,在Servlet技术中,提供了两个保存会话数据的对象,分别是 Cookie 和 Session。
Cookie 对象
Cookie 是一种会话技术,它用于将会话过程中的数据保存到用户的浏览器中,从而使浏览器和服务器可以更好地进行数据交互。
在 Web 应用中,Cookie 的功能类似于会员卡,当用户通过浏览器访问 Web 应用时,服务器会给客户端发送一些信息,这些信息都保存在 Cookie 中。这样,当该浏览器再次访问服务器时,都会在请求头中将 Cookie 发送给服务器,方便服务器对浏览器做出正确的响应。
服务器向客户端发送 Cookie 时,会在 HTTP 响应头字段中增加 Set-Cookie 响应头字段。
Set-Cookie字段格式如下
Set-Cookie: user=itcast; Path=/;
Cookie API
为了封装 Cookie 信息,在 Servlet API 中提供了一个 javax.servlet.类,该类包含了生成 Cookie 信息和提取 Cookie 信息各个属性的方法。
构造方法
在 Cookie 的构造方法中,参数 name 用于指定 Cookie 的名称,value 用于指定 Cookie 的值,Cookie 一旦创建,它的名称就不能更改,Cookie 的值可以为任何值,创建后允许被修改。
public Cookie(String name, String value)
Cookie 类的常用方法
获取 request 对象的所有 Cookie 信息
Cookie[] cookies = request.getCookies();
方法 | 说明 |
Cookie[] getCookies() | 获取所有的Cookie对象,并存放在数组中 |
注意:Cookie 对象的 Max-Age 属性的值默认是 -1,即浏览器关闭时,删除这个 Cookie 对象。
实例
@WebServlet("/time")public class LastAccessServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=utf-8"); String lasttime = null; // 获取所有的cookie,并存放在数组中 Cookie[] cookies = req.getCookies(); // 遍历cookie数组 for (int i = 0; i < cookies.length; i++) { if("lastAccess".equals(cookies[i].getName())){ lasttime = cookies[i].getValue(); break; } } // 判断是否存在名称为lastAccess的cookie if(lasttime==null){ resp.getWriter().println("首次登录"); }else{ resp.getWriter().println("上次访问的时间是:" + lasttime); } // 创建cookie,将当前时间作为cookie的值发送给客户端 Cookie cookie = new Cookie(("lastAccess"), LocalDateTime.now().toString()); resp.addCookie(cookie); }}
show第一次访问
第二次访问
Session对象
Cookie 技术可以将用户的信息保存在各自的浏览器中,并且可以在多次请求下实现数据的共享。但是,如果传递的信息比较多,使用 Cookie 技术显然会增大服务器端程序处理的难度,这时,可以使用 Session 技术。Session 是一种将会话数据保存到服务器端的技术。
当浏览器访问 Web 服务器时,Servlet 容器就会创建一个 Session 对象(保存在服务器)和 ID 属性(返回给浏览器),当客户端后续访问服务器时,只要将标识号传递给服务器,服务器就能判断出该请求是哪个客户端发送的,从而选择与之对应的 Session 对象为其服务。 需要注意的是,由于客户端需要接收、记录和回送 Session 对象的 ID,因此,通常情况下,Session 是借助 Cookie 技术来传送 ID 属性的。
HttpSession API
HttpServletRequest 定义了用于获取 Session 对象的 getSession() 方法,该方法有两种重载形式:
public HttpSession getSession(boolean create)public HttpSession getSession()
上面重载的两个方法都用于返回与当前请求相关的 HttpSession 对象。不同的是,第 1 个 getSession() 方法根据传递的参数来判断是否创建新的 HttpSession 对象,如果参数为 true,则在相关的 HttpSession 对象不存在时创建并返回新的 HttpSession 对象,否则不创建新的 HttpSession 对象,而是返回 null。第 2 个 getSession() 方法则相当于第 1 个方法参数为 true 时的情况,在相关的 HttpSession 对象不存在时总是创建新的 HttpSession 对象。
注意:由于 getSession() 方法可能会产生发送会话标识号的 Cookie 头字段,因此,必须在发送任何响应内容之前调用 getSession() 方法。
HttpSession 接口中的常用方法
Session超时管理
在一定时间内,如果某个客户端一直没有请求访问,那么,Web 服务器就会认为该客户端已经结束请求,并且将与该客户端会话对应的 HttpSession 对象变成垃圾对象,等待垃圾收集器将其从内存中清除。反之,如果浏览器超时后,再次向服务器发出请求访问,那么,Web 服务器则会创建一个新的 HttpSession 对象,并为其分配一个新的 ID 属性。
在会话过程中,会话的有效时间可以在 web.xml 文件中设置,其默认值由 Servlet 容器定义。
在上述配置信息中,配置的时间值是以分钟为单位的,如果
Session 对象的两个应用实例
实现购物车
当用户使用浏览器访问某个网站的图书列表页面时,如果购买某一本书,那么首先会判断书籍是否存在,如果存在就加入购物车,跳转到购物车中所购买的列表页面。否则,返回图书列表页面。
1. 用于创建封装图书信息类
import java.io.Serializable;// 用于封装图书信息public class Book implements Serializable { private static final long serialVersionUID = 1L; private String id; private String name; public Book(){ } public Book(String id, String name){ this.id = id; this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
2. 创建数据库模拟类
import java.util.Collection;import java.util.LinkedHashMap;import java.util.Map;// 用于模拟保存所有图书的数据库public class BookDB { private static Map
3. 创建Servlet
1)创建一个名称为 ListServlet 的 Servlet 类,该 Servlet 用于显示所有可购买图书的列表,通过单击 “购买” 链接,便可将指定的图书添加到购物车中。
2)创建一个名称为 PurchaseServlet 的 Servlet 类,实现了两个功能,一个是将用户购买的图书信息保存到 Session 对象中;一个实在用户购买图书结束后,将页面重定向到用户已经购买的图书列表。该类在实现时,通过 ArrayList 集合模拟了一个购物车,然后将购买的所有图书添加到购物车中,最后通过 Session 对象传递给 CartServlet,由 CartServlet 展示用户已经购买的图书。
import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.java.io.IOException;import java.util.ArrayList;import java.util.List;@WebServlet("/PurchaseServlet")public class PurchaseServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获得用户购买的商品 String id = req.getParameter("id"); if(id == null){ // 如果id为null,重定向到ListBookServlet页面 String url = "/ListServlet"; resp.sendRedirect(url); return; } Book book = BookDB.getBook(id); // 创建或者获得用户的Session对象 HttpSession session = req.getSession(); // 从Session对象中获得用户的购物车 List
3)创建一个名称为 CartServlet 的 Servlet 类,该类用于展示用户已经购买的图书列表
实现用户登录
当用户访问某个网站的首页时,首先会判断用户是否登录,如果已经登录则在首页中显示用户登录信息,否则进入登录页面,完成用户登录功能,然后显示用户登录信息。在用户登录的情况下,如果单击用户登录界面中的 “退出” 时,就会注销当前用户的信息,返回首界面。
1. 创建封装用户的信息类
public class User { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }}
2. 创建Servlet
该 Servlet 用于显示网站的首页,如果用户没有登录,那么首界面会提示用户登录,否则,显示用户已经登录的信息。为了判断用户是否登录,该类在实现时,获取了保存用户信息的 Session 对象。
@WebServlet("/index")public class IndexServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); HttpSession session = req.getSession(); User user = (User)session.getAttribute("user"); if(user == null){ out.println("您还没有登录, 请 登录"); }else{ out.println("欢迎您," + user.getUsername() + "
"); out.println("退出"); Cookie cookie = new Cookie("JSESSIONID", session.getId()); cookie.setPath("/"); cookie.setMaxAge(60 * 30); resp.addCookie(cookie); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); }}
该 Servlet 用于显示用户登录成功后的界面,如果用户登录成功,则跳转到网站首页,否则,则提示给用户登录失败。
@WebServlet("/login")public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=utf-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); PrintWriter out = resp.getWriter(); System.out.println(username + password); if("admin".equals(username) && "123".equals(password)){ User user = new User(); user.setUsername(username); user.setPassword(password); HttpSession session = req.getSession(); session.setAttribute("user", user);// Cookie cookie = new Cookie("JSESSIONID", session.getId());// cookie.setMaxAge(60 * 30);// cookie.setPath("/");// resp.addCookie(cookie); resp.sendRedirect("/index"); }else{ out.write("用户名或密码错误,登录失败
"); out.println("返回"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); }}
该 Servlet 用于完成用户注销功能,当用户单击 退出 时,该类会将 Session 对象中的用户信息移除,并跳转到网站的首界面。
@WebServlet("/LogoutServlet")public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getSession().removeAttribute("user"); resp.sendRedirect("/index"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); }}
3. 创建登录页面
login.html,该页面中包含用户登录表单信息
4. 启动项目,查看结果
直接访问首页
登录页面
登录失败后
利用 Session 实现一次性验证码
一次性验证码的功能同样可以使用 Session 来实现,这里要实现的验证码是 4 个随机字符,需要对上面的第二个应用案例进行改写,增加一次性验证码的实现。
1)修改表单页面 login.html,增加验证码的输入框和验证码图片,其中验证码的图片来自 CheckServlet 类。
2)编写 CheckServlet 类,用于产生验证码图片
package com.lz.jiaotong.wanghengbo;import javax.imageio.ImageIO;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.javax.servlet.javax.servlet.javax.servlet.java.awt.*;import java.awt.image.BufferedImage;import java.io.ByteArrayOutputStream;import java.io.IOException;public class CheckServlet extends HttpServlet { private static int WIDTH = 60; private static int HEIGHT = 20; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); resp.setContentType("image/jpeg"); ServletOutputStream sos = resp.getOutputStream(); // 设置浏览器不缓存此图片 resp.setHeader("Pragma", "No-cache"); resp.setHeader("Cache-Control", "non-cache"); resp.setDateHeader("Expires", 0); // 创建内存图形并获得其图形上下文 BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); // 产生随机的验证码 char[] rands = generateCheckCode(); // 产生图像 drawBackground(g); drawRands(g, rands); // 结束图像的绘制,完成图像 g.dispose(); // 将图像输出到客户端 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(image, "JPEG", bos); byte[] buf = bos.toByteArray(); resp.setContentLength(buf.length); sos.write(buf); bos.close(); sos.close(); // 将当前验证码存入到Session中 session.setAttribute("check_code", new String(rands)); } // 生成一个4字符的验证码 private char[] generateCheckCode(){ String chars = "0123456789abcdefghigklmnopqrstuvwxyz"; char[] rands = new char[4]; for (int i = 0; i < 4; i++) { int rand = (int)(Math.random() * 36); rands[i] = chars.charAt(rand); } return rands; } private void drawRands(Graphics g, char[] rands){ g.setColor(Color.BLACK); g.setFont(new Font(null, Font.ITALIC|Font.BOLD, 18)); // 在不同高度上输出验证码的每个字符 g.drawString("" + rands[0], 1, 17); g.drawString("" + rands[1], 16, 15); g.drawString("" + rands[2], 31, 18); g.drawString("" + rands[3], 46, 16); System.out.println(rands); } private void drawBackground(Graphics g){ // 画背景 g.setColor(new Color(0xDCDCDC)); g.fillRect(0, 0, WIDTH, HEIGHT); // 随机产生120个干扰点 for (int i = 0; i < 120; i++) { int x = (int)(Math.random() * WIDTH); int y = (int)(Math.random() * HEIGHT); int red = (int)(Math.random() * 255); int green = (int)(Math.random() * 255); int blue = (int)(Math.random() * 255); g.setColor(new Color(red, green, blue)); g.drawOval(x, y, 1, 0); } }}
3)对 LoginServlet 类进行修改,增加对验证码的判断。
@WebServlet("/login")public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); String username = req.getParameter("username"); String password = req.getParameter("password"); String checkCode = req.getParameter("check_code"); String savedCode = (String)req.getSession().getAttribute("check_code"); if("admin".equals(username) && "123".equals(password) && checkCode!=null && checkCode.equals(savedCode)){ User user = new User(); user.setUsername(username); user.setPassword(password); HttpSession session = req.getSession(); session.setAttribute("user", user); resp.sendRedirect("/index"); }else if(checkCode!=null && checkCode.equals(savedCode)){ out.write("用户名或密码错误,登录失败
"); out.println("返回"); }else{ out.println("验证码错误"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); }}
4)效果展示
验证码输入错误后
验证码和密码同时输入正确
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。