JavaEE-实现一个服务器版本的“表白墙”

实现一个服务器版本的“表白墙”

实现的这个表白墙,就通过服务器,来保存这里的消息数据。
从而进一步的做到“持久化”存储~~

在实现这个程序的时候,就需要先考虑清楚,客户端和服务器如何进行交互~
约定前后端交互的接口~
(自定义应用层协议)

既然是搞一个服务器,服务器就得提供一些服务,具体是提供啥样的服务?以及这些服务该如何触发?

对于表白墙来说,主要要提供两个接口~

  1. 告诉服务器,当前留言了一条啥样的数据~(当用户点击提交按钮的时候,就会给服务器发送一个HTTP请求,让服务器把这个消息给存储下来)
  2. 从服务器获取到,当前都有哪些留言数据~(当页面加载,就需要从服务器获取到曾经存储的这些消息内容)

第一个接口

约定好,为了实现这个效果,客户端要发送一个啥样的HTTP请求,服务器返回一个啥样的HTTP响应~

请求:
POST /message
{
	from: "黑猫",
	to: "白猫",
	message: "喵" 
}

或者

POST /messageWall
from=黑猫&to=白猫&message=喵

或者

GET /message?from=黑猫&to=白猫&message=喵

或者

POST /message
	{
		f: "黑猫",
		t: "白猫",
		m: "喵" 
	}

按照上述的思路发散开,有无数种方式来约定请求格式!
方法可以变,路径可以变,参数的名字可以变~

这么多的约定方式,到底采取哪一种?
哪种都可以!只要能够明确下来其中的一种,并且在后续编写前端/后端代码的时候能够严格执行,就是ok的。
这也是约定前后端接口的意义!
自定义协议!(约束程序员的自由,不能随便乱写代码~)

当前就是用第一种方式!

请求:
POST /message
{
	from: "黑猫",
	to: "白猫",
	message: "喵" 
}

响应:
HTTP/1.1 200 OK
{
	ok: true
}

第二个接口

请求:
GET /message

响应:
HTTP/1.1 200 OK
Content-Type:application/json
[
	{
		from: "黑猫",
		to: "白猫", 
		message: "喵",
	},
	{
		from: "黑猫",
		to: "白猫", 
		message: "喵",
	},
	{
		from: "黑猫",
		to: "白猫", 
		message: "喵",
	},
]

确定接口之后,就可以编写代码了~

后端开发

先进行准备工作.

1.创建项目(maven)

在这里插入图片描述

2.引入依赖

引入Servlet,去中央仓库找~
在这里插入图片描述
在这里插入图片描述
接下来就是jackson
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.创建目录结构

在这里插入图片描述

<!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>

4.编写代码

在这里插入图片描述
这个和前面约定的前后端交互接口是匹配的~

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;

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 处理提交消息请求
        resp.getWriter().write("hello post");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取消息列表
        resp.getWriter().write("hello get");
    }
}

5/6. 打包和部署

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7. 验证

在这里插入图片描述

初步后端代码

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

    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);
        // 通过 ContentType 来告知页面,返回的数据是 json格式
        // 有了这样的声明,此时 jquery ajax 就会自动的帮我们把字符串转成 js 对象
        // 如果没有, jquery ajax 就只是当成字符串来处理
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write("{  \"ok\":true }");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取消息列表,只要把消息列表中的内容整个返回给客户端即可
        // 此处需要使用 ObjectMapper 把 Java 对象,转成 JSON 格式字符串
        String jsonString = objectMapper.writeValueAsString(messages);
        System.out.println("jsonString: " +jsonString);
        resp.getWriter().write(jsonString);
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当前我们已经把后端逻辑编写完毕,接下来来写前端代码

前端代码

在webapp里面放~
在这里插入图片描述

<!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>
<body>
    <div class="container">
        <h1>表白墙</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;
            padding: 0;
        }
        .container {
            width: 400px;
            margin: 0 auto;
        }
        h1 {
            text-align: center;
            padding: 20px 0;
        }
        p {
            color: #666;
            text-align: center;
            font-size: 14px;
            padding: 10px 0;
        }
        .row {
            height: 40px;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        span {
            width: 100px;
            line-height: 40px;
        }
        .edit {
            width: 200px;
            height: 30px;
        }
        .submit {
            width: 304px;
            height: 40px;
            color: white;
            background-color: orange;
            border: none;
        }
    </style>

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

    <script>
        // 加入 ajax 的代码,此处要加入的逻辑有两个部分
        // 点击按钮提交的时候,ajax 要构造数据发送到服务器
        // 页面加载的时候,从服务器获取消息列表,并在界面上直接显示

        function getMessage() {
            $.ajax({
               type: 'get',
               url: 'message',
               success: function(body) {
                // 当前 body 已经是 一个 js对象数组了,ajax 会根据响应的 content type 来在自动解析
                // 如果服务器返回的 content type 已经是 application/json了, ajax 就会把body自动转成 js 的对象
                // 如果客户端没有自动转,也可以通过 JSON.parse() 这个函数来手动转
                // 依次来取数组中的每个元素
                for (let message of body) {
                    let row =document.createElement('div');
                        row.className='row';
                        row.innerHTML=message.from+'对'+message.to+'说:'+message.message;
                        container.appendChild(row);
                }
               } 
            });
        }

        // 加上函数调用
        getMessage();

        // 给点击按钮注册点击事件
        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. 把构造好的元素添加进去
            let container = document.querySelector('.container');
            container.appendChild(row);
            // 4. 同时清理之前输入框的内容
            for (var i = 0; i < 3; i++) {
                edits[i].value = '';
            }

            // 4. 把当前获取到的输入框内容,构造成以一个 HTTP POST 请求,通过 ajax 发送给服务器
            let body = {
                from: from,
                to: to,
                message: msg
            };
            $.ajax({
                type: "post",
                url: "message",
                contentType: "application/json;charset=utf-8",
                data: JSON.stringify(body),
                success: function(body) {
                    alert("消息提交成功!");
                },
                error: function() {
                    alert("消息提交失败!");
                }
            })
        }
    </script>
</body>
</html>

在这里插入图片描述
当页面加载的时候,我们就能够看到有一个这个ajax请求,这个请求就是从服务器获取消息列表的~

在这里插入图片描述
此处看到是空着了,刚才不是明明往服务器上提交了三条记录?
在这里插入图片描述
刚刚这个代码是把消息保存到了list中,内容中的数据我们一旦程序重启就会丢失。
因此,上述逻辑,只能保证页面刷新后数据不丢失,而不能保证服务器重启后数据不丢失~
当然,要想更加彻底解决这个问题,就需要把数据保存到硬盘上(可以是文件,也可以是数据库)
在这里插入图片描述
当前确实可以证明,即使页面关闭之后,之前提交的消息是不丢失的~
(页面加载的时候,从服务器获取到了消息列表,并显示在了浏览器页面中)

后端代码优化

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

public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java107?characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "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(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();
            }
        }
    }
}


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.io.Reader;
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 doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 处理提交消息请求
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        // 最简单的保存方法就是保存在内存中
        //messages.add(message);
        // 通过 ContentType 来告知页面,返回的数据是 json格式
        // 有了这样的声明,此时 jquery ajax 就会自动的帮我们把字符串转成 js 对象
        // 如果没有, jquery ajax 就只是当成字符串来处理
        save(message);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write("{ \"ok\":true }");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取消息列表,只要把消息列表中的内容整个返回给客户端即可
        // 此处需要使用 ObjectMapper 把 Java 对象,转成 JSON 格式字符串
        List<Message> messages = load();
        String jsonString = objectMapper.writeValueAsString(messages);
        System.out.println("jsonString: " + jsonString);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(jsonString);
    }

    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) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }

    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) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return messages;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

摸鱼王胖嘟嘟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值