🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!欢迎志同道合的朋友一起加油喔🤺🤺🤺
目录
(1) 定义了一个DUBtil类,这个类是一个工具类,主要用于处理数据库连接和断开的操作
客户端与服务器之间的通信流程
理解当前案例的前后端交互流程![](https://img-blog.csdnimg.cn/124f27ec3fd54b1a9821db0d7ab1d17e.png)
表白墙的交互接口
在当前表白墙的案例中,我的需求主要是为了实现服务器来保存用户提交的留言。
第一个交互接口:客户端从服务器拿数据。
当页面加载(刷新页面)的时候,客户端就需要给服务器发送一个请求,把之前已经保存在服务器上的信息,获取下来,展示到浏览器的页面上。
第二个交互接口:从客户端往服务器提交数据。
当浏览器页面的用户点击提交的时候,就要给服务器发送一个请求,把这次留言的信息传给服务器。
纯前端的表白墙 html 页面代码
下面代码是【纯前端的表白墙 html 页面代码】,也就是【不涉及前后端交互的一个简单 html 实现的页面】,在下面的内容中,我们需要对这里的代码进行修改。最重要的是,我们应该理解,html 代码在什么场景下,修改了哪些部分。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表白墙</title>
<style>
* {
/* 消除浏览器默认样式 */
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 600px;
margin: 20px auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
margin: 20px auto;
}
.row {
/* 开启弹性布局 */
display: flex;
height: 40px;
/* 水平方向居中 */
justify-content: center;
/* 竖直方向居中 */
align-items: center;
}
.row span {
width: 80px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 280px;
height: 30px;
color: white;
background-color: orange;
/* 去掉默认边框 */
border: none;
border-radius: 3px;
}
.row button:active {
background-color: gray;
}
</style>
</head>
<body>
<div class="container">
<h1>表白墙</h1>
<p>输入内容后点击提交,信息将显示到下方表格</p>
<div class="row">
<span>谁: </span>
<input type="text">
</div>
<div class="row">
<span>对谁: </span>
<input type="text">
</div>
<div class="row">
<span>说: </span>
<input type="text">
</div>
<div class="row">
<button>提交</button>
</div>
<div class="row">
<button id="revert">撤销</button>
</div>
</div>
<script>
// 实现将提交的内容呈现在页面显示
let containerDiv = document.querySelector('.container');
let inputs = document.querySelectorAll('input');
let button = document.querySelector('button');
button.onclick = function() {
//分别获取三个输入框的内容
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if(from == '' || to == '' || msg == '') {
return;
}
//构建一个新的div
let rowDiv = document.createElement('div');
//此处class属性名不构造row防止撤销把自己删除了
rowDiv.className = 'row message';
rowDiv.innerHTML = from + ' 对 ' + to + ' 说 ' + msg;
containerDiv.appendChild(rowDiv);
// 完成提交后 清空输入框内的内容
for(let input of inputs) {
input.value = '';
}
let revertButton =document.querySelector('#revert');
revertButton.onclick = function() {
//删除最后一条消息
//选中所有的row message,找出最后一个row message,然后进行删除
let rows = document.querySelectorAll('.message');
//如果没有数据就不删了
if(rows == null || rows.length == 0) {
return;
}
containerDiv.removeChild(rows[rows.length-1]);
}
}
</script>
</body>
</html>
第一个交互接口:客户端从服务器拿数据
1. 通过 Servlet 构造 GET 响应
(1) 步骤
服务器 解析请求、根据请求计算响应的步骤:
- 首先,Tomcat 服务器自动为我们实现了读取请求的逻辑。
- 其次,通过 jackson API 来将 Java 对象中的字符串解析成 json 格式的数据,并写在 HTTP 响应的 正文body 中。
- 最后,Tomcat 服务器自动为我们实现了返回响应的逻辑。
(2) 代码
//从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//显示的告诉浏览器,数据是json格式的,字符集是utf8的
resp.setContentType("application/json;charSet=utf8");
//writeValue方法只是把messageList转成json格式的字符串
//并写在HTTP响应的正文body中
objectMapper.writeValue(resp.getWriter(),messageList);
}
2. 通过 ajax 构造 GET 请求
首先,我们必须明确,GET 请求在当前案例的逻辑是什么?
答:GET 请求:点击浏览器刷新按钮,将服务器的数据展示在浏览器上。
怎么展示?
答:先要获取 HTTP 响应中正文 body 的内容,再展示前端页面上。
(1) 步骤
客户端 构造 GET 请求、获取响应、显示响应结果的步骤:
- 首先,从 HTTP 响应中的正文 body 中获取 json 格式的内容。
- 其次,从 客户端获取到 HTTP响应 的时候,响应中的 正文body 已然从 json 格式自动转换成了 数组形式,我们就可以遍历这个数组获取每个对象,将对象的属性拼接成字符串返回。
- 最后,将 数组body中的 from, to, message 的三个值挂在 DOM 树的末尾,这样一来,就可以在浏览器上显示出来了。
(2) 代码
// [新增] 在页面加载的时候, 使用jQuery的ajax方法发送HTTP GET请求
//从服务器获取到数据并添加到页面中
$.ajax({
type: 'get', // 设定请求类型为GET
url: 'message', // 设定目标URL为"message"
success: function(body) { // 定义请求成功时的回调函数
// 此处拿到的 body 就是一个 js 的对象数组了.
// 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
// 自动帮我们把 json 字符串转成 js 对象数组
// 查找类名为'container'的div元素
let containerDiv = document.querySelector('.container');
// 接下来遍历这个body数组, 把元素取出来, 构造到页面中即可,此处相当于增强for循环
for (let message of body) {
// 对于body数组中的每个元素,创建一个新的div元素
let rowDiv = document.createElement('div');
// 为新创建的div元素设置类名为'row message'
rowDiv.className = 'row message';
// 设置新创建的div元素的HTML内容。这里将每个消息的"from", "to", 和 "message"字段拼接成一段文字。
rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
// 将新创建的div元素添加到containerDiv元素的子节点列表的末尾,从而将其显示在页面上
containerDiv.appendChild(rowDiv);
}
}
});
第二个交互接口:从客户端往服务器提交数据
1. 通过 ajax 构造 POST 请求
首先,我们必须明确,POST 请求在当前案例的逻辑是什么?
答:POST请求:点击提交按钮,将客户端的数据提交到服务器上。
怎么提交?
答:客户端先将内容写在 HTTP 请求中的正文 body 中,服务器接收到 HTTP请求后,读取请求中的正文 body 内容,并以顺序表这个数据结构保存起来。
(1) 步骤
客户端 构造 POST 请求、获取响应、显示响应结果的步骤:
- 首先,它创建一个名为
body
的JavaScript对象,此对象包含三个属性:from
、to
和message
,这些属性的值分别由变量from
、to
和msg
提供,分别代表消息的来源,消息的接收者,以及消息内容。 - 然后,它将
body
对象转换成JSON格式的字符串,存储在strBody
变量中。这是因为在HTTP请求中,数据需要以字符串的形式发送。 - 接着,它打印出
strBody
的内容。这通常是为了进行调试,或者在控制台确认发送的数据。 - 最后,它使用jQuery的
ajax
函数发送一个HTTP POST请求。此请求的目标URL为message
,发送的数据为strBody
,并声明其内容类型(Content-Type)为JSON格式,字符编码为UTF-8。 - 在请求成功后,它会执行一个回调函数,打印出"数据发布成功"的消息,表示数据已经成功发送。
(2) 代码
// 4. [新增] 给服务器发起 post 请求, 把上述数据提交到服务器这边
// 定义一个JSON对象,用于包含要发送的消息
let body = {
"from": from,
"to": to,
"message": msg
};
// 使用JSON.stringify方法将上述对象转换成字符串,以便能够作为HTTP请求体发送
let strBody = JSON.stringify(body);
// 使用console.log函数输出strBody的值,主要用于调试
console.log("strBody: " + strBody);
// 使用jQuery的ajax方法发送HTTP POST请求
$.ajax({
type: 'post', // 设定请求类型为POST
url: 'message', // 设定目标URL为"message"
data: strBody, // 设定请求体的内容为之前定义的字符串strBody
contentType: "application/json; charset=utf8", // 设定请求头部的Content-Type为"application/json; charset=utf8",告诉服务器发送的数据是JSON格式且字符编码为UTF-8
success: function(body) { // 定义请求成功时的回调函数
console.log("数据发布成功"); // 请求成功时,使用console.log函数输出一段信息,表示数据发布成功
}
});
2. 通过 Servlet 构造 POST 响应
(1) 步骤
服务器 解析请求、根据请求计算响应的步骤:
- 首先,Tomcat 服务器自动为我们实现了读取请求的逻辑。
- 其次,通过 jackson API 来将 json 格式的数据解析成 Java 对象,最终以键值对的形式呈现出来,再将整个对象放入顺序表中,暂时存起来。
- 接着,我们手动设置 HTTP 响应的 header 头、响应正文 body…
- 最后,Tomcat 服务器自动为我们实现了返回响应的逻辑。
(2) 代码
//向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//把body中的数据读取出来了,然后解析成Message对象
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
//此处用简单粗暴的方式来保存数据,将数据存入messageList这个顺序表中
messageList.add(message);
//此处的状态码可以省略.默认也是200
resp.setStatus(200);
}
前后端完全分离的总代码
1. ajax 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表白墙</title>
<style>
/* * 通配符选择器, 是选中页面所有元素 */
* {
/* 消除浏览器的默认样式. */
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 600px;
margin: 20px auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
margin: 20px 0;
}
.row {
/* 开启弹性布局 */
display: flex;
height: 40px;
/* 水平方向居中 */
justify-content: center;
/* 垂直方向居中 */
align-items: center;
}
.row span {
width: 80px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 280px;
height: 30px;
color: white;
background-color: orange;
/* 去掉边框 */
border: none;
border-radius: 5px;
}
/* 点击的时候有个反馈 */
.row button:active {
background-color: grey;
}
</style>
</head>
<body>
<div class="container">
<h1>表白墙</h1>
<p>输入内容后点击提交, 信息会显示到下方表格中</p>
<div class="row">
<span>谁: </span>
<input type="text">
</div>
<div class="row">
<span>对谁: </span>
<input type="text">
</div>
<div class="row">
<span>说: </span>
<input type="text">
</div>
<div class="row">
<button id="submit">提交</button>
</div>
<div class="row">
<button id="revert">撤销</button>
</div>
<!-- <div class="row">
xxx 对 xx 说 xxxx
</div> -->
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
// 实现提交操作. 点击提交按钮, 就能够把用户输入的内容提交到页面上显示.
// 点击的时候, 获取到三个输入框中的文本内容
// 创建一个新的 div.row 把内容构造到这个 div 中即可.
let containerDiv = document.querySelector('.container');
let inputs = document.querySelectorAll('input');
let button = document.querySelector('#submit');
button.onclick = function() {
// 1. 获取到三个输入框的内容
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if (from == '' || to == '' || msg == '') {
return;
}
// 2. 构造新 div
let rowDiv = document.createElement('div');
rowDiv.className = 'row message';
rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
containerDiv.appendChild(rowDiv);
// 3. 清空之前的输入框内容
for (let input of inputs) {
input.value = '';
}
// 4. [新增] 给服务器发起 post 请求, 把上述数据提交到服务器这边
// 定义一个JSON对象,用于包含要发送的消息
let body = {
"from": from,
"to": to,
"message": msg
};
// 使用JSON.stringify方法将上述对象转换成字符串,以便能够作为HTTP请求体发送
let strBody = JSON.stringify(body);
// 使用console.log函数输出strBody的值,主要用于调试
console.log("strBody: " + strBody);
// 使用jQuery的ajax方法发送HTTP POST请求
$.ajax({
type: 'post', // 设定请求类型为POST
url: 'message', // 设定目标URL为"message"
data: strBody, // 设定请求体的内容为之前定义的字符串strBody
contentType: "application/json; charset=utf8", // 设定请求头部的Content-Type为"application/json; charset=utf8",告诉服务器发送的数据是JSON格式且字符编码为UTF-8
success: function(body) { // 定义请求成功时的回调函数
console.log("数据发布成功"); // 请求成功时,使用console.log函数输出一段信息,表示数据发布成功
}
});
}
let revertButton = document.querySelector('#revert');
revertButton.onclick = function() {
// 删除最后一条消息.
// 选中所有的 row, 找出最后一个 row, 然后进行删除
let rows = document.querySelectorAll('.message');
if (rows == null || rows.length == 0) {
return;
}
containerDiv.removeChild(rows[rows.length - 1]);
}
// [新增] 在页面加载的时候, 使用jQuery的ajax方法发送HTTP GET请求
//从服务器获取到数据并添加到页面中
$.ajax({
type: 'get', // 设定请求类型为GET
url: 'message', // 设定目标URL为"message"
success: function(body) { // 定义请求成功时的回调函数
// 此处拿到的 body 就是一个 js 的对象数组了.
// 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
// 自动帮我们把 json 字符串转成 js 对象数组
//此次在控制台打印body,用于观察body的数据格式
console.log(body);
// 查找类名为'container'的div元素
let containerDiv = document.querySelector('.container');
// 接下来遍历这个body数组, 把元素取出来, 构造到页面中即可,此处相当于增强for循环
for (let message of body) {
// 对于body数组中的每个元素,创建一个新的div元素
let rowDiv = document.createElement('div');
// 为新创建的div元素设置类名为'row message'
rowDiv.className = 'row message';
// 设置新创建的div元素的HTML内容。这里将每个消息的"from", "to", 和 "message"字段拼接成一段文字。
rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
// 将新创建的div元素添加到containerDiv元素的子节点列表的末尾,从而将其显示在页面上
containerDiv.appendChild(rowDiv);
}
}
});
</script>
</body>
</html>
2. Servlet 代码
class Message {
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
//使用这个List来保存所有消息
private List<Message> messageList = new ArrayList<Message>();
private ObjectMapper objectMapper = new ObjectMapper();
//从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//显示的告诉浏览器,数据是json格式的,字符集是utf8的
resp.setContentType("application/json;charSet=utf8");
//writeValue方法只是把messageList转成json格式的字符串
//并写在HTTP响应的正文body中
objectMapper.writeValue(resp.getWriter(),messageList);
}
//向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//把body中的数据读取出来了,然后解析成Message对象
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
//此处用简单粗暴的方式来保存数据,将数据存入messageList这个顺序表中
messageList.add(message);
//此处的状态码可以省略.默认也是200
resp.setStatus(200);
}
}
3. 展示结果
(1) 提交数据展示
POST 请求与GET请求的抓包结果:
(2) 浏览器展示结果: ![](https://img-blog.csdnimg.cn/644df40756304f9b858c878da6e77ac4.gif)
4. 提出问题
在上面的客户端与服务器交互的过程中,从客户端往服务器提交数据,这一过程并没有什么问题,但客户端从服务器拿数据时,就出现了问题。
在我们使用 GET 请求与响应的时候,重启 Tomcat 服务器,然后刷新浏览器页面,之前客户端往服务器提交数据,就加载不出来了。这是为什么呢?
答:当前服务器把数据保存到了 messageList 变量,其实也就是将数据放到是内存中了,此时,一旦程序重启 ( 服务器重启 ),内存中的东西就没了。
private List<LovelyMessage> messageList = new ArrayList<>();
解决方案
从上面的存储方式看,我们从客户端发给服务器的数据,只是一份 “临时文件”,然而,那么,如何做到服务器重启后,数据也不丢失呢?
答:内存存储的是一份临时数据,那么,什么才能够持久化存储呢?一定就是硬盘了!如何写硬盘呢?
(1) 直接写到文件中
(2) 保存到数据库中
由于客户端发给服务器的数据,在服务器端没有做到持久化存储,所以,客户端这里的代码不需要改变,只需要改变服务器端的这边代码即可。
将数据写入数据库
(1) 定义了一个DUBtil类,这个类是一个工具类,主要用于处理数据库连接和断开的操作
- 为类定义了一个静态的
DataSource
成员,用于存储数据源。因为它是静态的,所以这个成员在整个进程中只有一个实例。 - 使用静态代码块来初始化
dataSource
。这个代码块会在类加载时执行,并且只会执行一次。这个代码块中设置了连接数据库的URL、用户名和密码。 - 提供一个静态方法
getConnection()
,用于获取数据库连接。它调用dataSource.getConnection()
方法获取一个数据库连接并返回。 - 提供一个静态方法
close()
,用于断开数据库连接和关闭资源。这个方法接收一个Connection
对象、一个PreparedStatement
对象和一个ResultSet
对象作为参数,并尝试关闭它们。
//通过这个类,把数据库连接过程封装一下
//此处把 DBUtil 作为一个工具类,提供 static 方法供其他代码使用
public class DBUtil {
//静态成员跟随对象的,类对象在整个进程中只有唯一一份
//静态成员相当于也是唯一的实例(单例模式,饿汉模式)
private static DataSource dataSource = new MysqlDataSource();
static {
//使用静态代码块,针对dataSource进行初始化操作
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/demo?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("1111");
}
//通过这个方法建立连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//通过这个方法断开连接,释放资源
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
if(resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
(2)实现从数据库获取所有的消息和保存一个新的消息
class Message {
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
//从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//显示的告诉浏览器,数据是json格式的,字符集是utf8的
resp.setContentType("application/json;charSet=utf8");
//顺序表接收从数据库读取到的所有message对象
List<Message> messageList = load();
//writeValue方法只是把messageList转成json格式的字符串
//并写在HTTP响应的正文body中
objectMapper.writeValue(resp.getWriter(),messageList);
}
//向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//把body中的数据读取出来了,然后解析成Message对象
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
//将message对象存入数据库
save(message);
//此处的状态码可以省略.默认也是200
resp.setStatus(200);
}
//提供一对方法
//往数据库中存一条消息
private void save(Message message) {
//JDBC操作
Connection connection = null;
PreparedStatement statement = null;
//1.建立连接
try {
connection = DBUtil.getConnection();
//2.构造sql语句
String sql = "insert into message values(?,?,?)";
statement = connection.prepareStatement(sql);
statement.setString(1,message.from);
statement.setString(2,message.to);
statement.setString(3,message.message);
//3.执行sql
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4,关闭连接
DBUtil.close(connection,statement,null);
}
}
//从数据库取所有消息
private List<Message> load() {
List<Message> messageList = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//1.和数据库建立连接
connection = DBUtil.getConnection();
//2.构造sql
String sql = "select * from message";
statement = connection.prepareStatement(sql);
//3.执行sql
resultSet = statement.executeQuery();
//遍历结果集合
while (resultSet.next()) {
Message message = new Message();
message.from = resultSet.getString("from");
message.to = resultSet.getString("to");
message.message = resultSet.getString("message");
messageList.add(message);
}
}catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源,断开连接
DBUtil.close(connection,statement,resultSet);
}
return messageList;
}
}
这个 MessageServlet 类主要包含四个方法:doGet,doPost,save,和 load。我将会按照这个顺序分别描述每个方法的执行过程。
- doGet 方法: 当客户端发送一个 GET 请求到 /message 这个 URL 的时候,doGet 方法会被调用。它首先设置 HTTP 响应的内容类型为 application/json;charset=utf8,然后调用 load 方法从数据库获取所有的消息,得到一个包含所有消息的 List<Message> 对象。然后,这个列表被转换为 JSON 格式的字符串,写入 HTTP 响应的正文中。这样,客户端就可以获取到所有的消息。
- doPost 方法: 当客户端发送一个 POST 请求到 /message 这个 URL 的时候,doPost 方法会被调用。它首先从 HTTP 请求的主体中读取数据,这些数据是 JSON 格式的,然后将这些数据解析为一个 Message 对象。然后,这个 Message 对象被传递给 save 方法,保存到数据库。最后,设置 HTTP 响应的状态码为 200,表示请求处理成功。
- save 方法: 这个方法接收一个 Message 对象,然后将这个对象保存到数据库。它首先获取一个数据库连接,然后创建一个 SQL INSERT 语句,将 Message 对象的 from,to,和 message 字段的值插入到数据库的 message 表中。然后,执行这个 SQL 语句,将数据保存到数据库。最后,关闭数据库连接和 SQL 语句对象,释放资源。
- load 方法: 这个方法从数据库加载所有的消息。它首先获取一个数据库连接,然后创建一个 SQL SELECT 语句,从 message 表中选择所有的记录。然后,执行这个 SQL 语句,获取结果集。遍历结果集,对于每一条记录,创建一个 Message 对象,将记录的 from,to,和 message 字段的值设置到 Message 对象中,然后将 Message 对象添加到列表中。最后,关闭数据库连接、SQL 语句对象、和结果集,释放资源。返回这个包含所有消息的列表。
(3) ObjectMapper类的使用
ObjectMapper
是Jackson库中的一个核心类,它提供了一些功能来将Java对象转换为JSON表示,以及将JSON字符串转换为Java对象。这个过程通常被称为序列化和反序列化。
- 序列化是将Java对象转换为JSON格式的过程
- 反序列化则是将JSON格式转换为Java对象的过程。
在上面的代码中,ObjectMapper的使用可以看在以下两处:
- 在doGet方法中,objectMapper.writeValue(resp.getWriter(),messageList);。这里使用ObjectMapper将Java对象(messageList)转换为JSON格式的字符串,并将其写入HTTP响应。
- 下面这种写法与上面这张写法等价
//writeValueAsString()方法将messageList转换成 JSON 字符串
String respJson = objectMapper.writeValueAsString(messageList);
//然后 将JSON 字符串写入响应
resp.getWriter().write(respJson);
- 在doPost方法中,Message message = objectMapper.readValue(req.getInputStream(),Message.class);。这里使用ObjectMapper从HTTP请求的输入流中读取JSON格式的字符串,然后将其转换为Message对象。
(4) 展示写入数据库
总结
- 基于 HTTP 协议,客户端与服务器通信流程的本质上就是:一发一收。
- 一发一收指的并不是只有一个客户端发送,一个服务器接收。一般情况下,一个服务器在同一时刻可以与许许多多的客户端交互。
- 可以联想到:我们通过百度查资料,同一时刻,可能就是成千上万的人同时向百度服务器发出查询请求。
- 然而,不同的客户端在与同一个服务器进行交互的时候,它们之间的约定是不一样的。( 比如:客户端 访问 / 接收路径,访问 / 接收数据… )
所以说,一发指的是客户端发一条指令,一收指的是服务器收到指令就会处理响应。
理解一发一收,对于 Web 开发是相当重要的。
在客户端发送请求之后,接着,服务器接收请求了,那么,服务器如何构造响应,选择在什么样的时刻处理请求,选择以什么样的格式返回响应等等…这些都是需要基于 “一发一收” 这样的规则。
综上所述,在写案例的时候,就需要先约定好:( 页面和服务器之间,要按照什么样的方式来交互),页面给服务器发送什么样的请求,服务器返回什么样的响应,这个是 Web 开发中最关键的,也是最难的步骤。
由于 前端负责构造发送请求,后端负责接收并解析请求;前端负责接收并解析响应,后端负责构造发送响应。如果不事先约定好,那么,就会造成无法正常沟通的状况。
比如:约定 HTTP请求 到底是 GET 还是 PUT ?约定 HTTP响应 到底是 json 格式 还是类似于 query string 的格式 ?约定 两者交互时的共同路径是什么 ?
同时,这也就是属于 Web程序 【设计】的一部分,这个和技术关系不大,主要是得理清楚业务流程。而业务流程取决于你的需求,这也就是你设计的初衷。
在当前表白墙的案例中,我的需求主要是为了实现服务器来保存用户提交的留言。
1. 第一个交互接口:从客户端往服务器提交数据。
当浏览器页面的用户点击提交的时候,就要给服务器发送一个请求,把这次留言的信息传给服务器。
2. 第二个交互接口:客户端从服务器拿数据。
当页面加载(刷新页面)的时候,客户端就需要给服务器发送一个请求,,把之前已经保存在服务器上的信息,获取下来,展示到浏览器的页面上。
表白墙 我们下期见