文章目录
- 一、前端页面样式代码
- 二、前后端衔接
- 1. 后端创建 maven 项目
- 2. 针对前后端交互的解释以及后端代码的实现
- 针对 post 请求解释前后端衔接
- 针对 Get 请求解释前后端衔接
- 3.后端与数据库的联系以及对数据的存取
- 单独封装数据库连接代码
- 解释后端存储 save 数据的代码
- 解释后端读取 load 数据代码
- 三、总结
本篇文章所实现的这个表白墙,是一个前后端分离的一个 web 程序。
本篇文章中整体的代码本人以及上传至 gitee 如有需要可以访问查看:整体代码
这篇文章会重点解释后端的实现,对此,前端页面样式构建的代码不会进行过多的解释,将会直接的呈现在大家面前。
一、前端页面样式代码
<!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>
</head>
<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: wheat;
background-color: #ff6600;
border: none;
}
/* 让点击的时候有一个反馈 */
.row button:active{
background-color: #535350;
}
</style>
<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>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
// 在这里实现提交操作,点击提交按钮,就可以将用户输入的内容提交到页面上来显示
//在点击的时候获取三个输入框中的文本内容
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 massage';
rowDiv.innerHTML = from + '对' + to + '说' + msg;
containerDiv.appendChild(rowDiv);
//3.清空前面的输入
for(let input of inputs){
input.value = '';
}
// 4. [新增] 给服务器发起 post 请求, 把上述数据提交到服务器这边
let body = {
"from": from,
"to": to,
"message": msg
};
let strBody = JSON.stringify(body);
console.log("strBody: " + strBody);
$.ajax({
type: 'post',
url: 'message',
data: strBody,
contentType: "application/json; charset=utf8",
success: function(body) {
console.log("数据发布成功");
}
});
}
let revertButton = document.querySelector('#revert');
revertButton.onclick = function(){
//删除最后一条消息
//选中所有的 row ,找出最后一个 row
let rows = document.querySelectorAll('.massage');
if (rows == null || rows.length == 0) {
return;
}
containerDiv.removeChild(rows[rows.length-1]);
}
// [新增] 在页面加载的时候, 发送 GET 请求, 从服务器获取到数据并添加到页面中
$.ajax({
// 将前面获取到变量名的值 给到这边对应的 value
type: 'get',
url: 'message',
success: function(body) {
// 此处拿到的 body 就是一个 js 的对象数组了.
// 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
// 自动帮我们把 json 字符串转成 js 对象数组
// 接下来遍历这个数组, 把元素取出来, 构造到页面中即可
let containerDiv = document.querySelector('.container')
for (let message of body) {
// 针对每个元素构造一个 div
let rowDiv = document.createElement('div');
rowDiv.className = 'row message';
rowDiv.innerHTML = message.from + '对' + message.to + '说:' + message.message;
containerDiv.appendChild(rowDiv);
}
}
});
</script>
</body>
</html>
浏览器页面展示:
二、前后端衔接
1. 后端创建 maven 项目
- 创建必要的目录文件 webapp、WEB-INF、web.xml
这里的 web.xml 中的代码如下:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
- 调整 pom.xml
这里需要再 maven 仓库中引入三个对应的 jar 包。分别是:
servlet: 该 jar 包提供了大量后续代码需要使用的 Tomcat API。
jackson: 便于前后端使用 Jackson 进行键值对构建
mysql: 用于之后将交互信息存储到数据库中,用于之后访问时信息不会消失。
代码展示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>MassageWall</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--对应的 servlet 的 jar 包-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--对应的 Jackson 的 jar 包-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.1</version>
</dependency>
<!--对应的 mysql 的 jar 包-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
</project>
- 将前端页面拷贝到 webapp 中
要注意,这里的 html 文件必须放对地方,否则后面代码的运行就会出现问题。
2. 针对前后端交互的解释以及后端代码的实现
首先,这里我们需要在 main 文件下创建一个新的 Java 文件,并在其中创建出两个新的类,来书写我们的后端代码。如图:
当前的代码是在 massageServlet 中实现的。
在所有的代码实现之前,我们都需要进行规划,来确保我们每一步都在正确的方向上。
对于这里的代码,我们首先就需要进行约定。
这里的约定,本质上就是描述一个 前后端信息交互时的格式。
针对 post 请求解释前后端衔接
- 前端页面的 post 请求约定
这里切记一点,这里的 前端页面 是存放在 webapp 文件夹中的,后端代码是可以接收到其发出的 post 请求的。
在前端页面中,点击提交时就会发出一个 post 请求。
此时,就会发送一个如下图所示的 Json 字符串。这个字符串就是对应的约定格式。
在前端代码中,构建这样的请求代码截取下来就是下图形式:
- 后端页面接受 post 请求的约定
对于后端代码,接受 post 请求实现的是 doPost 方法。在接受传入的信息之前,后端代码需要定义一个 class 来作为约定来接受信息。如图:
下半部分是 doPost 方法的实现,其中 readValue 会将获取到的 json 字符串转化为 java 对象。
后端代码这里的作用是: 将前端传递的信息进行获取并储存起来。
注:
这个问题会在后面与数据库连接的代码中进行讲解。
从整体上来简单解释一下前后端 post 请求之间的配合。
针对 Get 请求解释前后端衔接
- 前端页面的 get 请求
对于前端页面,我们知道,在我们根据文件目录进行访问时,每次访问,前面的数据信息就会消失。
但是,在与后端连接时,前端页面在加载时,就会向后端服务器发送一个 get 请求获取之前的信息。
之后将其显示在浏览器的页面上。
前端连接的代码如下:
这里的 ajax 会将后端传递过来的 json 格式字符串识别为 js 能够识别的数据。
- 后端代码实现 doGet 方法
对于后端,在得到前端 get 请求之后。就会执行 doGet 方法来实现对前端的相应。
即就是,将之前的信息进行读取并解析为 json 字符串后,将其发送到前端的 body 中。
代码如下:
注:
同样的,这句读取代码会在后面与数据库连接时进行解释。
从整体上简单解释一下前后端在 get 请求之间的配合。大致如下:
3.后端与数据库的联系以及对数据的存取
到这里,前后端之间的信息交互的代码已经结束了。
从这里开始,我将会进行后端对数据的存储,以及前端页面加载时数据从数据库中的读取进行解释。
单独封装数据库连接代码
首先在 DBUtil 中单独实现一个数据库连接的类,将其进行封装。
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//通过这个类将数据库连接封装一下
// 此处这个类作为一个工具类,提供 static 方法供以调用
public class DBUtil {
//静态成员跟随类对象,类对象在整个进程中只有一份
//静态成员相当于是唯一的事例。(单例模式,饿汉模式)
private static DataSource dataSource = new MysqlDataSource();
//这里的代码在类加载的时间就会被创建出来
static{
//使用静态代码块,针对 DataSource 进行初始化
//这里与 JDBC 有相似之处,需要将连接的信息建立起来
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/wall?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("wjh123456");
}
//通过这个方法来建立连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//通过这个方法断开连接,释放资源
//connection 就是指连接的状态
//statement 是指当前正在执行的 sql 语句
//resultSet 是指当前正在获取 sql 语句执行的结果
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
// 此处的三个 try catch 分开写更好, 避免前面的异常导致后面的代码不能执行.
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();
}
}
}
}
这里的代码还是比较好理解的,大致分为两部分:
1、实现一个连接方法,将代码和数据库的连接独立出来,在其他方法请求时立即反应并进行连接。(饿汉模式)。
这里的 static 使得代码在类加载时就已经生产出来了,也就是说一直在等待着被连接。
2、实现一个关闭方法,断开连接,并注意异常的处理。
注意事项:
解释后端存储 save 数据的代码
这里解释的就是在 doPost 中的 save 方法。
这里的 save 与 JDBC 中的存储非常相似,代码不难理解,大致分为四步:
1、建立连接
2、构造 SQL 语句
3、执行 SQL 语句
4、断开连接
代码如下:
private void save(Message message){
//JDBC 操作
Connection connection = null;
PreparedStatement statement = null;
try {
//1. 建立连接
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);
}
}
注意事项:
解释后端读取 load 数据代码
这里解释的就是 doGet 中的 load 方法。
同样的,这里的代码与 JDBC 中的操作很是相似,代码同样不难理解,大致分为下面四步:
1、与数据库建立连接
2、构造 SQL 语句
3、执行 SQL 语句
4、遍历结果集合,并存放到链表中进行返回
5、断开与数据库连接
//从数据库中获取所有消息
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();
// 4. 遍历结果集合
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 {
// 5. 需要释放资源, 断开连接
DBUtil.close(connection, statement, resultSet);
}
return messageList;
}
三、总结
到这里,前后端分离的实现就已经大功告成了。
整体的运行展示:
1.启动服务器
2.访问网页页面
从整体的逻辑上看,前端,后端,数据库三者之间的联系,大致如下图所示:
码子不易,您小小的点赞是对我最大的鼓励!!!