当前位置: 首页 > news >正文

【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();//    向服务器提交数据@Overrideprotected 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);}//    从服务器获取数据@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//显示告诉浏览器,数据是 json 格式,字符集是 utf8resp.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.构造新的divlet 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元素构造一个divlet 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();//    向服务器提交数据@Overrideprotected 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);}//    从服务器获取数据@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//显示告诉浏览器,数据是 json 格式,字符集是 utf8resp.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) {//JDBCConnection 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.执行sqlstatement.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.构造sqlString sql = "select * from message";statement = connection.prepareStatement(sql);//3.执行sqlresultSet = 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;}@Overrideprotected 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.编写sqlString 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();}}}
}

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

相关文章:

【JavaEE初阶】Servlet (三)MessageWall

在我们之前博客中写到的留言墙页面,有很严重的问题:(留言墙博客) 如果刷新页面/关闭页面重开,之前输入的消息就不见了.如果一个机器上输入了数据,第二个机器上是看不到的. 针对以上问题,我们的解决思如如下: 让服务器来存储用户提交的数据,由服务器保存. 当有新的浏览器打开页…...

D. Make It Round

在Berlandia发生了通货膨胀&#xff0c;所以商店需要改变商品的价格。 商品n的当前价格已经给出。允许将该商品的价格提高k倍&#xff0c;1≤k≤m&#xff0c;k为整数。输出商品的最圆的可能的新价格。也就是在最后有最大数量的零的那个。 例如&#xff0c;数字481000比数字1…...

Python网站页面开发HTML总结

Python网站页面开发HTML总结 一、HTML基础语法 1.HTML是什么&#xff1f; ●HTML是HyperText Mark-up Language的首字母简写&#xff0c;即超文本标记语言。 ●HTML不是一种编程语言&#xff0c;而是一种标记语言。 ●超文本指的是超链接&#xff0c;标记指的是标签&#xf…...

[个人笔记] vCenter设置时区和NTP同步

VMware虚拟化 - 运维篇 第三章 vCenter设置时区和NTP同步 VMware虚拟化 - 运维篇系列文章回顾vCenter设置时区和NTP同步&#xff08;附加&#xff09;ESXi设置alias参考链接 系列文章回顾 第一章 vCenter给虚机添加RDM磁盘 第二章 vCenter回收活跃虚拟机的剩余可用空间 vCente…...

(原创)Flutter与Native通信的方式:EventChannel和BasicMessageChannel

前言 上一篇博客主要介绍了MethodChannel的使用方式 Flutter与Native通信的方式&#xff1a;MethodChannel 这篇博客接着讲另外两种通信方式 EventChannel和BasicMessageChannel EventChannel用于从native向flutter发送通知事件&#xff0c;例如flutter通过其监听Android的重…...

【解决】el-tree报Cannot read property ‘getCheckedKeys‘ of undefined

如果你报错 Cannot read property getCheckedKeys of undefined 或者 Cannot read property getCheckedNodes of undefined 只要在你的在<el-tree>上加个这个&#xff0c;就可以了 ref"tree"...

车载软件架构 —— 信息安全与基础软件

车载软件架构 —— 信息安全与基础软件 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生在世,最怕…...

C\C++内存管理

目录 1.C/C内存分布2.C语言中动态内存管理方式3.C中动态内存管理3.1new/delete内置类型3.2new和delete操作自定义类型 4.operator new与operator delete函数4.2重载operator new与operator delete&#xff08;了解&#xff09; 5.new和delete的实现原理5.1内置类型5.2 自定义类…...

会议室预约系统-检验是否被预约核心SQL

会议室预约时&#xff0c;判断能否被预约&#xff0c;即查询是否已经有预约记录&#xff0c;存在不能被预约。 s,e&#xff1b;表示已经预约的开始结束时间&#xff1b; ns,ne&#xff0c;表示表单提交的预约时间&#xff1b; 只需要(ns,ne)与(s,e)区间没有交集&#xff0c;可…...

C++11类模板

类模板是用来生成类的蓝图&#xff0c;与函数模板的不同之处是&#xff0c;编译器不能为类模板推断模板参数类型。 所以我们在使用类的时候要带上<>并且指定类型如下 vector<int> v; // 需要带上<int> 哦定义类模板 如下&#xff0c;和函数模板差不多都是…...

SpiderFlow爬虫平台(爬虫学习)

申明 作为自己学习的记录,方面后期查阅 官网 SpiderFlow官网 简介 spider-flow 是一个爬虫平台&#xff0c;以图形化方式定义爬虫流程&#xff0c;无需代码即可实现一个爬虫 是使用springboot开发的项目,后端代码直接运行即可使用...

Rime输入法配置

Rime输入法在我电脑上&#xff0c;删了装&#xff0c;装了删&#xff0c;已经反复好几次了。就像是Vim&#xff0c;用它的时候&#xff0c;感觉各种配置太麻烦&#xff0c;想要的功能不知道怎么实现。转用其它编辑器的时候&#xff0c;却又念着它的快捷键和可定制性&#xff0c…...

R语言学习笔记--列表list、数据框

列表 1-列表 列表可以包含不同类型的对象&#xff0c;也就是说&#xff0c;列表不是将某些具体的值组织起来&#xff0c;而是组织R对象。列表将数据组织在一个一维集合中。 列表非常好用&#xff0c;因为它可以装任何类型的对象&#xff0c;不要求数据之间是同质的。 创建列…...

电磁波定义、特性以及信道相关知识

文章目录 前言一、电磁波的定义、特性、波谱1、电磁波的特性2、电磁波谱的划分及用途 二、地球大气层的结构三、电磁波的传播方式1、地波&#xff08;ground-wave&#xff09;2、天波&#xff08;sky-wave&#xff09;3、视线传播&#xff08;line-of-sight&#xff09;①、相关…...

TCP KeepAlive与HTTP Keep-Alive

TCP KeepAlive与HTTP Keep-Alive TCP KeepAliveHTTP Keep-AliveTCP服务器怎么检测客户端断开连接 TCP KeepAlive TCP连接建立之后&#xff0c;如果应用程序或者上层协议一直不发送数据&#xff0c;或者隔很长时间才发送一次数据&#xff0c;那么TCP需要判断是应用程序掉线了还…...

SkyWalking链路追踪-Agent (代理人)

基础概念&#xff1a; SkyWalking链路追踪代理&#xff08;SkyWalking Tracing Agent&#xff09;是一种用于收集和传输链路追踪数据的工具。它与应用程序一起部署&#xff0c;并通过自动或手动方式来收集关于应用程序中的请求路径和操作的信息。该代理将收集到的数据发送到Sky…...

多线程案例 | 单例模式、阻塞队列、定时器、线程池

多线程案例 1、案例一&#xff1a;线程安全的单例模式 单例模式 单例模式是设计模式的一种 什么是设计模式&#xff1f; 设计模式好比象棋中的 “棋谱”&#xff0c;红方当头炮&#xff0c;黑方马来跳&#xff0c;针对红方的一些走法&#xff0c;黑方应招的时候有一些固定的…...

C++文件操作

1.写文件 //文件操作 #include<fstream> int main() {//写文件//路径 -- 此路径没有就生成给文件 string filePath R"(E:\项目\test.txt)";//打开文件 ios::app在后面追加内容 啥也不跟是覆盖写入ofstream fout(filePath, ios::app);//检查是否打开成功if (…...

overleaf(latex) 公式过大,需要调小字体,同时公式编号字体不变的方法

提问&#xff1a;用latex编辑的双列排版的论文中&#xff0c;如果一个包含矩阵的公式中&#xff0c;矩阵过大&#xff0c;导致超出列的范围&#xff0c;一般该如何调整呢&#xff1f; 回答&#xff1a;如果你在LaTeX中的双列排版中遇到了一个矩阵过大而导致超出列范围的问题&a…...

flink采用thrift读取tablets一个天坑

原先的配置 [INFO] StarRocksSourceBeReader [open Scan params.mem_limit 8589934592 B] [INFO] StarRocksSourceBeReader [open Scan params.query-timeout-s 600 s] [INFO] StarRocksSourceBeReader [open Scan params.keep-alive-min 100 min] [INFO] StarRocksSourceBeRea…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践

前言&#xff1a;本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中&#xff0c;跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南&#xff0c;你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案&#xff0c;并结合内网…...

怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)

+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...