• 表白墙完善(数据库,前端,后端Servlet),再谈Cookie和Session。以及一个关于Cookie的练习小程序


    目录

    表白墙引入数据库 

    再谈Cookie和session

    得到Cookie

    ​编辑

    设置Cooie

    使用Cookie编写一个登入的小界面


    表白墙引入数据库 

    1.先引入数据库的依赖(驱动包),5.1.49

    pom.xml中,在之前的两个之前,再去添加一个

    1. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    2. <dependency>
    3. <groupId>mysql</groupId>
    4. <artifactId>mysql-connector-java</artifactId>
    5. <version>5.1.49</version>
    6. </dependency>

    2.创建本地的数据库

    1. create table messageWall(`from` varchar(20),`to` varchar(20),message varchar(1024));

    3.之前的代码中有一段可以删掉了

    1. //此处把消息保存到内存中(一旦重启服务器,内存数据就会消失了。更科学的做法,应该是保存到数据库里面)
    2. private List<Message> messageList=new ArrayList<>();

    这个代码需要删除,因为我们已经决定使用数据库去存储了,就不需要本地去存了。

     完整代码

    1. import com.fasterxml.jackson.databind.ObjectMapper;
    2. import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
    3. import javax.servlet.ServletException;
    4. import javax.servlet.annotation.WebServlet;
    5. import javax.servlet.http.HttpServlet;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletResponse;
    8. import javax.sql.DataSource;
    9. import java.io.IOException;
    10. import java.sql.Connection;
    11. import java.sql.PreparedStatement;
    12. import java.sql.ResultSet;
    13. import java.sql.SQLException;
    14. import java.util.ArrayList;
    15. import java.util.List;
    16. class Message{
    17. public String from;
    18. public String to;
    19. public String message;
    20. @Override
    21. public String toString() {
    22. return "Message{" +
    23. "from='" + from + '\'' +
    24. ", to='" + to + '\'' +
    25. ", message='" + message + '\'' +
    26. '}';
    27. }
    28. }
    29. @WebServlet("/message")
    30. public class MessageServlet extends HttpServlet {
    31. //首先要把一个json转化为java对象
    32. private ObjectMapper objectMapper=new ObjectMapper();
    33. //此处把消息保存到内存中(一旦重启服务器,内存数据就会消失了。更科学的做法,应该是保存到数据库里面)
    34. private List<Message> messageList=new ArrayList<>();
    35. @Override
    36. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    37. //1.需要能够读取请求body,转换成java对象
    38. Message message=objectMapper.readValue(req.getInputStream(),Message.class);
    39. //2.得到message之后,需要把message保存到服务器中
    40. try {
    41. save(message);
    42. } catch (SQLException e) {
    43. e.printStackTrace();
    44. }
    45. System.out.println("服务器收到message:"+message.toString());
    46. //3.返回响应,(其实没啥大必要,主要是返回一个200ok就行,body可以没有)
    47. resp.setStatus(200); //设置成功状态码,会更加清晰
    48. resp.getWriter().write("ok");
    49. }
    50. @Override
    51. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    52. List<Message>messageList= null;
    53. try {
    54. messageList = load();
    55. } catch (SQLException e) {
    56. e.printStackTrace();
    57. }
    58. //1.把内存中的这些Message,组织成json格式,返回到响应中
    59. String respJson=objectMapper.writeValueAsString(messageList);
    60. //这个代码十分关键,告诉浏览器,返回的响应的body是json格式(utf8编码)
    61. resp.setContentType("application/json; charset=utf8");
    62. resp.getWriter().write(respJson);
    63. // 2.针对List/数组这种,jackon会自动把数据整理成json数组,里面每个对象,又会被jsckon转换成{}json对象(json对象属性名字,也是和Message类的成员名字对应的)
    64. }
    65. private void save(Message message) throws SQLException {
    66. //通过jdbc从数据库中存储数据。
    67. DataSource dataSource=new MysqlDataSource();
    68. //useSSL=false 此处的SSL就是HTTPS中的加密方案
    69. ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/message?characterEncoding=utf8&&useSSL=false");
    70. ((MysqlDataSource)dataSource).setUser("root");
    71. ((MysqlDataSource)dataSource).setPassword("lcl15604007179");
    72. //2.建立链接
    73. Connection connection=dataSource.getConnection();
    74. //3.构造SQL
    75. String sql="insert into messageWall values(?,?,?)";
    76. PreparedStatement statement=connection.prepareStatement(sql);
    77. statement.setString(1, message.from);
    78. statement.setString(2, message.from);
    79. statement.setString(3, message.from);
    80. //4.执行SQL
    81. statement.executeUpdate();
    82. //5.释放资源,关闭连接
    83. statement.close();
    84. connection.close();
    85. }
    86. private List<Message> load() throws SQLException {
    87. //通过jdbc,从数据库读取数据
    88. //1。创建数据源
    89. DataSource dataSource=new MysqlDataSource();
    90. ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/message?characterEncoding=utf8&&useSSL=false");
    91. ((MysqlDataSource) dataSource).setUser("root");
    92. ((MysqlDataSource)dataSource).setPassword("lcl15604007179");
    93. //2.建立连接
    94. Connection connection= dataSource.getConnection();
    95. //3.构造SQL
    96. String sql="select *from messageWall";
    97. PreparedStatement statement=connection.prepareStatement(sql);
    98. //4.执行SQL
    99. ResultSet resultSet= statement.executeQuery();
    100. //5.遍历结果集合
    101. List <Message> messageList=new ArrayList<>();
    102. while (resultSet.next()){
    103. Message message=new Message();
    104. message.from=resultSet.getString("from");
    105. message.to=resultSet.getString("to");
    106. message.message=resultSet.getString("message");
    107. messageList.add(message);
    108. }
    109. //关闭连接,释放资源
    110. resultSet.close();
    111. statement.close();
    112. connection.close();
    113. return messageList;
    114. }
    115. }

    我们可以知道,表白墙上的东西,即使你关闭服务器,我们的数据也是保存的,这也是游戏停服了但是你的数据不丢失的原因。

    再谈Cookie和session

    Cookie是浏览器在本地持久化存储数据的一种机制

    1.Cookie的数据从哪里来?

    服务器返回给浏览器的

    2.Cookie的数据长什么样子?

    Cookie中是键值对结构的数据,并且这里的键值对都是程序员自定义的。

    3.Cookie有什么用

    Cookie可以在浏览器这边存储一些临时性数据

    其中最典型的一种使用方式,就是用来存储“身份标识”

    sessionId->Cookie和Session之间的联动了

    4.Cookie到哪里去

    Cookie的内容会在下次访问该网站的时候,自动被带到HTTP请求中

    5.Cookie怎么存储的

    浏览器按照不同的域名分别存储Cookie域名和域名之间不能打扰。

    Cookie存储在硬盘上的

    Cookie存储往往会有一个超时时间(看浏览器不同而定,支付宝很短,安全)

    得到Cookie

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.Cookie;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. @WebServlet("/getcookie")
    9. public class GetCookieServlet extends HttpServlet {
    10. @Override
    11. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    12. Cookie[] cookies = req.getCookies();
    13. if (cookies != null) {
    14. for (Cookie cookie : cookies) {
    15. System.out.println(cookie.getName() + ":" + cookie.getValue());
    16. }
    17. } else {
    18. resp.getWriter().write("当前请求中没有cookie");
    19. }
    20. resp.getWriter().write("ok");
    21. }
    22. }

    设置Cooie

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.Cookie;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. @WebServlet("/setcookie")
    9. public class SetCookieServlet extends HttpServlet {
    10. //期望通过doGet方法,把一个自定义的cookie数据返回到浏览器这边。
    11. @Override
    12. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    13. Cookie cookie=new Cookie("date","2023-09-23");
    14. resp.addCookie(cookie);
    15. Cookie cookie1=new Cookie("time","19:55");
    16. resp.addCookie(cookie1);
    17. resp.getWriter().write("setCookie ok");
    18. }
    19. }

    我们需要是先设置Cookie之后,就可以此时拿到Cookie的内容,当然Cookie里面的数据,只是在浏览器休息休息,真正发挥作用,还是得在服务器这边的逻辑生效的。

    Cookie结合Session实现登入效果,此时就能更清楚的看出来

    sessionId是一个广义的概念,不同的库中具体实现过程会有一些细节的差异,在Servlet里,把这个属性具体叫做JSESSIONID

    getSession背后做的事情(会话,就相当于账户,用户和服务器的交流,之前有没有这个账户)

    1.读取请求中的Cookie,看Cookie里面是否有JESSIONID属性,以及值是什么,如果没有,就认为需要创建新的会话,如果有,就拿着这个ID去查询当前的session是否存在

    要是session存在,就直接返回该session

    要是session不存在,就准备创建新的会话。

    2.如果当前确实需要创建会话,就会创建一个Session对象,同时生成唯一的一个JESSIONID,以JSESSIONID为key,SESSION对象为value,把这个键值对插入到服务器上述的哈希表中

    3.刚才生成的JESSIONID又会通过addCookie方法,加入到响应中,此时响应里就会带有Set-Cookie字段,这里的值就是JSEEION=xxxxxxx通过响应,就把JSESSIOID返回到浏览器这边了。

    这一行小小的,能量大大的🙉🙉🙉

     HttpSession session=req.getSession(true);

    问题1:什么情况会有sessionId但是没有session呢

    服务器这边存的session对象也是在内存中进行的

    比如把sessionId返回给浏览器了,sessionId和session对象是保存在服务器内存的,此时如果服务器重启了,内存中这些会话数据就没了,但是浏览器中的Cookie还是存在的

    session存在内存中不太合理,实践中往往会把这种会话保存到其他介质上,来达到持久化存储目的(mysql,redis)

    使用Cookie编写一个登入的小界面

    简单的一个小的前端代码

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6. <title>Document</title>
    7. </head>
    8. <form action="login" method="post">
    9. <input type="text" name="username">
    10. <input type="password" name="password">
    11. <input type="submit" value="登入">
    12. <!-- 当前页面是一个form表单-->
    13. </form>
    14. </body>
    15. </html>

    后端的登入代码编写

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import javax.servlet.http.HttpSession;
    7. import java.io.IOException;
    8. @WebServlet("/index")
    9. public class indexServlet extends HttpServlet {
    10. @Override
    11. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    12. //先验证用户的登入状态,如果未登入,就要求用户要先登入一下
    13. HttpSession session=req.getSession(false);
    14. if(session==null){
    15. //用户尚未登入
    16. resp.setContentType("text/html;charset=utf8");
    17. resp.getWriter().write("请先登入,再访问主页");
    18. return;
    19. }
    20. //已经登入成功了
    21. //就可以取出之前的attribute
    22. String username=(String) session.getAttribute("username");
    23. Long time=(Long) session.getAttribute("time");
    24. System.out.println("username="+username+",time"+time);
    25. //根据这样的内容构造页面
    26. resp.setContentType("text/html;charset=utf8");
    27. resp.getWriter().write("欢迎您,"+username+"!上次登入时间"+time);
    28. }
    29. }

    重定向的内容编写 

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import javax.servlet.http.HttpSession;
    7. import java.io.IOException;
    8. @WebServlet("/login")
    9. public class LoginServlet extends HttpServlet {
    10. @Override
    11. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    12. //1.获取到用户名和密码
    13. String username = req.getParameter("username");
    14. String password = req.getParameter("password");
    15. if (username == null || password == null || username.equals("") || password.equals("")) {
    16. resp.setContentType("text/html;charset=utf8");
    17. resp.getWriter().write("请求的参数不完整");
    18. return;
    19. }
    20. //2.验证用户密码是否正确
    21. //正常的验证,是从数据库读取数据
    22. //注册账号就会给数据库插入用户名和密码,登入的时候就是验证当前用户名是否存在,以及密码是否匹配
    23. //当前为了简单,先不引入数据库,直接通过硬编码的方式来判定用户名和密码
    24. //此处约定,合法的用户名是:zhangsan,密码:123
    25. if (!username.equals("zhangsan")) {
    26. resp.setContentType("text/html;charset=utf8");
    27. resp.getWriter().write("用户名错误!");
    28. return;
    29. }
    30. if (!password.equals("123")) {
    31. resp.setContentType("text/html;charset=utf8");
    32. resp.getWriter().write("密码错误");
    33. return;
    34. }
    35. //3.登入成功了,此时可以给这个用户创建会话(就是这个人在不在账户上)
    36. HttpSession session = req.getSession(true);
    37. //会话总,可以顺便保存点自定义的数据,比如保存一个登入的时间戳
    38. //setAttribute后面的value是个Object,想要存什么都可以!!
    39. session.setAttribute("username", username);
    40. session.setAttribute("time", System.currentTimeMillis());
    41. //4.让页面自动跳转到网站主页
    42. //此处约定的路径是index(使用Servlet生成一个动态页面)
    43. resp.sendRedirect("index");
    44. }
    45. }

    当前程序设计三个部分进行联动——以下是登入成功的效果

    1.登入界面(静态的html,使用form构造http请求)

    2.LoginServlet(doPost处理登入的逻辑流程 1234)

    3.IndexServlet(doGet处理主页的生成)

  • 相关阅读:
    python线程安全队列讲解
    【数学分析】集合 ① ( 集合概念 | 集合表示 | 常用的数集合 | 集合的表示 )
    强化学习 多臂赌博机
    【 0 基础 Docker 极速入门】镜像、容器、常用命令总结
    JavaScript:隐式转换、显示转换、隐式操作、显示操作
    【测开方法论】学习后如何举一反三
    Flink集群配置
    qlib自动化quant
    vue面试题汇总
    errMsg: “getUserProfile:fail can only be invoked by user TAP gesture.(微信小程序报错)
  • 原文地址:https://blog.csdn.net/weixin_72953218/article/details/133974969