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

news2024/11/29 5:26:14

文章目录

  • 原来版本涉及的问题
  • 设计程序
    • 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;
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何学习数据结构和算法

背景&#xff1a; 对待数据结构与算法的态度可能大多数人就是觉得晦涩难懂。这节课我们跟随老师看看老师是如何带领我们入门的。 定义&#xff1a; 首先我们了解数据结构和算法的定义&#xff1a; 从广义上讲&#xff0c;数据结构就是指一组数据的存储结构。算法就是操作数…

MES系统8路热电偶温度输出太网口

8路热电偶温度模块可以同时采集8个热电偶信号&#xff0c;并且具备高精度、高稳定性和良好的抗干扰性能&#xff0c;非常适合工业领域中需要监测多个物体温度的应用场景。 该热电偶温度模块拥有以下几个特点&#xff1a; 1. 8个差分输入通道&#xff0c;支持多种类型的热电偶…

【排序】归并排序(递归+非递归图示详解哦)

全文目录 引言归并排序思路递归实现 归排非递归思路实现 总结 引言 在本篇文章中&#xff0c;将继续介绍一种排序算法&#xff1a;归并排序。 归并排序运用了归并的思想&#xff0c;即将两个有序数列归并为一个有序数列。在前面的合并两个有序链表时&#xff0c;运用了这种思想…

四福来轮全向底盘实现写字功能

1. 功能说明 本文示例将实现R310b样机四福来轮全向底盘绘制“探索者”空心字的功能。 2. 电子硬件 本实验中采用了以下硬件&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板 Bigfish2.1扩展板 SH-ST步进电机扩展板电池11.1v动力电池 其它 步进…

干货分享:AI绘图学习心得-Midjourney绘画AI,让你的AI绘画之路少走弯路

干货分享&#xff1a;AI绘图学习心得-Midjourney绘画AI 最重要的Prompt和参数基本 Prompts高级Prompts 一、构图指令结构二、常用指令分享三、操作技巧总结四、常用风格词汇五、常用构图词汇六、高频实用词汇推荐&#xff1a;七、其他AI资料获取&#xff1a; 本篇没有什么长篇大…

01-Vue技术栈之基础篇(上)

目录 1、Vue简介1.1 Vue官网1.2 介绍与描述1.3 Vue 的特点1.4 与其它 JS 框架的关联1.5 Vue 周边库 2. 初识Vue2.1 Vue初体验2.2 注意事项2.3 js表达式和js代码&#xff08;语句&#xff09; 3、Vue模板语法3.1 语法分类3.2 插值语法3.3 指令语法 4、Vue模板语法4.1 数据绑定方…

Java中几种常量池面试总结

字符串常量池&#xff08;string pool&#xff09; 字符串常量池是JVM为了提升性能和减少内存消耗针对字符串&#xff08;String类&#xff09;专门开辟的一块区域&#xff0c;主要目的是为了避免字符串的重复创建。 当需要使用字符串时&#xff0c;先去字符串池中查看该字符…

使用vscode 创建vue3.0项目,应用element-plus框架

使用npm指令创建项目 npm init vite-app 项目名称 npm install npm run dev输入http://localhost:3000/ 查看 2、可自定义vue模板 输入vue.json 回车。复制下述代码&#xff0c;然后保存。 {"Print to console": {"prefix": "vue","b…

每天一道算法练习题--Day15 第一章 --算法专题 --- -----------二叉树的遍历

概述 二叉树作为一个基础的数据结构&#xff0c;遍历算法作为一个基础的算法&#xff0c;两者结合当然是经典的组合了。很多题目都会有 ta 的身影&#xff0c;有直接问二叉树的遍历的&#xff0c;有间接问的。比如要你找到树中满足条件的节点&#xff0c;就是间接考察树的遍历…

STM32物联网实战开发(3)——串口打印

串口打印 串口的使用在单片机开发过程中经常出现&#xff0c;因为他在显示数据和调试过程中特别的方便&#xff0c;使用起来也很简单。 1.用STM32CubeMx配置串口 串口1模式选择异步&#xff0c;不开启硬件控制流&#xff08;串口通信分为同步通信和异步通信&#xff0c;他们往…

云HIS : 电子病历模板制作过程技术经验分享

电子病历的制作就是按照医院机构的特色&#xff0c;根据不同业务需求&#xff0c;使用模板编辑与预览工具&#xff0c; 综合运用工具模块制作个性化、实用化、特色化电子病历模板的过程。 按照制作流程分为以下几个步骤&#xff1a; 1.明确病历类型&#xff1a;根据业务方向…

掌握好这几款TikTok数据分析工具,让你轻松提高曝光率!

为什么别人在TikTok发的普普通通的视频却有那么高的流量、几天内疯狂涨粉&#xff0c;而自己想破脑袋装饰自己的视频&#xff0c;结果却不如人意。 其实原因很简单&#xff0c;TikTok不像国内的抖音只面向中华民族&#xff0c;而是覆盖了150多个国家和75种语言用户&#xff0c…

【五一创作】Scratch资料袋

Scratch软件是免费的、免费的、免费的。任何需要花钱才能下载Scratch软件的全是骗子。 1、什么是Scratch Scratch是麻省理工学院的“终身幼儿园团队”开发的一种图形化编程工具。是面向青少年的一款模块化&#xff0c;积木化、可视化的编程语言。 什么是模块化、积木化&…

【VM服务管家】VM4.x算子SDK开发_3.1 环境配置类

目录 3.1.1 环境配置&#xff1a;CSharp算子SDK开发环境配置方法3.1.2 算子封装&#xff1a;使用C封装算子SDK的方法3.1.3 异常中断&#xff1a;算子SDK软件运行报错“托管调试助手”中断的解决方法3.1.4 深度学习&#xff1a;GPU运行深度学习算子引发StackOverFlow异常的方法 …

FP独立站推广成本太高?那是因为你没看到这篇!

近年来&#xff0c;越来越多的商家开始搭建自己的跨境电商独立站&#xff0c;做起了FP独立站。那么用独立站做FP到底有什么优势&#xff1f;还有&#xff0c;推广成本真的很高吗&#xff1f;今天这期就给大家扒一扒。 用独立站做FP的优势 1、塑造品牌&#xff0c;扩大经营触及…

【HarmonyOS】元服务WebView组件 H5使用localstorage

在日常开发中我们会在应用种接入H5网页&#xff0c;localStorage作为H5本地存储web storage特性的API之一&#xff0c;主要作用是将数据保存在客户端中。对于快速开发元服务&#xff0c;通过WebView组件运行H5如何使用localstorage呢&#xff1f;下文以API7 JavaUI为例为大家做…

k8s 集群搭建详细教程

参考&#xff1a; Kubernetes 文档 / 入门 / 生产环境 / 使用部署工具安装 Kubernetes / 使用 kubeadm 引导集群 / 安装 kubeadm B. 准备开始 一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令每…

3.3 Linux shell命令(权限、输入输出)

目录 shell shell概述 shell分类 查看当前系统的shell 权限相关命令&#xff08;也是shell命令&#xff09; 基本命令 输入输出相关操作 输出命令 输入输出重定向 通配符 管道 历史查询、补齐功能 历史查询 自动补齐 命令置换 shell 什么是shell shell是一种负…

【VM服务管家】VM4.0软件使用_1.2 工具类

目录 1.2.1 文本保存&#xff1a;逐行保存格式化模块输出的方法1.2.2 脚本模块&#xff1a;循环模块搭配脚本使用的方法1.2.3 几何查找&#xff1a;彩色图像的几何查找方法1.2.4 深度学习&#xff1a;图像分割的面积的获取方法1.2.5 颜色识别&#xff1a;使用颜色识别工具做分类…

【Leetcode -86.分隔链表 -92.反转链表Ⅱ】

Leetcode Leetcode -86.分隔链表Leetcode -92.反转链表Ⅱ Leetcode -86.分隔链表 题目&#xff1a;给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每…