image.png

什么是会话技术

1.用户打开同一个浏览器,访问到我们的web服务器的资源建立会话,对方断开连接该会话才会结束,在一次会话中可以包含多次请求和响应。通俗易懂的理解:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于用一个浏览器,以便于在同一次会话的多次请求间共享数据。
2.这是因为http协议是无状态的,每次浏览器向服务器请求时,没有绑定会话信息服务器都会认为该请求是为新请求,没有任何记忆功能,所以我们需要会话跟踪技术实现会话内数据共享。
会话技术实现方式
实现方式:
1.客户端会话跟踪技术:Cookie
2.服务端会话跟踪技术:Session
3.token或者jwt——新的

cookie

什么是Cookie

Cookie:客户端会话技术,将数据保存到客户端,以后每次请求都携带Cookie数据进行访问
Cookie 数据存放在浏览器端(客户端)

创建Cookie

1.创建Cookie
Cookie cookie = new Cookie(“key”,”value”);
2.使用response响应Cookie给客户端(浏览器)
response.addCookie(cookie);
3.使用response响应Cookie给客户端(浏览器)
image.png

获取Cookie

获取客户端携带的所有Cookie,使用request对象

  1. Cookie[] cookies = request.getCookies();
  2. cookie.getName();
  3. cookie.getValue();
  1. package com.mayikt.servlet;
  2. import jakarta.servlet.ServletException;
  3. import jakarta.servlet.annotation.WebServlet;
  4. import jakarta.servlet.http.Cookie;
  5. import jakarta.servlet.http.HttpServlet;
  6. import jakarta.servlet.http.HttpServletRequest;
  7. import jakarta.servlet.http.HttpServletResponse;
  8. import java.io.IOException;
  9. /**
  10. * @author 余胜军
  11. * @ClassName AddCookieServlet
  12. * @qq 644064779
  13. * @addres www.mayikt.com
  14. * 微信:yushengjun644
  15. */
  16. @WebServlet("/addCookieServlet")
  17. public class AddCookieServlet extends HttpServlet {
  18. @Override
  19. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  20. Cookie cookie = new Cookie("mayikt", "yushengjun");
  21. resp.addCookie(cookie);
  22. }
  23. }
  24. package com.mayikt.servlet;
  25. import jakarta.servlet.ServletException;
  26. import jakarta.servlet.annotation.WebServlet;
  27. import jakarta.servlet.http.Cookie;
  28. import jakarta.servlet.http.HttpServlet;
  29. import jakarta.servlet.http.HttpServletRequest;
  30. import jakarta.servlet.http.HttpServletResponse;
  31. import java.io.IOException;
  32. /**
  33. * @author 余胜军
  34. * @ClassName GetCookieServlet
  35. * @qq 644064779
  36. * @addres www.mayikt.com
  37. * 微信:yushengjun644
  38. */
  39. @WebServlet("/getCookieServlet")
  40. public class GetCookieServlet extends HttpServlet {
  41. @Override
  42. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  43. Cookie[] cookies = req.getCookies();
  44. for (int i = 0; i < cookies.length; i++) {
  45. Cookie cookie = cookies[i];
  46. System.out.println("key:" + cookie.getName() + "," +cookie.getValue());
  47. }
  48. }
  49. }

在没有清理浏览器缓存的情况下?请问重启tomcat服务器?cookie数据会丢失吗?
不会的

Cookie的原理解析

基本实现原理

Cookie实现是基于HTTP协议的
1.响应头:set—cookie
客户端(浏览器端)发送请求达到服务器端,服务器端会创建cookie,会将该cookie数据
返回给客户端,在响应头中设置 set—cookie value cookie数据。
image.png
2.请求头:cookie
同一个浏览器发送请求时,在请求中设置该cookie数据 存放在请求头中。
cookie value

Cookie过期时间

setMaxAge(int seconds):设置Cookie存活时间
1.正数:将Cookie写入浏览器所在的电脑硬盘,持久化存储,到期自动删除
2.负数:默认值,Cookie存储在浏览器内存中,当浏览器关闭,内存释放,则Cookie被销毁。
3.零:删除对应Cookie

session使用

1.服务器端会话跟踪技术:将数据保存在服务器端
底层基于cookie实现封装的
2.常用的API:
2.1void session.setAttribute(k,v) session存入值 key=name,value ‘yushengjun’
2.2Object session.getAttribute(k) 获取到session中的值
2.3void removeAttribute(k) 删除我们的session

session原理

1.当我们客户端发送请求达到服务器端时创建session,会得到一个sessionid,在将该
sessionid 响应在响应头
2.客户端(浏览器)接受响应头中的sessionid ,会将该sessionid的值 存放在浏览器中。
session本质上就是基于cookie实现封装的。
3.使用同一个浏览器发送请求时,访问通一个服务器端,会在请求头中设定该sessionid 的值,服务器端就会从请求头中获取到该sessionid 查找对应session。
session 数据存放在服务器端 cookie将数据存放在本地。

image.png

session细节

1.当客户端关闭后,服务器不关闭的话,获取到的session是否是同一个。因为客户端关闭后,cookie对象被销毁,客户端请求服务器会创建新的session。如果需要相同,可以设置cookie的最大存活时间,让cookie持久化保存两次获取Session是否为同一个
2.在默认情况下,不是同一个。如果需要两个Session相同,则可以创建一个Cookie对象,key为:JSESSIONID,设置一下最大存活时间,让Cookie持久化保存Session的ID,就可以实现客户端关闭,两次获取Session就是同一个。

  1. Cookie c = new Cookie("JSESSIONID",session.getId());
  2. c.setMaxAge(60*60); //1个小时有效期
  3. response.addCookie(c);

2.客户端不关闭,服务器关闭后的话,两次获取的Session是同一个吗?
不是同一个,但是为了确保数据不丢失,因为同样服务器关闭后session对象会被销毁 ,如果想确保数据不丢失,可以使session钝化,即在服务器正常关闭之前,将session对象序列化到硬盘上。下次在服务器启动后,将session文件反序列化转化为内存中的session对象即可。
0D202066E021E4F4FB978F1647C0D742
tomcat自动完成以下工作:
1.session的钝化:在服务器正常关闭之前,将session对象系列化到硬盘上。
2.session的活化: 在服务器启动后,将session文件转化为内存中的session对象即可。
3.session什么时候被销毁?
1.服务器关闭;
2.session对象调用invalidate() ;
3.session默认失效时间 30分钟。
token—-

session与cookie区别

1.session用于存储一次会话的多次请求的数据,存在服务器端;
2.session可以存储任意类型,任意大小的数据。
session与Cookie的区别:
1.session存储数据在服务器端,Cookie在客户端;
2.session没有数据大小限制,Cookie有数据大小限制;
3.session数据安全,Cookie相对于不安全。

用户登录注册案例

用户登录

使用session保存用户会话信息。

数据库访问层

  1. package com.mayikt.dao;
  2. import com.mayikt.entity.MayiktUserEntity;
  3. import com.mayikt.utils.MayiktJdbcUtils;
  4. import java.sql.Connection;
  5. import java.sql.PreparedStatement;
  6. import java.sql.ResultSet;
  7. /**
  8. * @author 余胜军
  9. * @ClassName MayiktDao
  10. * @qq 644064779
  11. * @addres www.mayikt.com
  12. * 微信:yushengjun644
  13. */
  14. public class MayikUsertDao {
  15. /**
  16. * 用户登录成功之后 该方法返回 用户登录成功之后对象
  17. */
  18. public MayiktUserEntity login(String userName, String userPwd) {
  19. try {
  20. Connection connection = MayiktJdbcUtils.getConnection();
  21. String loginSql = "select * from mayikt_users where userName=? and userPwd=?;";
  22. PreparedStatement preparedStatement = connection.prepareStatement(loginSql);
  23. preparedStatement.setString(1, userName);
  24. preparedStatement.setString(2, userPwd);
  25. ResultSet resultSet = preparedStatement.executeQuery();
  26. if (!resultSet.next()) { // 查询不到用户数据
  27. return null;
  28. }
  29. // 将db中数据 返回给客户端 查询到数据
  30. Integer id = resultSet.getInt(1);
  31. String dbUserName = resultSet.getString(2);
  32. String dbUserPwd = resultSet.getString(3);
  33. MayiktUserEntity mayiktUserEntity = new MayiktUserEntity(id, dbUserName, dbUserPwd);
  34. return mayiktUserEntity;
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. return null;
  38. }
  39. }
  40. }

业务逻辑层

  1. package com.mayikt.service;
  2. import com.mayikt.dao.MayikUsertDao;
  3. import com.mayikt.entity.MayiktUserEntity;
  4. /**
  5. * @author 余胜军
  6. * @ClassName MayikUsertService
  7. * @qq 644064779
  8. * @addres www.mayikt.com
  9. * 微信:yushengjun644
  10. */
  11. public class MayikUsertService {
  12. private MayikUsertDao mayikUsertDao = new MayikUsertDao();
  13. public MayiktUserEntity login(String userName, String userPwd) {
  14. return mayikUsertDao.login(userName, userPwd);
  15. }
  16. }

视图层

  1. package com.mayikt.servlet;
  2. import com.mayikt.entity.MayiktUserEntity;
  3. import com.mayikt.service.MayikUsertService;
  4. import jakarta.servlet.ServletException;
  5. import jakarta.servlet.annotation.WebServlet;
  6. import jakarta.servlet.http.HttpServlet;
  7. import jakarta.servlet.http.HttpServletRequest;
  8. import jakarta.servlet.http.HttpServletResponse;
  9. import jakarta.servlet.http.HttpSession;
  10. import org.apache.commons.lang3.StringUtils;
  11. import java.io.IOException;
  12. /**
  13. * @author 余胜军
  14. * @ClassName LoginServlet
  15. * @qq 644064779
  16. * @addres www.mayikt.com
  17. * 微信:yushengjun644
  18. */
  19. @WebServlet("/login")
  20. public class LoginServlet extends HttpServlet {
  21. private MayikUsertService mayikUsertService = new MayikUsertService();
  22. @Override
  23. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  24. // 转发login页面
  25. req.getRequestDispatcher("login.jsp").forward(req, resp);
  26. }
  27. @Override
  28. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  29. // 点击登录的时候 获取到用户的参数
  30. String userName = req.getParameter("userName");
  31. if (StringUtils.isEmpty(userName)) {
  32. //转发到错误页面
  33. req.setAttribute("errorMsg", "用户名称不能够是为空!");
  34. req.getRequestDispatcher("error.jsp").forward(req, resp);
  35. return;
  36. }
  37. String userPwd = req.getParameter("userPwd");
  38. // 参数验证
  39. if (StringUtils.isEmpty(userPwd)) {
  40. //转发到错误页面
  41. req.setAttribute("errorMsg", "userPwd不能够是为空!");
  42. req.getRequestDispatcher("error.jsp").forward(req, resp);
  43. return;
  44. }
  45. // 在调用业务逻辑层
  46. MayiktUserEntity mayiktUserEntity = mayikUsertService.login(userName, userPwd);
  47. if (mayiktUserEntity == null) {
  48. // 用户名称或者密码错误!
  49. req.setAttribute("errorMsg", "用户名称或者是密码错误!");
  50. req.getRequestDispatcher("login.jsp").forward(req, resp);
  51. return;
  52. }
  53. // 能够db中查询到对象 登录成功了 将用户数据存放在session中
  54. HttpSession session = req.getSession();
  55. session.setAttribute("user", mayiktUserEntity);
  56. // 在转发到首页(重定向到首页)
  57. // req.getRequestDispatcher("index.jsp").forward(req, resp);
  58. resp.sendRedirect("index.jsp");
  59. }
  60. }
  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: mayikt
  4. Date: 2022/6/6
  5. Time: 17:12
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <!DOCTYPE html>
  10. <html>
  11. <head>
  12. <title>登录测试页面</title>
  13. <form action="/mayikt_session_war_exploded/login" method="post">
  14. <label>用户名: </label><input type="text" name="userName"/><br>
  15. <label>密&nbsp码&nbsp: </label><input type="password" name="userPwd"/><br>
  16. ${errorMsg}
  17. <input type="submit" value="登录 "/>
  18. </form>
  19. </head>
  20. </html>

相关配置文件

  1. driverClass=com.mysql.cj.jdbc.Driver
  2. url=jdbc:mysql://127.0.0.1:3306/mayikt?serverTimezone=GMT%2B8
  3. user=root
  4. password=root

记住密码

思路:
用户登录成功之后,会将用户的名称和密码 写入在cookie中,
当我们用户下次登录时,会直接从cookie中获取到数据 回显到
login.jsp中 这样的话就不需要用户重复的数据用户名称和密码。

image.png

改造servlet

  1. package com.mayikt.servlet;
  2. import com.mayikt.entity.MayiktUserEntity;
  3. import com.mayikt.service.MayikUsertService;
  4. import jakarta.servlet.ServletException;
  5. import jakarta.servlet.annotation.WebServlet;
  6. import jakarta.servlet.http.*;
  7. import org.apache.commons.lang3.StringUtils;
  8. import java.io.IOException;
  9. /**
  10. * @author 余胜军
  11. * @ClassName LoginServlet
  12. * @qq 644064779
  13. * @addres www.mayikt.com
  14. * 微信:yushengjun644
  15. */
  16. @WebServlet("/login")
  17. public class LoginServlet extends HttpServlet {
  18. private MayikUsertService mayikUsertService = new MayikUsertService();
  19. @Override
  20. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  21. // 转发login页面
  22. req.getRequestDispatcher("login.jsp").forward(req, resp);
  23. }
  24. @Override
  25. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  26. // 点击登录的时候 获取到用户的参数
  27. String userName = req.getParameter("userName");
  28. if (StringUtils.isEmpty(userName)) {
  29. //转发到错误页面
  30. req.setAttribute("errorMsg", "用户名称不能够是为空!");
  31. req.getRequestDispatcher("error.jsp").forward(req, resp);
  32. return;
  33. }
  34. String userPwd = req.getParameter("userPwd");
  35. // 参数验证
  36. if (StringUtils.isEmpty(userPwd)) {
  37. //转发到错误页面
  38. req.setAttribute("errorMsg", "userPwd不能够是为空!");
  39. req.getRequestDispatcher("error.jsp").forward(req, resp);
  40. return;
  41. }
  42. // 在调用业务逻辑层
  43. MayiktUserEntity mayiktUserEntity = mayikUsertService.login(userName, userPwd);
  44. if (mayiktUserEntity == null) {
  45. // 用户名称或者密码错误!
  46. req.setAttribute("errorMsg", "用户名称或者是密码错误!");
  47. req.getRequestDispatcher("login.jsp").forward(req, resp);
  48. return;
  49. }
  50. // 判断用户是否记住密码
  51. String rememberPassword = req.getParameter("rememberPassword");
  52. if ("on".equals(rememberPassword)) {
  53. // 如果有记住密码则 将密码保存在cookie中
  54. Cookie userNameCookie = new Cookie("userName", userName);
  55. Cookie userPwdCookie = new Cookie("userPwd", userPwd);
  56. resp.addCookie(userNameCookie);
  57. resp.addCookie(userPwdCookie);
  58. }
  59. // 能够db中查询到对象 登录成功了 将用户数据存放在session中
  60. HttpSession session = req.getSession();
  61. session.setAttribute("user", mayiktUserEntity);
  62. // 在转发到首页(重定向到首页)
  63. // req.getRequestDispatcher("index.jsp").forward(req, resp);
  64. resp.sendRedirect("index.jsp");
  65. }
  66. }

改造jsp

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: mayikt
  4. Date: 2022/6/6
  5. Time: 17:12
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <!DOCTYPE html>
  10. <html>
  11. <head>
  12. <title>登录测试页面</title>
  13. <form action="/mayikt_session_war_exploded/login" method="post">
  14. <label>用户名: </label><input type="text" name="userName" value="${cookie.userName.value}"/><br>
  15. <label>密&nbsp码&nbsp: </label><input type="password" name="userPwd" value="${cookie.userPwd.value}"/><br>
  16. <label>记住密码: </label><input type="checkbox" name="rememberPassword"/><br>
  17. ${errorMsg}
  18. <input type="submit" value="登录 "/>
  19. </form>
  20. </head>
  21. </html>

用户注册

数据库访问层

  1. package com.mayikt.dao;
  2. import com.mayikt.entity.MayiktUserEntity;
  3. import com.mayikt.utils.MayiktJdbcUtils;
  4. import java.sql.Connection;
  5. import java.sql.PreparedStatement;
  6. import java.sql.ResultSet;
  7. /**
  8. * @author 余胜军
  9. * @ClassName MayiktDao
  10. * @qq 644064779
  11. * @addres www.mayikt.com
  12. * 微信:yushengjun644
  13. */
  14. public class MayikUsertDao {
  15. /**
  16. * 用户登录成功之后 该方法返回 用户登录成功之后对象
  17. */
  18. public MayiktUserEntity login(String userName, String userPwd) {
  19. ResultSet resultSet = null;
  20. PreparedStatement preparedStatement = null;
  21. Connection connection = null;
  22. try {
  23. connection = MayiktJdbcUtils.getConnection();
  24. String loginSql = "select * from mayikt_users where userName=? and userPwd=?;";
  25. preparedStatement = connection.prepareStatement(loginSql);
  26. preparedStatement.setString(1, userName);
  27. preparedStatement.setString(2, userPwd);
  28. resultSet = preparedStatement.executeQuery();
  29. if (!resultSet.next()) { // 查询不到用户数据
  30. return null;
  31. }
  32. // 将db中数据 返回给客户端 查询到数据
  33. Integer id = resultSet.getInt(1);
  34. String dbUserName = resultSet.getString(2);
  35. String dbUserPwd = resultSet.getString(3);
  36. MayiktUserEntity mayiktUserEntity = new MayiktUserEntity(id, dbUserName, dbUserPwd);
  37. return mayiktUserEntity;
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. return null;
  41. } finally {
  42. MayiktJdbcUtils.closeConnection(resultSet, preparedStatement, connection);
  43. }
  44. }
  45. public MayiktUserEntity findByUserName(String userName) {
  46. ResultSet resultSet = null;
  47. PreparedStatement preparedStatement = null;
  48. Connection connection = null;
  49. try {
  50. connection = MayiktJdbcUtils.getConnection();
  51. String loginSql = "select * from mayikt_users where userName=?";
  52. preparedStatement = connection.prepareStatement(loginSql);
  53. preparedStatement.setString(1, userName);
  54. resultSet = preparedStatement.executeQuery();
  55. if (!resultSet.next()) { // 查询不到用户数据
  56. return null;
  57. }
  58. // 将db中数据 返回给客户端 查询到数据
  59. Integer id = resultSet.getInt(1);
  60. String dbUserName = resultSet.getString(2);
  61. String dbUserPwd = resultSet.getString(3);
  62. MayiktUserEntity mayiktUserEntity = new MayiktUserEntity(id, dbUserName, dbUserPwd);
  63. return mayiktUserEntity;
  64. } catch (Exception e) {
  65. e.printStackTrace();
  66. return null;
  67. } finally {
  68. MayiktJdbcUtils.closeConnection(resultSet, preparedStatement, connection);
  69. }
  70. }
  71. public int register(String userName, String userPwd) {
  72. Connection connection = null;
  73. PreparedStatement preparedStatement = null;
  74. try {
  75. connection = MayiktJdbcUtils.getConnection();
  76. // sql语句写的操作 ----加上事务
  77. MayiktJdbcUtils.beginTransaction(connection); // 开启事务
  78. String insertSql = "INSERT INTO `mayikt`.`mayikt_users` (`id`, `userName`, `userPwd`) VALUES (null, ?, ?);";
  79. preparedStatement = connection.prepareStatement(insertSql);
  80. preparedStatement.setString(1, userName);
  81. preparedStatement.setString(2, userPwd);
  82. int result = preparedStatement.executeUpdate();
  83. // 代码执行没有问题的情况下 则会提交数据
  84. MayiktJdbcUtils.commitTransaction(connection); // 提交事务
  85. return result;
  86. } catch (Exception e) {
  87. // 程序代码报错之后 是需要回滚事务
  88. e.printStackTrace();
  89. MayiktJdbcUtils.rollBackTransaction(connection);// 回滚事务
  90. return 0;
  91. } finally {
  92. MayiktJdbcUtils.closeConnection(preparedStatement, connection);
  93. }
  94. }
  95. }

业务逻辑层

  1. public int register(String userName, String userPwd) {
  2. return mayikUsertDao.register(userName, userPwd);
  3. }
  4. public MayiktUserEntity findByUserName(String userName) {
  5. return mayikUsertDao.findByUserName(userName);
  6. }

视图层

  1. package com.mayikt.servlet;
  2. import com.mayikt.entity.MayiktUserEntity;
  3. import com.mayikt.service.MayikUsertService;
  4. import jakarta.servlet.ServletException;
  5. import jakarta.servlet.annotation.WebServlet;
  6. import jakarta.servlet.http.HttpServlet;
  7. import jakarta.servlet.http.HttpServletRequest;
  8. import jakarta.servlet.http.HttpServletResponse;
  9. import org.apache.commons.lang3.StringUtils;
  10. import java.io.IOException;
  11. /**
  12. * @author 余胜军
  13. * @ClassName RegisterServlet
  14. * @qq 644064779
  15. * @addres www.mayikt.com
  16. * 微信:yushengjun644
  17. */
  18. @WebServlet("/register")
  19. public class RegisterServlet extends HttpServlet {
  20. private MayikUsertService mayikUsertService = new MayikUsertService();
  21. @Override
  22. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  23. // 转发到register.jsp
  24. req.getRequestDispatcher("register.jsp").forward(req, resp);
  25. }
  26. @Override
  27. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  28. // 转发到注册插入数据
  29. // 点击注册的时候 获取到用户的参数
  30. String userName = req.getParameter("userName");
  31. if (StringUtils.isEmpty(userName)) {
  32. //转发到错误页面
  33. req.setAttribute("errorMsg", "用户名称不能够是为空!");
  34. req.getRequestDispatcher("register.jsp").forward(req, resp);
  35. return;
  36. }
  37. String userPwd = req.getParameter("userPwd");
  38. // 参数验证
  39. if (StringUtils.isEmpty(userPwd)) {
  40. //转发到错误页面
  41. req.setAttribute("errorMsg", "userPwd不能够是为空!");
  42. req.getRequestDispatcher("register.jsp").forward(req, resp);
  43. return;
  44. }
  45. // 用户注册之前根据用户名称查询该用户是否存在如果不存在的情况下才可以注册 如果存在的话就无法注册
  46. MayiktUserEntity dbMayiktUserEntity = mayikUsertService.findByUserName(userName);
  47. if (dbMayiktUserEntity != null) {
  48. req.setAttribute("errorMsg", "该用户" + userName + ",在数据库中存在无法重复注册!");
  49. req.getRequestDispatcher("register.jsp").forward(req, resp);
  50. return;
  51. }
  52. //用户数据注册
  53. int register = mayikUsertService.register(userName, userPwd);
  54. if (register <= 0) {
  55. // 注册失败了 //转发到错误页面
  56. req.setAttribute("errorMsg", "注册失败!");
  57. req.getRequestDispatcher("register.jsp").forward(req, resp);
  58. return;
  59. }
  60. // 注册成功之后就直接重定向到登录请求
  61. resp.sendRedirect("login");
  62. }
  63. }
  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: mayikt
  4. Date: 2022/6/6
  5. Time: 17:12
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <!DOCTYPE html>
  10. <html>
  11. <head>
  12. <title>注册页面</title>
  13. <form action="/mayikt_session_war_exploded/register" method="post">
  14. <label>用户名: </label><input type="text" name="userName"/><br>
  15. <label>密&nbsp&nbsp&nbsp码: </label><input type="password" name="userPwd"/><br>
  16. <span style="color: red">${errorMsg}</span>
  17. <input type="submit" value="注册"/>
  18. </form>
  19. </head>
  20. </html>

图形验证码

图形底层实现原理
java支持根据内容生成图片
abcd 企业实际开发中图形验证码工具类 底层细节我们自己去开发的

1.生成图形验证码内容 abch
2.调用java的api 将我们的该内容 生成一张图片abch
3.将该形验证码内容 abch 存放在session中

用户点击注册时:获取用户输入的图形验证码和session中验证码比对 如果一致的情况下
则开始做注册流程。

image.png

图形验证码工具类

  1. package com.mayikt.utils;
  2. import jakarta.servlet.http.HttpServletRequest;
  3. import jakarta.servlet.http.HttpServletResponse;
  4. import jakarta.servlet.http.HttpSession;
  5. import java.awt.Color;
  6. import java.awt.Font;
  7. import java.awt.Graphics;
  8. import java.awt.image.BufferedImage;
  9. import java.util.Random;
  10. import javax.imageio.ImageIO;
  11. /**
  12. * 工具类,生成随机验证码
  13. */
  14. public class RandomValidateCode {
  15. public static final String MAYIKT_RANDOMVALIDATECODE = "RandomValidateCode";// 放到session中的key
  16. private Random random = new Random();
  17. private String randString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生的字符串
  18. private int width = 100;// 图片宽度
  19. private int height = 26;// 图片高度
  20. private int lineSize = 40;// 干扰线数量
  21. private int stringNum = 4;// 随机产生的字符数量
  22. /*
  23. * 获得字体
  24. */
  25. private Font getFont() {
  26. return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
  27. }
  28. /*
  29. * 获得颜色
  30. */
  31. private Color getRandColor(int fc, int bc) {
  32. if (fc > 255)
  33. fc = 255;
  34. if (bc > 255)
  35. bc = 255;
  36. int r = fc + random.nextInt(bc - fc - 16);
  37. int g = fc + random.nextInt(bc - fc - 14);
  38. int b = fc + random.nextInt(bc - fc - 18);
  39. return new Color(r, g, b);
  40. }
  41. /**
  42. * 生成随机图片
  43. */
  44. public void getRandcode(HttpServletRequest request, HttpServletResponse response) {
  45. HttpSession session = request.getSession();
  46. // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
  47. BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
  48. Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,该对象可以在图像上进行各种绘制操作
  49. g.fillRect(0, 0, width, height);
  50. g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));
  51. g.setColor(getRandColor(110, 133));
  52. // 绘制干扰线
  53. for (int i = 0; i <= lineSize; i++) {
  54. drowLine(g);
  55. }
  56. // 绘制随机字符
  57. String randomString = "";
  58. for (int i = 1; i <= stringNum; i++) {
  59. randomString = drowString(g, randomString, i);
  60. }
  61. session.removeAttribute(MAYIKT_RANDOMVALIDATECODE);
  62. session.setAttribute(MAYIKT_RANDOMVALIDATECODE, randomString);
  63. g.dispose();
  64. try {
  65. ImageIO.write(image, "JPEG", response.getOutputStream());// 将内存中的图片通过流动形式输出到客户端
  66. } catch (Exception e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. /*
  71. * 绘制字符串
  72. */
  73. private String drowString(Graphics g, String randomString, int i) {
  74. g.setFont(getFont());
  75. g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));
  76. String rand = getRandomString(random.nextInt(randString.length()));
  77. randomString += rand;
  78. g.translate(random.nextInt(3), random.nextInt(3));
  79. g.drawString(rand, 13 * i, 16);
  80. return randomString;
  81. }
  82. /*
  83. * 绘制干扰线
  84. */
  85. private void drowLine(Graphics g) {
  86. int x = random.nextInt(width);
  87. int y = random.nextInt(height);
  88. int xl = random.nextInt(13);
  89. int yl = random.nextInt(15);
  90. g.drawLine(x, y, x + xl, y + yl);
  91. }
  92. /*
  93. * 获取随机的字符
  94. */
  95. public String getRandomString(int num) {
  96. return String.valueOf(randString.charAt(num));
  97. }
  98. }
  99. package com.mayikt.servlet;
  100. import jakarta.servlet.ServletException;
  101. import jakarta.servlet.annotation.WebServlet;
  102. import jakarta.servlet.http.HttpServlet;
  103. import jakarta.servlet.http.HttpServletRequest;
  104. import jakarta.servlet.http.HttpServletResponse;
  105. import java.io.IOException;
  106. /**
  107. * 前台验证码处点击刷新,发送到该servlet的请求,
  108. * 该servlet调用生成验证码的工具类返回一个图像验证码
  109. */
  110. @WebServlet(name = "VerifycodeServlet", urlPatterns = "/VerifycodeServlet")
  111. public class VerifycodeServlet extends HttpServlet {
  112. private static final long serialVersionUID = 1L;
  113. public void doGet(HttpServletRequest request, HttpServletResponse response)
  114. throws ServletException, IOException {
  115. response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片
  116. response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容
  117. //做浏览器兼容
  118. response.setHeader("Cache-Control", "no-cache");
  119. response.setDateHeader("Expire", 0);
  120. RandomValidateCode randomValidateCode = new RandomValidateCode();
  121. try {
  122. randomValidateCode.getRandcode(request, response);//输出图片方法
  123. } catch (Exception e) {
  124. e.printStackTrace();
  125. }
  126. }
  127. public void doPost(HttpServletRequest request, HttpServletResponse response)
  128. throws ServletException, IOException {
  129. doGet(request, response);
  130. }
  131. }

注册jsp加上图形验证码

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: mayikt
  4. Date: 2022/6/6
  5. Time: 17:12
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <!DOCTYPE html>
  10. <html>
  11. <head>
  12. <title>注册页面</title>
  13. <form action="/mayikt_session_war_exploded/register" method="post">
  14. <label>用户名: </label><input type="text" name="userName"/><br>
  15. <label>密&nbsp&nbsp&nbsp码: </label><input type="password" name="userPwd"/><br>
  16. <label>验证码: </label><input type="text" name="code"/><img id="exchangecode" src="VerifycodeServlet">
  17. <a id="ecode" href="#">看不清?换一张图片</a><br>
  18. <span style="color: red">${errorMsg}</span>
  19. <input type="submit" value="注册"/>
  20. </form>
  21. <script type="text/javascript">
  22. window.onload = function () {
  23. //获取img标签的对象
  24. img = document.getElementById("exchangecode");
  25. img.onclick = function () {
  26. //加时间戳,避免浏览器缓存
  27. var date = new Date().getTime()
  28. img.src = "VerifycodeServlet?" + date;
  29. }
  30. //获取a标签的对象
  31. ec = document.getElementById("ecode");
  32. ec.onclick = function () {
  33. //加时间戳
  34. var date = new Date().getTime()
  35. img.src = "VerifycodeServlet?" + date;
  36. }
  37. }
  38. </script>
  39. </head>
  40. </html>

注册验证图形验证码

  1. package com.mayikt.servlet;
  2. import com.mayikt.entity.MayiktUserEntity;
  3. import com.mayikt.service.MayikUsertService;
  4. import com.mayikt.utils.RandomValidateCode;
  5. import jakarta.servlet.ServletException;
  6. import jakarta.servlet.annotation.WebServlet;
  7. import jakarta.servlet.http.HttpServlet;
  8. import jakarta.servlet.http.HttpServletRequest;
  9. import jakarta.servlet.http.HttpServletResponse;
  10. import jakarta.servlet.http.HttpSession;
  11. import org.apache.commons.lang3.StringUtils;
  12. import java.io.IOException;
  13. /**
  14. * @author 余胜军
  15. * @ClassName RegisterServlet
  16. * @qq 644064779
  17. * @addres www.mayikt.com
  18. * 微信:yushengjun644
  19. */
  20. @WebServlet("/register")
  21. public class RegisterServlet extends HttpServlet {
  22. private MayikUsertService mayikUsertService = new MayikUsertService();
  23. @Override
  24. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  25. // 转发到register.jsp
  26. req.getRequestDispatcher("register.jsp").forward(req, resp);
  27. }
  28. @Override
  29. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  30. // 转发到注册插入数据
  31. // 点击注册的时候 获取到用户的参数
  32. String userName = req.getParameter("userName");
  33. if (StringUtils.isEmpty(userName)) {
  34. //转发到错误页面
  35. req.setAttribute("errorMsg", "用户名称不能够是为空!");
  36. req.getRequestDispatcher("register.jsp").forward(req, resp);
  37. return;
  38. }
  39. String userPwd = req.getParameter("userPwd");
  40. // 参数验证
  41. if (StringUtils.isEmpty(userPwd)) {
  42. //转发到错误页面
  43. req.setAttribute("errorMsg", "userPwd不能够是为空!");
  44. req.getRequestDispatcher("register.jsp").forward(req, resp);
  45. return;
  46. }
  47. // 图形验证码 比较 是在 注册之前
  48. // 比较图形验证码
  49. String userCode = req.getParameter("code"); // 用户输入的图形验证码
  50. // 从session中获取图形验证码
  51. HttpSession session = req.getSession();
  52. String sessionCode = (String) session.getAttribute(RandomValidateCode.MAYIKT_RANDOMVALIDATECODE);
  53. if (!sessionCode.equalsIgnoreCase(userCode)) {
  54. req.setAttribute("errorMsg", "图形验证码不正确,请重新输入!");
  55. req.getRequestDispatcher("register.jsp").forward(req, resp);
  56. return;
  57. }
  58. // 用户注册之前根据用户名称查询该用户是否存在如果不存在的情况下才可以注册 如果存在的话就无法注册
  59. MayiktUserEntity dbMayiktUserEntity = mayikUsertService.findByUserName(userName);
  60. if (dbMayiktUserEntity != null) {
  61. req.setAttribute("errorMsg", "该用户" + userName + ",在数据库中存在无法重复注册!");
  62. req.getRequestDispatcher("register.jsp").forward(req, resp);
  63. return;
  64. }
  65. //用户数据注册
  66. int register = mayikUsertService.register(userName, userPwd);
  67. if (register <= 0) {
  68. // 注册失败了 //转发到错误页面
  69. req.setAttribute("errorMsg", "注册失败!");
  70. req.getRequestDispatcher("register.jsp").forward(req, resp);
  71. return;
  72. }
  73. // 注册成功之后就直接重定向到登录请求
  74. resp.sendRedirect("login");
  75. }
  76. }

过滤器

过滤器应用场景

过滤器是处于客户端与服务器资源文件之间的一道过滤网,在访问资源文件之前,通过一系列的过滤器对请求进行修改、判断等,把不符合规则的请求在中途拦截或修改。也可以对响应进行过滤,拦截或修改响应.
应用场景: 判断用户是否登录、过滤器请求记录日志、身份验证、权限控制等。
什么是过滤器 拦截过滤请求
过滤器可以 减少代码冗余性问题

使用方式

  1. package com.mayikt.filter;
  2. import jakarta.servlet.*;
  3. import jakarta.servlet.annotation.WebFilter;
  4. import jakarta.servlet.http.HttpServletRequest;
  5. import jakarta.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.PrintWriter;
  8. import java.util.logging.LogRecord;
  9. /**
  10. * @author 余胜军
  11. * @ClassName MayiktFilter
  12. * @qq 644064779
  13. * @addres www.mayikt.com
  14. * 微信:yushengjun644
  15. */
  16. @WebFilter("/*")
  17. public class MayiktFilter implements Filter {
  18. @Override
  19. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  20. HttpServletRequest req = (HttpServletRequest) servletRequest;
  21. HttpServletResponse response = (HttpServletResponse) servletResponse;
  22. response.setHeader("Content-type", "text/html;utf-8");
  23. String userName = req.getParameter("userName");
  24. if (!"mayikt".equals(userName)) {
  25. PrintWriter writer = response.getWriter();
  26. writer.print("权限不足");
  27. writer.close();
  28. return;
  29. }
  30. //放行
  31. filterChain.doFilter(req, response);
  32. }
  33. }

拦截器路径配置

1.所有资源拦截:@WebFilter(“/“) //这是指访问所有资源的时候都会经过过滤器
静态资源(css/js/mp4)
2.具体资源路z径拦截:@WebFilter(“/index.jsp”) //这是指访问index.jsp的时候会经过过滤器
3.具体目录拦截:@WebFilter(“/mayik/
“) //这是指访问mayikt目录下的所有资源时会经过过滤器
127.0.0.1:8080/mayikt/A
127.0.0.1:8080/mayikt/B
4.具体后缀名拦截:@WebFilter(“*.jsp”) //这时指访问后缀名为.jsp的资源时会经过过滤器

过滤器链

我们过滤器1执行完毕之后 在执行过滤器2
注解配置的Filter,优先级按照过滤器类名(字符串)的自然排序
image.png

使用过滤器验证会话信息

需求:使用过滤器验证用户的会话信息,判断用户是否已经登录 如果 没有登录的话 则跳转到登录页面。排查“loginServlet、RegisterServlet”

  1. package com.mayikt.filter;
  2. import jakarta.servlet.*;
  3. import jakarta.servlet.annotation.WebFilter;
  4. import jakarta.servlet.annotation.WebServlet;
  5. import jakarta.servlet.http.HttpServletRequest;
  6. import jakarta.servlet.http.HttpServletResponse;
  7. import jakarta.servlet.http.HttpSession;
  8. import java.io.IOException;
  9. /**
  10. * @author 余胜军
  11. * @ClassName UserSessionFilter
  12. * @qq 644064779
  13. * @addres www.mayikt.com
  14. * 微信:yushengjun644
  15. */
  16. @WebFilter("/*")// 过滤器所有的请求
  17. public class UserSessionFilter implements Filter {
  18. private String[] excludeUrls = new String[]{"/login", "/register", "/VerifycodeServlet"};
  19. @Override
  20. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  21. // 从session获取到用户的会话信息 判断用户是否登录过
  22. HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
  23. HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
  24. // 定义一个数组 哪些 请求是需要排除的
  25. for (int i = 0; i < excludeUrls.length; i++) {
  26. String excludeUrl = "/mayikt_session_war_exploded" + excludeUrls[i];
  27. String requestURI = httpServletRequest.getRequestURI();
  28. if (excludeUrl.equals(requestURI)) {
  29. // 放行请求
  30. filterChain.doFilter(httpServletRequest, httpServletResponse);
  31. return;
  32. }
  33. }
  34. // 排除请求
  35. HttpSession session = httpServletRequest.getSession();
  36. Object user = session.getAttribute("user");
  37. if (user == null) {
  38. // 当前用户没有登录或者登录会话失效
  39. // 重定向到登录页面
  40. httpServletResponse.sendRedirect("/mayikt_session_war_exploded/login");
  41. return;
  42. }
  43. // 用户已经登录了 正常放行请求
  44. filterChain.doFilter(httpServletRequest, httpServletResponse);
  45. }
  46. }

获取当前上下文

request.contextPath();

监听器

  1. 监听器Listener就是在application,session,request三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件。
    2. Listener是Servlet的监听器,可以监听客户端的请求,服务端的操作等。
    3. Listener实现了javax.servlet.ServletContextListener 接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。主要作用是:做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等.
    1.ServletContext监听
    ServletContextListener:用于对Servlet整个上下文进行监听;
    ServletContextAttributeListener:对Servlet上下文属性的监听。
    2.Session监听
    HttpSessionListener接口:对Session的整体状态的监听;
    HttpSessionAttributeListener接口:对session的属性监听。
    3.Request监听
    ServletRequestListener:用于对Request请求进行监听;
    ServletRequestAttributeListener:对Request属性的监听。

Listener用法