先提供一个之前写过的表白墙的前端代码:
表白墙
表白墙
输入后点击提交, 就会把信息显示在表格中
谁: 对谁: 说:
形如:
当我们输入一些内容:
但是一旦刷新后,所有数据都没了!
因为当前的数据只是在内存中存储的!关了再开,内存中原来的数据就没了 ~~
这样显然不能达到我们的预期。解决方案:
需要让用户留言的数据能够在服务器这边保存,就可以保证即使页面关闭,数据也不会丢失!!!
点击提交,希望数据能够在服务器这里保存,势必要把数据发给服务器 (存档);
当关闭页面再打开的时候,就需要从服务器获取到之前保存过的数据,在页面上显示出来 (读档)!
参考博客:https://blog.csdn.net/yyhgo_/article/details/128468738?spm=1001.2014.3001.5501
创建一个新的 Maven 项目!(引入 Servlet 依赖 和 Jackson 依赖)
pom.xml:
4.0.0 org.example MessageWall 1.0-SNAPSHOT 8 8 javax.servlet javax.servlet-api 3.1.0 provided com.fasterxml.jackson.core jackson-databind 2.13.4 mysql mysql-connector-java 5.1.49
把之前实现的表白墙前端页面文件拷贝到 webapp 目录中!
首先创建一个 Message 类:
public class Message {private String from;private String to;private String message;public String getFrom() {return from;}public void setFrom(String from) {this.from = from;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
MessageServlet 类:
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;@WebServlet("/message")
public class MessageServlet extends HttpServlet {// 这个对象在多个方法中都需要使用private ObjectMapper objectMapper = new ObjectMapper();private List messageList = new ArrayList<>();// 负责让页面获取到数据@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}// 提交数据@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取到 body 中的数据并解析Message message = objectMapper.readValue(req.getInputStream(), Message.class);// 把这个 message 保存一下. 简单的办法就是保存在内存中.messageList.add(message);resp.setStatus(200);System.out.println("提交数据成功: from=" + message.getFrom()+ ", to=" + message.getTo() + ", message=" + message.getMessage());}}
补充 第4步:
点击发送按钮,给服务器发个 post 请求 ~~
表白墙
表白墙
输入后点击提交, 就会把信息显示在表格中
谁: 对谁: 说:
细节:
1)启动 tomcat 服务器
2)通过 表白墙.html 发送请求
访问 http://127.0.0.1:8080/MessageWall/表白墙.html:
过程中使用 Fiddler 抓包:
请求:
服务器解析结果:
响应:
MessageServlet 类:
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;@WebServlet("/message")
public class MessageServlet extends HttpServlet {// 这个对象在多个方法中都需要使用private ObjectMapper objectMapper = new ObjectMapper();private List messageList = new ArrayList<>();// 负责让页面获取到数据@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// body 就是响应的 body 内容 (json 数组).// jquery 非常智能的帮我们把 json 数组给解析成了 js 对象数组// 但是有个前提条件, 就是响应的 Content-Type 得是 application/jsonresp.setContentType("application/json; charset=utf8");// 把 messageList 转成 json 字符串,并且返回给页面就行了.resp.getWriter().write(objectMapper.writeValueAsString(messageList));}// 提交数据@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取到 body 中的数据并解析Message message = objectMapper.readValue(req.getInputStream(), Message.class);// 把这个 message 保存一下. 简单的办法就是保存在内存中.messageList.add(message);resp.setStatus(200);System.out.println("提交数据成功: from=" + message.getFrom()+ ", to=" + message.getTo() + ", message=" + message.getMessage());}}
什么时候来发这个请求呢?
页面加载的时候,我们就希望进行读档操作!
==================================================================================
在 html 文件中,哪里是页面加载的时候呢?
直接写在 script 标签里的代码,都是在页面加载的时候执行的!
表白墙
表白墙
输入后点击提交, 就会把信息显示在表格中
谁: 对谁: 说:
function 中的参数 body 就是响应的 body 内容 (json 数组)!
jquery 非常智能地帮我们把 json 数组给解析成了 js 对象数组!但是有个前提条件,就是响应的 Content-Type 得是 application/json 格式!
如果 jquery 没做这个事情,就需要使用 JSON.parse 来完成 ~~
1)重新启动 tomcat 服务器
2)访问 http://127.0.0.1:8080/MessageWall/表白墙.html
此时提交数据后,无论怎样刷新,数据仍然保留!!!成功 ~
服务器重启,原有的数据就没了 ~~
页面刷新过程中使用 Fiddler 抓包:
请求:
响应:
我们这个程序目前最大的问题就是:数据在内存中,服务器一旦重启就没了。我们需要让数据在数据库中持久化保存!JDBC!!!
中央仓库中搜索 mysql,选择:
这里选择 5.1.49:
将代码拷贝到 pom.xml 中:
设计有几张表,表里有什么 ~~
1.message 表;
2.三个列:from、to、message
注意: from 等关键字,需要加上反引号
``
!!!
Java的JDBC编程 博客链接:https://blog.csdn.net/yyhgo_/article/details/128061324?spm=1001.2014.3001.5501
通过数据库来 存 / 读 数据,就不再需要 ArrayList 了 ~~
主要是两个方法:
private void save(Message message)
:把数据保存到数据库中private List
:从数据库查询数据load()
完整代码:
public class Message {private String from;private String to;private String message;public String getFrom() {return from;}public void setFrom(String from) {this.from = from;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;import javax.sql.DataSource;// 使用这个类来封装 DataSource 的单例
public class DBUtil {private static volatile DataSource dataSource = null;private DBUtil() {}public static DataSource getDataSource() {if (dataSource == null) {synchronized (DBUtil.class) {if (dataSource == null) {dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java105?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");// 数据库密码.((MysqlDataSource)dataSource).setPassword("632yyh..");}}}return dataSource;}}
import com.fasterxml.jackson.databind.ObjectMapper;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;@WebServlet("/message")
public class MessageServlet extends HttpServlet {// 这个对象在多个方法中都需要使用private ObjectMapper objectMapper = new ObjectMapper();// 负责让页面获取到数据@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 显式声明当前的响应数据格式 不要让客户端去猜!!!resp.setContentType("application/json; charset=utf8");// 把 messageList 转成 json 字符串, 并且返回给页面就行了.List messageList = null;try {messageList = load();} catch (SQLException e) {e.printStackTrace();}resp.getWriter().write(objectMapper.writeValueAsString(messageList));}// 提交数据@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取到 body 中的数据并解析Message message = objectMapper.readValue(req.getInputStream(), Message.class);// 把这个 message 保存一下. 简单的办法就是保存在内存中.// messageList.add(message);try {save(message);} catch (SQLException e) {e.printStackTrace();}resp.setStatus(200);System.out.println("提交数据成功: from=" + message.getFrom()+ ", to=" + message.getTo() + ", message=" + message.getMessage());}private void save(Message message) throws SQLException {// 把数据保存到数据库中// 1. 先有一个数据源DataSource dataSource = DBUtil.getDataSource();// 2. 建立连接Connection connection = dataSource.getConnection();// 3. 构造 SQLString sql = "insert into message values(?, ?, ?)";PreparedStatement statement = connection.prepareStatement(sql);statement.setString(1, message.getFrom());statement.setString(2, message.getTo());statement.setString(3, message.getMessage());// 4. 执行 SQLint ret = statement.executeUpdate();System.out.println("ret = " + ret);// 5. 关闭连接statement.close();connection.close();}private List load() throws SQLException {// 从数据库查询数据// 1. 先有一个数据源DataSource dataSource = DBUtil.getDataSource();// 2. 建立连接Connection connection = dataSource.getConnection();// 3. 构造 SQLString sql = "select * from message";PreparedStatement statement = connection.prepareStatement(sql);// 4. 执行 SQLResultSet resultSet = statement.executeQuery();// 5. 遍历结果集合List messageList = new ArrayList<>();while (resultSet.next()) {Message message = new Message();message.setFrom(resultSet.getString("from"));message.setTo(resultSet.getString("to"));message.setMessage(resultSet.getString("message"));messageList.add(message);}// 6. 关闭连接statement.close();connection.close();return messageList;}}
细节:
数据源不需要创建多份,因此可以使用单例模式:单独构造一个 类DBUtil !
Servlet 代码中是否涉及到 多线程/线程安全 的问题呢?
Servlet 写的是一个服务器。同一时刻,可能要处理多个客户端的请求!
一旦同时有多个客户端都发来请求,服务器势必就需要同时处理多个请求。Tomcat 内部正是使用了多线程的方式来处理的 ~~
1)重新启动 tomcat 服务器
2)访问 http://127.0.0.1:8080/MessageWall/表白墙.html
此时提交数据后,无论怎样刷新,还是重新启动服务器,数据仍然保留!!!成功 ~
此时查看数据库中 message 表的数据:
完!提前祝大家 2023 新年快乐!~~