javaEE初阶 — 服务器版本的表白墙案例

文章目录

  • 原来版本涉及的问题
  • 设计程序
    • 1 点击提交
    • 2 页面加载
  • 实现后端代码
    • 1 新建一个 Maven 项目。
    • 2 按照之前第一个 Servlet 程序的步骤来进行设置
    • 3 新建一个 MessageServlet 类
  • 实现前端代码
    • 1 点击提交的时给服务器发送一个 POST 请求
    • 2 在页面加载时发送一个 GET 请求
    • 3 将数据保存到数据库中

原来版本涉及的问题


表白墙链接

之前完成的表白墙有两个非常严重的问题:

1、如果刷新页面或者关闭重开,此时表白墙之前保存的消息就消失了

2、表白墙的数据只能在本地浏览器中看见



此时如果刷新页面或者关闭重开,此时表白墙的数据就消失了。



解决思路

让服务器来存储用户提交的数据,有服务器保存。

当有新的浏览器打开页面的时候,从服务器获取数据。

设计程序


实现一个 web 程序,务必要考虑前后端如何交互,要约定好前后端交互的数据格式。

比如说:
设计前后端交互接口、请求是什么样的、响应是什么样的、浏览器什么时候发这个请求、浏览器按照什么样的格式来解析。


有两个环节涉及到了前后端的交互:

一个是 点击提交 的时候,也就是浏览器把表白信息发到服务器。
一个是 页面加载 的时候,也就是浏览器从服务器获取到表白信息。

1 点击提交


请求 可以使用 POST,再使用一个 /message 这样的路径。

约定当前 body 是按照 json 格式来进行提供

{
  from: "张三",
  to: "李四",
  message: "卧槽"
}


响应 可以约定为,HTTP/1.1 200 OK

2 页面加载


请求 可以约定为 GET,再来一个 /message 路径,响应 也可以约定为 HTTP/1.1 200 OK

只不过此时的响应要按照 json数组 的格式来进行解析。

[
  {
    from: "张三",
    to: "李四",
    message: "卧槽"
  },
  
  {
    from: "张三",
    to: "李四",
    message: "卧槽"
  } 
]


此处的约定没有固定的强制要求,只要能保证必要的需求即可。
此处的目的就是为了前端代码和后端代码能够对上。

实现后端代码

1 新建一个 Maven 项目。


2 按照之前第一个 Servlet 程序的步骤来进行设置


第一个Servlet 程序链接

1、首先要引入 Servlet、jackson、mysql 依赖,将这三个依赖引入到 dependencies 标签中。

打开 https://mvnrepository.com/,搜索 servlet,找到 3.1.0 版本。



选择如上图的 Servlet,点击进去选择 3.1.0版。



点击进去之后将 Maven 下的代码复制到 pom.xml 文件的 dependencies 标签中。



jackson 选择如下图的





点击 2.14.2 版本,其余的步骤与 servlet 一样。



mysql 依赖选择如下图的点击


这里引入 mysql 依赖是因为可以使用 数据库来保存用户提交的数据。

选择 5.1.49 版本。



其余的步骤也与 servlet 一样。




以上是三个依赖引入好的样子。


2、接下来开始创建目录




3、往web.xml 中添加一点内容

3 新建一个 MessageServlet 类


这里的路径要和之前约定好的相同。



1、重写 doPost 和 doGet 方法




2、实现向服务器提交数据的 POST 请求

要先定义一个 Message 类,描述请求 body 的内容,方便 jackson 进行 json 解析。

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


先构建一个 ObjectMapper,再读取 body 里的内容,然后再解析成一个 Message 对象,
最后就是填到 List 变量里。

// 暂时使用 List 变量保存所有消息 —— 比较简单粗暴
private List<Message> messageList = new ArrayList<>();

// 向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    // 构造一个 ObjectMapper
    ObjectMapper objectMapper = new ObjectMapper();
    // 把 body 的内容读取出来,解析成一个 Massage 对象
    Message message = objectMapper.readValue(req.getInputStream(), Message.class);
    messageList.add(message);
    // 设置状态码,不设置默认也是 200
    resp.setStatus(200);
}



3、实现从服务器获取数据的 GET 请求

获取数据直接从 List 变量获取即可,也就是把 List 对应的结果给转成 json 格式的字符串,返回即可。

// 从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    // 显示的告诉浏览器,数据格式是 json 格式,字符集是 utf-8
    resp.setContentType("application/json; charset = utf-8");
    // 第一个参数表示写到哪里,第二个参数表示写的内容是什么
    objectMapper.writeValue(resp.getWriter(), messageList);
}


getWriter() 这个方法同时把 java 对象转成了 json 字符串和吧这个字符串写到响应对象中。

针对 doGet,只是把 messageList 转成 json 字符串,然后返回给浏览器即可。


此时后端代码就写完了,启动服务器,然后打开 postman 发送请求验证一下。



先选择 POST,在 body 里输入内容后点击 Send 发送一个请求。

之后,切换为 GET 接收,再次点击 Send 就可以得到下面的结果了,下面是发送了三次请求的结果。

实现前端代码


编写前端代码,让页面能够发起请求,并解析响应。

post 是点击提交按钮的时候发起的,get 是页面加载的时候发起的。

1 点击提交的时给服务器发送一个 POST 请求


首先要将前端代码的文件复制到 webapp 目录下。





然后以 vscode 打开。




首先要引入 jQuery

搜索 jQuery cdn,将链接复制到 script 标签里的 src 属性里。

 <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>


POST 是在点击提交按钮的时候触发的,点击这里的 button 就是点击了按钮。
此时就会触发了 POST 请求。

 let button = document.querySelector('#submit');




当前的代码再点击提交按钮后,会触发 onclick 回调方法,这里的回调方法只是构造了一个新的 div。

接下来要做的就是实现一个新的步骤,把上述代码中的数据提交到服务器里。

 // [新增]4. 使用 ajax 构造一个 post 请求, 把上述数据提交到服务器里
 // 构造一个 body
 let body = {
     "from": from,
     "to": to,
     "message": message 
 }

 $.ajax({
     // 这里是要构造的请求类型
     type: 'post',
     // 这里的路径要和之前约定好的前后端交互接口一致
     url: i'message',
     // post 请求是有 body 的,所以就要设置一个 body
     data: 
 });




这里设置的 body 是 定义了一个 js 对象,类似于 json 的键值对。

key 是一个字符串,也就是图中的 “from”、“to”、“message” 三个。
value 则是 js 中的变量/常量,也就是字符串后面的值。


在 js 中要求对象的 key 务必是字符串,因此此处的代码还可以是以下的写法:





当前 body 里的 vlaue 值是由页面上的输入框读取到的内容放到变量里的。

需要注意的是当前的 js 对象不是字符串,在网络传输中,只能传字符串,不能传对象。
接下来需要把这个对象转成一个字符串。




接下来进行的操作是将 js 对象转成一个 json 格式的字符串。

在 js 中内置了 json 的转换库,此时就不需要像 java 好要有第三方库 jackson 了。

可以使用 JSON.stringify 转为 json 格式的字符串。

// 将 js 对象转为 json 格式的字符串
let strBody = JSON.stringify(body);
// 打印日志
console.log("strBody:" + strBody);
$.ajax({
    // 这里是要构造的请求类型
    type: 'post',
    // 这里的路径要和之前约定好的前后端交互接口一致
    url: 'message',
    // post 请求是有 body 的,所以就要设置一个 body
    data: strBody,
    // 指定 body 的具体格式
    setContentType: "application/json; charset = utf-8",
    success: function(body) {
        console.log("数据发布成功!")
    }
});



接下来启动服务器观察结果。

在启动服务器之后,就可以通过浏览器来打开表白墙的页面了。

在地址栏输入路径,就可以看到表白墙页面了。




打开 fiddler 抓包观察结果。





根据前端代码的设置可以看到抓包的结果各个设置是一样的。

2 在页面加载时发送一个 GET 请求


这里构造的就是一个 get 请求了。

 // [新增] 在页面加载的时候,发送 GET 请求,从服务器获取数据并添加到页面中
 $.ajax({
     type: 'get',
     url: 'message',
     success: function(body) {
         // 这里的 body 已经是一个 js 的对象数组了 
         // 本来服务器返回的是一个 json 格式的字符串,但是 jQuery 的 ajax 自动识别并转化了
         // 接下来遍历这个数据,把元素取出来构造页面中即可
         for(let message of body) {
             // 针对每一个元素构造一个 div
             let rowDiv = document.createElement('div');
             rowDiv.className = 'row'; // 有了一个 row 的属性
             rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
             containerDiv.appendChild(rowDiv); 
         }
     }
 });


本来需要将 json 格式的字符串转为一个 js 对象数组,但是由于 jQuery 的 ajax 自动转化了。
因此这里的 body 已经是一个 js 对象了。

3 将数据保存到数据库中


由于当前的数据是借助变量保存的,重启服务器后就会导致数据消失。
因此想要永久的保存,就需要来借助数据库保存。


1、首先要创建一个数据表。



当前已创建完成。


2、创建一个 DBUtil 类。

需要注意的是 jdbc:mysql://127.0.0.1:3306/web?characterEncoding=utf8&useSSL=false
这条语句里的 web 是我的数据库名,在这里要根据实际情况来更改。

// 通过这个类把数据库连接过程封装一下
// 此处把 DBUtil 作为一个工具类,提供 static 方法来供其他代码调用
public class DBUtil {
    private static DataSource dataSource = new MysqlDataSource();
    
    static {
        // 使用静态代码块,针对 dataSource 进行初始化操作
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/web?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
         // 密码是什么,写什么
        ((MysqlDataSource)dataSource).setPassword("000000");
    }

    // 通过这个方法来建立连接
    public static Connection getConnection() throws SQLException {
        return (Connection)dataSource.getConnection();
    }

    // 通过这个方法来释放资源
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
        // 此处的 三个 try catch 分开写,避免前面的异常导致后面的代码不能运行
        if (resultSet != null) {
            try {
                connection.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();
            }
        }
    }
}



3、提供一对方法来保存数据

save 方法是用来往数据库中存数据。

 private void save(Message messageWall) {
        // JDBC 操作
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1.建立连接
            connection = DBUtil.getConnection();
            // 2.构造 sql 语句
            String sql = "insert into messagewall values(?, ?, ?)";
            statement = (PreparedStatement)connection.prepareStatement(sql);
            // 将上面的三个 ? 占位符替换为 from to message
            statement.setString(1, messageWall.from);
            statement.setString(2, messageWall.to);
            statement.setString(3, messageWall.message);
            // 3.执行 sql
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭连接
            DBUtil2.close(connection, statement, null);
        }
    }


load 方法是用来从数据库中拿数据。

 private List<Message> load() {

        List<Message> messageList = new ArrayList<>();

        Connection connection = null;
        ResultSet resultSet = null;
        PreparedStatement statement = null;
        try {
            // 1.和数据库建立连接
            connection = DBUtil.getConnection();
            // 2.构造 sql 语句
            String sql = "select * from messagewall";
            statement = (PreparedStatement)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 中
                messageList.add(message);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 5.断开连接
            DBUtil2.close(connection, statement, resultSet);
        }
        return messageList;
    }

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

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

相关文章

【2023 年第十三届 MathorCup 高校数学建模挑战赛】C 题 电商物流网络包裹应急调运与结构优化问题 赛后总结之31页论文及代码

相关信息 &#xff08;1&#xff09;建模思路 【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 详细建模过程解析及代码实现 【2023 年第十三届 MathorCup 高校数学建模挑战赛】 B 题 城市轨道交通列车时刻表优化问题 详细建…

2.3 定点乘法运算

学习目标&#xff1a; 如果我要学习定点乘法运算&#xff0c;我会按照以下步骤进行学习&#xff1a; 确定学习目标&#xff1a;明确学习定点乘法运算的目的和重点&#xff0c;以便有针对性地进行学习。 掌握基础知识&#xff1a;首先需要了解定点数和定点乘法的基础知识&…

PySide2 QWebEngine与Web js交互

文章目录 单向交互双向传值案例 单向交互 QWebEngineView加载web页面&#xff0c;web页面中点击按钮&#xff0c;执行js代码&#xff0c;js的返回值传给QWebEnginePage&#xff0c;使用python进行保存结果。 单向&#xff0c;js向python(PySide2)端传输数据。 前端实现 <…

力扣刷题day35|416分割等和子集

416. 分割等和子集 力扣题目链接 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割…

智能网联汽车城市化的进程和思考

4月19日&#xff0c;工信部官网显示&#xff0c;支持湖北&#xff08;襄阳&#xff09;、浙江&#xff08;德清&#xff09;、广西&#xff08;柳州&#xff09;创建国家级车联网先导区。至此&#xff0c;车联网国家级先导区正式扩容&#xff0c;由4个增至7个。智能网联作为新生…

网络字节序和主机字节序详解(附代码)

一、网络字节序和主机字节序 网络字节序和主机字节序是计算机网络中常用的两种数据存储格式。 主机字节序&#xff1a; 指的是在计算机内部存储数据时采用的字节排序方式。对于一个长为4个字节的整数&#xff0c;若采用大端字节序&#xff0c;则该整数在内存中的存储顺序是&a…

前端面试题(持续更新中)

【1】null和undefined的区别 同&#xff1a; 1.都是js的基本类型&#xff0c;保存在栈中&#xff0c;表示“无、没有”的意思。 2.if语句中的null和undefined都是false。 var a undefined var b null if (!a) {console.log(undefined is false); } if (!b) {console.log(null…

手动搭建高可用的 kubernetes 集群(v1.16.6)

手动搭建高可用的 kubernetes 集群(v1.16.6) 目录 手动搭建高可用的 kubernetes 集群(v1.16.6) 1、组件版本和配置策略 1.1 主要组件版本1.2 主要配置策略2、初始化系统和全局变量 2.1 集群规划2.2 初始化系统环境 2.2.1 关闭防火墙2.2.2 关闭 swap 分区2.2.3 关闭 SELinux2.2.…

【MySQL自学之路】第5天——对数据表数据的增删改查1

目录 前言 使用的数据库 数据表 ​编辑 表结构 插入数据&#xff08;insert into&#xff09; 插入一条数据 插入多条数据 修改数据&#xff08;update set&#xff09; 修改一条数据的值 ​编辑 修改多条数据的值 删除数据&#xff08;delete from&#xff09;…

【云原生】Epinio--Kubernetes 的应用程序开发引擎

Kubernetes 已成为容器编排的事实标准&#xff0c;改变了我们的开发流程。十年前&#xff0c;我们只需要将代码打包成 war/jar 包&#xff0c;然后启动应用即可。然而&#xff0c;现在面向 Kubernetes 的开发&#xff0c;交付的产物有可能是 Helm Chart、Workload Yaml、Docker…

Postman测试实践笔记

Postman测试实践 文章目录 Postman测试实践一、Postman安装与使用1.1 Postman下载及安装1.1.2 Postman Mac版 1.2 Postman 更新1.2.1 mac 版更新 1.3 Postman 其他问题 二、网络相关知识2.1 接口2.1.1 软件为什么需要接口 2.2 接口测试2.2.1 什么是接口测试&#xff1a;2.2.2 为…

经典回归算法

回归的概念 回归方程&#xff1a; 写成矩阵&#xff1a; 核心问题&#xff0c;构建预测函数z来映射特征矩阵x和标签y的线性关系 预测的目标值&#xff0c;有连续值也有离散值 连续值&#xff0c;就直接预测输出就行离散值&#xff0c;需要在输出端加一个变换函数例如。Si…

C#,生信软件实践(02)——欧洲分子生物学实验室(EMBL格式文件)转为核酸序列或多肽序列(FASTA格式文件)的源代码

>生信老白写的基础代码.fasta MAYBENOANYUSAGE 1 EMBL 1.1 EMBL组织 欧洲分子生物学实验室EMBL&#xff08;European Molecular Biology Laboratory&#xff09;1974年由欧洲14个国家加上亚洲的以色列共同发起建立&#xff0c;现在由欧洲30个成员国政府支持组成&#xf…

Android 项目必备(四十五)-->2023 年如何构建 Android 应用程序

Android 是什么 Android 是一种基于 Linux 内核并由 Google 开发的开源操作系统。它用于各种设备包括智能手机、平板电脑、电视和智能手表。 目前&#xff0c;Android 是世界上移动设备使用最多的操作系统; 根据 statcounter 的一份最近 12 个月的样本报告;Android 的市场份额…

三、SpringMVC

三、SpringMVC 1、SpringMVC简介 1.1、什么是MVC MVC是一种软件架构的思想&#xff0c;将软件按照模型、视图、控制器来划分 M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为实体…

ApachePOI操作Excel快速入门使用

简介 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目&#xff0c;主要任务是创建和维护Java API&#xff0c;以基于Office Open XML标准&#xff08;OOXML&#xff09;和Microsoft的OLE 2复合文档格式&#xff08;OLE2&#xff09;处理各种文件格式&#xff0…

【KVM虚拟化】· 命令行KVM安装linux

目录 &#x1f341;基础本环境配置 &#x1f341;添加lvm卷 &#x1f341;qemu-img创建磁盘文件 &#x1f342;创建raw格式 &#x1f342;创建虚拟机 &#x1f342;转换格式为qcow2 &#x1f341;virt-install命令参数 &#x1f341;案例操作 &#x1f990;博客主页&#xff1a…

论文笔记:Model-Contrastive Federated Learning

0 简介 论文&#xff1a;Model-Contrastive Federated Learning 代码&#xff1a;https://github.com/QinbinLi/MOON 相关链接&#xff1a;本文主要是将SimCLR对比学习的思想迁移到联邦学习中&#xff0c;关于SimCLR的介绍见https://blog.csdn.net/search_129_hr/article/deta…

Mysql 管理

目录 0 课程视频 1 系统数据库 -> 安装完mysql ->自带四个数据库 2 常用工具 -> 写脚本用 2.1 mysql 客户端工具 2.2 mysqladmin 2.3 mysqlbinlog -> 二进制日志 -> 运维讲解 2.4 mysqlshow 2.5 mysqldump 备份用 ->导出 2.6 mysqlimport/source -…

工控老司机告诉你热电偶和RTD的区别

热电偶和热电阻都是温度传感器&#xff0c;但它们的原理、功能特性和应用场景有所不同。 一、原理区别 首先&#xff0c;热电偶是利用两种不同金属之间的热电效应来测量温度的。其原理是利用温度差引起的金属之间的热电势差进行测量。两种金属之间存在一种热电势&#xff08;…