Java EE Servlet之服务器版表白墙

news2025/4/23 15:34:18

文章目录

  • 1. 准备工作
  • 2. 约定前后端交互接口
  • 3. 编写提交消息
  • 4. 数据存入文件
  • 5. 引入数据库

1. 准备工作

我们要把表白墙程序修改成服务器版本
这样即使页面关闭, 表白墙的内容也不会丢失

此处,服务器要实现的功能,主要是两个方面:

  1. 页面加载的时候,网页要从服务器这里获取到当前表白数据
    (让网页端给服务器发起 http 请求,服务器返回响应里就带着刚才的这些数据)
  2. 点击提交的时候,网页就要把用户输入的信息,发送给服务器这面,服务器扶着保存

在一个网站中,服务器起到最主要的效果,往往就是“存储数据”
因此服务器这边往往也就需要能够提供两种风格的接口,存数据,取数据

2. 约定前后端交互接口

服务器这边就需要给网页提供两个 http 的接口

1)获取消息
网页加载的时候,给服务器发送一个 ajax 请求

请求:
GET/message

响应:
HTTP/1.1 200 OK
Content-Type: application/json
在这里插入图片描述
此处的请求和响应的细节,都是可以随意设计的,只要能达成效果

2)提交消息
用户点击 提交 按钮的时候 ajax 给服务器器发送一个请求
目的是为了把用户咋输入框输入的内容,给发送给服务器
在这里插入图片描述

正式编写代码之前,一定要把前后端交互的接口给确定下来
这个就是后续编写代码的依据

编写前端代码:
构造 HTTP 请求(请求是什么样子的)
解析 HTTP 响应(响应是什么样子的)

编写后端代码:
解析 HTTP 请求(请求是什么样子的)
构造 HTTP 响应(响应是什么样子的)

这些都是需要设计好前后端交互接口才嫩个回答的问题

这个过程,就是 自定义应用层协议

3. 编写提交消息

  1. 先写前端代码,发送请求
  2. 再写后端代码,解析请求,构造响应
  3. 再写前端代码,解析响应

我们需要把 网页 放入到 webapp 目录里

tomcat 这样的项目,可以包含一些 html、css、js
这些内容都是在 webapp 目录中

在这里插入图片描述

在这里插入图片描述


编写前端代码,发送 http post 请求
在这里插入图片描述

使用 ajax,需要先引入 jquery 这个库
在这里插入图片描述
前端引入第三方库,往往就是通过 script 标签,写一个地址即可

这个代码在点击按钮的回调函数中
会在点击按钮之后被调用
在这里插入图片描述
前端 ajax 请求,url 路径,写作“message”,前面不带 / ,此时这是一个相对路径的写法

后端处理 ajax 请求,url 路径,写作“/message”,前面带 / ,此时是 Servlet 要求的写法


服务器读取上述请求,并计算出响应

要确定 java 代码中,类的属性的名字 和 json 中的属性的名字保持一致
在这里插入图片描述
在这里插入图片描述


回到前端代码,处理服务器返回的响应

在这里插入图片描述
此处 success 回调函数,不是立即执行的,而是在浏览器收到服务器返回的,成功,这样的响应的时候,才会执行到 function

这个函数的第一个参数,就是响应数据的 body 中的内容
在这里插入图片描述
为了和请求对的上
一般,服务器返回的时候,也是用 json 格式
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

服务器收到的请求
在这里插入图片描述
浏览器收到的响应
在这里插入图片描述
用 抓包工具查看
在这里插入图片描述

在这里插入图片描述
在代码中写的是一个 相对路径
在这里插入图片描述
最终发送的请求,会被转成绝对路径
就是把相对路径前面,品尚当前 html 所在的 context path 里

响应数据
在这里插入图片描述

4. 数据存入文件

当前已经把 数据提交到服务器保存了
目前还是需要能够把 服务器的数据 拿回到 客户端页面上,并显示

为什么还要从服务器拿小希?

  1. 当前界面上显示的数据,也是在浏览器内存中报讯的,刷新界面/关闭的重新打开 数据就没了
  2. 其他客户端打开页面也是有数据的

这个时候,就需要在页面加载的时候,发起请求

1)客户端在页面加载的时候,发起一个 http 请求
在这里插入图片描述
2)服务器收到这个请求,要处理这个请求并生成响应
在这里插入图片描述

服务器收到的每条消息,都转换成了 Message 对象,放到上述 List 中了
返回的结果,也就是这个 List 的数据
需要把 List 里的每个 Message 取出来,转成 json 字符创,最终拼到一起,得到了响应结果
在这里插入图片描述

jackson 看到了 messageList 是一个 List 类型
转成的json 字符串就是一个 json 数组[]
jackson 自动遍历 List 里的每个元素把每个元素,分别都转成 json 字符串
在这里插入图片描述

确保这几个代码的执行顺序 setStatus 和 setContentType 必须在 getWriter 前面
否则可能不会生效(构造出一个非法的 http 响应报文)
这个事情可以认为是 Servlet bug

3)客户端收到响应,就需要针对响应数据进行解析处理
把响应中的信息,构造成页面元素(html片段),并显示出来

这段代码中,需要拼接出 html 片段
在这里插入图片描述
body 就是服务器返回的响应
数据 json 格式的数组

当响应中,header 带有 Content-Type: application/jsonjquery
就会自动的把 json 字符串,解析成 js 对象了

如果没有带 Content-Type: application/json
就需要通过 js 代码 JSON.parse 方法来手动把 json 字符串转成js 对象

在这里插入图片描述
此时,响应数据中,带有 content type 的
所以此时 jquery 自定帮我们完成解析了

当下 body 就已经是一个 js 对象了(数组对象)

这个就是要构造的内容
在这里插入图片描述
构造出来后,加到这个后面
在这里插入图片描述

在这里插入图片描述
通过类选择器,针对 class 属性进行选择
在这里插入图片描述
html 中的每一个元素/标签,都存在一个 js 的对应的对象,来表示
称为 DOM(文档对象模型)

5. 引入数据库

如何把消息数据存储到数据库中
把数据库引入到代码中

1)引入数据库的依赖

2)建库建表
建库建表,需要用到 sql,都可以写到 文件 中,后续如果需要把表啥的往其他的机器上迁移,建表操作就会比较方便

3)编写数据库代码

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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 javax.sql.DataSource;
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;

    @Override
    public String toString() {
        return "Message{" +
                "from='" + from + '\'' +
                ", to='" + to + '\'' +
                ", message='" + message + '\'' +
                '}';
    }
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    // 引入数据库, 此时 messageList 就不再需要了.
    // private List<Message> messageList = new ArrayList<>();

    private DataSource dataSource = new MysqlDataSource();

    @Override
    public void init() throws ServletException {
        // 1. 创建数据源
        ((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/message_wall?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource) dataSource).setUser("root");
        ((MysqlDataSource) dataSource).setPassword("123456");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 读取前端发来的数据, 把这个数据保存到服务器这边.
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        System.out.println("请求中收到的 message: " + message);
        // 最简单的办法, 直接在内存中保存. 可以使用一个集合类, 把所有收到的 message 都存到内存中.
        // 很明显, 保存到内存, 并非是一个非常合理的办法. 后续一旦重启服务器, 数据丢失了.
        // 相比之下, 把这个数据持久化存储到数据库中, 更科学的.
        // messageList.add(message);
        // 插入数据库
        try {
            save(message);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        // 返回一个响应
        resp.setStatus(200);
        resp.getWriter().write("ok");
        // resp.setContentType("application/json");
        // resp.getWriter().write("{ ok: true }");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过这个方法来处理当前获取消息列表的 get 请求. 不需要解析参数, 直接返回数据即可.
        resp.setStatus(200);
        resp.setContentType("application/json; charset=utf8");
        // 从数据库查询
        List<Message> messageList = null;
        try {
            messageList = load();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        String respJson = objectMapper.writeValueAsString(messageList);
        resp.getWriter().write(respJson);
    }

    private void save(Message message) throws SQLException {
        // 通过这个方法把 message 插入到数据库中

        // 1. 建立连接
        Connection connection = dataSource.getConnection();

        // 2. 构造 SQL
        String sql = "insert into message values(?, ?, ?)";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, message.from);
        statement.setString(2, message.to);
        statement.setString(3, message.message);

        // 3. 执行 SQL
        statement.executeUpdate();

        // 4. 回收资源
        statement.close();
        connection.close();
    }

    private List<Message> load() throws SQLException {
        // 通过这个方法从数据库读取到 message.

        // 1. 建立连接
        Connection connection = dataSource.getConnection();

        // 2. 构造 SQL
        String sql = "select * from message";
        PreparedStatement statement = connection.prepareStatement(sql);

        // 3. 执行 sql
        ResultSet resultSet = statement.executeQuery();

        // 4. 遍历结果集合
        List<Message> messageList = new ArrayList<>();
        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);
        }

        // 5. 回收资源
        resultSet.close();
        statement.close();
        connection.close();

        // 6. 返回 messageList
        return messageList;
    }
}

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


到此一个简单的,依靠 servlet 的web 页面到此结束了~
下次再见~

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

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

相关文章

CSS 动态提示框

​​ <template> <div class"terminal-loader"><div class"terminal-header"><div class"terminal-title">提示框</div><div class"terminal-controls"><div class"control close"…

Qt 5.9.4 转 Qt 6.6.1 遇到的问题总结(一)

最近公司对大家的开发的硬件环境进行了升级&#xff0c;电脑主机的配置、显示器&#xff08;两台大屏显示器&#xff09;变得的逼格高多了。既然电脑上的开发环境都需要重装&#xff0c;就打算把开发环境也升级到最新版本&#xff0c;要用就用最新版本。下面对升级后的开发环境…

数据库开发之子查询案例的详细解析

1.5 案例 基于之前设计的多表案例的表结构&#xff0c;我们来完成今天的多表查询案例需求。 准备环境 将资料中准备好的多表查询的数据准备的SQL脚本导入数据库中。 分类表&#xff1a;category 菜品表&#xff1a;dish 套餐表&#xff1a;setmeal 套餐菜品关系表&#x…

LeetCode刷题--- 黄金矿工

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述…

2017年喜茶数字营销变化

1. 什么是数字营销&#xff1f;数字化时代&#xff0c;消费者行为模式发生了哪些变化&#xff1f; 数字营销是指使用数字渠道和平台&#xff0c;通过在线手段推广产品或服务&#xff0c;与目标受众进行互动和沟通的一种营销方式。它涵盖了多种在线渠道&#xff0c;包括社交媒…

【赠书第15期】案例学Python(基础篇)

文章目录 前言 1 简介 2 功能列表 3 实现 3.1 学生类 3.2 学生管理系统类 3.3 使用示例 4 推荐图书 5 粉丝福利 前言 当涉及案例学 Python 时&#xff0c;可以选择一个具体的问题或场景&#xff0c;通过编写代码来解决或模拟这个问题。以下是一个例子&#xff0c;通过…

自动化测试系列 之 Python单元测试框架unittest

一、概述 什么是单元测试 单元测试是一种软件测试方法&#xff0c;是测试最小的可测试单元&#xff0c;通常是一个函数或一个方法。 在软件开发过程中&#xff0c;单元测试作为一项重要的测试方法被广泛应用。 为什么需要单元测试 单元测试是软件开发中重要的一环&#xf…

HackTheBox - Medium - Linux - Interface

Interface Interface 是一种中等难度的 Linux 机器&#xff0c;具有“DomPDF”API 端点&#xff0c;该端点通过将“CSS”注入处理后的数据而容易受到远程命令执行的影响。“DomPDF”可以被诱骗在其字体缓存中存储带有“PHP”文件扩展名的恶意字体&#xff0c;然后可以通过从其…

前端开发工具之HBuilder X

HBuilderX&#xff08;简称HX&#xff09;是一款由DCloud开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为前端开发者设计。它不仅是一个编辑器&#xff0c;也可以看作是一个通用的IDE&#xff0c;类似于VSCode、Sublime和WebStorm。HBuilderX支持开发各种Web项…

论文阅读——EfficientViT(cvpr2023)

EfficientViT: Memory Efficient Vision Transformer with Cascaded Group Attention 1、 从三个角度探讨如何提高vision transformers的效率&#xff1a;内存访问、计算冗余和参数使用。 2.1. Memory Efficiency 红色字体表示操作所花费的时间主要由内存访问决定&#xff0c;…

RSA加密解密——用shell加密java解密

功能描述 使用shell opensll对明文进行RSA加密&#xff0c;将密文用java的RSA工具对密文解密。这应该是全网第一个同时用到shell和java的RSA加密解密教程。中间有很多坑&#xff0c;都踩过了&#xff0c;可以放心使用代码。 正确的实现流程 shell端 首先生成公钥私钥 &…

C/C++ 对象、继承和引用

ostream和ofstream类凸现了引用的一个有趣属性。正如ofstream 对象可以使用 ostream类的方法&#xff0c;这使得文件输入/输出的格式与控制台输入/输出相同。使得能够将特性从一个类传递给另一个类的语言特性被称为继承。 简单地说&#xff0c;ostream 是基类&#xff0c;而ofs…

<软考高项备考>《论文专题 - 37 采购管理(1) 》

1 成本管理基础 1.1 写作要点 过程定义、作用写作要点、思路规划采购管理规划采购管理是记录项目采购决策、明确采购方法&#xff0c;及识别潜在卖方的过程。作用:确定是否从项目外部获取货物和服务&#xff0c;如果是&#xff0c;则还要确定将在什么时间、以什么方式获取什么…

OSPF的DR与BDR-新版(16)

目录 整体拓扑 操作步骤 1.基本配置 1.1 配置R1的IP 1.2 配置R2的IP 1.3 配置R3的IP 1.4 配置R4的IP 1.5 检测R1与R4连通性 1.6 检测R1与R2连通性 1.7 检测R1与R3连通性 2.搭建基本的OSPF网络 2.1 配置R1 OSPF 2.2 配置R2 OSPF 2.3 配置R3 OSPF 2.4 配置R4 OSPF…

力扣刷题总结 栈与队列

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 一、栈和队列的基础知识 队列是先进先出&#xff0c;栈是先进后出。同时二者都是容器适配器而不是容器。 二、题目实战 232.用栈…

帆软报表如何灵活控制水印的显示

在帆软报表中如果要显示水印,如果要全部都要显示,只需要到决策系统--安装设置中打开水印开关。如果想要某个报表显示水印,可以在设计器的水印设置中为该报表设置水印。 但是如果碰到这种需求,比如某些人或者某些角色需要显示水印,其他人不显示。或者是预览报表需要显示水印…

conda环境下face_alignment.LandmarksType._2D AttributeError: _2D解决方法

1 问题描述 运行retalking模型时&#xff0c;代码抛出异常&#xff0c;信息如下所示&#xff1a; Traceback (most recent call last):File "D:/ml/video-retalking/inference.py", line 345, in <module>main()File "D:/ml/video-retalking/inference.…

C++初阶(类中的默认成员函数)

呀哈喽&#xff0c;我是结衣 今天给大家带来的是类里面的默认成员函数&#xff0c;一共有六个默认的成员函数哦&#xff0c;包括构造函数&#xff0c;析构函数&#xff0c;拷贝构造函数&#xff0c;运算符重载函数&#xff0c;const成员函数&#xff0c;那么正篇开始。 文章目…

【OpenCV】OpenCV 4.9.0 正式发布

​ 开源计算机视觉库 OpenCV 4.9.0 已于2023年12月29日正式发布。 此次发布有DNN模块对ONNX Attention、Einsum等层的支持、新的fastGEMM实现、transformers的实验性支持等诸多亮点。 OpenCV 4.9.0 更新内容&#xff1a; &#xff08;来自OpenCV中国团队以及中国社区的贡献…

解决Windows11安装Docker 一直starting 的办法

Starting the Docker Engine... Docker Engine is the underlying technology that runs containers 关闭docker 管理员身份执行wsl --update后在启动。 另外&#xff0c;docker desktop-unexpected wsl error问题跟标题问题好像是同一个问题&#xff0c;我的是一直让其star…