作者
:学Java的冬瓜
博客主页
:☀冬瓜的主页🌙
专栏
:【JavaEE】
分享
: 寂寞会发慌,孤独是饱满的。——史铁生《命若琴弦》
主要内容
:前后端交互接口协商,约定好,使用什么数据格式传输,什么时候发送请求,发送什么请求。使用数据库对浏览器提交到服务器的信息进行长期的保存。前端html作为主体,CSS修饰html,使用js来操作dom树,并且在js中使用ajax来构造各种请求,使用ajax构造body为 json格式的post请求。后端内容将数据库连接过程使用DBUtil封装,使用MessageServlet.java来处理 前端发来的各种http请求。服务器根据请求对数据进行在数据库 存档,读档,删档的操作。
文章目录
- 一、准备工作
- 二、前端内容
- 三、后端内容
- 四、成果展示
一、准备工作
重点:
协商前后端交互接口
写web程序前,需要约定好,前后端如何进行交互,约定好交互的数据格式。比如请求的格式,响应的格式,浏览器什么时候发送请求,服务器按照什么格式来解析浏览器的请求,以及写回到浏览器使用什么格式数据。如下图,就使用post请求提交表白信息到服务器,再用get请求从服务器取表白信息,全过程中http报文交互的body格式全部使用json格式。
需求:点击提交时,浏览器使用post请求提交一份表白信息发送到浏览器存档;页面加载时,浏览器使用get请求发送给浏览器,从服务器读取全部表白信息;点击重置时,浏览器发送delete请求给服务器,删除服务器存档的最后一份表白信息。
理解:为什么使用数据库存储数据?
1> 如果不使用后端代码,只使用前端代码,可以展示表白墙的效果,但是message数据只是保存在浏览器中,当刷新一下页面,表白的信息就不在了。
2> 加入后端代码后,如果是使用一个集合来保存message信息,那么提交数据给服务器可以使用post提交,获取数据可以在加载页面时,使用get请求从服务器获取,刷新页面是给浏览器发送一个get请求,从集合中取出全部message信息显示到浏览器上,因此刷新页面数据还在。但是因为数据是存储在集合中,也就是内存中,当服务器一关闭,数据就不存在了。
3> 为了防止上述问题,最后可以使用数据库,存储在本地硬盘中,这样的话,即使服务器关闭,数据仍然存在。
二、前端内容
下面为
message.html:
代码,html作为页面的主体部分,并在html中引入css。在使用js中的ajax构造body为json格式的post请求前,先引入jQuery,然后在html的body标签中引入js文件。
<!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>
<!--引入css-->
<link rel="stylesheet" href="./messageWall.css">
</head>
<body>
<div class="all">
<div class="container">
<h2>表白墙</h2>
<p>输入后点击提交,信息会显示在表格下方</p>
<div class="row">
<span>谁:</span>
<input type="text" class="from">
</div>
<div class="row">
<span>对谁:</span>
<input type="text" class="to">
</div>
<div class="row">
<span>说:</span>
<input type="text" class="message">
</div>
<div class="row">
<button id="submit">提交</button>
<button id="reset">重置</button>
</div>
</div>
<div class="Conversation"></div>
</div>
<!-- 使用ajax前先引入jquery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<!--引入js-->
<script src="./messageWall.js"></script>
</body>
</html>
下面为
message.css:
代码,使用css修饰html页面
/* 通配符选择器,选中所有标签 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.all{
margin: 0 auto;
padding: 0;
background-color: pink;
height: 650px;
}
.container{
width: 600px;
height: 280px;
margin: 0px auto;
padding: 20px;
}
/* 设置h2,p居中 */
h2 {
text-align: center;
}
p {
text-align: center;
color: #666;
/* 先竖直,再水平 */
margin: 20px 0;
}
/* 设置弹性布局 */
.row {
/* 开启弹性布局 */
display: flex;
height: 40px;
/* 水平方向居中 */
justify-content: center;
}
/* 设置提示框的长度 */
.row span {
width: 80px;
}
/* 设置输入框的长度和高度 */
.row input {
width: 200px;
height: 30px;
}
.row button {
color: white;
background-color: orange;
width: 120px;
height: 35px;
border: none;
/* margin-left: 20px;
margin-right: 20px; */
margin: 20px;
}
/* 设置点击提交时变灰色 */
button:active {
background-color: #666;
}
/* 设置结果的div样式 */
.result {
text-align: center;
margin: 5px;
line-height: 40px;
}
.Conversation{
width: 280px;
height: 280px;
margin-top: 40px;
margin-left: auto;
margin-right: auto;
padding: 20px;
background-color: rgba(0,128,0,0.6);
}
下面为
message.js
代码,用于操作dom树,以及使用ajax构造请求的body格式为json的post请求。
- 按下提交时,使用ajax(得先引入jquery)给服务器发送一条post请求,提交表白信息到服务器
- 加载页面时,使用ajax给服务器发送一条get请求,从服务器获得所有表白信息
- 点击重置时,使用ajax给服务器发送一条delete请求,服务器将数据库的最后一条表白信息删除,然后将剩下的全部表白信息响应到ajax中,这里就需要用 js先把原来页面中的所有表白信息div删除,使用响应结果(删除最后一条表白信息后的数据) 构造表白信息div,再展示到浏览器上。
// 一.实现表白墙展示
let ConversationDiv = document.querySelector('.Conversation');
let inputs = document.querySelectorAll('input');
let submit = document.querySelector('#submit');
submit.onclick = function(){
// 1.获取到三个input的值
let from = inputs[0].value;
let to = inputs[1].value;
let mesg = inputs[2].value;
if(from == '' || to == '' || mesg == ''){
return;
}
// 2.构造新的展示div
let resultDiv = document.createElement('div');
resultDiv.className = 'row message result';
resultDiv.innerHTML = from + ' 对: ' + to + ' 说: ' + mesg;
ConversationDiv.appendChild(resultDiv);
// 3.清空表格中的内容
for(let input of inputs){
input.value = '';
}
// 【新增一】 按下提交时,使用ajax(得先引入jquery)给服务器发送一条post请求
// 注意:body内的数据的名称(左边)必须和后端的使用jackson解析成的 Message的字段类型一致;右边的则是上面定义获取的变量
let body = {
"from":from,
"to":to,
"message":mesg
}
let jsonBody = JSON.stringify(body);
$.ajax({
type: 'post',
url: './message',
contentType: 'application/json; charset=utf-8',
data: jsonBody,
success: function(){
// 这里的body是响应报文json格式的字符串 转换成的js对象
console.log("请求发送成功!");
}
})
}
// 【新增二】 页面加载时,从服务器获取 所有信息并显示在浏览器上
$.ajax({
type: 'get',
url: './message',
success: function(body){
console.log("响应接收成功!");
let ConversationDiv = document.querySelector('.Conversation');
for(let message of body){
// 对每一个message元素构造一个div
let resultDiv = document.createElement('div');
resultDiv.className = 'row message result';
resultDiv.innerHTML = message.from + ' 对: ' + message.to + ' 说: ' + message.message;
ConversationDiv.appendChild(resultDiv);
}
}
})
// 二.重置时把表格下的最后一条内容清除
let reset = document.querySelector('#reset');
reset.onclick = function(){
//【新增三】 点击重置时,不是直接删除最后一个节点,而是发送delete请求,服务器处理delete请求,然后显示剩下的所有信息
$.ajax({
type: 'delete',
url: './message',
success: function(body){
// 1.先选中父元素ConversationDiv,然后删除所有子元素
let ConversationDiv = document.querySelector('.Conversation');
while(ConversationDiv.firstChild){
ConversationDiv.removeChild(ConversationDiv.firstChild)
}
for(let message of body){
// 2.对响应数据内容进行页面显示,对每一个message元素构造一个div
let resultDiv = document.createElement('div');
resultDiv.className = 'row message result';
resultDiv.innerHTML = message.from + ' 对: ' + message.to + ' 说: ' + message.message;
ConversationDiv.appendChild(resultDiv);
}
}
})
}
三、后端内容
- 使用MessageServlet处理前端发来的各种请求,注意这里需要针对前端发来的body类型为json格式的内容进行解析,可以使用jackson来解析。
doPost
方法处理前端提交 表白信息的post请求,会在执行doPost方法中 调用save方法 将表白信息保存在数据库中。doGet
方法处理前端加载页面时 发来的get请求,会在执行doGet方法中 调用load方法将数据库中所有表白信息查出来,写回到浏览器。doDelete
方法处理前端重置,发来的删除最后一条表白信息的delete请求,会在执行doDelete方法中 调用delete方法将数据库中的最后一条信息删除,然后将剩下的内容写回浏览器。- 使用
MessageServlet.java
类解决浏览器发来的各种请求,使用DBUtil.java
类作为工具类,用来封装数据库连接的过程。
使用
MessageServlet.java
类解决浏览器发来的各种请求。
package servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
import util.DBUtil;
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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
// 使用Message来装填jackson解析的前端发来的json格式的字符串。
class Message {
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
// 使用jackson解析浏览器发来的json格式的数据
private ObjectMapper objectMapper = new ObjectMapper();
// 客户端(浏览器)按提交按钮时,向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 将req里的键值对读出,并和Message比对属性名给value,返回Message对象
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
// 把这一份表白信息保存到数据库
int count = save(message);
if(count == 1){
System.out.println("表白信息成功写入数据库");
}else {
System.out.println("表白信息写入数据库失败");
}
}
// 浏览器加载时,从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 把messageList这个Java集合对象转成json格式的字符串,再把字符串写入resp的body中
//注意:一定要记得设置响应报文的格式,否则前端代码会认为是其它格式,可能会按照其它格式解析
resp.setContentType("application/json; charset=utf-8");
// 从数据库获取所有表白信息
List<Message> messageList = load();
objectMapper.writeValue(resp.getOutputStream(), messageList);
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json; charset=utf-8");
// 从数据库获取所有表白信息
// 1.获取最后一份表白信息,并从数据库删除
List<Message> messageList = load();
if(messageList.size() == 0){
return;
}
Message messageEnd = messageList.get(messageList.size()-1);
int count = delete(messageEnd);
if(count == 1){
System.out.println("表白信息删除成功");
}else {
System.out.println("表白信息删除失败");
}
// 2.获取删除最后一条信息后的 全部表白信息,并写回到浏览器
messageList = load();
objectMapper.writeValue(resp.getOutputStream(), messageList);
}
private int save(Message message){
Connection connection = null;
PreparedStatement preparedStatement = null;
int count = 0;
try {
// 1.获取连接
connection = DBUtil.getConnection();
// 2.编写sql
String sql = "insert into message values(?,?,?)";
// 3.获取预编译对象,进行预编译
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,message.from);
preparedStatement.setString(2,message.to);
preparedStatement.setString(3,message.message);
// 4.执行sql语句
count = preparedStatement.executeUpdate();
// 5.处理结果
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, preparedStatement, null);
}
return count;
}
private List<Message> load(){
// 从数据库查询表白信息,把每条信息都放进这个集合里
List<Message> messageList = new ArrayList<>();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 1.获取连接
connection = DBUtil.getConnection();
// 2.编写sql
String sql = "select * from message";
// 3.获取预编译对象,进行预编译
preparedStatement = connection.prepareStatement(sql);
// 4.执行sql语句
resultSet = preparedStatement.executeQuery();
// 5.处理结果集
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 throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, preparedStatement, resultSet);
}
return messageList;
}
private int delete(Message message){
Connection connection = null;
PreparedStatement preparedStatement = null;
int count = 0;
try {
// 1.获取连接
connection = DBUtil.getConnection();
// 2.编写sql
String sql = "delete from message where `from` = ? and `to` = ? and message = ?";
// 3.获取预编译对象,进行预编译
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, message.from);
preparedStatement.setString(2, message.to);
preparedStatement.setString(3, message.message);
// 4.执行sql语句
count = preparedStatement.executeUpdate();
// 5.处理结果
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, preparedStatement, null);
}
return count;
}
}
使用
DBUtil.java
类作为工具类,用来封装数据库连接的过程
package util;
import com.mysql.cj.jdbc.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// DBUtil作为一个工具类,通过这个类,把数据库连接过程封装一下
public class DBUtil {
// 数据源是单例,饿汉模式创建mysql数据源
private static DataSource dataSource = new MysqlDataSource();
static {
// 使用静态代码块, 对 dataSource初始化
// 理解:这里的Url中的 jdbc:mysql是协议名称,其后跟ip和端口,然后是数据库 + query string
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/myProject?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("xxx");//写你自己的数据库密码哦
}
// 获取数据库连接对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 关闭资源封装
public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (preparedStatement != null){
try {
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
四、成果展示
1、输入:
输入表白信息(提交两份表白信息):
点击提交:
数据库中:
2、查询
提交表白信息后,重启服务器,输入地址,可以查询到之前提交的表白信息
会先展示出页面,过一小段时间后,就从数据库中查询出来,展示在页面上了
3、重置
点击重置后,页面中可以看到删除了最后一条表白信息:
数据库中: