我们之前实现过这样一个表白墙,具体前端代码参考 表白墙 这篇文章
但是我们之前写的这个表白墙有一些问题:
1.如果我们刷新页面/重新开启,之前的数据就不见了
2.我们只能在单机操作,其他机器不能看见
于是我们现在就来解决这些问题,让服务器来存储用户提交的数据,当有新的浏览器打开该页面时,在从服务器获取数据,首先我们创建一个web项目,引入相关依赖
在src下创建webapp/WEB-INF/web.xml,并在pom.xml下面引入mysql依赖,servlet依赖和jackson依赖
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.49version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.14.1version>
dependency>
dependencies>
引入依赖之后记得刷新,
然后创建servelet类,并指明访问路径为message,具体实现我们后面在具体写
@WebServlet("/messagewell")
public class MessageWellServlet extends HttpServlet {
然后我们将我们之前写好的表白墙前端代码导入到webapp目录下,大家之前去我之前的文章里复制即可
既然我们想要进行前后端交互,就得约定好接口,前端给服务器发什么样的HTTP请求,服务器返回什么样的HTTP响应
1.页面加载,浏览器从服务器获取表白信息
前端请求: GET/message
响应: HTTP/1.1 200OK,返回json数组形式的数据
2.提交表白信息,浏览器将表白信息发送到服务器
前端请求:POST/message,发送json形式的数据
响应:HTTP/1.1 200OK
我们前端提交数据后,使用json格式发给服务器,我们需要构建一个这样的类,然后使用jackson进行接收数据
class Message {
public String from;
public String to;
public String message;
}
我们来实现一下当前端提交数据时,我们服务器的处理
List<Message> list = new ArrayList<>();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
//将body中的内容进行读取
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
//将获取到的message对象加入到成员变量list中
list.add(message);
//设置响应状态码
resp.setStatus(200);
}
有了doPost的基础,我们doGET方法就简单的多了,直接将list中的所有数据写回响应即可
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应格式
resp.setContentType("application/json; charset=utf8");
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(),list);
}
该方法是将java对象转成json字符串,并将其写入到响应中,如果大家觉得这个方法看起来费劲的话,大家也可以换一种方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应格式
resp.setContentType("application/json; charset=utf8");
ObjectMapper mapper = new ObjectMapper();
//将java对象转成json字符串
String jsonResp = mapper.writeValueAsString(list);
resp.getWriter().write(jsonResp);
}
我们前端需要发送两部分请求:
1.post,当我们点击提交表白信息的时候发起
2.get,我们加载页面的时候发起
我们使用VScode打开前端代码,引入jquery依赖
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
然后我们使用ajax构造请求
我们看一下我们之前写的前端代码,当我们onclick提交时,我们只是构造了一个div加入到页面内,现在我们增加一下,让其提交给后端
我们将输入框读取到的数据,构建成一个js对象,但是我们body只能传输字符串不能传输对象,于是我们需要将对象转成一个json格式的字符串
strBody = JSON.stringify(body);
strBody = JSON.stringify(body);
$.ajax({
type: 'post',
url: 'messagewell',
data: strBody,
contentType: "application/json; charset=utf8",
success: function(body) {
console.log("数据提交成功");
}
});
然后使用ajax将数据提交给服务器,我们来测试一下当前代码,我们使用tomcat部署,并访问
然后我们点击提交,我们看到确认发送了一个HTTP请求
这里就证明我们提交表白信息这一前后端操作是正确的
接下来我们来实现当我们刷新页面时读取服务器数据,我们使用ajax发送GET请求
//当我们页面加载时,给服务器发送GET请求,获取数据,添加到页面中
$.ajax({
type: 'get',
url: 'messagewell',
success: function(body) {
//此数body就是一个js格式的字符串,但是我们这里需要js对象数组
//jquery会帮我们将js对象字符串解析成js对象数组
for(let message of body) {
let rowDiv = document.createElement('div');
rowDiv.className = 'row';
rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说 ' + message.message;
containerDiv.appendChild(rowDiv);
}
}
})
我们这里的body,jquery为我们将js格式字符串解析为js对象数组,我们需要创建div标签,将每个js对象的数据添加到里面,然后将div添加到页面即可
现在我们重启服务器来验证一下
我们先随便提交几条数据,然后我们来尝试一下刷新页面
我们刷新后,数据仍然在页面上,我们在刷新的同时,给服务器发送了一个GET请求
同样的服务器将所有的表白信息响应给我们的浏览器
这样一个服务器版本的表白墙就实现完成了,大家需要注意的是我们的数据是在内存中存放的,如果我们重启服务器之后,之前的数据就不见了,如果想要持久化存储就需要借助数据库了
我们这里只需要创建一张message信息表,表中有三个属性(from,to,message)
大家需要注意我们在创表过程中的一些问题,因为我们的from和to是我们mysql中的关键字,所以我们需要加上`,接下来我们就使用JDBC来和数据库进行交互操作
因为我们数据库连接操作和关闭资源需要频频使用,所以我们这里创建一个DBUtil工具类来简化操作
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.*;
//DButi作为工具类,供其他类使用
public class DBUtil {
private static DataSource dataSource = new MysqlDataSource();
static{
//对datasuorce初始化
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/zd?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("自己的密码");
}
//通过该方法获取连接
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();
}
}
}
}
接下来我们在servlet类下实现两个方法,save()将我们前端提交的数据添加到数据库中,load()将我们数据库中的所有数据返回给前端
public void save(Message message) {
Connection connection = null;
PreparedStatement statement = null;
try {
//获取连接
connection = DBUtil.getConnection();
//构造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);
//执行sql
statement.executeUpdate();
}catch (SQLException e) {
e.printStackTrace();
}finally {
//关闭连接
DBUtil.close(connection,statement,null);
}
}
public List<Message> load() {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
List<Message> messageList = new ArrayList<>();
try {
//获取连接
connection = DBUtil.getConnection();
//构造sql语句
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");
messageList.add(message);
}
}catch (SQLException e) {
e.printStackTrace();
}finally {
//关闭连接
DBUtil.close(connection,statement,resultSet);
}
return messageList;
}