情人节到了,手把手教你做一个表白墙,附有详细步骤

◕‿◕之前博主已经写过一个表白墙页面版的了,上次的比较简单,只是单纯地使用前端知识来完成的,有兴趣的可以看一下

🌹前 端 简 易 实 现 表 白 墙🌹
正因为只是利用前端知识来实现的,即所有数据在浏览器关闭后会丢失。这次,我们带领大家实现一个可以前后端交互的表白墙,这种表白墙的数据可以存储在服务器上,因此可以实现持久化保存~下面,让我们开始吧!

在这里插入图片描述

💗 配置Maven项目

1. 创建Maven项目

在这里插入图片描述

首先我们需要新建一个Maven项目,保存路径根据自己情况设置就行,其他的不用修改,这一步比较简单,就不细说了

2. 引入依赖

我们需要在pom.xm中引入两个依赖,一个是Servlet依赖,一个是Jackon依赖:

<?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>messagewall</artifactId>
    <version>1.0-SNAPSHOT</version>
<dependencies>
    <!-- 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>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.1</version>
    </dependency>

</dependencies>

</project>

3. 构造目录

在这里插入图片描述
我们构造如图所示的版本的目录结构即可,然后在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>

💙 约定前后端交互接口

所谓 “前后端交互接口” 是进行 Web 开发中的关键环节,具体来说:就是允许页面给服务器发送哪些 HTTP 请求,并且每种请求预期获取什么样的 HTTP 响应。此步是网页开发中最关键最有难度的步骤,要好好学哦!

  1. 第一个交互接口:当页面这里用户点击提交的时候,就要给服务器发送一个请求,把这次留言的信息传给服务器
  2. 第二个交互接口:当页面加载的时候,就需要给服务器发送一个请求,把之前已经保存在服务器上的信息获取下来,展示到页面上

接口格式可以约定如下:
在这里插入图片描述

💚 实现服务器端代码

在约定好前后端交互的接口后,我们就可以创建一个类来实现服务器端的代码了。
相关代码如下(附有注释)

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.*;
import java.util.List;

class Message {//表示其中一条请求的Jackon数据格式
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    private List<Message> messageList = new ArrayList<>();

    // 这个方法用来处理, 从服务器获取到消息数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        objectMapper.writeValue(resp.getWriter(), messageList);
    }

    // 这个方法用来处理, 从客户端提交数据给服务器
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        messageList.add(message);
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write("{\"ok\": 1}");
    }
}

💛 调整前端页面代码

当前服务器已经准备好接收浏览器的请求了,那么接下来我们就需要修改前端代码来真的构造出这个请求。
具体需求:

  1. 在页面加载的时候,访问服务器,从服务器这边获取到消息列表,并展示出来
  2. 点击提交按钮的时候,把当前的数据构造成一个HTTP请求,发送给服务器

具体思路:
要想进行这个前后端交互的过程,我们就需要使用到ajax,因此,我们需要引入jQuery来确保能使用ajax,然后我们就可以编写相关代码了。
完整的html代码如下:

<!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>
    <div class="container">
        <h1 class="title">表白墙</h1>
        <p>输入后点击提交, 会将信息显示在表格中</p>
        <div class="row">
            <span>谁: </span>
            <input class="edit" type="text">
        </div>
        <div class="row">
            <span>对谁: </span>
            <input class="edit" type="text">
        </div>
        <div class="row">
            <span>说什么: </span>
            <input class="edit" type="text">
        </div>
        <div class="row">
            <input type="button" value="提 交" class="submit">
        </div>
    </div>
     
    <style>
        * {
            margin: 0;/*设置外边距为0*/
            padding: 0;/*设置内边距为0*/
            box-sizing: border-box;/*设置边框不会撑大盒子*/
        }
        .title{
            color:red;
            font-family:KaiTi;
        }
        .container {
            width: 400px;
            margin: 0 auto;/*设置居中对齐*/
            padding-top: 50px;
        }
     
        h1 {
            text-align: center;
            padding-top: 50px;
        }
     
        p {
            color:black;
            text-align: center;
            font-size: 14px;
            padding: 10px 0;
        }
     
        .row {
            height: 40px;
            display: flex;/*弹性布局*/
            justify-content: center;
            align-items: center;
            font-family: KaiTi;
            font-weight: 700;
        }
     
        span {
            width: 100px;
            line-height: 40px;
        }
     
        .edit {
            width: 200px;
            height: 30px;
            padding-left: 5px;
        }
     
        .submit {
            width: 304px;
            height: 40px;
            color: white;
            background-color: orange;
            border: none;/*去除边框*/
            border-radius: 15px;
        }
        .submit:active{
            background-color:rgb(181, 184, 38);
        }/*设置点击提交按钮时的效果*/
        html, body {
       height: 100%;/* 设置整体页面高度,让页面和浏览器窗口一样高 */
       background-image: url("表白墙壁纸.png");/*设置背景图片*/
       background-position: center center;
       background-size:cover;
       background-repeat: no-repeat; }
    </style>
     <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
        //1. 在页面加载的时候,访问服务器,从服务器这边获取到消息列表,并展示出来
        function load() {
            // 通过这个 load 函数, 从服务器上获取到消息, 并进行展示
            $.ajax({
                type: 'GET',
                url: 'message',
                success: function(data, status) {//构造一个回调函数
                    // data 是响应的 body, 此时的响应可能只是一个字符串格式, 可以手动的进行一个解析, 按照 json 格式解析成对象
                    let container = document.querySelector('.container');
                    // let messages = JSON.parse(data);
                    let messages = data;
                    for (let message of messages) {//解析相关响应后进行一系列地html拼装
                        let row = document.createElement('div');//构造出一行来
                        row.className = 'row';
                        row.innerHTML = message.from + '对' + message.to + '说: '+ message.message;
                        container.appendChild(row);//把每一条消息都加到父元素中
                    }
                }
            });
        }
        load();
        //2. 点击提交按钮的时候,把当前的数据构造成一个HTTP请求,发送给服务器
    // 给点击按钮注册点击事件
    let submit = document.querySelector('.submit');//获取到提交按钮
    submit.onclick = function () {
        // 1. 获取到编辑框内容
        let edits = document.querySelectorAll('.edit');
        let from = edits[0].value;
        let to = edits[1].value;
        let message = edits[2].value;
        console.log(from + "," + to + "," + message);
        //对用户输入的内容做一个检查,确保是合法的提交
        if (from == '' || to == '' || message == '') {
            return;
        }
        // 2. 构造 html 元素
        let row = document.createElement('div');
        row.className = 'row';
        row.innerHTML = from + '对' + to + '说: ' + message;
        // 3. 把构造好的元素添加到DOM树中
        let container = document.querySelector('.container');
        container.appendChild(row);
        // 4. 同时清理之前输入框的内容
        for (let i = 0; i < 3; i++) {
            edits[i].value = '';
        }
        $.ajax({
                type: "POST",
                url: "message",
                data: JSON.stringify({from: from, to: to, message: message}),
                contentType: "application/json; charset=utf-8",
                success: function(data, status) {
                    if (data.ok == 1) {
                        console.log('提交消息成功!');
                    } else {
                        console.log('提交消息失败!');
                    }
                }
            })
    }
    </script>
</body>
</html>

写完后用Smart Tomcat进行打包部署后,我们在表白墙中输入内容后就可以保存到服务器中,这样在页面刷新时就不会丢失了:在这里插入图片描述
在这里插入图片描述
当前服务器是把数据给保存到了messageList变量中,变量就是位于内存中,此时此刻,一旦程序重启(服务器重启),内存中的东西就没了,那么如何让做到让服务器重启后数据还能不丢失呢?此时此刻我们就需要对数据进行持久化存储了

💜 将数据进行持久化存储

1. 将数据写入文件中

使数据进行持久化存储有两种方法,其中一种就是将数据写入文件中,此时我们就要用到前面的文件操作相关知识了。
相关代码如下(注意改动位置)

class Message {//表示其中一条请求的Jackon数据格式
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    //此处填要保存文件的路径
    private String filePath = "此处填自己希望把文件保存的位置的路径即可";

    // 这个方法用来处理, 从服务器获取到消息数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
    }

    // 这个方法用来处理, 从客户端提交数据给服务器
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        // 在这里, 要进行一个 "写文件" 操作
        save(message);
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write("{\"ok\": 1}");
    }

    private void save(Message message) {
        System.out.println("向文件中写入数据!");
        try (FileWriter fileWriter = new FileWriter(filePath, true)) {
            // 写入文件的格式也有很多方式. 可以直接写 json, 也可以使用行文本(每个记录占一行, 字段之间使用分隔符区分)
            fileWriter.write(message.from + "\t" + message.to + "\t" + message.message + "\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:
其中append中的参数设置为true的作用是将文件的打开方式设置为追加写的方式打开(使用输出流对象的时候),这样不会清空文件原有的内容,而是直接往最后来拼接
验证程序:在这里插入图片描述
在这里插入图片描述
当我们在页面中输入数据并提交后,可以看到编译器中已经提示向文件中写入数据了在这里插入图片描述
我们打开文件,同样可以看到已经保存好的数据,此时表示我们的数据已经可以持久化保存了,但当我们刷新页面后,可以看到页面上仍然没有任何东西:在这里插入图片描述
原因是此时我们只实现了将数据保存,而没有实现当页面刷新后把保存好的数据加载出来,那么我们只需要把文件中的数据加载回来显示到响应中即可。
我们需要构建一个load方法:

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.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

class Message {//表示其中一条请求的Jackon数据格式
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    //此处填要保存文件的路径
    private String filePath = "此处填自己希望把文件保存的位置的路径即可";

    // 这个方法用来处理, 从服务器获取到消息数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        List<Message> messageList = load();
        objectMapper.writeValue(resp.getWriter(), messageList);
    }

    private List<Message> load() {
        // 这个方法负责读文件, 把读到的数据获取到之后, 放到 List<Message> 中
        List<Message> messageList = new ArrayList<>();
        System.out.println("从文件加载!");
        //此处我们需要按行读取. FileReader 本身不支持. 需要套上一层BufferedReader
        //当然这里使用 Scanner 也行
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
            while (true) {
                String line = bufferedReader.readLine();
                if (line == null) {
                    break;
                }
                // 如果读取到 line 的内容, 就把 line 解析成一个 Message 对象
                String[] tokens = line.split("\t");
                Message message = new Message();
                message.from = tokens[0];
                message.to = tokens[1];
                message.message = tokens[2];
                messageList.add(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return messageList;
    }
    // 这个方法用来处理, 从客户端提交数据给服务器
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        // 在这里, 要进行一个 "写文件" 操作
        save(message);
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write("{\"ok\": 1}");
    }

    private void save(Message message) {
        System.out.println("向文件中写入数据!");
        try (FileWriter fileWriter = new FileWriter(filePath, true)) {
            // 写入文件的格式也有很多方式. 可以直接写 json, 也可以使用行文本(每个记录占一行, 字段之间使用分隔符区分)
            fileWriter.write(message.from + "\t" + message.to + "\t" + message.message + "\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

接下来我们使用Smart Tomcat重新打包部署程序,打开页面后刷新一下,就可以看到之前已经保存在文件中的数据了:在这里插入图片描述

2. 将数据保存到数据库中

除了将数据写入文件进行保存,我们也可以把数据保存到数据库中。

(1)引入数据库jar包

在使用数据库进行保存时,首先我们就需要先引入数据库的jar包,方法为从Maven的中央仓库中引入

  <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

(2)建库建表

引入jar包后,我们就可以写相关代码了,但在这之前,我们应该先在mysql中创建相关的数据库和数据表:

create table message(`from` varchar(1024),`to` varchar(1024),`message` varchar(1024));

注意,由于from和to为数据库中的关键字,为了防止冲突,应该加上反引号

(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;

public class DBUtil {
    private static final String URL = "此处填自己的数据库路径";
    private static final String USERNAME = "填自己数据库用户名";
    private static final String PASSWORD = "填自己数据库密码";

    private static volatile DataSource dataSource = null;

    public static DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setURL(URL);
                    ((MysqlDataSource)dataSource).setUser(USERNAME);
                    ((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();
            }
        }
    }
}

然后可以编写相关JDBC代码了(从数据库中读取相关数据和写入相关数据)

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.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

class Message {
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        List<Message> messageList = load();
        objectMapper.writeValue(resp.getWriter(), messageList);
    }

    private List<Message> load() {
        List<Message> messageList = new ArrayList<>();
        System.out.println("从数据库读取数据!");

        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");
                messageList.add(message);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return messageList;
    }

    // 这个方法用来处理, 从客户端提交数据给服务器
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);

        // 在这里, 要进行一个 "写文件" 操作
        save(message);

        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write("{\"ok\": 1}");
    }

    private void save(Message message) {
        System.out.println("向数据库中写入数据!");

        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
            int ret = statement.executeUpdate();
            if (ret == 1) {
                System.out.println("插入成功!");
            } else {
                System.out.println("插入失败!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }
}

验证程序
在这里插入图片描述
!
编译器中成功显示向数据库中写入数据并插入成功了!在这里插入图片描述
可以看到也我们成功将数据插入数据库中了!

3. 总结

当前我们的场景中,通过写文件方式存储数据要比存入数据库更简单一些;持久化存储,不仅仅是写数据库这一种办法,写文件有的时候也是简单有效的;一般来说,如果问题场景本身就比较简单,数据格式也不复杂,数据量也不大。这种直接就写文件即可,如果问题场景比较复杂(数据需要进行一系列计算加工),写数据库更合适~

那么,本篇博客到此就结束啦!博主已经将实现一个可前后端交互的表白墙的总体思路交给大家了,大家可以根据自己的需求加上各种图片哦,快去试试吧😘

  • 32
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 34
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春风~十一载

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值