📍内容导读📍
- 🍅1.约定接口
- 🍅2.后端框架搭建
- 🍅3.实现服务器端代码
- 🍅4.构造请求测试服务器端
- 🍅5.调整前端页面代码
- 🍅6.数据存入数据库
🍅1.约定接口
实现这个表白墙案例的第一步,就是需要自定义应用层协议,确定好客户端和服务器如何进行交互。
数据能够进行存储的格式有很多种,也就是前后端需要共同指定数据格式,以便在客户端向服务器发送给去数据请求后,能够按照彼此约定好的应用层协议进行数据解析。
对于表白墙来说,主要要提供两个接口,要约定好客户端要发送一个怎样的HTTP请求,服务器返回一个怎样的HTTP响应,下边我们会直接指定数据格式为json
格式:
接口一:
告诉服务器,当前留言了一条怎样的数据
(当用户点击提交按钮的时候,就会给服务器发送一个HTTP请求,让服务器把这个消息给存下来)
接口二:
从服务器获取到当前都有哪些留言数据
(当页面加载,就需要从服务器获取到曾经存储的留言内容)
在我们确定好接口后,就可以进行代码的编写了。
🍅2.后端框架搭建
我们接下来,就按照常规Servlet程序的搭建流程进行搭建,先进性整体框架的搭建。
1.创建maven项目
2.引入依赖
(引入Servlet依赖和JSON依赖)
3.创建目录
4.编写代码
(只编写简单代码,用于测试是否搭建接口完成)
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello get");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello post");
}
}
5、6.打包部署
7.验证
🍅3.实现服务器端代码
先将消息列表存储到内容中(通过顺序表实现)
/**
* 与json格式对应的类
*/
class Message {
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
//用于将类和json进行转换的类
private ObjectMapper objectMapper=new ObjectMapper();
//用于存放消息的顺序表
private List<Message> messages=new ArrayList<>();
/**
* 处理提交消息请求,对数据进行保存
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Message message=objectMapper.readValue(req.getInputStream(),Message.class);
messages.add(message);
//指定响应的数据格式
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write("{\"ok\":true}");
}
/**
*获取消息列表,把消息列表中的内容返回给客户端
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将Java对象转成JSON格式字符串
String jsonString=objectMapper.writeValueAsString(messages);
System.out.println("jsonString:"+jsonString);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(jsonString);
}
}
🍅4.构造请求测试服务器端
利用应用postman
来进行构造请求,用于测试服务器端代码。
postman
可自行下载,专门用来构造HTTP请求,进行服务器端的测试。首先我们在idea
通过smart tomcat
启动服务器,然后进行测试。
对接口一进行测试,构造POST请求,输入数据。
对接口二进行测试,构造GET请求,得到对接口一测试时输入的消息列表,测试完成。
🍅5.调整前端页面代码
在之前文章【JavaScript进阶3.2 表白墙案例】的表白墙代码可以直接拿来用,再进行调整,完成两个接口的功能即可。
将该前端html
文件拷贝到webapp
目录下,再进一步调整完善前端代码的ajax
请求
对前端代码的调整,主要的逻辑有两部分:
1.点击提交按钮时,ajax
要构造数据发送给服务器。
2.页面加载的时候,从服务器获取消息列表,并在界面上直接显示。
首先我们还是先引入jQuery
功能1:把当前输入框的内容,构造成一个HTTP POST
请求,通过ajax
发送给服务器。
功能2:通过函数完成消息列表的获取打印。
完整前端代码:
<!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>Document</title>
</head>
<body>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: rgb(30,100,200);
}
.container {
width: 100%;
}
h3 {
text-align: center;
padding: 30px 0;
font-size: 24px;
color: rgb(255,140,10);
}
p {
text-align: center;
color: rgba(255, 50, 100);
font-size: 18px;
padding: 5px 0;
}
.row {
width: 400px;
height: 50px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.row span{
width: 100px;
height: 40px;
text-align: center;
padding-right: 0px;
font-size: 24px;
color: rgb(255,140,10);
}
.row input {
width: 300px;
height: 40px;
border: 2px solid rgb(255, 140,160);
border-radius: 5px;
outline: 0;
text-align: left;
padding-left: 0px;
margin-left: 0px;
text-indent: 0.4em;
font-size: 20px;
color: rgb(9, 245, 135);
}
.row #submit{
width: 200px;
height: 40px;
border-radius: 10px;
font-size: 24px;
border: 0px solid rgb(255, 140, 160);
background-color: rgb(255, 140, 160);
color: aliceblue;
line-height: 40px;
margin-top: 8px;
}
.row #submit:active{
background-color: rgb(140,180,240);
}
</style>
<div class="container">
<h3>表白墙</h3>
<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>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
function getMessages() {
$.ajax({
type:"get",
url:'message',
success:function(body) {
let container=document.querySelector('.container');
for(let message of body) {
let div=document.createElement('div');
div.innerHTML=message.from+'对'+message.to+'说:'+message.message;
div.className='row';
container.appendChild(div);
}
}
})
}
getMessages();
// 当用户点击submit,就会获取到input中的内容,从而把内容构造成一个div,插入到页面末尾
let submitBtn=document.querySelector('#submit');
submitBtn.onclick=function() {
// 1.获取到3个input中的内容
let inputs=document.querySelectorAll('input');
let from=inputs[0].value;
let to=inputs[1].value;
let msg=inputs[2].value;
if(from==''||to==''||msg=='') {
// 用户还没有提交完,暂时先不提交数据
return;
}
// 2.生成一个新的div,内容是input里面的内容,把这个新的div加到页面中
let div=document.createElement('div');
div.innerHTML=from+'对'+to+'说:'+msg;
div.className='row';
let container=document.querySelector('.container');
container.appendChild(div);
//3.清空之前输入框内的内容
for(let i=0;i<inputs.length;i++) {
inputs[i].value='';
}
//4.功能一
let body={
from:from,
to:to,
message:msg
};
$.ajax({
type:"post",
url:"message",
contentType:"application/json;charset=utf8",
data:JSON.stringify(body),
success:function(body) {
alert("消息提交成功!");
},
error:function(body) {
alert("消息提交失败!");
}
});
}
</script>
</body>
</html>
效果预览:
通过将消息存入内容的方式,只要服务器不重启,可以使得页面即使刷新,消息列表也不会丢失,但如果将服务器重启,消息列表一定会丢失。所以如果想要将数据持久化存储,需要将数据写入硬盘,可以通过写入文件或者写入数据库的方式,下边我们就将消息存入数据库,实现数据的持久化存储。
🍅6.数据存入数据库
1)引入mysql
数据库依赖
2)创建数据库
3)创建DBUtil
类,用于与数据库的交互。
public class DBUtil {
private static final String url="jdbc:mysql://localhost:3306/homework?characterEncoding=utf8&useSSL=false";
private static final String user="root";
private static final String password="1234";
private volatile static DataSource dataSource=null;
//线程安全的单例模式
private static DataSource getDataSource() {
if(dataSource==null) {
synchronized (DBUtil.class) {
if(dataSource==null) {
dataSource=new MysqlDataSource();
((MysqlDataSource)dataSource).setURL(url);
((MysqlDataSource)dataSource).setUser(user);
((MysqlDataSource)dataSource).setPassword(password);
}
}
}
return dataSource;
}
public static Connection getConnection() throws SQLException {
return getDataSource().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();
}
}
}
}
由于客户端发出的请求可能存在线程安全的问题,所以得到数据源的方法使用线程安全的单例模式
4)调整Servlet
代码,完成数据存入数据库关键方法:
完整代码:
/**
* 与json格式对应的类
*/
class Message {
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
//用于将类和json进行转换的类
private ObjectMapper objectMapper=new ObjectMapper();
//用于存放消息的顺序表
// private List<Message> messages=new ArrayList<>();
/**
* 处理提交消息请求,对数据进行保存
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Message message=objectMapper.readValue(req.getInputStream(),Message.class);
// messages.add(message);
//指定响应的数据格式
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write("{\"ok\":true}");
}
/**
*获取消息列表,把消息列表中的内容返回给客户端
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将Java对象转成JSON格式字符串
String jsonString=objectMapper.writeValueAsString(messages);
System.out.println("jsonString:"+jsonString);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(jsonString);
}
/**
* 把一条消息保存到数据库中
* @param message
*/
private void save(Message message) {
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 {
DBUtil.close(connection,statement,null);
}
}
/**
* 从数据库中获取到所有的消息
* @return
*/
private List<Message> load() {
List<Message> messages=new ArrayList<>();
Connection connection=null;
PreparedStatement statement=null;
ResultSet resultSet=null;
try {
connection=DBUtil.getConnection();
String sql="select * from message";
statement=connection.prepareStatement(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");
messages.add(message);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(connection,statement,resultSet);
}
return messages;
}
}
效果演示:
由上述演示可得,现在的消息已经写入数据库,能够持久化存储了,至此,表白墙小案例也就大功告成了,快自己动手试试吧!