xtools-app一款基于JDK25,SpringBoot4,SpringCloud的最新微服务脚手架
xtools-app 设计文档 开源地址: https://gitee.com/jun-xtools/xtools-app.git 一、功能和用途 1.1 项目概述 项目属性 值 项目名称 xtools-app 项目版本 1.0.0 父POM org.xujun:xtools-parent-cloud:5.0.0 JDK版本 25 项目描述 低调大师工具箱,基础应用模块,适配JDK25 组织 org.xujun (https://www.xujun.org) xtools-app 是一套基于 Spring Boot 构建的企业级基础应用平台,提供系统管理、代码生成、监控管理等核心功能。项目采用多模块架构,支持独立部署(Standalone)和微服务部署两种模式。 1.2 技术特点 采用最新的 JDK 25 版本,充分利用虚拟线程(Virtual Thread)、ScopedValue 等新特性 基于 Spring Boot 4.0.6 构建,支持自动配置和快速开发 集成 Spring Cloud Alibaba 2025.1.0.0 微服务框架 使用 MyBatis-Plus 3.5.16 简化数据访问层开发 集成 Elasticsearch 实现日志存储和检索(Spring Data BOM 2025.1.5) 支持 Nacos 3.1.1 服务注册与发现、Sentinel 1.8.9 流量控制和熔断降级 使用 Redis 实现分布式缓存和会话管理 使用 RabbitMQ(Spring AMQP 4.0.3)实现异步消息处理 支持 Knife4j 4.5.0 自动生成 API 文档 使用 SM2/SM3 国密算法保障密码安全 1.3 核心功能 #mq6disnaqhi0o8stwjd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disnaqhi0o8stwjd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disnaqhi0o8stwjd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disnaqhi0o8stwjd .error-icon{fill:#a44141;}#mq6disnaqhi0o8stwjd .error-text{fill:#ddd;stroke:#ddd;}#mq6disnaqhi0o8stwjd .edge-thickness-normal{stroke-width:1px;}#mq6disnaqhi0o8stwjd .edge-thickness-thick{stroke-width:3.5px;}#mq6disnaqhi0o8stwjd .edge-pattern-solid{stroke-dasharray:0;}#mq6disnaqhi0o8stwjd .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disnaqhi0o8stwjd .edge-pattern-dashed{stroke-dasharray:3;}#mq6disnaqhi0o8stwjd .edge-pattern-dotted{stroke-dasharray:2;}#mq6disnaqhi0o8stwjd .marker{fill:lightgrey;stroke:lightgrey;}#mq6disnaqhi0o8stwjd .marker.cross{stroke:lightgrey;}#mq6disnaqhi0o8stwjd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disnaqhi0o8stwjd p{margin:0;}#mq6disnaqhi0o8stwjd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disnaqhi0o8stwjd .cluster-label text{fill:#F9FFFE;}#mq6disnaqhi0o8stwjd .cluster-label span{color:#F9FFFE;}#mq6disnaqhi0o8stwjd .cluster-label span p{background-color:transparent;}#mq6disnaqhi0o8stwjd .label text,#mq6disnaqhi0o8stwjd span{fill:#ccc;color:#ccc;}#mq6disnaqhi0o8stwjd .node rect,#mq6disnaqhi0o8stwjd .node circle,#mq6disnaqhi0o8stwjd .node ellipse,#mq6disnaqhi0o8stwjd .node polygon,#mq6disnaqhi0o8stwjd .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disnaqhi0o8stwjd .rough-node .label text,#mq6disnaqhi0o8stwjd .node .label text,#mq6disnaqhi0o8stwjd .image-shape .label,#mq6disnaqhi0o8stwjd .icon-shape .label{text-anchor:middle;}#mq6disnaqhi0o8stwjd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disnaqhi0o8stwjd .rough-node .label,#mq6disnaqhi0o8stwjd .node .label,#mq6disnaqhi0o8stwjd .image-shape .label,#mq6disnaqhi0o8stwjd .icon-shape .label{text-align:center;}#mq6disnaqhi0o8stwjd .node.clickable{cursor:pointer;}#mq6disnaqhi0o8stwjd .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disnaqhi0o8stwjd .arrowheadPath{fill:lightgrey;}#mq6disnaqhi0o8stwjd .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disnaqhi0o8stwjd .flowchart-link{stroke:lightgrey;fill:none;}#mq6disnaqhi0o8stwjd .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disnaqhi0o8stwjd .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disnaqhi0o8stwjd .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disnaqhi0o8stwjd .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disnaqhi0o8stwjd .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disnaqhi0o8stwjd .cluster text{fill:#F9FFFE;}#mq6disnaqhi0o8stwjd .cluster span{color:#F9FFFE;}#mq6disnaqhi0o8stwjd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disnaqhi0o8stwjd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disnaqhi0o8stwjd rect.text{fill:none;stroke-width:0;}#mq6disnaqhi0o8stwjd .icon-shape,#mq6disnaqhi0o8stwjd .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disnaqhi0o8stwjd .icon-shape p,#mq6disnaqhi0o8stwjd .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disnaqhi0o8stwjd .icon-shape rect,#mq6disnaqhi0o8stwjd .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disnaqhi0o8stwjd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disnaqhi0o8stwjd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disnaqhi0o8stwjd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}认证安全模块认证模块Token管理、白名单风控模块IP风险、URI风险文件模块文件操作、S3存储参数模块系统参数工具定时任务模块动态定时任务标签模块Swagger标签拦截监控模块监控客户端Boot Admin Client健康检查Health Controller监控服务端Boot Admin Server公共模块缓存模块Redis缓存、AOP日志远程调用HTTP服务调用、拦截器JAR管理JAR加载、初始化日志总线事件发布、异步存储日志过滤HTTP请求拦截、请求响应日志消息队列RabbitMQ、错误重试任务调度异步任务总线、任务记录限流降级Sentinel、BlockException处理通用配置公共配置项代码生成模块数据源管理多数据源、连接测试表结构管理数据库同步、字段配置代码生成Velocity模板、前后端代码代码预览下载在线预览、ZIP下载系统管理模块用户管理CRUD 、角色分配、状态管理角色管理权限分配、菜单分配菜单管理树形结构、动态加载、接口权限部门管理树形结构、人员管理字典管理类型管理、项管理、Excel导入导出日志管理操作日志、系统日志、Elasticsearch存储任务管理定时任务配置、任务监控、异步任务系统监控Redis监控、MySQL监控、ES监控JAR管理JAR加载、依赖缓存文件管理上传下载、S3存储、生命周期管理公告管理公告发布、用户公告参数管理系统参数配置、参数缓存风控管理IP黑名单、URI黑名单、本地缓存地址管理IP归属地查询、地址缓存更新历史数据变更记录1.4 功能关系图 #mq6disobaoyc7r4t0av{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobaoyc7r4t0av .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobaoyc7r4t0av .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobaoyc7r4t0av .error-icon{fill:#a44141;}#mq6disobaoyc7r4t0av .error-text{fill:#ddd;stroke:#ddd;}#mq6disobaoyc7r4t0av .edge-thickness-normal{stroke-width:1px;}#mq6disobaoyc7r4t0av .edge-thickness-thick{stroke-width:3.5px;}#mq6disobaoyc7r4t0av .edge-pattern-solid{stroke-dasharray:0;}#mq6disobaoyc7r4t0av .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobaoyc7r4t0av .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobaoyc7r4t0av .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobaoyc7r4t0av .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobaoyc7r4t0av .marker.cross{stroke:lightgrey;}#mq6disobaoyc7r4t0av svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobaoyc7r4t0av p{margin:0;}#mq6disobaoyc7r4t0av .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobaoyc7r4t0av .cluster-label text{fill:#F9FFFE;}#mq6disobaoyc7r4t0av .cluster-label span{color:#F9FFFE;}#mq6disobaoyc7r4t0av .cluster-label span p{background-color:transparent;}#mq6disobaoyc7r4t0av .label text,#mq6disobaoyc7r4t0av span{fill:#ccc;color:#ccc;}#mq6disobaoyc7r4t0av .node rect,#mq6disobaoyc7r4t0av .node circle,#mq6disobaoyc7r4t0av .node ellipse,#mq6disobaoyc7r4t0av .node polygon,#mq6disobaoyc7r4t0av .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobaoyc7r4t0av .rough-node .label text,#mq6disobaoyc7r4t0av .node .label text,#mq6disobaoyc7r4t0av .image-shape .label,#mq6disobaoyc7r4t0av .icon-shape .label{text-anchor:middle;}#mq6disobaoyc7r4t0av .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobaoyc7r4t0av .rough-node .label,#mq6disobaoyc7r4t0av .node .label,#mq6disobaoyc7r4t0av .image-shape .label,#mq6disobaoyc7r4t0av .icon-shape .label{text-align:center;}#mq6disobaoyc7r4t0av .node.clickable{cursor:pointer;}#mq6disobaoyc7r4t0av .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobaoyc7r4t0av .arrowheadPath{fill:lightgrey;}#mq6disobaoyc7r4t0av .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobaoyc7r4t0av .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobaoyc7r4t0av .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobaoyc7r4t0av .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobaoyc7r4t0av .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobaoyc7r4t0av .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobaoyc7r4t0av .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobaoyc7r4t0av .cluster text{fill:#F9FFFE;}#mq6disobaoyc7r4t0av .cluster span{color:#F9FFFE;}#mq6disobaoyc7r4t0av div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobaoyc7r4t0av .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobaoyc7r4t0av rect.text{fill:none;stroke-width:0;}#mq6disobaoyc7r4t0av .icon-shape,#mq6disobaoyc7r4t0av .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobaoyc7r4t0av .icon-shape p,#mq6disobaoyc7r4t0av .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobaoyc7r4t0av .icon-shape rect,#mq6disobaoyc7r4t0av .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobaoyc7r4t0av .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobaoyc7r4t0av .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobaoyc7r4t0av :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}用户登录认证菜单访问数据操作SM2加密传输认证授权Token管理Redis存储权限验证RBAC模型角色操作日志消息队列ElasticsearchRedis缓存代码生成数据库系统监控RedisMySQL1.5 功能层次图 #mq6disobvm5opy0ckn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobvm5opy0ckn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobvm5opy0ckn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobvm5opy0ckn .error-icon{fill:#a44141;}#mq6disobvm5opy0ckn .error-text{fill:#ddd;stroke:#ddd;}#mq6disobvm5opy0ckn .edge-thickness-normal{stroke-width:1px;}#mq6disobvm5opy0ckn .edge-thickness-thick{stroke-width:3.5px;}#mq6disobvm5opy0ckn .edge-pattern-solid{stroke-dasharray:0;}#mq6disobvm5opy0ckn .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobvm5opy0ckn .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobvm5opy0ckn .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobvm5opy0ckn .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobvm5opy0ckn .marker.cross{stroke:lightgrey;}#mq6disobvm5opy0ckn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobvm5opy0ckn p{margin:0;}#mq6disobvm5opy0ckn .edge{stroke-width:3;}#mq6disobvm5opy0ckn .section--1 rect,#mq6disobvm5opy0ckn .section--1 path,#mq6disobvm5opy0ckn .section--1 circle,#mq6disobvm5opy0ckn .section--1 polygon,#mq6disobvm5opy0ckn .section--1 path{fill:#1f2020;}#mq6disobvm5opy0ckn .section--1 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon--1{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge--1{stroke:#1f2020;}#mq6disobvm5opy0ckn .edge-depth--1{stroke-width:17;}#mq6disobvm5opy0ckn .section--1 line{stroke:#e0dfdf;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-0 rect,#mq6disobvm5opy0ckn .section-0 path,#mq6disobvm5opy0ckn .section-0 circle,#mq6disobvm5opy0ckn .section-0 polygon,#mq6disobvm5opy0ckn .section-0 path{fill:#0b0000;}#mq6disobvm5opy0ckn .section-0 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-0{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-0{stroke:#0b0000;}#mq6disobvm5opy0ckn .edge-depth-0{stroke-width:14;}#mq6disobvm5opy0ckn .section-0 line{stroke:#f4ffff;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-1 rect,#mq6disobvm5opy0ckn .section-1 path,#mq6disobvm5opy0ckn .section-1 circle,#mq6disobvm5opy0ckn .section-1 polygon,#mq6disobvm5opy0ckn .section-1 path{fill:#4d1037;}#mq6disobvm5opy0ckn .section-1 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-1{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-1{stroke:#4d1037;}#mq6disobvm5opy0ckn .edge-depth-1{stroke-width:11;}#mq6disobvm5opy0ckn .section-1 line{stroke:#b2efc8;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-2 rect,#mq6disobvm5opy0ckn .section-2 path,#mq6disobvm5opy0ckn .section-2 circle,#mq6disobvm5opy0ckn .section-2 polygon,#mq6disobvm5opy0ckn .section-2 path{fill:#3f5258;}#mq6disobvm5opy0ckn .section-2 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-2{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-2{stroke:#3f5258;}#mq6disobvm5opy0ckn .edge-depth-2{stroke-width:8;}#mq6disobvm5opy0ckn .section-2 line{stroke:#c0ada7;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-3 rect,#mq6disobvm5opy0ckn .section-3 path,#mq6disobvm5opy0ckn .section-3 circle,#mq6disobvm5opy0ckn .section-3 polygon,#mq6disobvm5opy0ckn .section-3 path{fill:#4f2f1b;}#mq6disobvm5opy0ckn .section-3 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-3{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-3{stroke:#4f2f1b;}#mq6disobvm5opy0ckn .edge-depth-3{stroke-width:5;}#mq6disobvm5opy0ckn .section-3 line{stroke:#b0d0e4;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-4 rect,#mq6disobvm5opy0ckn .section-4 path,#mq6disobvm5opy0ckn .section-4 circle,#mq6disobvm5opy0ckn .section-4 polygon,#mq6disobvm5opy0ckn .section-4 path{fill:#6e0a0a;}#mq6disobvm5opy0ckn .section-4 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-4{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-4{stroke:#6e0a0a;}#mq6disobvm5opy0ckn .edge-depth-4{stroke-width:2;}#mq6disobvm5opy0ckn .section-4 line{stroke:#91f5f5;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-5 rect,#mq6disobvm5opy0ckn .section-5 path,#mq6disobvm5opy0ckn .section-5 circle,#mq6disobvm5opy0ckn .section-5 polygon,#mq6disobvm5opy0ckn .section-5 path{fill:#3b0048;}#mq6disobvm5opy0ckn .section-5 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-5{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-5{stroke:#3b0048;}#mq6disobvm5opy0ckn .edge-depth-5{stroke-width:-1;}#mq6disobvm5opy0ckn .section-5 line{stroke:#c4ffb7;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-6 rect,#mq6disobvm5opy0ckn .section-6 path,#mq6disobvm5opy0ckn .section-6 circle,#mq6disobvm5opy0ckn .section-6 polygon,#mq6disobvm5opy0ckn .section-6 path{fill:#995a01;}#mq6disobvm5opy0ckn .section-6 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-6{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-6{stroke:#995a01;}#mq6disobvm5opy0ckn .edge-depth-6{stroke-width:-4;}#mq6disobvm5opy0ckn .section-6 line{stroke:#66a5fe;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-7 rect,#mq6disobvm5opy0ckn .section-7 path,#mq6disobvm5opy0ckn .section-7 circle,#mq6disobvm5opy0ckn .section-7 polygon,#mq6disobvm5opy0ckn .section-7 path{fill:#154706;}#mq6disobvm5opy0ckn .section-7 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-7{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-7{stroke:#154706;}#mq6disobvm5opy0ckn .edge-depth-7{stroke-width:-7;}#mq6disobvm5opy0ckn .section-7 line{stroke:#eab8f9;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-8 rect,#mq6disobvm5opy0ckn .section-8 path,#mq6disobvm5opy0ckn .section-8 circle,#mq6disobvm5opy0ckn .section-8 polygon,#mq6disobvm5opy0ckn .section-8 path{fill:#161722;}#mq6disobvm5opy0ckn .section-8 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-8{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-8{stroke:#161722;}#mq6disobvm5opy0ckn .edge-depth-8{stroke-width:-10;}#mq6disobvm5opy0ckn .section-8 line{stroke:#e9e8dd;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-9 rect,#mq6disobvm5opy0ckn .section-9 path,#mq6disobvm5opy0ckn .section-9 circle,#mq6disobvm5opy0ckn .section-9 polygon,#mq6disobvm5opy0ckn .section-9 path{fill:#00296f;}#mq6disobvm5opy0ckn .section-9 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-9{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-9{stroke:#00296f;}#mq6disobvm5opy0ckn .edge-depth-9{stroke-width:-13;}#mq6disobvm5opy0ckn .section-9 line{stroke:#ffd690;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-10 rect,#mq6disobvm5opy0ckn .section-10 path,#mq6disobvm5opy0ckn .section-10 circle,#mq6disobvm5opy0ckn .section-10 polygon,#mq6disobvm5opy0ckn .section-10 path{fill:#01629c;}#mq6disobvm5opy0ckn .section-10 text{fill:lightgrey;}#mq6disobvm5opy0ckn .node-icon-10{font-size:40px;color:lightgrey;}#mq6disobvm5opy0ckn .section-edge-10{stroke:#01629c;}#mq6disobvm5opy0ckn .edge-depth-10{stroke-width:-16;}#mq6disobvm5opy0ckn .section-10 line{stroke:#fe9d63;stroke-width:3;}#mq6disobvm5opy0ckn .disabled,#mq6disobvm5opy0ckn .disabled circle,#mq6disobvm5opy0ckn .disabled text{fill:lightgray;}#mq6disobvm5opy0ckn .disabled text{fill:#efefef;}#mq6disobvm5opy0ckn .section-root rect,#mq6disobvm5opy0ckn .section-root path,#mq6disobvm5opy0ckn .section-root circle,#mq6disobvm5opy0ckn .section-root polygon{fill:hsl(180, 1.5873015873%, 48.3529411765%);}#mq6disobvm5opy0ckn .section-root text{fill:#2c2c2c;}#mq6disobvm5opy0ckn .section-root span{color:#2c2c2c;}#mq6disobvm5opy0ckn .section-2 span{color:#2c2c2c;}#mq6disobvm5opy0ckn .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mq6disobvm5opy0ckn .edge{fill:none;}#mq6disobvm5opy0ckn .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mq6disobvm5opy0ckn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}xtools-app基础应用平台系统管理用户管理增删改查角色分配密码管理状态管理数据脱敏角色管理角色配置菜单分配菜单管理树形结构动态加载接口权限配置部门管理树形结构字典管理类型管理项管理Excel导入导出日志管理操作日志系统日志ES存储检索任务管理定时任务配置任务执行监控系统监控Redis监控MySQL监控ES监控文件管理上传下载S3存储生命周期管理参数管理系统参数配置风控管理IP黑名单URI黑名单代码生成数据源管理多数据源配置连接测试表结构管理数据库同步字段配置代码生成Velocity模板前后端代码代码预览下载在线预览ZIP打包下载公共能力缓存管理Redis缓存缓存枚举AOP日志记录远程调用HTTP服务调用日志处理HTTP请求日志日志总线MQ异步存储消息队列RabbitMQ错误重试机制任务调度异步任务总线动态定时任务限流降级Sentinel集成二、项目结构设计 2.1 整体架构 #mq6disoby53mnb5emq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disoby53mnb5emq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disoby53mnb5emq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disoby53mnb5emq .error-icon{fill:#a44141;}#mq6disoby53mnb5emq .error-text{fill:#ddd;stroke:#ddd;}#mq6disoby53mnb5emq .edge-thickness-normal{stroke-width:1px;}#mq6disoby53mnb5emq .edge-thickness-thick{stroke-width:3.5px;}#mq6disoby53mnb5emq .edge-pattern-solid{stroke-dasharray:0;}#mq6disoby53mnb5emq .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disoby53mnb5emq .edge-pattern-dashed{stroke-dasharray:3;}#mq6disoby53mnb5emq .edge-pattern-dotted{stroke-dasharray:2;}#mq6disoby53mnb5emq .marker{fill:lightgrey;stroke:lightgrey;}#mq6disoby53mnb5emq .marker.cross{stroke:lightgrey;}#mq6disoby53mnb5emq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disoby53mnb5emq p{margin:0;}#mq6disoby53mnb5emq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disoby53mnb5emq .cluster-label text{fill:#F9FFFE;}#mq6disoby53mnb5emq .cluster-label span{color:#F9FFFE;}#mq6disoby53mnb5emq .cluster-label span p{background-color:transparent;}#mq6disoby53mnb5emq .label text,#mq6disoby53mnb5emq span{fill:#ccc;color:#ccc;}#mq6disoby53mnb5emq .node rect,#mq6disoby53mnb5emq .node circle,#mq6disoby53mnb5emq .node ellipse,#mq6disoby53mnb5emq .node polygon,#mq6disoby53mnb5emq .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disoby53mnb5emq .rough-node .label text,#mq6disoby53mnb5emq .node .label text,#mq6disoby53mnb5emq .image-shape .label,#mq6disoby53mnb5emq .icon-shape .label{text-anchor:middle;}#mq6disoby53mnb5emq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disoby53mnb5emq .rough-node .label,#mq6disoby53mnb5emq .node .label,#mq6disoby53mnb5emq .image-shape .label,#mq6disoby53mnb5emq .icon-shape .label{text-align:center;}#mq6disoby53mnb5emq .node.clickable{cursor:pointer;}#mq6disoby53mnb5emq .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disoby53mnb5emq .arrowheadPath{fill:lightgrey;}#mq6disoby53mnb5emq .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disoby53mnb5emq .flowchart-link{stroke:lightgrey;fill:none;}#mq6disoby53mnb5emq .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disoby53mnb5emq .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disoby53mnb5emq .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disoby53mnb5emq .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disoby53mnb5emq .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disoby53mnb5emq .cluster text{fill:#F9FFFE;}#mq6disoby53mnb5emq .cluster span{color:#F9FFFE;}#mq6disoby53mnb5emq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disoby53mnb5emq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disoby53mnb5emq rect.text{fill:none;stroke-width:0;}#mq6disoby53mnb5emq .icon-shape,#mq6disoby53mnb5emq .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disoby53mnb5emq .icon-shape p,#mq6disoby53mnb5emq .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disoby53mnb5emq .icon-shape rect,#mq6disoby53mnb5emq .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disoby53mnb5emq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disoby53mnb5emq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disoby53mnb5emq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}聚合聚合聚合聚合xtools-app父模块 v1.0.0xtools-app-common公共模块xtools-app-sys系统管理模块xtools-app-gen代码生成模块xtools-app-monitor监控模块xtools-app-standalone独立部署模块common-cache缓存模块common-call远程调用模块common-config通用配置common-jarJAR管理模块common-job任务模块common-log日志模块common-mq消息队列模块common-sentinel限流降级模块common-task异步任务模块common-log-bus日志总线common-log-filter日志过滤器sys-api系统API接口sys-auth认证授权sys-biz系统业务逻辑sys-boot系统启动模块sys-call系统远程调用sys-file文件管理sys-file-web文件Web接口sys-log-bus-elasticsearchES日志存储sys-param参数管理sys-risk风控管理sys-scheduled定时任务sys-tag标签管理gen-biz代码生成业务gen-boot代码生成启动monitor-boot监控服务端monitor-client监控客户端monitor-health健康检查2.2 分层架构 #mq6disob27tb9nfnb3k{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disob27tb9nfnb3k .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disob27tb9nfnb3k .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disob27tb9nfnb3k .error-icon{fill:#a44141;}#mq6disob27tb9nfnb3k .error-text{fill:#ddd;stroke:#ddd;}#mq6disob27tb9nfnb3k .edge-thickness-normal{stroke-width:1px;}#mq6disob27tb9nfnb3k .edge-thickness-thick{stroke-width:3.5px;}#mq6disob27tb9nfnb3k .edge-pattern-solid{stroke-dasharray:0;}#mq6disob27tb9nfnb3k .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disob27tb9nfnb3k .edge-pattern-dashed{stroke-dasharray:3;}#mq6disob27tb9nfnb3k .edge-pattern-dotted{stroke-dasharray:2;}#mq6disob27tb9nfnb3k .marker{fill:lightgrey;stroke:lightgrey;}#mq6disob27tb9nfnb3k .marker.cross{stroke:lightgrey;}#mq6disob27tb9nfnb3k svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disob27tb9nfnb3k p{margin:0;}#mq6disob27tb9nfnb3k .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disob27tb9nfnb3k .cluster-label text{fill:#F9FFFE;}#mq6disob27tb9nfnb3k .cluster-label span{color:#F9FFFE;}#mq6disob27tb9nfnb3k .cluster-label span p{background-color:transparent;}#mq6disob27tb9nfnb3k .label text,#mq6disob27tb9nfnb3k span{fill:#ccc;color:#ccc;}#mq6disob27tb9nfnb3k .node rect,#mq6disob27tb9nfnb3k .node circle,#mq6disob27tb9nfnb3k .node ellipse,#mq6disob27tb9nfnb3k .node polygon,#mq6disob27tb9nfnb3k .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disob27tb9nfnb3k .rough-node .label text,#mq6disob27tb9nfnb3k .node .label text,#mq6disob27tb9nfnb3k .image-shape .label,#mq6disob27tb9nfnb3k .icon-shape .label{text-anchor:middle;}#mq6disob27tb9nfnb3k .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disob27tb9nfnb3k .rough-node .label,#mq6disob27tb9nfnb3k .node .label,#mq6disob27tb9nfnb3k .image-shape .label,#mq6disob27tb9nfnb3k .icon-shape .label{text-align:center;}#mq6disob27tb9nfnb3k .node.clickable{cursor:pointer;}#mq6disob27tb9nfnb3k .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disob27tb9nfnb3k .arrowheadPath{fill:lightgrey;}#mq6disob27tb9nfnb3k .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disob27tb9nfnb3k .flowchart-link{stroke:lightgrey;fill:none;}#mq6disob27tb9nfnb3k .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob27tb9nfnb3k .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disob27tb9nfnb3k .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob27tb9nfnb3k .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disob27tb9nfnb3k .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disob27tb9nfnb3k .cluster text{fill:#F9FFFE;}#mq6disob27tb9nfnb3k .cluster span{color:#F9FFFE;}#mq6disob27tb9nfnb3k div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disob27tb9nfnb3k .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disob27tb9nfnb3k rect.text{fill:none;stroke-width:0;}#mq6disob27tb9nfnb3k .icon-shape,#mq6disob27tb9nfnb3k .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob27tb9nfnb3k .icon-shape p,#mq6disob27tb9nfnb3k .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disob27tb9nfnb3k .icon-shape rect,#mq6disob27tb9nfnb3k .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob27tb9nfnb3k .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disob27tb9nfnb3k .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disob27tb9nfnb3k :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}基础设施层Mapper层Service层Controller层过滤器层异步异步存储HttpLogFilter请求响应日志Order: 200AuthFilter认证授权Order: 201接收HTTP请求参数验证 @Valid调用Service层返回统一响应 Result实现业务逻辑事务控制调用Mapper层对象转换 Convert缓存操作 Cache数据库访问SQL执行结果映射Redis缓存RabbitMQ消息ElasticsearchS3文件存储MySQL数据库2.3 模块职责 层级 职责 说明 过滤器层 请求拦截 HttpLogFilter 记录请求响应日志,AuthFilter 验证认证授权 Controller层 接口暴露 接收请求、参数验证、调用Service、返回统一Result响应 Service层 业务逻辑 事务控制、业务验证、调用Mapper、对象转换 Service Base层 基础CRUD 封装通用增删改查,减少重复代码 Mapper层 数据访问 MyBatis-Plus Mapper,数据库操作 Entity层 实体对象 数据库表映射实体 DTO层 数据传输 请求DTO(req)、响应DTO(resp)、Excel DTO Convert层 对象转换 MapStruct 转换器,Entity <-> DTO Config层 配置管理 模块配置、白名单、初始化 MQ层 消息处理 RabbitMQ 消息消费者 Job层 定时任务 BaseJob 定时任务实现 Utils层 工具方法 密码加密、数据源工具等 AOP层 切面增强 Redis操作日志、存储操作日志 2.4 包结构设计 复制代码 xtools.app.{module} ├── controller # 控制器 ├── service # 服务接口 │ ├── base # 基础CRUD服务接口 │ └── impl # 服务实现 ├── mapper # MyBatis Mapper ├── model │ ├── entity # 实体类 │ ├── dto │ │ ├── req # 请求DTO(AddReq, UpdateReq, PageReq) │ │ ├── resp # 响应DTO │ │ └── excel # Excel导入导出DTO │ └── vo # 视图对象 ├── convert # MapStruct 对象转换器 ├── config # 模块配置 ├── utils # 工具类 ├── mq # RabbitMQ 消息消费者 ├── job # 定时任务 ├── enums # 枚举类 ├── init # 初始化(ApplicationRunner) └── aop # AOP切面 2.5 系统边界视图 #mq6disob13pvp6w4wy7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disob13pvp6w4wy7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disob13pvp6w4wy7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disob13pvp6w4wy7 .error-icon{fill:#a44141;}#mq6disob13pvp6w4wy7 .error-text{fill:#ddd;stroke:#ddd;}#mq6disob13pvp6w4wy7 .edge-thickness-normal{stroke-width:1px;}#mq6disob13pvp6w4wy7 .edge-thickness-thick{stroke-width:3.5px;}#mq6disob13pvp6w4wy7 .edge-pattern-solid{stroke-dasharray:0;}#mq6disob13pvp6w4wy7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disob13pvp6w4wy7 .edge-pattern-dashed{stroke-dasharray:3;}#mq6disob13pvp6w4wy7 .edge-pattern-dotted{stroke-dasharray:2;}#mq6disob13pvp6w4wy7 .marker{fill:lightgrey;stroke:lightgrey;}#mq6disob13pvp6w4wy7 .marker.cross{stroke:lightgrey;}#mq6disob13pvp6w4wy7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disob13pvp6w4wy7 p{margin:0;}#mq6disob13pvp6w4wy7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disob13pvp6w4wy7 .cluster-label text{fill:#F9FFFE;}#mq6disob13pvp6w4wy7 .cluster-label span{color:#F9FFFE;}#mq6disob13pvp6w4wy7 .cluster-label span p{background-color:transparent;}#mq6disob13pvp6w4wy7 .label text,#mq6disob13pvp6w4wy7 span{fill:#ccc;color:#ccc;}#mq6disob13pvp6w4wy7 .node rect,#mq6disob13pvp6w4wy7 .node circle,#mq6disob13pvp6w4wy7 .node ellipse,#mq6disob13pvp6w4wy7 .node polygon,#mq6disob13pvp6w4wy7 .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disob13pvp6w4wy7 .rough-node .label text,#mq6disob13pvp6w4wy7 .node .label text,#mq6disob13pvp6w4wy7 .image-shape .label,#mq6disob13pvp6w4wy7 .icon-shape .label{text-anchor:middle;}#mq6disob13pvp6w4wy7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disob13pvp6w4wy7 .rough-node .label,#mq6disob13pvp6w4wy7 .node .label,#mq6disob13pvp6w4wy7 .image-shape .label,#mq6disob13pvp6w4wy7 .icon-shape .label{text-align:center;}#mq6disob13pvp6w4wy7 .node.clickable{cursor:pointer;}#mq6disob13pvp6w4wy7 .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disob13pvp6w4wy7 .arrowheadPath{fill:lightgrey;}#mq6disob13pvp6w4wy7 .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disob13pvp6w4wy7 .flowchart-link{stroke:lightgrey;fill:none;}#mq6disob13pvp6w4wy7 .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob13pvp6w4wy7 .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disob13pvp6w4wy7 .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob13pvp6w4wy7 .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disob13pvp6w4wy7 .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disob13pvp6w4wy7 .cluster text{fill:#F9FFFE;}#mq6disob13pvp6w4wy7 .cluster span{color:#F9FFFE;}#mq6disob13pvp6w4wy7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disob13pvp6w4wy7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disob13pvp6w4wy7 rect.text{fill:none;stroke-width:0;}#mq6disob13pvp6w4wy7 .icon-shape,#mq6disob13pvp6w4wy7 .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob13pvp6w4wy7 .icon-shape p,#mq6disob13pvp6w4wy7 .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disob13pvp6w4wy7 .icon-shape rect,#mq6disob13pvp6w4wy7 .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob13pvp6w4wy7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disob13pvp6w4wy7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disob13pvp6w4wy7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}数据层公共模块层业务模块层应用层用户层Web前端xtools-app-standalone独立部署应用SysApplication系统管理应用GenApplication代码生成应用MonitorApplication监控服务应用sys-biz系统业务gen-biz代码生成业务sys-scheduled动态定时任务sys-log-bus-elasticsearchES日志存储common-cachecommon-callcommon-jarcommon-log-buscommon-log-filtercommon-mqcommon-sentinelcommon-taskcommon-configMySQLRedisElasticsearchRabbitMQS3存储三、项目功能设计 3.1 认证授权设计 3.1.1 登录认证流程 #mq6disobw2d1e48pd88{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobw2d1e48pd88 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobw2d1e48pd88 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobw2d1e48pd88 .error-icon{fill:#a44141;}#mq6disobw2d1e48pd88 .error-text{fill:#ddd;stroke:#ddd;}#mq6disobw2d1e48pd88 .edge-thickness-normal{stroke-width:1px;}#mq6disobw2d1e48pd88 .edge-thickness-thick{stroke-width:3.5px;}#mq6disobw2d1e48pd88 .edge-pattern-solid{stroke-dasharray:0;}#mq6disobw2d1e48pd88 .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobw2d1e48pd88 .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobw2d1e48pd88 .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobw2d1e48pd88 .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobw2d1e48pd88 .marker.cross{stroke:lightgrey;}#mq6disobw2d1e48pd88 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobw2d1e48pd88 p{margin:0;}#mq6disobw2d1e48pd88 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobw2d1e48pd88 .cluster-label text{fill:#F9FFFE;}#mq6disobw2d1e48pd88 .cluster-label span{color:#F9FFFE;}#mq6disobw2d1e48pd88 .cluster-label span p{background-color:transparent;}#mq6disobw2d1e48pd88 .label text,#mq6disobw2d1e48pd88 span{fill:#ccc;color:#ccc;}#mq6disobw2d1e48pd88 .node rect,#mq6disobw2d1e48pd88 .node circle,#mq6disobw2d1e48pd88 .node ellipse,#mq6disobw2d1e48pd88 .node polygon,#mq6disobw2d1e48pd88 .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobw2d1e48pd88 .rough-node .label text,#mq6disobw2d1e48pd88 .node .label text,#mq6disobw2d1e48pd88 .image-shape .label,#mq6disobw2d1e48pd88 .icon-shape .label{text-anchor:middle;}#mq6disobw2d1e48pd88 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobw2d1e48pd88 .rough-node .label,#mq6disobw2d1e48pd88 .node .label,#mq6disobw2d1e48pd88 .image-shape .label,#mq6disobw2d1e48pd88 .icon-shape .label{text-align:center;}#mq6disobw2d1e48pd88 .node.clickable{cursor:pointer;}#mq6disobw2d1e48pd88 .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobw2d1e48pd88 .arrowheadPath{fill:lightgrey;}#mq6disobw2d1e48pd88 .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobw2d1e48pd88 .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobw2d1e48pd88 .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobw2d1e48pd88 .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobw2d1e48pd88 .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobw2d1e48pd88 .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobw2d1e48pd88 .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobw2d1e48pd88 .cluster text{fill:#F9FFFE;}#mq6disobw2d1e48pd88 .cluster span{color:#F9FFFE;}#mq6disobw2d1e48pd88 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobw2d1e48pd88 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobw2d1e48pd88 rect.text{fill:none;stroke-width:0;}#mq6disobw2d1e48pd88 .icon-shape,#mq6disobw2d1e48pd88 .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobw2d1e48pd88 .icon-shape p,#mq6disobw2d1e48pd88 .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobw2d1e48pd88 .icon-shape rect,#mq6disobw2d1e48pd88 .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobw2d1e48pd88 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobw2d1e48pd88 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobw2d1e48pd88 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}验证失败验证成功用户不存在用户存在已锁定已过期正常密码错误是否密码正确用户请求登录前端获取验证码GET /sys/login/captcha前端获取SM2公钥POST /sys/login/public-key用户输入账号密码使用SM2公钥加密提交登录请求POST /sys/login/passwd验证验证码Redis: UID_CAPTCHA返回验证码错误SM2解密密码验证公钥匹配查询用户信息返回用户不存在检查账号状态锁定/过期返回账号已锁定返回账号已过期验证密码SM3加密比对记录错误次数Redis计数器错误次数超限?锁定账号Redis: LOCK_SYS_USER返回密码错误清除错误计数生成TokenUUID accessToken + refreshToken缓存登录用户Redis: AUTH_SYS_USER返回Token信息3.1.2 Token管理机制 Token 基于 UUID 生成,存储在 Redis 中,包含四种键类型: Redis Key 说明 TTL accessToken:{uuid} Token -> 登录用户映射 60分钟 refreshToken:{uuid} 刷新Token -> AccessToken映射 60分钟 user:{userId} 用户 -> Token映射(单设备登录) 60分钟 mask:{userId} 数据脱敏忽略标记 按配置 Token 刷新流程:客户端使用 refreshToken 请求 GET /sys/login/refresh/{refreshToken},后端查找对应的 accessToken,获取登录用户信息,生成新的 Token 对。 3.1.3 授权设计(RBAC模型) #mq6disob5ogni39ranu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disob5ogni39ranu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disob5ogni39ranu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disob5ogni39ranu .error-icon{fill:#a44141;}#mq6disob5ogni39ranu .error-text{fill:#ddd;stroke:#ddd;}#mq6disob5ogni39ranu .edge-thickness-normal{stroke-width:1px;}#mq6disob5ogni39ranu .edge-thickness-thick{stroke-width:3.5px;}#mq6disob5ogni39ranu .edge-pattern-solid{stroke-dasharray:0;}#mq6disob5ogni39ranu .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disob5ogni39ranu .edge-pattern-dashed{stroke-dasharray:3;}#mq6disob5ogni39ranu .edge-pattern-dotted{stroke-dasharray:2;}#mq6disob5ogni39ranu .marker{fill:lightgrey;stroke:lightgrey;}#mq6disob5ogni39ranu .marker.cross{stroke:lightgrey;}#mq6disob5ogni39ranu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disob5ogni39ranu p{margin:0;}#mq6disob5ogni39ranu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disob5ogni39ranu .cluster-label text{fill:#F9FFFE;}#mq6disob5ogni39ranu .cluster-label span{color:#F9FFFE;}#mq6disob5ogni39ranu .cluster-label span p{background-color:transparent;}#mq6disob5ogni39ranu .label text,#mq6disob5ogni39ranu span{fill:#ccc;color:#ccc;}#mq6disob5ogni39ranu .node rect,#mq6disob5ogni39ranu .node circle,#mq6disob5ogni39ranu .node ellipse,#mq6disob5ogni39ranu .node polygon,#mq6disob5ogni39ranu .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disob5ogni39ranu .rough-node .label text,#mq6disob5ogni39ranu .node .label text,#mq6disob5ogni39ranu .image-shape .label,#mq6disob5ogni39ranu .icon-shape .label{text-anchor:middle;}#mq6disob5ogni39ranu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disob5ogni39ranu .rough-node .label,#mq6disob5ogni39ranu .node .label,#mq6disob5ogni39ranu .image-shape .label,#mq6disob5ogni39ranu .icon-shape .label{text-align:center;}#mq6disob5ogni39ranu .node.clickable{cursor:pointer;}#mq6disob5ogni39ranu .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disob5ogni39ranu .arrowheadPath{fill:lightgrey;}#mq6disob5ogni39ranu .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disob5ogni39ranu .flowchart-link{stroke:lightgrey;fill:none;}#mq6disob5ogni39ranu .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob5ogni39ranu .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disob5ogni39ranu .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob5ogni39ranu .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disob5ogni39ranu .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disob5ogni39ranu .cluster text{fill:#F9FFFE;}#mq6disob5ogni39ranu .cluster span{color:#F9FFFE;}#mq6disob5ogni39ranu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disob5ogni39ranu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disob5ogni39ranu rect.text{fill:none;stroke-width:0;}#mq6disob5ogni39ranu .icon-shape,#mq6disob5ogni39ranu .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob5ogni39ranu .icon-shape p,#mq6disob5ogni39ranu .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disob5ogni39ranu .icon-shape rect,#mq6disob5ogni39ranu .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob5ogni39ranu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disob5ogni39ranu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disob5ogni39ranu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}多对多多对多多对多多对多包含拥有匹配key: 模块:方法value: 角色ID列表用户 SysUser用户角色关联SysUserRole角色 SysRole角色菜单关联SysRoleMenu菜单 SysMenu接口权限SysInterfacePerm角色ID列表roleIds权限缓存Redis Hash权限验证3.1.4 权限验证流程 #mq6disobedavs1jgrrw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobedavs1jgrrw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobedavs1jgrrw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobedavs1jgrrw .error-icon{fill:#a44141;}#mq6disobedavs1jgrrw .error-text{fill:#ddd;stroke:#ddd;}#mq6disobedavs1jgrrw .edge-thickness-normal{stroke-width:1px;}#mq6disobedavs1jgrrw .edge-thickness-thick{stroke-width:3.5px;}#mq6disobedavs1jgrrw .edge-pattern-solid{stroke-dasharray:0;}#mq6disobedavs1jgrrw .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobedavs1jgrrw .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobedavs1jgrrw .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobedavs1jgrrw .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobedavs1jgrrw .marker.cross{stroke:lightgrey;}#mq6disobedavs1jgrrw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobedavs1jgrrw p{margin:0;}#mq6disobedavs1jgrrw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobedavs1jgrrw .cluster-label text{fill:#F9FFFE;}#mq6disobedavs1jgrrw .cluster-label span{color:#F9FFFE;}#mq6disobedavs1jgrrw .cluster-label span p{background-color:transparent;}#mq6disobedavs1jgrrw .label text,#mq6disobedavs1jgrrw span{fill:#ccc;color:#ccc;}#mq6disobedavs1jgrrw .node rect,#mq6disobedavs1jgrrw .node circle,#mq6disobedavs1jgrrw .node ellipse,#mq6disobedavs1jgrrw .node polygon,#mq6disobedavs1jgrrw .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobedavs1jgrrw .rough-node .label text,#mq6disobedavs1jgrrw .node .label text,#mq6disobedavs1jgrrw .image-shape .label,#mq6disobedavs1jgrrw .icon-shape .label{text-anchor:middle;}#mq6disobedavs1jgrrw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobedavs1jgrrw .rough-node .label,#mq6disobedavs1jgrrw .node .label,#mq6disobedavs1jgrrw .image-shape .label,#mq6disobedavs1jgrrw .icon-shape .label{text-align:center;}#mq6disobedavs1jgrrw .node.clickable{cursor:pointer;}#mq6disobedavs1jgrrw .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobedavs1jgrrw .arrowheadPath{fill:lightgrey;}#mq6disobedavs1jgrrw .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobedavs1jgrrw .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobedavs1jgrrw .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobedavs1jgrrw .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobedavs1jgrrw .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobedavs1jgrrw .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobedavs1jgrrw .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobedavs1jgrrw .cluster text{fill:#F9FFFE;}#mq6disobedavs1jgrrw .cluster span{color:#F9FFFE;}#mq6disobedavs1jgrrw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobedavs1jgrrw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobedavs1jgrrw rect.text{fill:none;stroke-width:0;}#mq6disobedavs1jgrrw .icon-shape,#mq6disobedavs1jgrrw .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobedavs1jgrrw .icon-shape p,#mq6disobedavs1jgrrw .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobedavs1jgrrw .icon-shape rect,#mq6disobedavs1jgrrw .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobedavs1jgrrw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobedavs1jgrrw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobedavs1jgrrw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}是否是否无效有效使用AntPathMatcher是否用户发起接口请求AuthFilter拦截请求是否在认证白名单?跳过认证是否在登录白名单?仅验证登录状态验证AccessTokenToken有效?返回未授权获取LoginUserDtoPremUtils.checkInterfacePerm从URI提取模块名如 /sys/user -> sys/user查询Redis权限缓存key: sys/user:GET匹配权限规则?获取允许的角色ID列表用户角色ID在允许列表中?放行请求返回权限不足存储用户上下文到CommonHolder3.1.5 权限缓存初始化 系统启动时 InitSys(ApplicationRunner, Order: 200)执行权限缓存加载: 查询所有 SysInterfacePerm 记录 按 模块名:HTTP方法 分组 以 JSON 字符串存入 Redis Hash(key: AUTH_SYS_URI) 使用 ScopedValue 传递日志追踪上下文 3.2 日志管理设计 3.2.1 日志类型 日志类型 说明 存储方式 HTTP请求日志 请求URI、方法、参数、IP、Header RabbitMQ异步 HTTP响应日志 响应状态码、Header、Body、耗时 RabbitMQ异步 操作日志 用户操作记录、权限验证记录 MySQL + RabbitMQ 系统日志 各类系统事件 MySQL / Elasticsearch Redis操作日志 缓存操作记录 LogBus异步 存储操作日志 文件存储操作记录 LogBus异步 任务日志 定时任务执行记录 MySQL 3.2.2 日志处理流程 #mq6disobwxp0hy3uzu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobwxp0hy3uzu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobwxp0hy3uzu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobwxp0hy3uzu .error-icon{fill:#a44141;}#mq6disobwxp0hy3uzu .error-text{fill:#ddd;stroke:#ddd;}#mq6disobwxp0hy3uzu .edge-thickness-normal{stroke-width:1px;}#mq6disobwxp0hy3uzu .edge-thickness-thick{stroke-width:3.5px;}#mq6disobwxp0hy3uzu .edge-pattern-solid{stroke-dasharray:0;}#mq6disobwxp0hy3uzu .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobwxp0hy3uzu .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobwxp0hy3uzu .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobwxp0hy3uzu .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobwxp0hy3uzu .marker.cross{stroke:lightgrey;}#mq6disobwxp0hy3uzu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobwxp0hy3uzu p{margin:0;}#mq6disobwxp0hy3uzu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobwxp0hy3uzu .cluster-label text{fill:#F9FFFE;}#mq6disobwxp0hy3uzu .cluster-label span{color:#F9FFFE;}#mq6disobwxp0hy3uzu .cluster-label span p{background-color:transparent;}#mq6disobwxp0hy3uzu .label text,#mq6disobwxp0hy3uzu span{fill:#ccc;color:#ccc;}#mq6disobwxp0hy3uzu .node rect,#mq6disobwxp0hy3uzu .node circle,#mq6disobwxp0hy3uzu .node ellipse,#mq6disobwxp0hy3uzu .node polygon,#mq6disobwxp0hy3uzu .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobwxp0hy3uzu .rough-node .label text,#mq6disobwxp0hy3uzu .node .label text,#mq6disobwxp0hy3uzu .image-shape .label,#mq6disobwxp0hy3uzu .icon-shape .label{text-anchor:middle;}#mq6disobwxp0hy3uzu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobwxp0hy3uzu .rough-node .label,#mq6disobwxp0hy3uzu .node .label,#mq6disobwxp0hy3uzu .image-shape .label,#mq6disobwxp0hy3uzu .icon-shape .label{text-align:center;}#mq6disobwxp0hy3uzu .node.clickable{cursor:pointer;}#mq6disobwxp0hy3uzu .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobwxp0hy3uzu .arrowheadPath{fill:lightgrey;}#mq6disobwxp0hy3uzu .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobwxp0hy3uzu .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobwxp0hy3uzu .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobwxp0hy3uzu .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobwxp0hy3uzu .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobwxp0hy3uzu .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobwxp0hy3uzu .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobwxp0hy3uzu .cluster text{fill:#F9FFFE;}#mq6disobwxp0hy3uzu .cluster span{color:#F9FFFE;}#mq6disobwxp0hy3uzu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobwxp0hy3uzu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobwxp0hy3uzu rect.text{fill:none;stroke-width:0;}#mq6disobwxp0hy3uzu .icon-shape,#mq6disobwxp0hy3uzu .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobwxp0hy3uzu .icon-shape p,#mq6disobwxp0hy3uzu .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobwxp0hy3uzu .icon-shape rect,#mq6disobwxp0hy3uzu .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobwxp0hy3uzu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobwxp0hy3uzu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobwxp0hy3uzu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}存在不存在是否HTTP请求HttpLogFilterOrder: 200包装Request/ResponseContentCachingWrapperAuthFilterOrder: 201业务处理LogBus记录操作日志OPT_LOG本地LogBusService?直接写入数据库发布到MQRabbitMqEnums.SYS_LOGSysLogMq消费者并发5-10LogBusService.saveLog异步记录HTTP日志VirtualThreadLogBusService存在?3.2.3 Elasticsearch日志存储 当配置 sys.log.type=elasticsearch 时,EsSysLogServiceImpl(标记 @Primary)替代默认的 SysLogServiceImpl: 使用 Spring Data Elasticsearch Repository 存储日志 支持分页查询:match_phrase(精确匹配)、wildcard(模糊匹配)、时间范围过滤 支持链路追踪查询:按 logIndex 和 logTime 排序,最多查询 10,000 条 支持按时间范围批量删除:_delete_by_query 3.3 代码生成设计 3.3.1 代码生成流程 #mq6disob9ceb2rfpajo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disob9ceb2rfpajo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disob9ceb2rfpajo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disob9ceb2rfpajo .error-icon{fill:#a44141;}#mq6disob9ceb2rfpajo .error-text{fill:#ddd;stroke:#ddd;}#mq6disob9ceb2rfpajo .edge-thickness-normal{stroke-width:1px;}#mq6disob9ceb2rfpajo .edge-thickness-thick{stroke-width:3.5px;}#mq6disob9ceb2rfpajo .edge-pattern-solid{stroke-dasharray:0;}#mq6disob9ceb2rfpajo .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disob9ceb2rfpajo .edge-pattern-dashed{stroke-dasharray:3;}#mq6disob9ceb2rfpajo .edge-pattern-dotted{stroke-dasharray:2;}#mq6disob9ceb2rfpajo .marker{fill:lightgrey;stroke:lightgrey;}#mq6disob9ceb2rfpajo .marker.cross{stroke:lightgrey;}#mq6disob9ceb2rfpajo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disob9ceb2rfpajo p{margin:0;}#mq6disob9ceb2rfpajo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disob9ceb2rfpajo .cluster-label text{fill:#F9FFFE;}#mq6disob9ceb2rfpajo .cluster-label span{color:#F9FFFE;}#mq6disob9ceb2rfpajo .cluster-label span p{background-color:transparent;}#mq6disob9ceb2rfpajo .label text,#mq6disob9ceb2rfpajo span{fill:#ccc;color:#ccc;}#mq6disob9ceb2rfpajo .node rect,#mq6disob9ceb2rfpajo .node circle,#mq6disob9ceb2rfpajo .node ellipse,#mq6disob9ceb2rfpajo .node polygon,#mq6disob9ceb2rfpajo .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disob9ceb2rfpajo .rough-node .label text,#mq6disob9ceb2rfpajo .node .label text,#mq6disob9ceb2rfpajo .image-shape .label,#mq6disob9ceb2rfpajo .icon-shape .label{text-anchor:middle;}#mq6disob9ceb2rfpajo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disob9ceb2rfpajo .rough-node .label,#mq6disob9ceb2rfpajo .node .label,#mq6disob9ceb2rfpajo .image-shape .label,#mq6disob9ceb2rfpajo .icon-shape .label{text-align:center;}#mq6disob9ceb2rfpajo .node.clickable{cursor:pointer;}#mq6disob9ceb2rfpajo .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disob9ceb2rfpajo .arrowheadPath{fill:lightgrey;}#mq6disob9ceb2rfpajo .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disob9ceb2rfpajo .flowchart-link{stroke:lightgrey;fill:none;}#mq6disob9ceb2rfpajo .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob9ceb2rfpajo .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disob9ceb2rfpajo .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob9ceb2rfpajo .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disob9ceb2rfpajo .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disob9ceb2rfpajo .cluster text{fill:#F9FFFE;}#mq6disob9ceb2rfpajo .cluster span{color:#F9FFFE;}#mq6disob9ceb2rfpajo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disob9ceb2rfpajo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disob9ceb2rfpajo rect.text{fill:none;stroke-width:0;}#mq6disob9ceb2rfpajo .icon-shape,#mq6disob9ceb2rfpajo .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disob9ceb2rfpajo .icon-shape p,#mq6disob9ceb2rfpajo .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disob9ceb2rfpajo .icon-shape rect,#mq6disob9ceb2rfpajo .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disob9ceb2rfpajo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disob9ceb2rfpajo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disob9ceb2rfpajo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}在线预览打包下载直接生成配置数据源同步数据库表结构syncDbJDBC连接外部数据库DatabaseMetaData读取所有表getTables保存到gen_table读取表字段getColumns + getPrimaryKeys保存到gen_table_column配置生成参数模板选择 、包名 、模块名生成方式previewCodeVelocity渲染模板downloadCodeZIP打包genCode写入项目目录返回代码内容Map生成ZIP文件包含前后端代码3.3.2 模板引擎配置 使用 Apache Velocity 2.4.1 模板引擎 模板从 classpath 加载,UTF-8 编码 通过 GenProperties 配置后端/前端应用名、模块名、作者、版本等参数 支持过滤字段(正则匹配字段注释) 支持排除表(配置不生成的表名) 3.3.3 生成代码结构 复制代码 {backendAppName}/{moduleName}/{moduleName}-biz/src/main/java/{packageName}/{subPackageName}/ ├── controller/ # Controller类 ├── service/ # Service接口 │ ├── base/ # 基础CRUD │ └── impl/ # Service实现 ├── mapper/ # Mapper接口 ├── model/ │ ├── entity/ # 实体类 │ └── dto/ │ ├── req/ # 请求DTO │ └── resp/ # 响应DTO ├── convert/ # MapStruct转换器 └── utils/ # 工具类 {frontendAppName}/src/{subPackageName}/{subModuleName}/ ├── index.ts # API接口 └── {tableName}/index.vue # Vue页面 sql/ # SQL脚本 3.4 任务调度设计 3.4.1 任务类型 任务类型 说明 实现类 DEL_SYS_LOG 清理过期系统日志 SysLogJob DEL_SYS_FILE 清理过期文件 SysFileJob DEL_DISABLE_SYS_USER 清理禁用用户 SysUserJob 自定义任务 动态定时任务 SysScheduledService 3.4.2 定时任务实现 #mq6disobe13ipezkn9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobe13ipezkn9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobe13ipezkn9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobe13ipezkn9 .error-icon{fill:#a44141;}#mq6disobe13ipezkn9 .error-text{fill:#ddd;stroke:#ddd;}#mq6disobe13ipezkn9 .edge-thickness-normal{stroke-width:1px;}#mq6disobe13ipezkn9 .edge-thickness-thick{stroke-width:3.5px;}#mq6disobe13ipezkn9 .edge-pattern-solid{stroke-dasharray:0;}#mq6disobe13ipezkn9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobe13ipezkn9 .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobe13ipezkn9 .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobe13ipezkn9 .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobe13ipezkn9 .marker.cross{stroke:lightgrey;}#mq6disobe13ipezkn9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobe13ipezkn9 p{margin:0;}#mq6disobe13ipezkn9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobe13ipezkn9 .cluster-label text{fill:#F9FFFE;}#mq6disobe13ipezkn9 .cluster-label span{color:#F9FFFE;}#mq6disobe13ipezkn9 .cluster-label span p{background-color:transparent;}#mq6disobe13ipezkn9 .label text,#mq6disobe13ipezkn9 span{fill:#ccc;color:#ccc;}#mq6disobe13ipezkn9 .node rect,#mq6disobe13ipezkn9 .node circle,#mq6disobe13ipezkn9 .node ellipse,#mq6disobe13ipezkn9 .node polygon,#mq6disobe13ipezkn9 .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobe13ipezkn9 .rough-node .label text,#mq6disobe13ipezkn9 .node .label text,#mq6disobe13ipezkn9 .image-shape .label,#mq6disobe13ipezkn9 .icon-shape .label{text-anchor:middle;}#mq6disobe13ipezkn9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobe13ipezkn9 .rough-node .label,#mq6disobe13ipezkn9 .node .label,#mq6disobe13ipezkn9 .image-shape .label,#mq6disobe13ipezkn9 .icon-shape .label{text-align:center;}#mq6disobe13ipezkn9 .node.clickable{cursor:pointer;}#mq6disobe13ipezkn9 .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobe13ipezkn9 .arrowheadPath{fill:lightgrey;}#mq6disobe13ipezkn9 .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobe13ipezkn9 .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobe13ipezkn9 .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobe13ipezkn9 .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobe13ipezkn9 .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobe13ipezkn9 .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobe13ipezkn9 .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobe13ipezkn9 .cluster text{fill:#F9FFFE;}#mq6disobe13ipezkn9 .cluster span{color:#F9FFFE;}#mq6disobe13ipezkn9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobe13ipezkn9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobe13ipezkn9 rect.text{fill:none;stroke-width:0;}#mq6disobe13ipezkn9 .icon-shape,#mq6disobe13ipezkn9 .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobe13ipezkn9 .icon-shape p,#mq6disobe13ipezkn9 .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobe13ipezkn9 .icon-shape rect,#mq6disobe13ipezkn9 .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobe13ipezkn9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobe13ipezkn9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobe13ipezkn9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}成功失败任务执行BaseJob.runJobTaskBus.init设置任务状态ING执行任务逻辑执行成功?TaskBus.save状态: SUCCESSTaskBus.error状态: ERRORTaskBus -> RabbitMQ队列: sys.taskSysTaskMq消费者并发5-10SysTaskService.save写入任务记录3.4.3 动态定时任务 SysScheduledService 提供动态定时任务管理: init():启动时从数据库加载所有启用的定时任务 start():启动指定任务(创建 ScheduledTask 注册到 Spring TaskScheduler) stop():停止指定任务(取消 ScheduledTask) restart():重启指定任务 run():立即执行一次任务 任务初始化通过 InitSysScheduled(ApplicationRunner, Order: 200)在系统启动时自动完成。 3.5 缓存设计 3.5.1 缓存策略 项目使用 Redis 作为主要缓存介质,所有缓存键和 TTL 通过 AppCache 枚举集中管理: 缓存Key TTL 用途 UID_SM2 5分钟 SM2密钥对(每次登录生成) UID_CAPTCHA 1分钟 验证码 AUTH_SYS_USER 60分钟 登录用户Token AUTH_SYS_URI 永久 URI权限缓存(启动加载) AUTH_CLOUD_TOKEN 1分钟 微服务调用Token(一次性) LOCK_JOB 5分钟 Job分布式锁 LOCK_SYS_USER 按配置 用户锁定(密码错误超限) RISK_IP 永久 IP风控黑名单 RISK_URI 永久 URI风控黑名单 SYS_CACHE_PARAM 永久 系统参数缓存 SYS_CACHE_AP_RULE 永久 密码规则缓存 SYS_CACHE_JAR 永久 JAR依赖缓存 SYS_CACHE_ADDR 60分钟 IP归属地缓存 COUNT_SYS_USER_PASSWD_ERR 永久 密码错误计数 3.5.2 Redis操作日志AOP RedisServiceAop 切面环绕所有 RedisService 方法: 记录方法名、参数、返回值、执行时间 通过 LogBus 发布 REDIS 类型日志 仅在存在 LogTrack 上下文时记录 3.5.3 风控本地缓存 URI风控使用两级缓存架构: 一级缓存:Caffeine 本地缓存(20秒过期) 二级缓存:Redis String 缓存 查询顺序:Caffeine -> Redis 3.6 风控管理设计 #mq6disobkqi8q4u93a{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobkqi8q4u93a .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobkqi8q4u93a .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobkqi8q4u93a .error-icon{fill:#a44141;}#mq6disobkqi8q4u93a .error-text{fill:#ddd;stroke:#ddd;}#mq6disobkqi8q4u93a .edge-thickness-normal{stroke-width:1px;}#mq6disobkqi8q4u93a .edge-thickness-thick{stroke-width:3.5px;}#mq6disobkqi8q4u93a .edge-pattern-solid{stroke-dasharray:0;}#mq6disobkqi8q4u93a .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobkqi8q4u93a .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobkqi8q4u93a .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobkqi8q4u93a .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobkqi8q4u93a .marker.cross{stroke:lightgrey;}#mq6disobkqi8q4u93a svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobkqi8q4u93a p{margin:0;}#mq6disobkqi8q4u93a .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobkqi8q4u93a .cluster-label text{fill:#F9FFFE;}#mq6disobkqi8q4u93a .cluster-label span{color:#F9FFFE;}#mq6disobkqi8q4u93a .cluster-label span p{background-color:transparent;}#mq6disobkqi8q4u93a .label text,#mq6disobkqi8q4u93a span{fill:#ccc;color:#ccc;}#mq6disobkqi8q4u93a .node rect,#mq6disobkqi8q4u93a .node circle,#mq6disobkqi8q4u93a .node ellipse,#mq6disobkqi8q4u93a .node polygon,#mq6disobkqi8q4u93a .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobkqi8q4u93a .rough-node .label text,#mq6disobkqi8q4u93a .node .label text,#mq6disobkqi8q4u93a .image-shape .label,#mq6disobkqi8q4u93a .icon-shape .label{text-anchor:middle;}#mq6disobkqi8q4u93a .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobkqi8q4u93a .rough-node .label,#mq6disobkqi8q4u93a .node .label,#mq6disobkqi8q4u93a .image-shape .label,#mq6disobkqi8q4u93a .icon-shape .label{text-align:center;}#mq6disobkqi8q4u93a .node.clickable{cursor:pointer;}#mq6disobkqi8q4u93a .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobkqi8q4u93a .arrowheadPath{fill:lightgrey;}#mq6disobkqi8q4u93a .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobkqi8q4u93a .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobkqi8q4u93a .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobkqi8q4u93a .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobkqi8q4u93a .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobkqi8q4u93a .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobkqi8q4u93a .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobkqi8q4u93a .cluster text{fill:#F9FFFE;}#mq6disobkqi8q4u93a .cluster span{color:#F9FFFE;}#mq6disobkqi8q4u93a div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobkqi8q4u93a .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobkqi8q4u93a rect.text{fill:none;stroke-width:0;}#mq6disobkqi8q4u93a .icon-shape,#mq6disobkqi8q4u93a .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobkqi8q4u93a .icon-shape p,#mq6disobkqi8q4u93a .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobkqi8q4u93a .icon-shape rect,#mq6disobkqi8q4u93a .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobkqi8q4u93a .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobkqi8q4u93a .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobkqi8q4u93a :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}是否命中未命中是否请求到达IpRisk检查Redis Hash: RISK_IPIP在黑名单?拒绝请求UriRisk检查Caffeine缓存?获取URI黑名单列表查询Redis缓存RISK_URI写入Caffeine20秒过期URI包含黑名单字符串?放行请求 IP风控:启动时从数据库加载 IP 黑名单到 Redis Hash,支持动态添加/移除 URI风控:使用 Caffeine + Redis 两级缓存,启动时从数据库加载 URI 黑名单字符串 风控数据来源:SysRisk 实体,按 SysRiskType(IP/URI)分类存储 3.7 文件管理设计 #mq6disobq6yrsh31ada{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobq6yrsh31ada .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobq6yrsh31ada .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobq6yrsh31ada .error-icon{fill:#a44141;}#mq6disobq6yrsh31ada .error-text{fill:#ddd;stroke:#ddd;}#mq6disobq6yrsh31ada .edge-thickness-normal{stroke-width:1px;}#mq6disobq6yrsh31ada .edge-thickness-thick{stroke-width:3.5px;}#mq6disobq6yrsh31ada .edge-pattern-solid{stroke-dasharray:0;}#mq6disobq6yrsh31ada .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobq6yrsh31ada .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobq6yrsh31ada .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobq6yrsh31ada .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobq6yrsh31ada .marker.cross{stroke:lightgrey;}#mq6disobq6yrsh31ada svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobq6yrsh31ada p{margin:0;}#mq6disobq6yrsh31ada .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobq6yrsh31ada .cluster-label text{fill:#F9FFFE;}#mq6disobq6yrsh31ada .cluster-label span{color:#F9FFFE;}#mq6disobq6yrsh31ada .cluster-label span p{background-color:transparent;}#mq6disobq6yrsh31ada .label text,#mq6disobq6yrsh31ada span{fill:#ccc;color:#ccc;}#mq6disobq6yrsh31ada .node rect,#mq6disobq6yrsh31ada .node circle,#mq6disobq6yrsh31ada .node ellipse,#mq6disobq6yrsh31ada .node polygon,#mq6disobq6yrsh31ada .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobq6yrsh31ada .rough-node .label text,#mq6disobq6yrsh31ada .node .label text,#mq6disobq6yrsh31ada .image-shape .label,#mq6disobq6yrsh31ada .icon-shape .label{text-anchor:middle;}#mq6disobq6yrsh31ada .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobq6yrsh31ada .rough-node .label,#mq6disobq6yrsh31ada .node .label,#mq6disobq6yrsh31ada .image-shape .label,#mq6disobq6yrsh31ada .icon-shape .label{text-align:center;}#mq6disobq6yrsh31ada .node.clickable{cursor:pointer;}#mq6disobq6yrsh31ada .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobq6yrsh31ada .arrowheadPath{fill:lightgrey;}#mq6disobq6yrsh31ada .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobq6yrsh31ada .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobq6yrsh31ada .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobq6yrsh31ada .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobq6yrsh31ada .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobq6yrsh31ada .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobq6yrsh31ada .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobq6yrsh31ada .cluster text{fill:#F9FFFE;}#mq6disobq6yrsh31ada .cluster span{color:#F9FFFE;}#mq6disobq6yrsh31ada div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobq6yrsh31ada .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobq6yrsh31ada rect.text{fill:none;stroke-width:0;}#mq6disobq6yrsh31ada .icon-shape,#mq6disobq6yrsh31ada .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobq6yrsh31ada .icon-shape p,#mq6disobq6yrsh31ada .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobq6yrsh31ada .icon-shape rect,#mq6disobq6yrsh31ada .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobq6yrsh31ada .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobq6yrsh31ada .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobq6yrsh31ada :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}非法合法不支持支持超限合法已删除TEMP且过期正常文件上传请求SysFileOptServiceImpl.upload验证文件名拒绝上传验证扩展名bizType.extArr验证文件大小bizType.maxSize计算MD5和SM3哈希5GB以下文件生成UUID存储路径StorageService存储记录文件元数据类型: TEMP设置过期时间bizType.expiry文件下载请求SysFileOptServiceImpl.download检查文件状态返回文件不存在自动删除文件StorageService下载文件生命周期状态:TEMP(临时) -> OK(确认)或 DELETE(删除/过期) 3.8 系统监控设计 SysMonitorController(/sys/monitor)提供以下监控端点: 端点 方法 说明 /sys/monitor/redis GET Redis 监控(内存、连接数、命中率等) /sys/monitor/mysql/{type} GET MySQL 监控(进程列表、InnoDB状态等) /sys/monitor/elasticsearch/{type} GET Elasticsearch 监控(集群健康、索引统计等) 使用枚举类型选择不同的监控指标,委托给 boot 框架中的 RedisMonitor、MySqlMonitor、ElasticsearchMonitor 实现。 3.9 消息队列设计 #mq6disobme12hnjq7vc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#ccc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mq6disobme12hnjq7vc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mq6disobme12hnjq7vc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mq6disobme12hnjq7vc .error-icon{fill:#a44141;}#mq6disobme12hnjq7vc .error-text{fill:#ddd;stroke:#ddd;}#mq6disobme12hnjq7vc .edge-thickness-normal{stroke-width:1px;}#mq6disobme12hnjq7vc .edge-thickness-thick{stroke-width:3.5px;}#mq6disobme12hnjq7vc .edge-pattern-solid{stroke-dasharray:0;}#mq6disobme12hnjq7vc .edge-thickness-invisible{stroke-width:0;fill:none;}#mq6disobme12hnjq7vc .edge-pattern-dashed{stroke-dasharray:3;}#mq6disobme12hnjq7vc .edge-pattern-dotted{stroke-dasharray:2;}#mq6disobme12hnjq7vc .marker{fill:lightgrey;stroke:lightgrey;}#mq6disobme12hnjq7vc .marker.cross{stroke:lightgrey;}#mq6disobme12hnjq7vc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mq6disobme12hnjq7vc p{margin:0;}#mq6disobme12hnjq7vc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ccc;}#mq6disobme12hnjq7vc .cluster-label text{fill:#F9FFFE;}#mq6disobme12hnjq7vc .cluster-label span{color:#F9FFFE;}#mq6disobme12hnjq7vc .cluster-label span p{background-color:transparent;}#mq6disobme12hnjq7vc .label text,#mq6disobme12hnjq7vc span{fill:#ccc;color:#ccc;}#mq6disobme12hnjq7vc .node rect,#mq6disobme12hnjq7vc .node circle,#mq6disobme12hnjq7vc .node ellipse,#mq6disobme12hnjq7vc .node polygon,#mq6disobme12hnjq7vc .node path{fill:#1f2020;stroke:#ccc;stroke-width:1px;}#mq6disobme12hnjq7vc .rough-node .label text,#mq6disobme12hnjq7vc .node .label text,#mq6disobme12hnjq7vc .image-shape .label,#mq6disobme12hnjq7vc .icon-shape .label{text-anchor:middle;}#mq6disobme12hnjq7vc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mq6disobme12hnjq7vc .rough-node .label,#mq6disobme12hnjq7vc .node .label,#mq6disobme12hnjq7vc .image-shape .label,#mq6disobme12hnjq7vc .icon-shape .label{text-align:center;}#mq6disobme12hnjq7vc .node.clickable{cursor:pointer;}#mq6disobme12hnjq7vc .root .anchor path{fill:lightgrey!important;stroke-width:0;stroke:lightgrey;}#mq6disobme12hnjq7vc .arrowheadPath{fill:lightgrey;}#mq6disobme12hnjq7vc .edgePath .path{stroke:lightgrey;stroke-width:2.0px;}#mq6disobme12hnjq7vc .flowchart-link{stroke:lightgrey;fill:none;}#mq6disobme12hnjq7vc .edgeLabel{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobme12hnjq7vc .edgeLabel p{background-color:hsl(0, 0%, 34.4117647059%);}#mq6disobme12hnjq7vc .edgeLabel rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobme12hnjq7vc .labelBkg{background-color:rgba(87.75, 87.75, 87.75, 0.5);}#mq6disobme12hnjq7vc .cluster rect{fill:hsl(180, 1.5873015873%, 28.3529411765%);stroke:rgba(255, 255, 255, 0.25);stroke-width:1px;}#mq6disobme12hnjq7vc .cluster text{fill:#F9FFFE;}#mq6disobme12hnjq7vc .cluster span{color:#F9FFFE;}#mq6disobme12hnjq7vc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(20, 1.5873015873%, 12.3529411765%);border:1px solid rgba(255, 255, 255, 0.25);border-radius:2px;pointer-events:none;z-index:100;}#mq6disobme12hnjq7vc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#ccc;}#mq6disobme12hnjq7vc rect.text{fill:none;stroke-width:0;}#mq6disobme12hnjq7vc .icon-shape,#mq6disobme12hnjq7vc .image-shape{background-color:hsl(0, 0%, 34.4117647059%);text-align:center;}#mq6disobme12hnjq7vc .icon-shape p,#mq6disobme12hnjq7vc .image-shape p{background-color:hsl(0, 0%, 34.4117647059%);padding:2px;}#mq6disobme12hnjq7vc .icon-shape rect,#mq6disobme12hnjq7vc .image-shape rect{opacity:0.5;background-color:hsl(0, 0%, 34.4117647059%);fill:hsl(0, 0%, 34.4117647059%);}#mq6disobme12hnjq7vc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mq6disobme12hnjq7vc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mq6disobme12hnjq7vc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}成功失败成功失败是否消息生产者MqBus.push发送消息RabbitMQ Broker消费者组1: SysLogMq队列: sys.log并发: 5-10消费者组2: SysTaskMq队列: sys.task并发: 5-10处理成功?LogBusService.saveLog存储日志MqErrorHandle处理成功?SysTaskService.save存储任务记录SM3哈希消息Redis错误计数+1错误次数 >= 3?放弃消息删除计数器等待1秒抛出异常触发重投递队列定义: 队列 用途 消息类型 记录日志 sys.log 异步日志存储 LogBody 否 sys.task 异步任务记录 TaskInfo 是 错误处理:使用 SM3 哈希消息内容作为去重键,通过 Redis 计数器跟踪重试次数,最多重试 3 次。 四、编码规范设计 4.1 命名规范 类命名 类型 命名规范 示例 实体类 Sys + 功能名 SysUser、SysRole、SysMenu 请求DTO Sys + 功能名 + AddReq/UpdateReq/PageReq SysUserAddReq 响应DTO Sys + 功能名 + Resp SysUserResp Excel DTO Sys + 功能名 + Excel SysUserExcel Service接口 Sys + 功能名 + Service SysUserService Service实现 Sys + 功能名 + ServiceImpl SysUserServiceImpl Service Base Sys + 功能名 + BaseService SysUserBaseService Controller Sys + 功能名 + Controller SysUserController Mapper Sys + 功能名 + Mapper SysUserMapper Convert Sys + 功能名 + Convert SysUserConvert 枚举 功能名 + Enum SysRiskEnum 配置类 功能名 + Config SysConfig 初始化类 Init + 模块名 InitSys 消息消费者 Sys + 功能名 + Mq SysLogMq 定时任务 Sys + 功能名 + Job SysLogJob 工具类 功能名 + Utils PasswdUtils 方法命名 操作 命名规范 示例 查询单个 get + 功能名 getSysUser 分页查询 page + 功能名 pageSysUser 列表查询 list + 功能名 listSysRole 新增 add + 功能名 addSysUser 修改 update + 功能名 updateSysUser 删除 delete + 功能名 + ByIds deleteSysUserByIds 4.2 注释规范 类注释格式: java 复制代码 /** * <p>Title : 类名称</p> * <p>Description : 类描述</p> * <p>Company : org.xujun</p> * * @author : 作者名 * @version : 版本号 * @date : 日期 */ 方法注释格式: java 复制代码 /** * 方法描述 * * @param param 参数说明 * @return 返回值说明 */ 4.3 代码风格 Lombok:使用 @Data、@Builder、@Slf4j、@AllArgsConstructor、@NoArgsConstructor 等注解简化 POJO 代码 MapStruct:使用 @Mapper 注解定义对象转换器,编译期生成转换代码 MyBatis-Plus:使用 BaseMapper 简化 CRUD 操作,IService 封装 Service 层通用方法 构造器注入:使用 @RequiredArgsConstructor(Lombok)替代 @Autowired 字段注入 统一返回格式:所有 API 响应使用 Result<T> 统一封装 统一异常处理:BizError(业务错误)、BizWarning(业务警告)、UnauthorizedError(未授权)、BizPublicKeyError(密钥过期) API文档:使用 @Tag、@Operation、@Schema 注解生成 Knife4j API 文档 4.4 设计规范 分层原则:Controller -> Service -> Mapper,每层职责单一明确 单一职责:每个 Service 只负责一个业务领域 开闭原则:通过 @Primary 注解支持 Service 实现的运行时替换(如 EsSysLogServiceImpl 替换默认 SysLogServiceImpl) 基础抽象:BaseService + BaseServiceImpl 封装通用 CRUD,业务 Service 只关注差异化逻辑 过滤器链:使用 @Order 控制过滤器执行顺序(HttpLogFilter: 200 -> AuthFilter: 201) 初始化模式:ApplicationRunner + @Order 控制启动顺序 4.5 安全规范 安全措施 实现方式 说明 密码传输加密 SM2 非对称加密 服务端生成密钥对,客户端用公钥加密,服务端用私钥解密 密码存储加密 SM3 国密哈希 不可逆哈希存储,登录时对比哈希值 密钥管理 Redis 临时存储 SM2密钥对存储5分钟,防止重放攻击 SQL安全 MyBatis-Plus 参数化查询 防止SQL注入 数据验证 @Valid 注解 请求参数校验 认证授权 Token + RBAC UUID Token + Redis + 接口权限 数据脱敏 MaskIgnoreUtils 敏感字段按会话级别脱敏控制 账号锁定 Redis计数器 密码错误超限自动锁定 微服务认证 一次性Token Cloud Token 从 Redis Hash 删除后失效 五、项目依赖设计 5.1 核心框架依赖 依赖 版本 用途 Spring Boot 4.0.6 应用框架 Spring Framework 7.0.7 核心框架 Spring Security 7.0.5 安全框架 Spring Data BOM 2025.1.5 数据访问版本管理 Spring AMQP 4.0.3 RabbitMQ集成 Jackson BOM 2.21.2 JSON序列化(主) Jackson BOM 3.1.2 JSON序列化(新) MyBatis Spring Boot Starter 4.0.1 MyBatis集成 MyBatis-Plus 3.5.16 ORM增强工具 5.2 工具库依赖 依赖 版本 用途 Lombok 1.18.46 代码简化 MapStruct 1.6.3 对象映射 FastJSON2 2.0.60 JSON处理 Velocity 2.4.1 模板引擎(代码生成) Commons IO 2.22.0 IO工具 Commons Lang3 3.20.0 通用工具 Commons Text 1.15.0 文本处理 Caffeine 3.2.3 本地缓存(风控) 5.3 安全相关依赖 依赖 版本 用途 BouncyCastle 1.84 SM2/SM3国密算法 java-jwt 4.5.1 JWT Token Easy Captcha 1.6.2 验证码生成 5.4 文档相关依赖 依赖 版本 用途 Knife4j 4.5.0 API文档增强 Swagger Annotations 2.2.48 OpenAPI注解 SpringDoc OpenAPI 3.0.3 OpenAPI文档生成 5.5 消息队列依赖 依赖 版本 用途 Spring AMQP 4.0.3 RabbitMQ集成(由Spring Boot 4.0.6管理) 5.6 缓存依赖 依赖 版本 用途 Spring Data Redis 由Spring Boot管理 Redis集成 5.7 系统监控依赖 依赖 版本 用途 OSHI 6.12.0 系统信息采集 Spring Boot Admin 4.0.4 应用监控 5.8 数据库依赖 依赖 版本 用途 Druid 1.2.28 数据库连接池 5.9 文件处理依赖 依赖 版本 用途 Fesod Sheet 2.0.1-incubating Excel处理 S3 SDK 2.42.41 S3对象存储 5.10 其他工具依赖 依赖 版本 用途 ip2region 3.3.7 IP归属地查询 UserAgentUtils 1.21 浏览器标识解析 pinyin4j 2.5.1 拼音转换 thumbnailator 0.4.21 图片压缩 mmseg4j-core 1.10.0 中文分词 ZXing 3.5.4 二维码/条形码 PDFBox 3.0.7 PDF处理 Jsoup 1.22.2 HTML解析 JUnit Jupiter 6.0.3 单元测试 Byte Buddy 1.17.8 字节码操作 5.11 微服务相关依赖 依赖 版本 用途 Spring Cloud 2025.1.1 微服务框架 Spring Cloud Alibaba 2025.1.0.0 微服务组件 Nacos Client 3.1.1 服务注册与配置中心 Sentinel 1.8.9 流量控制与熔断降级 Seata 2.5.0 分布式事务 RocketMQ 5.3.1 消息队列(可选) XXL-Job 3.4.0 分布式任务调度(可选) 5.12 xtools内部框架依赖 所有 xtools 内部模块版本均为 5.0.0: 模块 用途 xtools-core 核心工具库 xtools-web Web工具库 xtools-extend 扩展工具库 xtools-api API接口定义 xtools-boot-api Boot API模块 xtools-boot-core Boot核心模块 xtools-boot-cache-redis Redis缓存模块 xtools-boot-db-mybatis MyBatis数据库模块 xtools-boot-db-mybatis-plus MyBatis-Plus模块 xtools-boot-elasticsearch Elasticsearch模块 xtools-boot-ip IP地址模块 xtools-boot-knife4j Knife4j文档模块 xtools-boot-log 日志模块 xtools-boot-mask 数据脱敏模块 xtools-boot-mq-base MQ基础模块 xtools-boot-mq-rabbit RabbitMQ模块 xtools-boot-storage-base 存储基础模块 xtools-boot-storage-s3 S3存储模块 xtools-boot-task 任务模块 xtools-boot-thread 线程模块 xtools-boot-web-base Web基础模块 xtools-boot-web-filter Web过滤器模块 xtools-cloud-alibaba-nacos Nacos集成 xtools-cloud-alibaba-sentinel Sentinel集成 xtools-cloud-call 微服务调用 六、技术选型说明 6.1 JDK 25 选择原因:最新LTS版本,提供长期支持和性能优化 主要新特性: 虚拟线程(Virtual Threads):轻量级线程,大幅提升并发能力,项目中用于异步日志记录(VirtualThreadTaskUtils.simple()) Scoped Value:虚拟线程间的上下文传递,项目中用于 LogTrackHolder 上下文传播 Structured Concurrency:结构化并发编程 改进的 ZGC/Shenandoah 垃圾回收器 Pattern Matching 增强 Record Classes 增强 6.2 Spring Boot 4.0.6 Spring Framework 版本:7.0.7 Spring Security 版本:7.0.5 主要特性: 支持 Jakarta EE 11 原生支持虚拟线程 改进的可观测性(Observability) 增强 GraalVM Native Image 支持 改进的自动配置机制 6.3 MyBatis-Plus 3.5.16 支持的 MyBatis 版本:4.0.1 主要特性: 简化 CRUD 操作(BaseMapper、IService) 内置分页插件 条件构造器(QueryWrapper、LambdaQueryWrapper) 自动填充、逻辑删除、乐观锁 代码生成器 SQL 性能分析 6.4 Elasticsearch Spring Data BOM 版本:2025.1.5 主要特性: 全文搜索和倒排索引 分布式架构,高可用 近实时搜索 项目中用于系统日志的存储和检索,支持分页查询、链路追踪和批量删除 6.5 Redis 版本说明:由 Spring Boot 4.0.6 管理 主要特性: 高性能键值缓存 支持多种数据结构(String、Hash、List、Set、ZSet) 项目中用于:Token存储、权限缓存、风控数据、分布式锁、参数缓存等 通过 RedisService 封装操作,AOP切面记录操作日志 6.6 RabbitMQ 版本说明:Spring AMQP 4.0.3(由Spring Boot管理) 主要特性: 可靠消息传递(确认机制、持久化) 灵活路由(Direct/Fanout/Topic交换机) 消息确认和重试机制 项目中用于:异步日志存储、异步任务记录 自定义错误处理:SM3去重 + Redis计数器 + 最多3次重试 6.7 Nacos 3.1.1 选择原因:Spring Cloud Alibaba 生态核心组件 主要特性: 服务注册与发现 动态配置管理 健康检查 支持微服务部署模式 6.8 其他重要依赖版本 依赖 版本 用途 选择原因 Sentinel 1.8.9 流量控制与熔断降级 阿里开源,轻量级高可用 FastJSON2 2.0.60 JSON序列化 高性能,国产开源 Lombok 1.18.46 代码简化 编译期注解处理,零运行时开销 MapStruct 1.6.3 对象映射 编译期生成,高性能 Velocity 2.4.1 模板引擎 代码生成模板渲染 Knife4j 4.5.0 API文档增强 增强Swagger UI,国人友好 BouncyCastle 1.84 加密库 SM2/SM3国密算法支持 OSHI 6.12.0 系统监控 跨平台系统信息采集 Easy Captcha 1.6.2 验证码生成 支持算术验证码、GIF动画验证码 Fesod Sheet 2.0.1-incubating Excel处理 Apache POI孵化项目 Druid 1.2.28 数据库连接池 阿里开源,监控功能完善 Caffeine 3.2.3 本地缓存 高性能,支持过期策略 S3 SDK 2.42.41 对象存储 AWS S3协议兼容 Jackson 2.21.2 JSON处理 Spring Boot默认JSON库 文档版本:v1.0 编写日期:2026-06-09 项目版本:1.0.0 父POM版本:xtools-parent-cloud:5.0.0 JDK版本:25 维护团队:xujun.org