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

基于Qt实现的自定义树结构容器:设计与应用

在Qt框架中,尽管其提供了许多强大的容器类(如 QList, QMap, QTreeWidget 等),但缺少一个通用的、灵活的树结构容器,直接支持多层级数据管理。为了满足这些需求,本文设计并实现了一个可复用的自定义树结构容器,并讨论其在不同项目中的应用。


在这里插入图片描述

1. 背景与动机

树结构在软件开发中是常见的数据组织形式,常用于以下场景:

  • 多层级文件管理器:文件夹与文件的树形展示。
  • 层次化关系管理:如公司组织结构、任务依赖关系。
  • 数据处理与分类:如属性分类、规则树等。

然而,Qt 中缺少直接的树结构容器(QTreeWidget 是 UI 组件,QAbstractItemModel 偏向于数据视图)。因此,我们实现了一个灵活、可扩展的 通用树结构容器,支持:

  1. 动态添加和删除节点。
  2. 为节点附加数据。
  3. 数据筛选与查找。
  4. 清晰的树形结构打印与调试。

2. 核心设计与实现

2.1 类设计概览

该树容器包含两个核心类:

  1. TreeNode

    • 表示树的单个节点。
    • 包括节点名称、父节点指针、子节点列表、节点数据。
    • 支持节点添加、删除、数据设置与清除等基本操作。
  2. Tree

    • 管理整个树的逻辑。
    • 提供全局的节点操作接口,如添加、删除节点,筛选节点数据,打印树结构等。
2.2 TreeNode 类实现

TreeNode 是树结构的核心,负责管理节点的层次关系和数据存储。以下是其关键代码逻辑:

class TreeNode {
public:explicit TreeNode(const QString& name, TreeNode* parent = nullptr);~TreeNode();// 添加子节点TreeNode* addChild(const QString& name);// 移除子节点bool removeChild(TreeNode* child);// 设置与清除节点数据void setData(const QVariant& data);void clearData();// 获取节点信息QVariant getData() const;const QList<TreeNode*>& getChildren() const;QString getName() const;TreeNode* getParent() const;
};

主要功能:

  • addChildremoveChild 实现树的动态结构调整。
  • setDataclearData 支持灵活的节点数据管理。
  • 提供对父子关系和数据的访问接口。

2.3 Tree 类实现

Tree 是一个树容器的管理类。其设计目标是:

  • 提供用户友好的接口,隐藏树节点的内部操作。
  • 支持全局的增删改查功能。

以下是 Tree 类的部分接口说明:

class Tree {
public:Tree();~Tree();// 节点操作TreeNode* addNode(TreeNode* parent, const QString& name);bool removeNode(TreeNode* node);// 数据操作void setNodeData(TreeNode* node, const QVariant& data);QVariant getNodeData(TreeNode* node) const;void clearNodeData(TreeNode* node);// 数据筛选与树形打印QList<TreeNode*> filterNodes(const QString& keyword) const;void printTree() const;
};

主要功能:

  • addNode:动态添加节点,支持将节点默认添加到根节点。
  • filterNodes:通过关键字查找包含特定数据的节点。
  • printTree:以层级缩进格式打印树的结构,便于调试。

2.4 调用示例

以下是使用 TreeTreeNode 的示例代码:

int main(int argc, char* argv[]) {QCoreApplication a(argc, argv);// 创建树容器Tree tree;// 添加节点TreeNode* root = tree.addNode(nullptr, tc("根节点"));TreeNode* nodeA = tree.addNode(root, tc("节点A"));TreeNode* nodeB = tree.addNode(root, tc("节点B"));TreeNode* nodeC = tree.addNode(nodeA, tc("节点C"));// 设置节点数据tree.setNodeData(nodeA, tc("温度过高"));tree.setNodeData(nodeB, tc("正常"));tree.setNodeData(nodeC, tc("压力过低"));// 打印树结构tree.printTree();// 筛选包含 "温度" 的节点QList<TreeNode*> filteredNodes = tree.filterNodes(tc("温度"));qDebug() << tc("筛选结果:");for (TreeNode* node : filteredNodes) {qDebug() << node->getName() << ":" << node->getData().toString();}return a.exec();
}

运行结果:

根节点 ()节点A (温度过高)节点C (压力过低)节点B (正常)筛选结果:
"节点A" : "温度过高"

3. 适用场景分析

该树容器的灵活性使其适用于多种场景,包括但不限于以下项目:

  1. 文件管理器

    • 以层次结构管理文件夹和文件。
    • 节点数据可存储文件的元信息(如路径、大小)。
  2. 组织结构管理

    • 用于显示公司组织架构(如部门、员工)。
    • 节点数据可附加员工信息。
  3. 规则引擎或决策树

    • 用于实现条件匹配规则。
    • 节点存储规则条件与结果。
  4. 动态数据分类

    • 实现类似标签分类的功能。
    • 支持实时增删节点。
  5. 调试工具

    • 用于显示复杂系统中的内部数据关系。

4. 优势与改进方向

4.1 优势
  1. 简单易用

    • 接口友好,隐藏复杂的内部操作。
    • 提供清晰的错误提示和默认行为。
  2. 高扩展性

    • 可以轻松添加新功能,如节点排序、自定义过滤条件等。
  3. 灵活性

    • 节点的数据类型为 QVariant,支持多种数据类型存储。
  4. 跨平台支持

    • 依赖 Qt 框架,具备良好的跨平台能力。
4.2 改进方向
  1. 线程安全

    • 增加对并发操作的支持,例如通过 QMutex 实现线程同步。
  2. 持久化

    • 增加树结构的序列化和反序列化功能,用于存储和加载数据。
  3. 性能优化

    • 对大规模树操作(如深度遍历)进行优化。
  4. 模型绑定

    • 将树容器与 QAbstractItemModel 绑定,支持直接用于 Qt 的视图类(如 QTreeView)。

5. 结语

本文介绍了一个基于 Qt 实现的自定义树结构容器,其功能涵盖了节点管理、数据存储、筛选与打印等操作,适用于多种项目场景。通过该容器,开发者可以更加灵活地管理复杂的层次化数据,同时其清晰的接口设计也便于扩展与维护。


6. 源码

以下是修正后的完整代码实现,包含 TreeNode.hTreeNode.cppTree.hTree.cppmain.cpp 文件。代码修复了根节点初始化问题,并增强了错误处理和默认逻辑。


TreeNode.h

#ifndef TREENODE_H
#define TREENODE_H#include <QString>
#include <QList>
#include <QVariant>#define tc(a) QString::fromLocal8Bit(a)class TreeNode {
public:explicit TreeNode(const QString& name, TreeNode* parent = nullptr);~TreeNode();// 添加子节点TreeNode* addChild(const QString& name);// 移除子节点bool removeChild(TreeNode* child);// 设置节点数据void setData(const QVariant& data);// 获取节点数据QVariant getData() const;// 移除节点数据void clearData();// 获取所有子节点const QList<TreeNode*>& getChildren() const;// 获取节点名称QString getName() const;// 获取父节点TreeNode* getParent() const;// 检查是否为叶子节点bool isLeaf() const;private:QString nodeName;             // 节点名称QVariant nodeData;            // 节点数据TreeNode* parentNode;         // 父节点QList<TreeNode*> childNodes;  // 子节点列表
};#endif // TREENODE_H

TreeNode.cpp

#include "TreeNode.h"
#include <QDebug>TreeNode::TreeNode(const QString& name, TreeNode* parent): nodeName(name), parentNode(parent) {}TreeNode::~TreeNode() {qDeleteAll(childNodes); // 删除所有子节点
}TreeNode* TreeNode::addChild(const QString& name) {TreeNode* child = new TreeNode(name, this);childNodes.append(child);return child;
}bool TreeNode::removeChild(TreeNode* child) {if (!child || !childNodes.contains(child)) {qWarning() << tc("移除失败:节点不存在!");return false;}childNodes.removeAll(child);delete child; // 删除子节点及其数据return true;
}void TreeNode::setData(const QVariant& data) {nodeData = data;
}QVariant TreeNode::getData() const {return nodeData;
}void TreeNode::clearData() {nodeData.clear();
}const QList<TreeNode*>& TreeNode::getChildren() const {return childNodes;
}QString TreeNode::getName() const {return nodeName;
}TreeNode* TreeNode::getParent() const {return parentNode;
}bool TreeNode::isLeaf() const {return childNodes.isEmpty();
}

Tree.h

#ifndef TREE_H
#define TREE_H#include "TreeNode.h"class Tree {
public:Tree();~Tree();// 添加节点TreeNode* addNode(TreeNode* parent, const QString& name);// 移除节点bool removeNode(TreeNode* node);// 设置节点数据void setNodeData(TreeNode* node, const QVariant& data);// 获取节点数据QVariant getNodeData(TreeNode* node) const;// 移除节点数据void clearNodeData(TreeNode* node);// 查找节点(通过名称)TreeNode* findNode(TreeNode* root, const QString& name) const;// 过滤节点(通过数据关键字)QList<TreeNode*> filterNodes(const QString& keyword) const;// 打印树结构void printTree() const;private:TreeNode* root;// 辅助递归方法void filterRecursive(TreeNode* node, const QString& keyword, QList<TreeNode*>& result) const;void printRecursive(TreeNode* node, int depth) const;
};#endif // TREE_H

Tree.cpp

#include "Tree.h"
#include <QDebug>Tree::Tree() {root = new TreeNode(tc("根节点"));qDebug() << tc("成功初始化根节点。");
}Tree::~Tree() {delete root; // 自动删除所有节点
}TreeNode* Tree::addNode(TreeNode* parent, const QString& name) {if (!parent) {if (!root) {qWarning() << tc("添加失败:根节点未创建!");return nullptr;}qDebug() << tc("未指定父节点,默认添加到根节点。");parent = root; // 如果父节点为空,默认添加到根节点}return parent->addChild(name);
}bool Tree::removeNode(TreeNode* node) {if (!node || node == root) {qWarning() << tc("移除失败:节点为空或为根节点!");return false;}TreeNode* parent = node->getParent();if (!parent) {qWarning() << tc("移除失败:父节点为空!");return false;}return parent->removeChild(node);
}void Tree::setNodeData(TreeNode* node, const QVariant& data) {if (!node) {qWarning() << tc("设置失败:节点为空!");return;}node->setData(data);
}QVariant Tree::getNodeData(TreeNode* node) const {if (!node) {qWarning() << tc("获取失败:节点为空!");return QVariant();}return node->getData();
}void Tree::clearNodeData(TreeNode* node) {if (!node) {qWarning() << tc("清除失败:节点为空!");return;}node->clearData();
}TreeNode* Tree::findNode(TreeNode* root, const QString& name) const {if (!root) return nullptr;if (root->getName() == name) return root;for (TreeNode* child : root->getChildren()) {TreeNode* found = findNode(child, name);if (found) return found;}return nullptr;
}QList<TreeNode*> Tree::filterNodes(const QString& keyword) const {QList<TreeNode*> result;filterRecursive(root, keyword, result);return result;
}void Tree::filterRecursive(TreeNode* node, const QString& keyword, QList<TreeNode*>& result) const {if (node->getData().toString().contains(keyword)) {result.append(node);}for (TreeNode* child : node->getChildren()) {filterRecursive(child, keyword, result);}
}void Tree::printTree() const {printRecursive(root, 0);
}void Tree::printRecursive(TreeNode* node, int depth) const {qDebug().noquote() << QString(depth * 2, ' ') + node->getName() + " (" + node->getData().toString() + ")";for (TreeNode* child : node->getChildren()) {printRecursive(child, depth + 1);}
}

main.cpp

#include <QCoreApplication>
#include "Tree.h"int main(int argc, char* argv[]) {QCoreApplication a(argc, argv);// 创建树Tree tree;// 创建子节点,明确传入父节点TreeNode* nodeA = tree.addNode(nullptr, tc("节点A")); // 默认添加到根节点TreeNode* nodeB = tree.addNode(nodeA, tc("节点B"));TreeNode* nodeC = tree.addNode(nodeA, tc("节点C"));// 添加数据tree.setNodeData(nodeA, tc("温度过高"));tree.setNodeData(nodeB, tc("正常"));tree.setNodeData(nodeC, tc("压力过低"));// 获取数据qDebug() << tc("节点A数据:") << tree.getNodeData(nodeA).toString();// 清除数据tree.clearNodeData(nodeC);// 过滤节点QList<TreeNode*> filteredNodes = tree.filterNodes(tc("温度"));qDebug() << tc("过滤结果:");for (TreeNode* node : filteredNodes) {qDebug() << node->getName() << ":" << node->getData().toString();}// 打印树结构tree.printTree();return a.exec();
}

运行结果

成功初始化根节点。
未指定父节点,默认添加到根节点。
未指定父节点,默认添加到根节点。
未指定父节点,默认添加到根节点。
节点A数据: "温度过高"
过滤结果:
"节点A" : "温度过高"
根节点 ()节点A (温度过高)节点B (正常)节点C ()

功能总结

该实现支持树节点的 添加、删除、查询、过滤,以及节点数据的 设置、获取、清除。同时,包含中文提示与日志输出,逻辑健壮且易于扩展。

相关文章:

基于Qt实现的自定义树结构容器:设计与应用

在Qt框架中&#xff0c;尽管其提供了许多强大的容器类&#xff08;如 QList, QMap, QTreeWidget 等&#xff09;&#xff0c;但缺少一个通用的、灵活的树结构容器&#xff0c;直接支持多层级数据管理。为了满足这些需求&#xff0c;本文设计并实现了一个可复用的自定义树结构容…...

网络命令Linux

目录 一&#xff0c;Linux 二&#xff0c;CMD 一&#xff0c;Linux ping www.baidu.com 测试联网 -c 2 次数&#xff0c;ping几次 &#xff0c; -i 间隔 -W timeout 超时时间&#xff0c;等待响应的超时时间 ss -lntup |grep -w 22 netstat -lntup |grep -w 22 lsof -i:22 ls…...

简单的Activiti Modoler 流程在线编辑器

简单的Activiti Modoler 流程在线编辑器 1.需求 我们公司使用的流程是activiti5.22.0&#xff0c;版本有些老了&#xff0c;然后使用的编辑器都是eclipse的流程编辑器插件&#xff0c;每次编辑流程需要打开eclipse进行编辑&#xff0c;然后再导入到项目里面&#xff0c;不是特…...

【NodeJS】Express写接口的整体流程

前提条件 开发 Node.js&#xff0c;首先就必须要安装 Node.js。推荐使用 nvm&#xff0c;它可以随意切换 node 版本。下载 nvm&#xff0c;具体可以看本人另一篇文章&#xff1a;nvm的作用、下载、使用、以及Mac使用时遇到commond not found:nvm如何解决。 nvm官方&#xff1…...

Oracle 锁表的解决方法及避免锁表问题的最佳实践

背景介绍 在 Oracle 数据库中&#xff0c;锁表或锁超时相信大家都不陌生&#xff0c;是一个常见的问题&#xff0c;尤其是在执行 DML&#xff08;数据操作语言&#xff09;语句时。当一个会话对表或行进行锁定但未提交事务时&#xff0c;其他会话可能会因为等待锁资源而出现超…...

关于 vue+element 日期时间选择器 限制只能选当天以及30天之前的日期

业务需求&#xff0c;需要实现选择当天以及30天之前的日期&#xff0c;于是我想到的是利用picker-options去限制可选范围 代码如下 <el-date-pickerv-model"searchData.acceptTime"type"datetimerange"value-format"yyyy-MM-dd hh:mm:ss"styl…...

租辆酷车小程序开发(二)—— 接入微服务GRPC

vscode中golang的配置 设置依赖管理 go env -w GO111MODULEon go env -w GOPROXYhttps://goproxy.cn,direct GO111MODULEauto 在$GOPATH/src 外面且根目录有go.mod 文件时&#xff0c;开启模块支持 GO111MODULEoff 无模块支持&#xff0c;go会从GOPATH 和 vendor 文件夹寻找包…...

如何在 Ubuntu 22.04 上安装 Metabase 数据可视化分析工具

简介 Metabase 提供了一个简单易用的界面&#xff0c;让你能够轻松地对数据进行探索和分析。通过本文的指导&#xff0c;你将能够在 Ubuntu 22.04 系统上安装并配置 Metabase&#xff0c;并通过 Nginx 进行反向代理以提高安全性。本教程假设你已经拥有了一个非 root 用户&…...

MySQL 用户与权限管理

MySQL 是一种广泛使用的关系型数据库管理系统,支持多用户访问和权限控制。在多用户环境下,数据库安全至关重要,而用户和权限管理是数据库管理中最基础也是最重要的一部分。通过合理地创建和管理用户、分配和管理权限、使用角色权限,可以有效地保护数据库,确保数据的安全性…...

【Web前端】如何构建简单HTML表单?

HTML 表单是 Web 开发中非常重要的组成部分。它们是与用户交互的主要方式&#xff0c;能够收集用户输入的数据。表单的灵活性使它们成为 HTML 中最复杂的结构之一&#xff0c;但若使用正确的结构和元素&#xff0c;可以确保其可用性和无障碍性。 表单的基本结构 HTML 表单使用…...

Spring Boot 3 集成 Spring Security(3)数据管理

文章目录 准备工作新建项目引入MyBatis-Plus依赖创建表结构生成基础代码 逻辑实现application.yml配置SecurityConfig 配置自定义 UserDetailsService创建测试 启动测试 在前面的文章中我们介绍了 《Spring Boot 3 集成 Spring Security&#xff08;1&#xff09;认证》和 《…...

书生大模型实战营第四期-入门岛-4. maas课程任务

书生大模型实战营第四期-入门岛-4. maas课程任务 任务一、模型下载 任务内容 使用Hugging Face平台、魔搭社区平台&#xff08;可选&#xff09;和魔乐社区平台&#xff08;可选&#xff09;下载文档中提到的模型&#xff08;至少需要下载config.json文件、model.safetensor…...

Spring ApplicationListener监听

【JavaWeb】Spring ApplicationListener-CSDN博客 ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现&#xff0c;内部实现原理是观察者设计模式&#xff0c;设计初衷也是为了系统业务逻辑之间的解耦&#xff0c;提高可扩展性以及可维护性。事件发布…...

K8s调度器扩展(scheduler)

1.K8S调度器 筛选插件扩展 为了熟悉 K8S调度器扩展步骤&#xff0c;目前只修改 筛选 插件 准备环境&#xff08;到GitHub直接下载压缩包&#xff0c;然后解压&#xff0c;解压要在Linux系统下完成&#xff09; 2. 编写调度器插件代码 在 Kubernetes 源代码目录下编写调度插件…...

IntelliJ IDEA 中,自动导包功能

在 IntelliJ IDEA 中&#xff0c;自动导包功能可以极大地提高开发效率&#xff0c;减少手动导入包所带来的繁琐和错误。以下是如何在 IntelliJ IDEA 中设置和使用自动导包功能的详细步骤&#xff1a; 一、设置自动导包 打开 IntelliJ IDEA&#xff1a; 启动 IntelliJ IDEA 并打…...

Spring事务笔记

目录 1.Spring 编程式事务 2.Transactional 3.事务隔离级别 4.Spring 事务传播机制 什么是事务? 事务是⼀组操作的集合, 是⼀个不可分割的操作. 事务会把所有的操作作为⼀个整体, ⼀起向数据库提交或者是撤销操作请求. 所以这组操作要么同时成 功, 要么同时失败 1.Spri…...

SQLite 管理工具 SQLiteStudio 3.4.5 发布

SQLiteStudio 3.4.5 版本现已发布&#xff0c;它带来了大量的 bug 修复&#xff0c;并增加了一些小功能。SQLiteStudio 是一个跨平台的 SQLite 数据库的管理工具。 具体更新内容包括&#xff1a; 现在可以使用 Collations Editor 窗口在数据库中注册 Extension-based collatio…...

QT 实现组织树状图

1.实现效果 在Qt中使用QGraphicsItem和QGraphicsScene实现树状图,你需要创建自定义的QGraphicsItem类来表示树的节点,并管理它们的位置和连接,以下是实现效果图。 2.实现思路 可以看见,上图所示,我们需要自定义连线类和节点类。 每个节点类Node,需要绘制矩形框体文字…...

go-学习

文章目录 简介标识符字符串的拼接&#xff0c;关键字数据类型声明变量常量算术运算符关系运算符逻辑运算符位运算赋值运算符其他运算符 简介 Go 语言的基础组成有以下几个部分&#xff1a; 1.包声明 2.引入包 3.函数 4.变量 5.语句 & 表达式 6.注释 package main import &q…...

【面试分享】主流编程语言的内存回收机制及其优缺点

以下是几种主流编程语言的内存回收机制及其优缺点&#xff1a; 一、Java 内存回收机制&#xff1a; Java 使用自动内存管理&#xff0c;主要通过垃圾回收器&#xff08;Garbage Collector&#xff0c;GC&#xff09;来回收不再被使用的对象所占用的内存。Java 的垃圾回收器会定…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...