【JavaEE初阶】Servlet (三)MessageWall

在我们之前博客中写到的留言墙页面,有很严重的问题:(留言墙博客)

  1. 如果刷新页面/关闭页面重开,之前输入的消息就不见了.
  2. 如果一个机器上输入了数据,第二个机器上是看不到的.

针对以上问题,我们的解决思如如下:
让服务器来存储用户提交的数据,由服务器保存.
当有新的浏览器打开页面的时候,从服务器获取数据.

此时服务器就可以用来存档和读档.

设计程序:
写web程序,务必要重点考虑前后端如何交互,约定好前后端交互的数据格式.
设计前后端交互接口: 1.请求是什么样 2. 响应是什么样 3.浏览器什么时候发送这个请求 4. 浏览器按照什么格式来解析

在我们的留言墙程序中,以下环节涉及到前后端交互:

  1. 点击提交,浏览器把表白墙信息发送到服务器这里
  2. 页面加载,浏览器从服务器获取到表白信息.
  1. 点击提交,浏览器把表白墙信息发送到服务器这里
    请求:
    POST/message
    按照json格式:
{
	from:"i",
	to:"you",
	message:"hello"
}

响应:
HTTP/1.1 200 OK

  1. 页面加载,浏览器从服务器获取到表白信息.
    请求:
    GET/message
    响应:
    HTTP/1.1 200 OK
    body部分:
[
	{
		from:"i",
		to:"you",
		message:"hello"
	}
	{
		from:"i",
		to:"you",
		message:"hello"
	}
]

此处约定的目的是为了前端代码和后端代码能够对应上.约定的方式可以有很多种.
通过约定,我们可以写出后端代码为:

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 List<Message> messageList = new ArrayList<>();
    ObjectMapper objectMapper = new ObjectMapper();

    //    向服务器提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //读取body中的内容,解析成 Message 对象
        Message message = objectMapper.readValue(req.getInputStream(),Message.class);
        //保存
        messageList.add(message);
        //设置状态码
        resp.setStatus(200);
    }
    //    从服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //显示告诉浏览器,数据是 json 格式,字符集是 utf8
        resp.setContentType("application/json;charset=utf8");
        //通过 writeValue 将 messageList(java对象) 转成 json 格式并将其写入 resp 中
        //objectMapper.writeValue(resp.getWriter(),messageList);

        //把java对象转成json字符串
        String jsonResp = objectMapper.writeValueAsString(messageList);
        System.out.println("jsonResp: "+jsonResp);
        //把这个字符串写回到响应 body 中
        resp.getWriter().write(jsonResp);
    }
}

通过Postman 构造POST请求,使用json语法编辑body部分,点击两次发送,再通过GET获取得到响应如下:
在这里插入图片描述
存档:
其次,我们再看前端代码:在前端代码中使用ajax发送一个post请求.
在这里插入图片描述
通过fiddler得到:
在这里插入图片描述
通过dopost 执行:
在这里插入图片描述
通过resp.setStatus(200);回到回调函数:
在这里插入图片描述
读档:根据ajax创建GET响应:
在这里插入图片描述
打开fiddler可以看到:
在这里插入图片描述
GET请求触发doGet方法:
在这里插入图片描述
我们可以得到完整的前端代码(包含撤销功能):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MessageBoard</title>
    <style>
        *{
            /* 消除浏览器的默认样式 */
            margin: 0;
            padding: 0;
            /* 保证盒子不会撑大 */
            box-sizing: border-box;
            /* background-color: rgba(255, 192, 203, 0.436); */
        }
        .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;
        }
    </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>

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

    <script>
        //实现提交操作,点击提交,就能够吧用户输入的内容提交到页面上显示
        //点击时,获取到三个输入框的文本内容
        //创建一个新的div.rom把内容构造到这个div中即可.
        let containerDiv = document.querySelector('.container');
        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请求,把上述数据提交到服务器
            //定义一个js对象
            let body = {
                from:from,
                to:to,
                message:msg
            };
            //将对象转成json字符串
            strBody = JSON.stringify(body);
            $.ajax({
                type:'post',
                url:'message',
                data:strBody,
                contentType:"application/json; charset=utf-8",
                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]);
            //[新增]删除
            $.ajax({
                type: 'delete',
                url: 'message',
                success: function(body){
                    // 1.先选中父元素ConversationDiv,然后删除所有子元素
                    let ConversationDiv = document.querySelector('.Conversation');
                    while(ConversationDiv.firstChild){
                        ConversationDiv.removeChild(ConversationDiv.firstChild)
                    }

                    for(let message of body){
                        // 2.对响应数据内容进行页面显示,对每一个message元素构造一个div
                        let resultDiv = document.createElement('div');
                        resultDiv.className = 'row message result';
                        resultDiv.innerHTML = message.from + ' 对: ' + message.to + ' 说: ' + message.message;
                        ConversationDiv.appendChild(resultDiv);
                    }
                }
            })
            
        }

        //[新增]在页面加载的时候,发送GET请求,从服务器获取到数据并添加到页面中
        $.ajax({
            type:'get',
            url:'message',
            success:function(body){
                let containerDiv = document.querySelector('.container');
                for(let message of body){
                    let rowDiv = document.createElement('div');
                    rowDiv.className ='row message';
                    rowDiv.innerHTML = message.from +' 对 '+ message.to +' 说 : ' + message.message;
                    containerDiv.appendChild(rowDiv);
                }
            }
        });
    </script>
</body>
</html>

在这里插入图片描述
刷新页面后数据也不会消失.
但是以上重启服务器后数据就消失了,所以我们可以把数据写入数据库中进行长久的保存.
C:\Users\xxxflower>mysql -uroot -p
Enter password: ****
create table message(from varchar(20),to varchar(20),message varchar(1024));
注意,由于from和to都是sql中的关键字,所以需要使用`.
创建表:
在这里插入图片描述
完整的后端代码:
MessageServlet.java:

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;

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

    //    向服务器提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //读取body中的内容,解析成 Message 对象
        Message message = objectMapper.readValue(req.getInputStream(),Message.class);
        //保存
        save(message);
        //messageList.add(message);
        //设置状态码
        resp.setStatus(200);
    }
    //    从服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //显示告诉浏览器,数据是 json 格式,字符集是 utf8
        resp.setContentType("application/json;charset=utf-8");
        //通过 writeValue 将 messageList(java对象) 转成 json 格式并将其写入 resp 中
        //objectMapper.writeValue(resp.getWriter(),messageList);

        //把java对象转成json字符串
        List<Message> messageList = load();
        String jsonResp = objectMapper.writeValueAsString(messageList);
        System.out.println("jsonResp: " + jsonResp);
        //把这个字符串写回到响应 body 中
        resp.getWriter().write(jsonResp);
    }
    //使用jdbc 往数据库里面存消息
    private void save(Message message) {
        //JDBC

        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 {
            //4.关闭连接
            DBUtil.close(connection,statement,null);
        }

    }
    //从数据库取所有消息
    private List<Message> load(){
        List<Message> messageList = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1.与数据库建立连接
            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();
                message.from = resultSet.getString("from");
                message.to = resultSet.getString("to");
                message.message = resultSet.getString("message");
                messageList.add(message);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //5.释放资源 断开连接
            DBUtil.close(connection,statement,resultSet);
        }
        return messageList;
    }
    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json; charset=utf-8");
        // 从数据库获取所有表白信息
        // 1.获取最后一份表白信息,并从数据库删除
        List<Message> messageList = load();
        if(messageList.size() == 0){
            return;
        }
        Message messageEnd = messageList.get(messageList.size()-1);
        int count = delete(messageEnd);
        if(count == 1){
            System.out.println("留言信息删除成功");
        }else {
            System.out.println("留言信息删除失败");
        }
        // 2.获取删除最后一条信息后的 全部表白信息,并写回到浏览器
        messageList = load();
        objectMapper.writeValue(resp.getOutputStream(), messageList);
    }
    private int delete(Message message) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        int count = 0;
        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.编写sql
            String sql = "delete from message where `from` = ? and `to` = ? and message = ?";
            // 3.获取预编译对象,进行预编译
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, message.from);
            preparedStatement.setString(2, message.to);
            preparedStatement.setString(3, message.message);
            // 4.执行sql语句
            count = preparedStatement.executeUpdate();
            // 5.处理结果

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }
        return count;
    }
}

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;

//这个类用于封装数据库连接过程
//此处把 DBUtil 作为一个工具类,提供 static 方法供其他代码使用
public class DBUtil {
    //静态成员跟随类对象,类对象在整个进程中只有唯一一份
    //静态成员相当于也是唯一的实例(单例模式,饿汉模式)
    private static DataSource dataSource = new MysqlDataSource();

    //使用静态代码块针对 DataDource 进行初始化操作
    static {
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/javaee?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("0828");
    }

    //建立连接
    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();
            }
        }
    }
}

最终实现效果:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/56369.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows 实例如何开放端口

矩池云 Windows 实例相比于 Linux 实例&#xff0c;除了在租用机器的时候自定义端口外&#xff0c;还需要在 Windows防火墙中添加入口规则。接下来将教大家如何设置 Windows 防火墙&#xff0c;启用端口。 租用成功后通过 RDP 链接连接服务器&#xff0c;然后搜索防火墙&#x…

动态获取数据合并el-row和el-col

原本后台返回数据都是各自独立&#xff0c;互不影响的&#xff0c;数据结构如图&#xff1a; [{"mainContent": "AA","secondContent": "b","testProject": "日常运行","result": "","…

新版塔罗占卜网站源码八字合婚风水起名附带搭建视频

新版塔罗占卜网站源码八字合婚风水起名PHP源码附带搭建视频,附带文本教学及视频教程安装方法以linux为例: 1、建议在服务器上面安装宝塔面板,以便操作,高逼格技术员可以忽略这步操作。 2、把安装包文件解压到根目录,同时建立数据库,把数据文件导入数据库 3、修改核心文件…

补充JDK源码-IDEA集成工具

在阅读JDK8源码的时候发现&#xff0c;只有一小部分常用包是存在源码及其注释的&#xff0c;而很多内部包是没有源码&#xff0c;class文件在阅读的时候对阅读者十分不友好。在网上搜集了很多资料都没有解决问题。 解决问题办法&#xff1a;参考文档。本文主要是根据这篇文章记…

Linux下基于Dockerfile构建镜像应用(1)

目录 基于已有容器创建镜像 Dockerfile构建SSHD镜像 构建镜像 测试容器 可以登陆 Dockerfile构建httpd镜像 构建镜像 测试容器 Dockerfile构建nginx镜像 构建镜像 概述&#xff1a; Docker 镜像是Docker容器技术中的核心&#xff0c;也是应用打包构建发布的标准格式。…

史上最细,接口自动化测试框架-Pytest+Allure+Excel整理(代码)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Allure框架 Allu…

Vue 自定义事件绑定与解绑

绑定自定义事件 说到 Vue 自定义事件&#xff0c;那就需要搞清楚一个问题&#xff0c;为啥有这个玩意。 说到自定义事件之前&#xff0c;需要理解 组件基础的概念。理解了基础概念之后&#xff0c;我们就知道 Vue 的父子之间的通信&#xff0c; 一是 父组件通过 Prop 向子组件…

qt系列-qt6在线安装慢的问题

.\qt-unified-windows-x64-online.exe --mirror https://mirrors.aliyun.com/qt/下载速度飞快

就业并想要长期发展选数字后端还是ic验证?

“就业并想要长期发展选数字后端还是ic验证&#xff1f;” 这是知乎上的一个热点问题&#xff0c;浏览量达到了13,183。看来有不少同学对这个问题感到疑惑。之前更新了数字后端&数字验证的诸多文章&#xff0c;从学习到职业发展&#xff0c;都写过&#xff0c;唯一没有做过…

Mybatis 知识点

Mybatis 知识点 1.1 Mybatis 简介 1.1.1 什么是 Mybatis Mybatis 是一款优秀的持久层框架支持定制化 SQL、存储过程及高级映射Mybatis 几乎避免了所有的 JDBC 代码和手动设置参数以及获取结果集MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO…

代码随想录算法训练营第三十二天 | 全是没接触过的知识点,要复习

以下题目多次复习 200 岛屿数量未看解答自己编写的青春版重点本题的解题思路&#xff0c;也是之前没有接触过的&#xff0c;四字总结&#xff1a;学会感染&#xff01; 题解的代码日后复习重新编写 32 最长有效括号未看解答自己编写的青春版重点这道题&#xff0c;动态规划的思…

小鹏遭遇“动荡”,自动驾驶副总裁吴新宙离职,现已完成团队过渡

根据最新消息&#xff0c;小鹏汽车的自动驾驶副总裁吴新宙宣布将加入全球GPU芯片巨头英伟达。吴新宙将成为该公司全球副总裁&#xff0c;直接向英伟达全球CEO黄仁勋汇报。小鹏汽车董事长何小鹏和吴新宙本人已在微博上确认该消息&#xff0c;并解释离职原因涉及家庭和多方面因素…

Spark提交流程

客户端通过脚本将任务提交到yarn执行&#xff0c;yarn启动APPMaster&#xff0c;APPMaster启动Driver线程&#xff0c;Driver负责初始化SparkContext并进行任务的切分和分配任务&#xff0c;交给Executor进行计算。

质数(判定质数 分解质因数 筛质数)

这里写目录标题 一、判定质数思路分析代码实现 二、分解质因数思路分析典型题目代码实现 三、质数筛经典题目思路分析1. 朴素筛法2. 埃氏筛法3. 欧拉筛法 一、判定质数 思路分析 由于每个合数的因子是成对出现的&#xff0c;即如果 d d d 是 n n n 的因子&#xff0c;那么 …

Qt实现引导界面UITour

介绍 最近做了一款键鼠自动化&#xff0c;想第一次安装打开后搞一个引导界面&#xff0c;找了好多资料没啥参考&#xff0c;偶然发现qt有引导界面如下图。 Qt整挺好&#xff0c;但是未找到源码&#xff0c;真的不想手撸&#xff0c;(源码找到了但是Qt整起来太复杂,没法拿来直接…

Python系统学习1-2

目录 一、硬件 二、软件&#xff1a;程序文档 三、基础知识 四、python执行过程 五、Pycharm使用技巧 一、硬件 计算机五大部件&#xff1a;运算器&#xff0c;存储器&#xff0c;控制器、输入设备&#xff0c;输出设备。 运算器和控制器 集成在CPU中。 存储&#xff1a…

Qt Creator 11 开放源码集成开发环境新增集成终端和 GitHub Copilot 支持

导读Qt 项目今天发布了 Qt Creator 11&#xff0c;这是一款开源、免费、跨平台 IDE&#xff08;集成开发环境&#xff09;软件的最新稳定版本&#xff0c;适用于 GNU/Linux、macOS 和 Windows 平台。 Qt Creator 11 的亮点包括支持标签、多外壳、颜色和字体的集成终端模拟器&am…

hcip——BGP实验

要求 1.搭建toop 2.地址规划 路由器AS接口地址R11 loop0:1.1.1.1 24 loop1 : 192.168.1.1 24 g0/0/0 12.0.0.1 24 R22 64512 g0/0/0: 12.0.0.2 24 g/0/01: 172.16.0.2 19 g0/0/2: 172.16.96.2 19 R32 64512g0/0/0: 172.16.0.3 19 g0/0/1:1…

在使用Python爬虫时遇到解析错误解决办法汇总

在进行Python爬虫任务时&#xff0c;遇到解析错误是常见的问题之一。解析错误可能是由于网页结构变化、编码问题、XPath选择器错误等原因导致的。为了帮助您解决这个问题&#xff0c;本文将提供一些实用的解决办法&#xff0c;并给出相关的代码示例&#xff0c;希望对您的爬虫任…

实现Feed流的三种模式:拉模式、推模式和推拉结合模式

在互联网产品中&#xff0c;Feed流是一种常见的功能&#xff0c;它可以帮助我们实时获取我们关注的用户的最新动态。Feed流的实现有多种模式&#xff0c;包括拉模式、推模式和推拉结合模式。在本文中&#xff0c;我们将详细介绍这三种模式&#xff0c;并通过Java代码示例来实现…