文章目录
- 表白墙
- 前言
- 1. 环境部署
- 1.1 创建maven项目
- 1.2 引入依赖
- 1.3 创建目录结构
- 1.4 部署程序
- 2. 前端页面
- 3. 后端实现
- 3.1 后端逻辑
- 3.2 后端代码
表白墙
前言
基于MySQL数据库和servlet实现的前后端交互的服务器版本表白墙。在页面输入表白内容,在本地通过数据库存储历次表白内容,保证网页刷新重进时数据仍存在。以下为打开表白墙效果展示:
我们可以在输入框输入表白对象,表白内容然后提交就能显示到新动态中,提交之后输入框自动清空内容。
完整项目代码可以通过我的gitee获取MessageWall
1. 环境部署
1.1 创建maven项目
我们在idea里面点击new project创建一个maven项目,然后一路next选择好项目位置以及命名即可。
1.2 引入依赖
在创建完maven项目之后我们需要加载依赖,部分同学可能由于网络问题难以加载,可以多试几遍,实在不行可以更换国内的镜像下载此处不作多介绍。以下需要引入的依赖主要有:java.servlet-api、mysql-connector-java,以及后续发送json格式的数据需要的jackson依赖(jackson-databind)
我们通过maven仓库官网https://mvnrepository.com/ 即可获取。
如图:复制链接黏贴到我们项目的pom.xml文件
代码 : 以下是我部署的依赖可以直接复制黏贴
<dependencies>
<!-- servlet依赖-->
<!-- 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依赖-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
<!-- 数据库依赖-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
1.3 创建目录结构
在我们的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>
1.4 部署程序
我们在插件市场搜索 Smart Tomcat 插件,将Tomcat集成到idea就不用我们手动打包,之后点击即可运行。
然后点击新增运行配置,将Smart Tomcat加入,此处选择Tomcat路径,如果还没有下载Tomcat,可以通过官网下载。博主使用的是 3.1版本的servlet+tomcat 8 。
然后就可以点击运行:出现以下结果就是部署成功了。之后我们就可以通过127.0.0.1:8080/MessageWall/xx.html(html页面)访问,其中MessageWall是Context path,一般默认是项目名。
2. 前端页面
由于该程序只是作为我们学习使用servlet实现前后端交互的一个开端,我们我们前端页面只包括:输入框 input 、提交按钮 button 、无语义标签 div 用来划分页面。
页面展示:
HTML代码: 除了html本身代码还包含通过 style 标签引入的css代码,通过 script 标签引入的js代码。
通过css实现页面样式以及布局,通过js实现提交按钮的点击效果(点击变灰)以及向服务器发送GET请求并获取数据加载到页面。
注意: 本次我们采用的是通过 form表单构造json格式的get请求发送到服务器 ,需要通过 jquery的ajax 实现:
- 导入jquery cdn,在浏览器搜索即可,也可以直接下载我的
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
- 通过ajax构造请求
$.ajax({
type: 'get',
url: 'message',
success: function(body) {
// 此处拿到的 body 就是一个 js 的对象数组了.
// 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
// 自动帮我们把 json 字符串转成 js 对象数组
// 接下来遍历这个数组, 把元素取出来, 构造到页面中即可
let containerDiv = document.querySelector('.qian')
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);
}
}
});
完整代码:
<!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;
}
.qian{
width: 300px;
height: 500px;
margin: 20px auto;
background-color: pink;
text-align: center;
}
</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="qian">
<h2>新动态</h2>
</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('.qian');
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 请求, 把上述数据提交到服务器这边
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('.message');
if (rows == null || rows.length == 0) {
return;
}
containerDiv.removeChild(rows[rows.length - 1]);
}
// [新增] 在页面加载的时候, 发送 GET 请求, 从服务器获取到数据并添加到页面中
$.ajax({
type: 'get',
url: 'message',
success: function(body) {
// 此处拿到的 body 就是一个 js 的对象数组了.
// 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
// 自动帮我们把 json 字符串转成 js 对象数组
// 接下来遍历这个数组, 把元素取出来, 构造到页面中即可
let containerDiv = document.querySelector('.qian')
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>
3. 后端实现
在后端实现中创建两个类即可,MessageServlet类由于实现前后端交互,DBUtils类用于操作数据库的工具类。
3.1 后端逻辑
- 前后端交互的数据约定为 json格式,在后端实现中也是通过导入的jackson库 解析该数据。
- 点击提交:浏览器将表白信息发送到服务器,对应着一对请求(Post)和响应
- 页面加载:浏览器从服务器哪获取到我们之前输入过的表白信息显示在页面,也对应一组请求(Get)与响应,该响应的body部分 通过json数组存储json格式的每条数据(json对象)。
由此我们在MassageServlet代码中只用实现 doPost()方法向服务器发送数据,doGet()方法从服务器获取数据,save()方法调用DBUtils类向数据库存储信息,load()方法从数据库取所有信息;
3.2 后端代码
MassageServlet.class:
- 在该类中 @WebServlet(“/message”) 对应着我们前端页面通过ajax构造请求发送的url路径一致,此处我们写的是相对路径。
- 导入jackson库之后我们就可以通过ObjectMapper类的readValue()读取请求中body的数据并规定以Massage.class格式读取,然后赋值给massage;
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
- massage.class,该类是为了存储读取到的json格式的键值对数据而创建。
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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @author zq
*/
class Message{
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
//private List<Message> messageList = new ArrayList<>();
//向服务器发送数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
//读取body中的内容赋值给massage对象
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
//通过简单粗暴的方法保存,list
//messageList.add(message);
save(message);
//设置响应状态码(可以不设置)
resp.setStatus(200);
}
//从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
ObjectMapper objectMapper = new ObjectMapper();
List<Message> messageList = load();
// objectMapper.writeValue(resp.getWriter(),messageList);
objectMapper.writeValue(resp.getWriter(),messageList);
}
//提供一对方法
//王数据库存一条消息
private void save(Message message) {
//这是基本的jdbc操作
//1.建立连接
Connection connection = null;
PreparedStatement statement =null;
try {
connection = DBUtil.getConnection();
//2.构造sql语句
String sql = "insert into message value(?,?,?)";
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<>();
//1.建立连接
Connection connection = null;
PreparedStatement statement =null;
ResultSet resultSet = null;
try {
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();
//根据列名取出sql语句
message.from = resultSet.getString("from");
message.to = resultSet.getString("to");
message.message = resultSet.getString("message");
messageList.add(message);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4.关闭连接
DBUtil.close(connection,statement,resultSet);
}
return messageList;
}
}
DBUtils.class:
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;
/**
* @author zq
*/
/*通过这个类将数据库连接封装起来
* 此处将DBUtil作为一个工具类,提供static方法共其他代码使用
* */
public class DBUtil {
//静态成员跟随类对象,类对象在整个进程中只有唯一一份
//静态成员相对于也是唯一实例,(单例模式,饿汉模式)
private static DataSource dataSource = new MysqlDataSource();
static{
//使用静态代码块,针对dataSource进行初始化操作
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/javaee?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("123456");
}
//通过该方法进行建立连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//通过这个方法进行释放资源
public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
//此处三个try-catch分开写更好
// 避免前面的出问题后面的执行不了
if (resultSet !=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}