【JavaEE】基于mysql与servlet自制简易的表白墙程序

Dear 丶 2023-09-24 22:01 95阅读 0赞

文章目录

  • 1 表白墙页面构建
  • 2 Servlet 回顾
  • 3 表白墙后端程序实现
    • 3.1 我们需要做什么?
    • 3.2 实现细节
  • 4 实现结果
  • 写在最后

1 表白墙页面构建

在这里插入图片描述
 该页面由标题、文本、三个 input 输入框与一个提交按钮构成,整体比较简单,相关样式文件和页面代码会在后面给出。

 我们需要解决的核心问题,就是考虑:如何让表白信息在页面上显示出来?
显然,我们可以使用 JavaScript 中的选择器,选中三个输入框,并对提交按钮添加点击监听事件。当我们点击按钮的时候,获取三个输入框的内容,并将输入框的内容以自己定义的格式插入到 html 中,并在浏览器上显示出来~

 需要注意的是,如果用户还未写完内容,即三个输入框中的内容没有输入完整,则不能进行提交~ 页面构建代码如下:

messageWall.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>表白墙</title>
  8. </head>
  9. <body>
  10. <style>
  11. * {
  12. margin: 0;
  13. padding: 0;
  14. box-sizing: border-box;
  15. }
  16. .container {
  17. width: 100%;
  18. }
  19. h3 {
  20. text-align: center;
  21. padding: 30px 0;
  22. font-size: 24px;
  23. }
  24. p {
  25. text-align: center;
  26. color: #999;
  27. padding: 10px 0;
  28. }
  29. .row {
  30. width: 400px;
  31. height: 50px;
  32. margin: 0 auto;
  33. display: flex;
  34. justify-content: center;
  35. align-items: center;
  36. }
  37. .row span {
  38. width: 60px;
  39. font-size: 20px;
  40. }
  41. .row input {
  42. width: 300px;
  43. height: 40px;
  44. line-height: 40px;
  45. font-size: 20px;
  46. text-indent: 0.5em;
  47. /* 去掉输入框的轮廓线 */
  48. outline: none;
  49. }
  50. .row #submit {
  51. width: 300px;
  52. height: 40px;
  53. font-size: 20px;
  54. line-height: 40px;
  55. margin: 0 auto;
  56. color: white;
  57. background-color: #fa8497;
  58. /* 去掉边框 */
  59. border: none;
  60. border-radius: 10px;
  61. }
  62. .row #submit:active {
  63. background-color: gray;
  64. }
  65. </style>
  66. <div class="container">
  67. <h3>小黄圆圆表白墙</h3>
  68. <p>输入后点击提交, 会将信息显示在表格中</p>
  69. <div class="row">
  70. <span>谁: </span>
  71. <input type="text">
  72. </div>
  73. <div class="row">
  74. <span>对谁: </span>
  75. <input type="text">
  76. </div>
  77. <div class="row">
  78. <span>说: </span>
  79. <input type="text">
  80. </div>
  81. <div class="row">
  82. <button id="submit">提交</button>
  83. </div>
  84. </div>
  85. <script>
  86. // 当用户点击 submit, 就会获取到 input 中的内容, 从而把内容构造成一个 div, 插入到页面末尾.
  87. let submitBtn = document.querySelector('#submit');
  88. submitBtn.onclick = function() {
  89. // 1. 获取到 3 个 input 中的内容.
  90. let inputs = document.querySelectorAll('input');
  91. let from = inputs[0].value;
  92. let to = inputs[1].value;
  93. let msg = inputs[2].value;
  94. if (from == '' || to == '' || msg == '') {
  95. // 用户还没填写完, 暂时先不提交数据.
  96. return;
  97. }
  98. // 2. 生成一个新的 div, 内容就是 input 里的内容. 把这个新的 div 加到页面中.
  99. let div = document.createElement('div');
  100. div.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
  101. div.className = 'row';
  102. let container = document.querySelector('.container');
  103. container.appendChild(div);
  104. // 3. 清空之前输入框的内容.
  105. for (let i = 0; i < inputs.length; i++) {
  106. inputs[i].value = '';
  107. }
  108. }
  109. </script>
  110. </body>
  111. </html>

来一个简单的测试~
在这里插入图片描述
 至此,程序都没有什么问题。但是,当我们点击页面刷新的时候,数据(表白)信息就丢失了。原因很简单~ 没有实现数据的持久化 怎么解决呢?显然,我们可以通过服务器,来对数据实现持久化存储,这就需要用到我们的 Servlet 了。
简而言之,就是通过 Servlet 程序处理页面的请求,将请求数据中的表白信息,持久化存储到数据库中,当再次刷新页面的时候,从服务器中拉取数据~


2 Servlet 回顾

Servlet是什么?

  • Servlet是JavaEE规范之一,规范就是接口
  • Servlet是JavaWeb的三大组件之一,三大组件分别是:Servlet程序、Filter过滤器、Listener监听器
  • Servlet是运行在服务器上的一个java小程序,可以接收客户端发来的请求,并响应数据给客户端

其他内容,可以参考笔者的 JavaWeb 专栏的 Servlet 部分,这里不再赘述:Servlet 核心编程

与笔者前面文章不同的是,这次我们使用 maven 来导入相关的依赖,在本 Demo 中,我们主要使用了 Servlet,mysql 以及 jackson 来解析 json 数据,相关依赖核心代码如下:

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>org.example</groupId>
  7. <artifactId>message_wall</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <properties>
  10. <maven.compiler.source>8</maven.compiler.source>
  11. <maven.compiler.target>8</maven.compiler.target>
  12. </properties>
  13. <dependencies>
  14. <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
  15. <dependency>
  16. <groupId>javax.servlet</groupId>
  17. <artifactId>javax.servlet-api</artifactId>
  18. <version>3.1.0</version>
  19. <scope>provided</scope>
  20. </dependency>
  21. <!-- 用于解析 json 的依赖 -->
  22. <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
  23. <dependency>
  24. <groupId>com.fasterxml.jackson.core</groupId>
  25. <artifactId>jackson-databind</artifactId>
  26. <version>2.12.7.1</version>
  27. </dependency>
  28. <!-- 引入 mysql 驱动包 -->
  29. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  30. <dependency>
  31. <groupId>mysql</groupId>
  32. <artifactId>mysql-connector-java</artifactId>
  33. <version>5.1.47</version>
  34. </dependency>
  35. </dependencies>
  36. </project>

3 表白墙后端程序实现

3.1 我们需要做什么?

核心:让表白数据不丢失

我们就需要通过服务器,来保存上述程序的消息数据,做到持久化存储~

那么问题来了~ 客户端 和 服务端该如何交互呢?
在这里插入图片描述
  试想一个场景,你来到一个陌生的国家,想要买一张回国的机票。但是,你给路人说:“你好~请问机场怎么走?” 路人:“What can I do for you?”
这里我们做出如下假设:

  1. 你不会说英语;
  2. 路人不会说中文;
  3. 你听不懂英语;
  4. 路人听不懂中文。

 路人表示:“你说什么~我完全听不懂的吖。” 而如果我们想让后端服务器能够正确的提供给客户端需要的服务,就需要前后端都能听得懂,说得通。因此,有必要统一语言,即自定义应用层协议,规范请求和响应的数据组织形式~

  那么,再回到问题本身。我们要写一个服务器,服务器是干什么的?既然是服务器,服务器就应该提供服务。试想一个这样的场景:你想要洗衣服,但是家里只提供给你了个智能电饭煲~ 有如下的功能:

  1. 煲汤
  2. 做饭

 显然,电饭煲再智能,它也是没有办法帮你洗衣服滴~ 对于前后端的交互来说,我们也需要约定好都需要什么样的功能,能提供什么样的功能,即约定好前后端交互的接口,定好相应的规范~
在这里插入图片描述

小结:**约定前后端交互的接口,自定义应用层协议~**

对于表白墙来说,主要提供如下两个接口:

  • 告诉服务器,当前留言了一个怎么样的数据:当用户点击提交按钮的时候,就会给服务器发送一个 http 请求,服务器将这个消息保存下来。
  • 从服务器获取到,当前都有哪些留言数据:当页面加载,就需要从服务器获取曾经存储的数据。

如何约定协议呢?

  • 只需要约定好,客户端应该发送一个怎么样的 http请求 服务器返回一个怎么样的 http响应。只要前后端都按照这个约定去做就好~
  • 常见的可以使用 json 等~ 这里,我们采用的就是 json 格式:
    在这里插入图片描述

3.2 实现细节

修改前端代码,使用 ajax 构造请求

  1. 点击提交的时候,ajax 要构造数据发送给服务器
  2. 页面加载的时候,从服务器获取消息列表,并在界面显示

JavaScript 的代码修改如下:

  1. <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  2. <script>
  3. function getMessages(){
  4. $.ajax({
  5. type: 'get',
  6. url: 'message',
  7. success: function(body){
  8. // 当前 body 已经是一个 js 对象数组了,ajax 会根据响应的 content type 自动解析
  9. // 如果服务器返回的 content-type 已经是 application/json 了,ajax 就会把 body 自动转成 js 的对象
  10. // 如果客户端没有自动转,也可以通过 JSON.parse() 手动转换
  11. // 依次来取数组中的每个元素
  12. let container = document.querySelector('.container');
  13. for(let message of body){
  14. let div = document.createElement('div');
  15. div.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
  16. div.className = 'row';
  17. container.appendChild(div);
  18. }
  19. }
  20. })
  21. }
  22. getMessages();
  23. // 当用户点击 submit, 就会获取到 input 中的内容, 从而把内容构造成一个 div, 插入到页面末尾.
  24. let submitBtn = document.querySelector('#submit');
  25. submitBtn.onclick = function() {
  26. // 1. 获取到 3 个 input 中的内容.
  27. let inputs = document.querySelectorAll('input');
  28. let from = inputs[0].value;
  29. let to = inputs[1].value;
  30. let msg = inputs[2].value;
  31. if (from == '' || to == '' || msg == '') {
  32. // 用户还没填写完, 暂时先不提交数据.
  33. return;
  34. }
  35. // 2. 生成一个新的 div, 内容就是 input 里的内容. 把这个新的 div 加到页面中.
  36. let div = document.createElement('div');
  37. div.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
  38. div.className = 'row';
  39. let container = document.querySelector('.container');
  40. container.appendChild(div);
  41. // 3. 清空之前输入框的内容.
  42. for (let i = 0; i < inputs.length; i++) {
  43. inputs[i].value = '';
  44. }
  45. // 4. 把当前获取到的输入框内容,构造成一个 HTTP POST 请求, 通过 ajax 发给服务器
  46. let body = {
  47. from: from,
  48. to: to,
  49. message: msg
  50. }
  51. $.ajax({
  52. type: 'post',
  53. url: 'message',
  54. contentType: 'application/json;charset=utf8',
  55. data: JSON.stringify(body),
  56. success: function(){
  57. alert("消息提交成功!");
  58. },
  59. error: function(){
  60. alert("消息提交失败!");
  61. }
  62. });
  63. }
  64. </script>

构建相应的类,方便存储 json 对应的数据,这里需要属性和 key 名称一致,便于 jackson 自动读取数据存储到该类的对象中~

Message.java

这里使用 public 修饰完全是为了图方便,读者可以自行封装,并提供相应的 get、set 方法,结果也是一样滴~

  1. class Message{
  2. public String from;
  3. public String to;
  4. public String message;
  5. }

创建数据库与相应的表

  1. create database message_wall;
  2. use message_wall;
  3. create table message(
  4. `from` varchar(1024),
  5. `to` varchar(1024),
  6. message varchar(4096)
  7. );

DBUtil.java
用于操作获取数据库资源的工具类,注意考虑线程安全问题~

  1. import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
  2. import javax.sql.DataSource;
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. /**
  8. * @author 兴趣使然黄小黄
  9. * @version 1.0
  10. * 方便与数据库之间的操作
  11. */
  12. @SuppressWarnings({
  13. "all"})
  14. public class DBUtil {
  15. private static final String URL = "jdbc:mysql://127.0.0.1:3306/message_wall?characterEncoding=utf8&useSSL=false";
  16. private static final String USER_NAME = "root";
  17. private static final String PASSWORD = "123456";
  18. private volatile static DataSource dataSource = null;
  19. private static DataSource getDataSource(){
  20. if (dataSource == null){
  21. synchronized (DBUtil.class) {
  22. if (dataSource == null) {
  23. dataSource = new MysqlDataSource();
  24. ((MysqlDataSource) dataSource).setURL(URL);
  25. ((MysqlDataSource) dataSource).setUser(USER_NAME);
  26. ((MysqlDataSource) dataSource).setPassword(PASSWORD);
  27. }
  28. }
  29. }
  30. return dataSource;
  31. }
  32. // 获取连接
  33. public static Connection getConnection() throws SQLException {
  34. return getDataSource().getConnection();
  35. }
  36. // 关闭连接
  37. public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
  38. if (resultSet != null){
  39. try {
  40. resultSet.close();
  41. } catch (SQLException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. if (statement != null){
  46. try {
  47. statement.close();
  48. } catch (SQLException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. if (connection != null){
  53. try {
  54. connection.close();
  55. } catch (SQLException e) {
  56. e.printStackTrace();
  57. }
  58. }
  59. }
  60. }

Servlet 程序的实现

具体可见代码注释~

  1. import com.fasterxml.jackson.databind.ObjectMapper;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.annotation.WebServlet;
  4. import javax.servlet.http.HttpServlet;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import java.io.IOException;
  8. import java.sql.Connection;
  9. import java.sql.PreparedStatement;
  10. import java.sql.ResultSet;
  11. import java.sql.SQLException;
  12. import java.util.ArrayList;
  13. import java.util.List;
  14. /**
  15. * @author 兴趣使然黄小黄
  16. * @version 1.0
  17. * servlet程序, 实现表白墙后台逻辑
  18. */
  19. class Message{
  20. public String from;
  21. public String to;
  22. public String message;
  23. }
  24. @SuppressWarnings({
  25. "all"})
  26. @WebServlet("/message")
  27. public class MessageServlet extends HttpServlet {
  28. private ObjectMapper objectMapper = new ObjectMapper(); // 用于解析 json
  29. @Override
  30. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  31. // 处理提交消息请求
  32. Message message = objectMapper.readValue(req.getInputStream(), Message.class); // 读取 json
  33. save(message); // 存储
  34. // 通过 ContentType 来告知页面, 返回的数据是 json 格式.
  35. // 有了这样的声明, 此时 jquery ajax 就会自动的帮我们把字符串转成 js 对象.
  36. // 如果没有, jquery ajax 就只是当成字符串来处理的~~
  37. resp.setContentType("application/json; charset=utf8");
  38. resp.getWriter().write("{ \"ok\": true }");
  39. }
  40. @Override
  41. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  42. // 获取到消息列表. 只要把消息列表中的内容整个的都返回给客户端即可
  43. // 此处需要使用 ObjectMapper 把 Java 对象, 转成 JSON 格式字符串~
  44. List<Message> messages = load(); // 获取数据
  45. String jsonString = objectMapper.writeValueAsString(messages);
  46. System.out.println("jsonString: " + jsonString);
  47. resp.setContentType("application/json; charset=utf8");
  48. resp.getWriter().write(jsonString);
  49. }
  50. /**
  51. * 将一条消息保存到数据库中
  52. * @param message 要保存的数据
  53. */
  54. private void save(Message message){
  55. Connection connection = null;
  56. PreparedStatement statement = null;
  57. try {
  58. // 1. 和数据库连接
  59. connection = DBUtil.getConnection();
  60. // 2. 构造 sql
  61. String sql = "insert into message values(?, ?, ?)";
  62. statement = connection.prepareStatement(sql);
  63. statement.setString(1, message.from);
  64. statement.setString(2, message.to);
  65. statement.setString(3, message.message);
  66. // 3. 执行 sql
  67. statement.executeUpdate();
  68. } catch (SQLException e) {
  69. e.printStackTrace();
  70. } finally {
  71. // 4. 释放资源
  72. DBUtil.close(connection, statement, null);
  73. }
  74. }
  75. /**
  76. * 从数据库中获取到所有的表白信息
  77. * @return 返回一个List,存储的就是表白信息
  78. */
  79. private List<Message> load(){
  80. List<Message> messages = new ArrayList<>();
  81. Connection connection = null;
  82. PreparedStatement statement = null;
  83. ResultSet resultSet = null;
  84. try {
  85. // 1. 和数据库连接
  86. connection = DBUtil.getConnection();
  87. // 2. 构造 sql
  88. String sql = "select * from message";
  89. statement = connection.prepareStatement(sql);
  90. // 3. 执行 sql
  91. resultSet = statement.executeQuery();
  92. // 4. 存储
  93. while (resultSet.next()){
  94. Message message = new Message();
  95. message.from = resultSet.getString("from");
  96. message.to = resultSet.getString("to");
  97. message.message = resultSet.getString("message");
  98. messages.add(message);
  99. }
  100. } catch (SQLException e) {
  101. e.printStackTrace();
  102. } finally {
  103. // 4. 释放资源
  104. DBUtil.close(connection, statement, resultSet);
  105. }
  106. return messages;
  107. }
  108. }

4 实现结果

启动 Tomcat 服务器,访问表白墙页面后,我们依次在页面中插入三条数据后刷新页面,结果如下图所示:
在这里插入图片描述
使用Fiddler进行抓包,请求和响应数据正常~

在这里插入图片描述

我们在数据库中查看,也能找到相应的数据~
在这里插入图片描述


写在最后

 本文相关代码已上传 gitee,如有需要请自取:JavaEE-表白墙Demo
 以上便是本文的全部内容啦!创作不易,如果你有任何问题,欢迎私信,感谢您的支持!

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,95人围观)

还没有评论,来说两句吧...

相关阅读