diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..fbcab77 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html diff --git a/.gitignore b/.gitignore index 5ce99cd..ed8368a 100644 --- a/.gitignore +++ b/.gitignore @@ -45,12 +45,3 @@ nbdist/ !*/build/*.java !*/build/*.html !*/build/*.xml - -bin/ -ry.bat -ry.sh -run.sh -package.bat -sql/quartz.sql - -**/application-local.yml diff --git a/DirectoryV3.xml b/DirectoryV3.xml deleted file mode 100644 index fa6d752..0000000 --- a/DirectoryV3.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 79f1739..0000000 --- a/Dockerfile +++ /dev/null @@ -1,50 +0,0 @@ -# ====================== 构建阶段 ====================== -FROM maven:3.9.9-eclipse-temurin-8 AS builder -WORKDIR /app - -# 缓存pom -COPY pom.xml . -COPY cmvr-iot-admin/pom.xml cmvr-iot-admin/ -COPY cmvr-iot-framework/pom.xml cmvr-iot-framework/ -COPY cmvr-iot-system/pom.xml cmvr-iot-system/ -COPY cmvr-iot-quartz/pom.xml cmvr-iot-quartz/ -COPY cmvr-iot-generator/pom.xml cmvr-iot-generator/ -COPY cmvr-iot-common/pom.xml cmvr-iot-common/ -COPY cmvr-iot-device/pom.xml cmvr-iot-device/ -COPY cmvr-iot-test/pom.xml cmvr-iot-test/ -COPY cmvr-iot-api/pom.xml cmvr-iot-api/ -COPY cmvr-iot-vi/pom.xml cmvr-iot-vi/ -COPY cmvr-iot-ti/pom.xml cmvr-iot-ti/ -COPY cmvr-iot-evaluation/pom.xml cmvr-iot-evaluation/ -COPY cmvr-iot-api/cmvr-iot-llm/pom.xml cmvr-iot-api/cmvr-iot-llm/ -COPY cmvr-iot-api/cmvr-iot-edge/pom.xml cmvr-iot-api/cmvr-iot-edge/ -COPY cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/pom.xml cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/ -COPY cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/pom.xml cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/ - -RUN mvn dependency:go-offline -B --no-transfer-progress - -COPY . . - -RUN mvn clean package -DskipTests -pl cmvr-iot-admin -am --no-transfer-progress - -# ====================== 运行阶段 ====================== -FROM openjdk:8-jdk-alpine - -WORKDIR /app - -# -------------------------- 【唯一正确写法】 -------------------------- -# 1. 先把所有jar复制进来 -COPY --from=builder /app/cmvr-iot-admin/target/*.jar ./ - -# 2. 自动删除不能运行的小jar(只保留可执行jar) -RUN find . -name "*.jar" -type f -size -20000k -delete - -# 3. 重命名为app.jar -RUN mv *.jar app.jar - -ENTRYPOINT ["java", "-jar", \ -"-Dspring.profiles.active=dev", \ -"-Djava.security.egd=file:/dev/./urandom", \ -"-XX:+UseG1GC", \ -"-Xms512m", "-Xmx1024m", \ -"app.jar"] diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index a73295e..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,43 +0,0 @@ -pipeline { - agent any - - stages { - stage('Build') { - steps { - sh 'mvn clean install -Dmaven.test.skip=true' - } - } - - stage('Deploy') { - parallel { - stage('Deploy to DEV') { - steps { - sh './ry.sh start dev' - } - } - stage('Deploy to TEST') { - steps { - sh './ry.sh start test' - } - } - stage('Deploy to PROD') { - steps { - sh './ry.sh start prod' - } - } - } - } - } - - post { - always { - archiveArtifacts artifacts: '**/*.jar', allowEmptyArchive: true - } - success { - echo 'Pipeline completed successfully.' - } - failure { - echo 'Pipeline failed.' - } - } -} \ No newline at end of file diff --git a/README.md b/README.md index 30fdc07..ecff97f 100644 --- a/README.md +++ b/README.md @@ -1,249 +1,153 @@ -# cmvr-iot +# CMVR IoT 物联网平台 -cmvr-iot 是一个基于 Java 8 和 Spring Boot 2.5 的多模块后端工程,提供设备管理、边缘机器人控制、测试编排、巡检、TTS、AIMA、VI/TI 等业务能力。工程入口在 `cmvr-iot-admin`,其余模块按业务和基础能力拆分。 +CMVR IoT 是招商车研机器人及智能设备管理平台。本项目以 RuoYi-Vue 3.9.2 为基础升级到 Spring Boot 4,保留原有 REST、前端和 gRPC 对外接口,并将 QUIC Gateway 集成到主应用进程中。 + +Java 包名、Maven 坐标统一使用 `com.cmvr`。旧项目 `cmvr-iot` 仅作为迁移来源,不参与本项目构建。 + +## 主要功能 + +- 系统管理:用户、角色、部门、菜单、字典、参数、日志和通知。 +- 设备管理:设备注册、终端配置、设备档案和机器人配置。 +- 测试业务:任务配置、任务编排、任务实例、检测项、语音唤醒、Flowise 和 AI 评估。 +- 智能巡检:机器人、地图、点位、任务、执行实例、巡检结果和告警。 +- 智能座舱:语音交互、触控交互、TTS、语料库和车机操作配置。 +- 专项业务:爱玛电动车测试、评价指标库和大模型服务。 +- 边缘控制:通过 gRPC 调用 AGV、相机、机械臂、灵巧手、机器人头部、麦克风和扬声器。 +- QUIC 接入:节点注册、心跳、设备快照、媒体 DATAGRAM 和 gRPC 地址同步。 +- 平台能力:Quartz 定时任务、代码生成、WebSocket、MinIO 文件服务和 Knife4j 接口文档。 ## 技术栈 -- Java 8 -- Spring Boot 2.5.15 -- Spring Security -- MyBatis Plus / MyBatis Plus Join -- MySQL / Redis -- Druid -- Quartz -- Knife4j / Swagger -- gRPC Java 1.58.0 -- Protobuf / protoc-maven-plugin -- MinIO +| 组件 | 版本或实现 | +| --- | --- | +| Java | 17 | +| Spring Boot | 4.0.6 | +| Spring Security | JWT 认证 | +| MyBatis | MyBatis-Plus 3.5.17、MPJ 1.5.9 | +| 数据库 | MySQL | +| 缓存 | Redis | +| RPC | gRPC 1.58.0、Protobuf 3.25.5 | +| QUIC | Netty QUIC 4.2.16.Final | +| API 文档 | Springdoc 3.0.3、Knife4j 4.5.0 | +| 前端 | Vue 3.4、Element Plus 2.9、Vite 5.3 | -## 模块说明 +## 工程结构 | 模块 | 说明 | | --- | --- | -| `cmvr-iot-admin` | Web 启动模块,包含 REST Controller、启动类和运行配置 | -| `cmvr-iot-framework` | Web、安全、配置、通用框架能力 | -| `cmvr-iot-common` | 公共工具、通用响应、基础常量和通用能力 | -| `cmvr-iot-system` | 系统管理、用户、角色、菜单、字典等基础业务 | -| `cmvr-iot-quartz` | 定时任务模块 | -| `cmvr-iot-generator` | 代码生成模块 | -| `cmvr-iot-device` | 设备领域模型与设备相关能力 | -| `cmvr-iot-test` | 测试任务、编排、执行实例等业务 | -| `cmvr-iot-vi` | VI 相关业务 | -| `cmvr-iot-ti` | TI 相关业务 | -| `cmvr-iot-evaluation` | 评测相关业务 | -| `cmvr-iot-inspection` | 巡检机器人、地图、任务、告警等业务 | -| `cmvr-iot-aima` | AIMA 相关业务 | -| `cmvr-iot-tts` | TTS 语音合成相关业务 | -| `cmvr-iot-api` | API 聚合模块 | -| `cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib` | gRPC proto 与生成代码模块 | -| `cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client` | 边缘设备 gRPC 客户端、设备控制服务和请求 VO | +| `cmvr-iot-admin` | Spring Boot 启动入口、REST 控制器和运行配置 | +| `cmvr-iot-framework` | 安全、Web、MyBatis、WebSocket 等框架配置 | +| `cmvr-iot-common` | 公共模型、注解、异常和工具类 | +| `cmvr-iot-system` | 用户、角色、菜单、字典、参数和通用分组 | +| `cmvr-iot-quartz` | Quartz 任务调度和任务日志 | +| `cmvr-iot-generator` | 代码生成 | +| `cmvr-iot-device` | 设备、终端和机器人配置 | +| `cmvr-iot-test` | 测试任务、流程、检测项和执行实例 | +| `cmvr-iot-vi` | 语音交互业务 | +| `cmvr-iot-ti` | 触控交互业务 | +| `cmvr-iot-evaluation` | 评价指标业务 | +| `cmvr-iot-inspection` | 智能巡检业务 | +| `cmvr-iot-aima` | 爱玛电动车专项业务 | +| `cmvr-iot-tts` | TTS 任务和车载语料 | +| `cmvr-iot-api` | 边缘服务和大模型 API 聚合模块 | +| `cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib` | 原有 gRPC 协议及生成代码 | +| `cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client` | 原有机器人 gRPC 客户端 | +| `cmvr-iot-quic-contract` | QUIC 控制、节点事件和媒体数据协议 | +| `cmvr-iot-quic` | 与主应用同进程运行的 QUIC Gateway | +| `ruoyi-ui` | Vue 3 管理控制台 | -## 目录结构 +## 环境准备 -```text -cmvr-iot -├── cmvr-iot-admin # Spring Boot 启动模块 -├── cmvr-iot-common # 公共模块 -├── cmvr-iot-framework # 框架模块 -├── cmvr-iot-system # 系统管理模块 -├── cmvr-iot-device # 设备模块 -├── cmvr-iot-test # 测试业务模块 -├── cmvr-iot-api -│ └── cmvr-iot-edge -│ ├── cmvr-iot-grpc-lib # proto 与 gRPC 生成代码 -│ └── cmvr-iot-grpc-client # gRPC 客户端与边缘控制服务 -├── sql # 增量 SQL -├── Dockerfile -├── Jenkinsfile -└── pom.xml # Maven 父工程 -``` - -## 环境要求 - -- JDK 1.8 -- Maven 3.6+ -- MySQL 5.7+/8.x +- JDK 17 +- Maven 3.6.3 或更高版本 +- MySQL 5.7/8.0 - Redis -- 可访问的 gRPC 机器人/边缘终端服务 -- 可选:MinIO、外部大模型/TTS/评测服务 +- Node.js 18/20 LTS 和 pnpm 9 +- MinIO,仅使用文件、语料或媒体存储功能时需要 -注意:`application-*.yml` 中包含环境相关地址、账号和密钥配置。实际部署或本地开发时,应使用本机配置、环境变量或配置中心覆盖,不要直接复用生产/测试环境敏感配置。 +默认激活 `test` profile,后端端口为 `13080`。运行前检查以下配置: -## 配置文件 +- `cmvr-iot-admin/src/main/resources/application-test.yml`:MySQL、Redis、MinIO、gRPC 和第三方服务。 +- `cmvr-iot-admin/src/main/resources/application.yml`:上传目录、JWT、MyBatis、Knife4j 和 QUIC。 +- 不要把生产密码、访问密钥或 TLS 私钥提交到仓库。 -主配置文件位于: +## 数据库初始化 -```text -cmvr-iot-admin/src/main/resources/application.yml -``` +新数据库以 `sql/ry_20260417.sql` 为基础脚本。按实际启用模块检查并执行以下补充脚本: -环境配置文件位于: +- `sql/quartz.sql`:Quartz 表结构。 +- `sql/aima_module.sql`:爱玛业务。 +- `sql/inspection_module.sql`、`inspection_result.sql`、`inspection_detection_alert.sql`:巡检业务。 +- `sql/tts_corpus_module.sql`:TTS 和语料业务。 +- `sql/quic_gateway_terminal_migration.sql`:QUIC 节点绑定及运行状态字段。 -```text -cmvr-iot-admin/src/main/resources/application-dev.yml -cmvr-iot-admin/src/main/resources/application-test.yml -cmvr-iot-admin/src/main/resources/application-prod.yml -``` +补充脚本可能面向不同历史库版本。已有数据库升级前应先备份,并确认字段或索引尚未存在。 -当前 `application.yml` 默认激活: - -```yaml -spring: - profiles: - active: test -``` - -如需切换环境,可以修改 `spring.profiles.active`,或启动时指定: - -```bash -java -jar cmvr-iot-admin-dev.jar --spring.profiles.active=dev -``` - -## 构建 +## 后端运行 在项目根目录执行: ```bash mvn clean package -DskipTests +java -jar cmvr-iot-admin/target/cmvr-iot-admin.jar ``` -只编译启动模块及其依赖: +也可以在 IDEA 中直接运行: + +```text +com.cmvr.CmvrIotApplication +``` + +DevTools 自动重启已关闭。修改代码后需要完整停止并重新启动应用,避免 MPJ 保留已经关闭的 Spring 上下文。 + +常用地址: + +- 后端 API:`http://localhost:13080` +- Knife4j 文档:`http://localhost:13080/doc.html` +- OpenAPI JSON:`http://localhost:13080/v3/api-docs/00-all` + +Knife4j 只展示带原有 `@ApiOperation` 注解的正式接口,并沿用中文 `@Api(tags=...)` 业务分类。 + +## 前端运行 ```bash -mvn -pl cmvr-iot-admin -am compile -DskipTests +cd ruoyi-ui +pnpm install +pnpm dev ``` -只重新生成并编译 gRPC 代码: +默认开发端口为 `80`。`.env.development` 中的 `VITE_API_URL` 必须与后端地址一致;本项目后端默认是 `http://localhost:13080`。更多说明见 [ruoyi-ui/README.md](ruoyi-ui/README.md)。 + +## gRPC 与 QUIC + +原有机器人 gRPC 客户端与 proto 均保留。终端 gRPC 地址优先读取 `de_device_terminal_config` 的 `host` 和 `port`,没有终端配置时使用当前 profile 中的 `grpc.client.grpc-server.address`。 + +QUIC 不是独立服务,`cmvr-iot-quic` 已作为 `cmvr-iot-admin` 的运行时依赖。启用时主应用同时启动: + +- QUIC:默认 `0.0.0.0:4433/udp` +- 节点和媒体事件:通过 Spring 单例 `NodeEventBroker` 在进程内直接分发,不占用内部端口 + +设置 `cmvr.quic.enabled=true` 前必须配置有效的 TLS 证书和私钥,否则应用会拒绝启动。详细配置见 [cmvr-iot-quic/README.md](cmvr-iot-quic/README.md)。 + +## 构建与验证 ```bash -mvn -pl cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib -am compile -DskipTests -``` +# 运行测试 +mvn test -## 启动 - -启动类: - -```text -cmvr-iot-admin/src/main/java/com/cmvr/CmvrIotApplication.java -``` - -IDE 中直接运行 `CmvrIotApplication` 即可。 - -打包后运行: - -```bash -java -jar cmvr-iot-admin/target/cmvr-iot-admin-dev.jar --spring.profiles.active=dev -``` - -默认开发端口以当前 profile 配置为准,例如 `application-dev.yml` 中为: - -```yaml -server: - port: 13080 -``` - -## 接口文档 - -项目集成 Knife4j / Swagger。服务启动后可访问: - -```text -http://localhost:13080/doc.html -``` - -如果端口或上下文路径被 profile 覆盖,请以实际配置为准。 - -## 数据库脚本 - -增量脚本位于: - -```text -sql/ -``` - -当前包含: - -- `aima_module.sql` -- `inspection_module.sql` -- `tts_corpus_module.sql` - -初始化数据库时,需要结合目标环境的基础库结构和增量脚本执行。 - -## gRPC 与边缘设备 - -边缘设备相关代码集中在: - -```text -cmvr-iot-api/cmvr-iot-edge/ -``` - -proto 文件位于: - -```text -cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/src/main/proto/ -``` - -gRPC 客户端服务位于: - -```text -cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/ -``` - -边缘控制器位于: - -```text -cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/ -``` - -新增或修改 proto 后,执行 Maven compile 会触发 `protoc-maven-plugin` 生成 Java 和 gRPC Stub 代码。业务代码应复用现有 gRPC 客户端管理工具获取 Stub,避免在业务层重复创建底层 `ManagedChannel`。 - -## 实时语音对讲 - -当前实时语音对讲链路为: - -```text -浏览器 WebSocket Binary PCM <-> Java 后端 <-> gRPC 双向流 <-> 机器人终端 -``` - -约定音频格式: - -- PCM_S16LE -- 48000 Hz -- 单声道 -- 16 bit -- 10 ms 一帧 -- 960 bytes/帧 - -相关文件: - -- WebSocket 控制器:`cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/WebRtcSignalingController.java` -- 业务会话管理:`cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/AudioService.java` -- gRPC 音频适配:`cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/adapter/RobotAudioGrpcAdapter.java` -- proto:`cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/src/main/proto/cmvr/api/robot_audio.proto` - -说明:历史 WebRTC 相关类可能仍保留在源码中,但当前浏览器音频传输链路使用 WebSocket 二进制 PCM。 - -## 开发约定 - -- Controller 层只做参数接收、基础校验和响应封装。 -- POST 控制类接口优先使用单个 `@RequestBody VO` 承载完整请求参数。 -- GET 查询类接口可以使用 query 参数绑定 VO。 -- 不建议在同一个接口中同时声明通用 VO 和零散业务参数。 -- gRPC 调用统一通过现有客户端管理类获取 Stub。 -- proto 修改后必须重新编译并确认生成代码已更新。 -- 不要提交本地日志、崩溃 dump、临时音频文件和包含真实密钥的配置。 - -## 常用命令 - -```bash -# 编译全部模块 -mvn clean compile -DskipTests - -# 编译启动模块及依赖 -mvn -pl cmvr-iot-admin -am compile -DskipTests - -# 打包 +# 构建全部后端模块 mvn clean package -DskipTests -# 运行指定 profile -java -jar cmvr-iot-admin/target/cmvr-iot-admin-dev.jar --spring.profiles.active=dev +# 构建前端生产包 +cd ruoyi-ui +pnpm build:prod ``` + +Windows 下也可以使用 `bin/package.bat`、`bin/run.bat` 和 `bin/clean.bat`。 + +## 排查提示 + +- `ApplicationContext ... has been closed already`:彻底停止旧 Java 进程后重新启动,不要使用 DevTools 热重启。 +- `cannot find a NameResolver for static://...`:这是 gRPC target scheme 解析问题,不代表网络不通;检查 `GrpcServiceManager` 的通道创建方式和终端地址格式。 +- QUIC 启动失败:检查证书、私钥、ALPN、UDP 端口占用和 native library 对应的操作系统架构。 +- 数据库提示缺少字段:确认基础脚本版本及对应模块迁移脚本已经执行。 diff --git a/bin/clean.bat b/bin/clean.bat new file mode 100644 index 0000000..24c0974 --- /dev/null +++ b/bin/clean.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] target· +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean + +pause \ No newline at end of file diff --git a/bin/package.bat b/bin/package.bat new file mode 100644 index 0000000..c693ec0 --- /dev/null +++ b/bin/package.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] Weḅwar/jarļ +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean package -Dmaven.test.skip=true + +pause \ No newline at end of file diff --git a/bin/run.bat b/bin/run.bat new file mode 100644 index 0000000..a7c4e12 --- /dev/null +++ b/bin/run.bat @@ -0,0 +1,14 @@ +@echo off +echo. +echo [��Ϣ] ʹ��Jar��������Web���̡� +echo. + +cd %~dp0 +cd ../cmvr-iot-admin/target + +set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m + +java -jar %JAVA_OPTS% cmvr-iot-admin.jar + +cd bin +pause \ No newline at end of file diff --git a/certs/cmvr-quic-ca.crt b/certs/cmvr-quic-ca.crt new file mode 100644 index 0000000..91e2619 --- /dev/null +++ b/certs/cmvr-quic-ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKzCCApOgAwIBAgIUTtZCyKM8INYxZKkfwbKdpHKLjn4wDQYJKoZIhvcNAQEL +BQAwHTEbMBkGA1UEAwwSQ01WUiBRVUlDIExvY2FsIENBMB4XDTI2MDcyNDA2NDQy +MFoXDTM2MDcyMTA2NDQyMFowHTEbMBkGA1UEAwwSQ01WUiBRVUlDIExvY2FsIENB +MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAmq2rHldOobaemqNfWggS +OVj3inKy6AYjfgtcXUfKs48DDbpZ9gyEd/YPJXA8C2jGPXpxzgnc7a4UCUVQZ8ah +ddoJtFcC+Q6BgjeMVqUdUubu5Y9HpkfU3lvnp4KhzvOeFnkKtrCzYIPa2nK3zLc7 +uCiuLlB+91KQSRXPFbc6N7H/EAfGmUHIwlZGysAkRN7b2TAoR4C7E96JLVtuUQsS +VtlEGpunSfuefFzeeZCMS6avLbB+a8Q6yUzLt6pqnheNsDB+jCCXodlJs5XS1AOB +W2GOpGFMj7dLoTD+eBIlAlrhWFcwKjzFmtp6LGl/Jy0O+E99X4TL72oNSOdTrO2O +iavXABz9IvWR2BrAyo5AKlTJqO6tmZw77iVti8jYi+HsXIVGQKMYwvv5k0jdHeIZ +FaDToUbFPP/zj0m8ZraMy+8eNAhScnx6Zs56fcncBuDti6pT+zKisjV1rH/sFvZY +wO1UvJlOEbvXrfYLPp58Aqe/toG2nV45a2Q4+x6AETV1AgMBAAGjYzBhMB0GA1Ud +DgQWBBRdHz+g2vVmqghDZi2kEHtZfoyHZzAfBgNVHSMEGDAWgBRdHz+g2vVmqghD +Zi2kEHtZfoyHZzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkq +hkiG9w0BAQsFAAOCAYEASuEoMFiVcg4iTMxO2kshFTJ6LIrqqGXBn+1j+yQ1ennG +mqPMo5fBOe/Kp3YWCnREQWu0+EEPEC9qWgIDOIm3v7ch4mZiW31GUOqae6bjprBe +er7ySElKGZ5GefKAq++we19A6WHnNxtNAT9BE1VSKUmkxEsnIkuwd+QMmQ9eaIRm +8RvzshWdUcyiBJg07sI3rPzPD/YpnfcYlAa2a0+oXJ3o3zlhdbs2S+9fIl+Y/zFN +wBaUV6ZNk0RFzOCA+jUq2jU5Y1pODcot3Mp2jCHzp4uTFyVqsoqc5USRB2TUILCP +acSbEjD9GnKaNU4miTcftnC85fnBAiZ5btZkXIs72ij+J3VW7QnbcFQG8bElngoR +mWizh6ByPQrsvyT0evJjdjpuOzILsVTAn64m0cYpnlR4g5orcEkIJHv4DzMhpXc2 +CvpcWwk2vJrUuws/LGxDATTAcqtIUIxAkxffqUsdB/6j8fdykNCvXFwNh/uPcawd +4kzh6dr+RFzHSMQ6oN16 +-----END CERTIFICATE----- diff --git a/certs/cmvr-quic-ca.key b/certs/cmvr-quic-ca.key new file mode 100644 index 0000000..4c2b3ac --- /dev/null +++ b/certs/cmvr-quic-ca.key @@ -0,0 +1,40 @@ +-----BEGIN PRIVATE KEY----- +MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQCaraseV06htp6a +o19aCBI5WPeKcrLoBiN+C1xdR8qzjwMNuln2DIR39g8lcDwLaMY9enHOCdztrhQJ +RVBnxqF12gm0VwL5DoGCN4xWpR1S5u7lj0emR9TeW+engqHO854WeQq2sLNgg9ra +crfMtzu4KK4uUH73UpBJFc8Vtzo3sf8QB8aZQcjCVkbKwCRE3tvZMChHgLsT3okt +W25RCxJW2UQam6dJ+558XN55kIxLpq8tsH5rxDrJTMu3qmqeF42wMH6MIJeh2Umz +ldLUA4FbYY6kYUyPt0uhMP54EiUCWuFYVzAqPMWa2nosaX8nLQ74T31fhMvvag1I +51Os7Y6Jq9cAHP0i9ZHYGsDKjkAqVMmo7q2ZnDvuJW2LyNiL4exchUZAoxjC+/mT +SN0d4hkVoNOhRsU8//OPSbxmtozL7x40CFJyfHpmznp9ydwG4O2LqlP7MqKyNXWs +f+wW9ljA7VS8mU4Ru9et9gs+nnwCp7+2gbadXjlrZDj7HoARNXUCAwEAAQKCAYAi +e49/pNqWghoTItM9xLldWAhdcMsSH1Y3wgweDoRxqbL2U0I9cFZy0OPZBo+YQowZ +RgwLcRbz1MBKPc3aSMWTep95uQEkaVe1YjFS2p3yLqH5AstoFjDuPmJjLWPpuVVX +sLXS+wsOO+7lDriLdpjlagpEsHTRqbIZXPeM4YtkwbV5SyZ64ZfCPU4sYo/jW6R6 +43nDUP9Dw3Nk7XJnNlbpDigY33T4sRPIqUJ+qtsf/WGlx6gzWax6Vni+8gqxQlIe +80XG6dHCM3UGFEdGF64PB2FuprsPWBSSau7L7I/gagiIuQbhs9VYXOanz1MQizMU +ZdK8cqmG/bpP+uY4VQLJ5Lxu87boEllGFHBOYTCjWq0zatzGMt1/DeggLnjgfC90 +5kOzlxl403j+4K8nqiHoKpAbOatwTxFz1up6XSecsarE1RKsCq8sIH+FjjCfO1Db +hBfv2a7/XemdcxHtl9Q/EOSDaAFOUQfFMDAc3rCH7/vonTzaaZq5ucWmjlBsv2EC +gcEAz+cH+3x09pXVOnM7zlWrGAQk69Fj/0BGs7g3GFf8ZvI/kkbez+9J1QGItxj+ +7Dm4Ay0kgxYi3DxFWbPLHTbFpVg2CyL08IQZSXJzokwz2V/HTd1a+OgzgB/dBNDc +V+XnxJI89+SI3VhOQZJG625l//lhHWCy2u0ULE7ZlK3ao95L86bSXQHI4dZ2nWXl +0f4ISJmm4qkEJAY+DkQeF3UZLumd1NRxy0LBdbYVM/wZIN+sGsRdQqQ9f+ik6+aX +YrjhAoHBAL52dJzIPIN1Z/Y9qxUrVLPE7K8Mm8KLaFIl/ztl3TFqaUvErHi66nx3 +MTwEnrQIBI31OKxB6Or2JLxYMvDTSVRV1K2tY53+K6Q8giWU4x3zFc/svyl35gkd +U1bLdfxXqKMLrvlmVWj6/RMoH7vd/aTcidYVvwOZgtL+6RahS4LfZ9qXAyREFAJa +VSI0HW5LLiOBLTegztT1CBVe7xb78bWFMiUkxre4XsLZYwFPzXzVPh6HloDcACDL +FPwLrfJrFQKBwQCvGDl90UzEnF4v0vsshLQLDvp1bS1VvTGOjPhB1WBq510o+e0P +nM1Gyvr0keWo19elPTDCAjOr3kreCHFpEkcVQRyK9o7pvad6Vx0SNDF6wpKdfm7u +sMknAC7prmnU0XkH8c3NTTkDiiqmSObXw2u+UK48ysL3ZLIXuvS+pkk8t6yp8Pa8 +hBNGOJQ/baFH4TXixx1pScWF/YfoBfB9+w4Rl4loxN9tu7QpSgfDd29GY3qUNIsC +5EYzYqD7WIJpD6ECgcEAkdIfdenYas14yw5r7ck/EGO00lDU8B3LwRlWUCOtNihC +dcAeTFDPNnwLNehTmYKJ+iXFPh04Nqw9c/YTCk651dfg/RfDLTNsNlIdUqirOkLi +cE7SDO2/MTtCkzEzI//5HNvVGx0+RyHioMgXg75yc8ZlwYLku9zMTL7dtnXHWmux +F6qGvT1iFGsUwxsjbU4iBQzhkbWMpX70sWf9pZs/c7qGqel+OyrtYkENi/ONYAXj +iXxFvmKxtmnFpzNJ+lABAoHBAJjs8jfEXJnJP80t93Bxg6NmfKhxUEm4ovcIeR8U +lEfb8Ind1ICrBWGVGOAkirTFZgFAAlEjne+lT1FYgf19oC+XbxFdl/e02M8KfflS +01+0/t6lEpefiU0dfW0dWtXOPaAVvpNgMkeMgBzB2Yz7ZNUrMypfCGk289qveWxB +8UbO+QLjTI+cFvPsmR95Eti/nAjd2fXGeqbR+z+DdQnz4BvXLSCQCw4on2+T+mpw +BprrEQmcdeZA8LE1zgcKtkZR1w== +-----END PRIVATE KEY----- diff --git a/certs/cmvr-quic-ca.srl b/certs/cmvr-quic-ca.srl new file mode 100644 index 0000000..a423a9b --- /dev/null +++ b/certs/cmvr-quic-ca.srl @@ -0,0 +1 @@ +2C945D70B02014891B6E09D57E377CEFB6D18498 diff --git a/certs/quic-gateway.crt b/certs/quic-gateway.crt new file mode 100644 index 0000000..5a24963 --- /dev/null +++ b/certs/quic-gateway.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDuzCCAiOgAwIBAgIULJRdcLAgFIkbbgnVfjd877bRhJgwDQYJKoZIhvcNAQEL +BQAwHTEbMBkGA1UEAwwSQ01WUiBRVUlDIExvY2FsIENBMB4XDTI2MDcyNDA2NDQz +NloXDTI4MTAyNjA2NDQzNlowGDEWMBQGA1UEAwwNMTkyLjE2OC4wLjIyMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdM3i1FYFKqNWJzhfhsD9nRUAuK +pzilz5uqCKAt8lKYYC9WnLHOYdiEjcHGnGr02yd6sWFH/LBbxNhzx8M7h4S4izuO +bhSlG1EIhkMiojzVD1e3P7YzXdEoVxTCfmMgBZQJG63GNOfzRawFYtEeGv7ndFVw +kitCYlyTza5KlBNlWpiNOPmmx4dLTdGLUk8a5TUm0zJ+b/LyzVsWUtr9sxKmKeG8 +0/77AeiL0hQE3xUt5QROTZjRTVhNHowv410dFMJyIfY4sab8ndc4SIwE9PCKg068 +4705vbFInBS3eTvQur5VLSZLPatnXGKzCXjci1lIQX2p/QIqADMGFWIN9OECAwEA +AaN4MHYwDwYDVR0RBAgwBocEwKgA3jAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAww +CgYIKwYBBQUHAwEwHQYDVR0OBBYEFLmoEtsglxm3mXh4l8OF31bt2ZhnMB8GA1Ud +IwQYMBaAFF0fP6Da9WaqCENmLaQQe1l+jIdnMA0GCSqGSIb3DQEBCwUAA4IBgQAR +eK1mD9rJkzHe4OusimQfcuDQW+0J32e4T/34RHlW+lIj7botFaElXIzO9S80tDwq +4d4ozNPKysqgJN9hv/BBMzJpZLwP2XozPaGLTNl1jRTCc9UhFUPrUeu0LbpQGBfC +6Ghq42V94zPAw4lnMujnkq8botk21hclbJORQ9kblXP31IdWCgiKSFLy1NTBmQmc +IxmR+SldMWYrWGWv/0I85AeMu6HR3+NKHmzDblm1HUHFekyC1f7sypNG+D1r8ab2 +GSijoCMKHSEOm81Vl/j5bgWQygnnIOhsLOUf2DZO6jC+VZmTKpMEJNHgwk23WBlu +FYz/X9p5z9ZucL8aBxegj7G1fI5Ik2O05+LLeqJMfspAm6ZcnRDxCVZWQ+K/dAle +fz+gTASzhHTsjEBeiX46LP0L2PVyBiPvNtD66e52LoM5ZigechZq91niLO+ipWdh +xq7ryJzmaAEQKPuYaoswriWzJam07ywX9yupGHzBA6vVgGy0jPAsnGCuZXTfDyA= +-----END CERTIFICATE----- diff --git a/certs/quic-gateway.csr b/certs/quic-gateway.csr new file mode 100644 index 0000000..c767f90 --- /dev/null +++ b/certs/quic-gateway.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICpDCCAYwCAQAwGDEWMBQGA1UEAwwNMTkyLjE2OC4wLjIyMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKdM3i1FYFKqNWJzhfhsD9nRUAuKpzilz5uq +CKAt8lKYYC9WnLHOYdiEjcHGnGr02yd6sWFH/LBbxNhzx8M7h4S4izuObhSlG1EI +hkMiojzVD1e3P7YzXdEoVxTCfmMgBZQJG63GNOfzRawFYtEeGv7ndFVwkitCYlyT +za5KlBNlWpiNOPmmx4dLTdGLUk8a5TUm0zJ+b/LyzVsWUtr9sxKmKeG80/77AeiL +0hQE3xUt5QROTZjRTVhNHowv410dFMJyIfY4sab8ndc4SIwE9PCKg0684705vbFI +nBS3eTvQur5VLSZLPatnXGKzCXjci1lIQX2p/QIqADMGFWIN9OECAwEAAaBHMEUG +CSqGSIb3DQEJDjE4MDYwDwYDVR0RBAgwBocEwKgA3jAOBgNVHQ8BAf8EBAMCBaAw +EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAGIcLeCE344z +PENI1/oONVHBzMMt5VN0P8jbkJOFgZ3a6AUhfqAmDNBr+8SBym+cX2Y9Q2BsaWAu +TKOBN+fs+fh5/NqF0hTNvmXzp89NFK5SlsTjoC21HJvK1HTNuNW8drOxNfWgFW3/ +gSCutcsWS9hVtYrV2FHQzOvVXvXKfmuTkZE8g92P3BCkvRm+ORxI0QfVS81/Ibnv +Yl+t/o2QCphdP+1OWzU6+Pccqi2xCyIc6jqCmh0b01zg265PTTOfICO6WQNtYcOn +308avDDpTneGl5vWRVdmmiXPqkc+dCesoguIEDUlerFpDKKY81P2GTpfjki93K7Z +2DJPs4P1cU0= +-----END CERTIFICATE REQUEST----- diff --git a/certs/quic-gateway.key b/certs/quic-gateway.key new file mode 100644 index 0000000..7e02c87 --- /dev/null +++ b/certs/quic-gateway.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCnTN4tRWBSqjVi +c4X4bA/Z0VALiqc4pc+bqgigLfJSmGAvVpyxzmHYhI3Bxpxq9NsnerFhR/ywW8TY +c8fDO4eEuIs7jm4UpRtRCIZDIqI81Q9Xtz+2M13RKFcUwn5jIAWUCRutxjTn80Ws +BWLRHhr+53RVcJIrQmJck82uSpQTZVqYjTj5pseHS03Ri1JPGuU1JtMyfm/y8s1b +FlLa/bMSpinhvNP++wHoi9IUBN8VLeUETk2Y0U1YTR6ML+NdHRTCciH2OLGm/J3X +OEiMBPTwioNOvOO9Ob2xSJwUt3k70Lq+VS0mSz2rZ1xiswl43ItZSEF9qf0CKgAz +BhViDfThAgMBAAECggEAC3+johwrdIcNFAMRZUuFE+EYZbCuEV1JHX90aBD8X5uo +Obyz2J8xF6z1osjEMbA6W1ZqGF/2oMbv6robc+JUrEU0UZ+2lm3qKJnDw5u+55wz +uaFHTF4vr6tcf9llzymRZJUzLTCLLJmKc3orymhtrdEp7GDoNPezM753Y6gt0P7Z +AzePK3d7YmEAcRkIDVtqQXyma4CPziItJrcF4Lumww6PxRzqYNb6jB8wsmf0B91U +iTtnJQoJfkOGTl5OyPp2s7A+qXqToIqAbIlzcF1Q7i0kohmhZHHIB8Qdk9O8IGb6 +kZuLbTIdIhTG2vyi8nqz+oMh6D+AJBy+GTLlK0LWCQKBgQDVIrGu9J76R7D3npRy +3okc6mVHo2InZaOeai4ZAe/CFVPcHecq7+bx06MxTqge0XYJd5UbO8qfRL5mRc8g +JwjUrnCzGvJHFavc3Xs221JgWAaNQ0+PtBKCLHQwbmu8V3NZHXcjyonMuQ2g2oOm +TYY7Adedci0SgSFlUy9TjifH6QKBgQDI8lcoojzmYkj0O8oO3dr01XbAEl5pxjyB +IsEpal6J8gdbbj8vzdWaGoHs/IoLPtwWbQGx7gUJfYtKp/DORw0WDFJmqrm/PGfh +RrLKasjp3GC06BU3GmnoKZxQM8PzY0ELWZsQM0fa+ROC1vMrNcHx5nZvcBwrkKXu +CEw2G4miOQKBgDMcUsfF2anjL0jyOl8hhnfsrcT0JUGVWhtPEybkE/7S5n1OnnTp +etRbEDNuzVo2mLvEdXlGaVywO4iDDRyEv9Vgz53jxF3PkJsyca3CAosgENInZhjr +8dRNnL9Qe3166ypfqoZmt4zkg6QjQpbK2HmmA3K6QpzBYqTNwfeji16hAoGBAKO3 +pkFp5TpC63NpXxe7s4/0dxrIHHoLU/JWcZAfpMS5Fztr2DlHd3dlj2OY4ZOF9GSl +DVN9PEdeLOV3bJ9zjfrfsScKg+mF+pC1PCfk1qqKrZPW3qoVcCIB/OPvOQAMZssr +h0Wssid69WWNYXNcChbfELF8Yscvw7Dqu8T9rKYpAoGAByn1Vfu95lAxQ36fxXnk +3CC9FkGcdfKGTqkFZHJWiJqaLL6eAbCwO38kywYZLANoSz03Qu3MmD0Gt0wyeP6I +a3o0goisV8s5W9q1P1i1K73xlbAPf54QsqoPNuXR8n67I9IzzL7EkPJiUsHuqNHW +Ffn4lzHEAxaTksNIaC6oIlo= +-----END PRIVATE KEY----- diff --git a/cmvr-iot-admin/pom.xml b/cmvr-iot-admin/pom.xml index 70aa36b..06ce377 100644 --- a/cmvr-iot-admin/pom.xml +++ b/cmvr-iot-admin/pom.xml @@ -5,7 +5,7 @@ cmvr-iot com.cmvr - 3.8.9 + 3.9.2 4.0.0 jar @@ -24,16 +24,20 @@ true - + - mysql - mysql-connector-java + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + com.github.xiaoymin + knife4j-openapi3-ui - + - com.cmvr - cmvr-iot-test + com.mysql + mysql-connector-j @@ -54,73 +58,72 @@ cmvr-iot-generator - + + com.cmvr + cmvr-iot-test + com.cmvr cmvr-iot-device - - com.cmvr cmvr-iot-vi - - com.cmvr cmvr-iot-ti - - com.cmvr cmvr-iot-evaluation - - com.cmvr cmvr-iot-inspection - - com.cmvr cmvr-iot-aima - - com.cmvr cmvr-iot-tts + + com.cmvr + cmvr-iot-quic + + - - dev - + - org.springframework.boot spring-boot-maven-plugin - 2.5.15 - com.cmvr.CmvrIotApplication - true + true repackage - - ${project.artifactId}-${spring.profiles.active} - + + org.apache.maven.plugins + maven-war-plugin + 3.1.0 + + false + ${project.artifactId} + + + ${project.artifactId} + diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/CmvrIotApplication.java b/cmvr-iot-admin/src/main/java/com/cmvr/CmvrIotApplication.java index 8cd2a20..07e75fc 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/CmvrIotApplication.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/CmvrIotApplication.java @@ -1,9 +1,8 @@ package com.cmvr; -import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; import org.springframework.scheduling.annotation.EnableScheduling; /** @@ -12,13 +11,13 @@ import org.springframework.scheduling.annotation.EnableScheduling; * @author cmvr-iot */ @EnableScheduling -@MapperScan("com.cmvr.**.mapper") @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) public class CmvrIotApplication { public static void main(String[] args) { - // System.setProperty("spring.devtools.restart.enabled", "false"); + // MPJ keeps its Spring context in a static holder that is not refreshed by DevTools. + System.setProperty("spring.devtools.restart.enabled", "false"); SpringApplication.run(CmvrIotApplication.class, args); System.out.println("招商车研物联网平台启动成功"); } diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaAlarmController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaAlarmController.java index a35c5ad..fa33906 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaAlarmController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaAlarmController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.aima; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaPhoneController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaPhoneController.java index 5b30a35..ec82b97 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaPhoneController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaPhoneController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.aima; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskController.java index ef713ee..227e7ce 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.aima; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskInstanceController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskInstanceController.java index 482dad2..5d29601 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskInstanceController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTaskInstanceController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.aima; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestCaseController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestCaseController.java index 8cabb2b..4c331fc 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestCaseController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestCaseController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.aima; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestLogController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestLogController.java index 1829f46..ebf450a 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestLogController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaTestLogController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.aima; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaVehicleController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaVehicleController.java index 15297f7..bed6581 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaVehicleController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/aima/AimaVehicleController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.aima; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/WebRtcSignalingController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/WebRtcSignalingController.java index 3cc8ea9..7e21d51 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/WebRtcSignalingController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/WebRtcSignalingController.java @@ -1,8 +1,8 @@ package com.cmvr.web.controller.api; import com.cmvr.edge.client.service.AudioService; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CaptchaController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CaptchaController.java index b3f1326..a612c91 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CaptchaController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CaptchaController.java @@ -3,9 +3,9 @@ package com.cmvr.web.controller.common; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.concurrent.TimeUnit; -import javax.annotation.Resource; +import jakarta.annotation.Resource; import javax.imageio.ImageIO; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.FastByteArrayOutputStream; import org.springframework.web.bind.annotation.GetMapping; @@ -23,7 +23,7 @@ import com.cmvr.system.service.ISysConfigService; /** * 验证码操作处理 * - * @author cmvr-iot + * @author ruoyi */ @RestController public class CaptchaController diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CommonController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CommonController.java index 4f50a54..71941c3 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CommonController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/common/CommonController.java @@ -1,49 +1,54 @@ package com.cmvr.web.controller.common; -import com.cmvr.common.config.CmvrIotConfig; -import com.cmvr.common.constant.Constants; -import com.cmvr.common.core.domain.AjaxResult; -import com.cmvr.common.utils.StringUtils; -import com.cmvr.common.utils.file.FileUploadUtils; -import com.cmvr.common.utils.file.FileUtils; -import com.cmvr.framework.config.ServerConfig; -import io.swagger.annotations.Api; -import lombok.RequiredArgsConstructor; +import java.util.ArrayList; +import java.util.List; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; +import com.cmvr.common.config.CmvrIotConfig; +import com.cmvr.common.core.domain.AjaxResult; +import com.cmvr.common.utils.StringUtils; +import com.cmvr.common.utils.file.FileUploadUtils; +import com.cmvr.common.utils.file.FileUtils; +import com.cmvr.framework.config.ServerConfig; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.util.ArrayList; -import java.util.List; - -@Api(tags = "通用请求处理") +/** + * 通用请求处理 + * + * @author ruoyi + */ @RestController @RequestMapping("/common") -@RequiredArgsConstructor -public class CommonController { +public class CommonController +{ private static final Logger log = LoggerFactory.getLogger(CommonController.class); - private final ServerConfig serverConfig; + @Autowired + private ServerConfig serverConfig; - private static final String FILE_DELIMETER = ","; + private static final String FILE_DELIMITER = ","; /** * 通用下载请求 - * + * * @param fileName 文件名称 - * @param delete 是否删除 + * @param delete 是否删除 */ @GetMapping("/download") - public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) { - try { - if (!FileUtils.checkAllowDownload(fileName)) { + public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) + { + try + { + if (!FileUtils.checkAllowDownload(fileName)) + { throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); } String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); @@ -52,10 +57,13 @@ public class CommonController { response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); FileUtils.setAttachmentResponseHeader(response, realFileName); FileUtils.writeBytes(filePath, response.getOutputStream()); - if (delete) { + if (delete) + { FileUtils.deleteFile(filePath); } - } catch (Exception e) { + } + catch (Exception e) + { log.error("下载文件失败", e); } } @@ -64,8 +72,10 @@ public class CommonController { * 通用上传请求(单个) */ @PostMapping("/upload") - public AjaxResult uploadFile(MultipartFile file) throws Exception { - try { + public AjaxResult uploadFile(MultipartFile file) throws Exception + { + try + { // 上传文件路径 String filePath = CmvrIotConfig.getUploadPath(); // 上传并返回新文件名称 @@ -77,7 +87,9 @@ public class CommonController { ajax.put("newFileName", FileUtils.getName(fileName)); ajax.put("originalFilename", file.getOriginalFilename()); return ajax; - } catch (Exception e) { + } + catch (Exception e) + { return AjaxResult.error(e.getMessage()); } } @@ -86,15 +98,18 @@ public class CommonController { * 通用上传请求(多个) */ @PostMapping("/uploads") - public AjaxResult uploadFiles(List files) throws Exception { - try { + public AjaxResult uploadFiles(List files) throws Exception + { + try + { // 上传文件路径 String filePath = CmvrIotConfig.getUploadPath(); List urls = new ArrayList(); List fileNames = new ArrayList(); List newFileNames = new ArrayList(); List originalFilenames = new ArrayList(); - for (MultipartFile file : files) { + for (MultipartFile file : files) + { // 上传并返回新文件名称 String fileName = FileUploadUtils.upload(filePath, file); String url = serverConfig.getUrl() + fileName; @@ -104,12 +119,14 @@ public class CommonController { originalFilenames.add(file.getOriginalFilename()); } AjaxResult ajax = AjaxResult.success(); - ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER)); - ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER)); - ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER)); - ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER)); + ajax.put("urls", StringUtils.join(urls, FILE_DELIMITER)); + ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMITER)); + ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMITER)); + ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMITER)); return ajax; - } catch (Exception e) { + } + catch (Exception e) + { return AjaxResult.error(e.getMessage()); } } @@ -119,21 +136,26 @@ public class CommonController { */ @GetMapping("/download/resource") public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) - throws Exception { - try { - if (!FileUtils.checkAllowDownload(resource)) { + throws Exception + { + try + { + if (!FileUtils.checkAllowDownload(resource)) + { throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); } // 本地资源路径 String localPath = CmvrIotConfig.getProfile(); // 数据库资源地址 - String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX); + String downloadPath = localPath + FileUtils.stripPrefix(resource); // 下载名称 String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); FileUtils.setAttachmentResponseHeader(response, downloadName); FileUtils.writeBytes(downloadPath, response.getOutputStream()); - } catch (Exception e) { + } + catch (Exception e) + { log.error("下载文件失败", e); } } diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceRegistrationController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceRegistrationController.java index 1f6f597..87ca10f 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceRegistrationController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceRegistrationController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.device; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import com.cmvr.edge.client.service.EdgeSystemService; import io.swagger.annotations.Api; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceTerminalConfigController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceTerminalConfigController.java index 8b7c672..3612d08 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceTerminalConfigController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceTerminalConfigController.java @@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.util.List; /** diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeRobotConfigController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeRobotConfigController.java index ed57df8..b486564 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeRobotConfigController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeRobotConfigController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.device; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import com.cmvr.common.annotation.Log; import com.cmvr.common.core.controller.BaseController; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/evaluation/AeIndicatorController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/evaluation/AeIndicatorController.java index 7664e03..37bfec3 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/evaluation/AeIndicatorController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/evaluation/AeIndicatorController.java @@ -1,59 +1,59 @@ -package com.cmvr.web.controller.evaluation; - -import com.cmvr.common.core.controller.BaseController; -import com.cmvr.common.core.domain.AjaxResult; - -import com.cmvr.evaluation.model.dto.AeIndicatorCreateDTO; -import com.cmvr.evaluation.model.dto.AeIndicatorUpdateDTO; -import com.cmvr.evaluation.service.AeIndicatorService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; - -@Api(tags = "评价管理--指标库") -@RestController -@RequestMapping("/evaluate/indicator") -@RequiredArgsConstructor -public class AeIndicatorController extends BaseController { - - private final AeIndicatorService indicatorService; - - @ApiOperation("根据父id查询指标") - @GetMapping("/getIndicatorByParentId") - public AjaxResult getIndicatorByParentId(@RequestParam Long parentId, @RequestParam Integer type) { - if (parentId == null || type == null) { - return AjaxResult.error("参数不能为空"); - } - return success(indicatorService.selectIndicatorByParentId(parentId, type)); - } - - @ApiOperation("新增指标") - @PostMapping("/indicator/insert") - public AjaxResult insertIndicator(@Valid @RequestBody AeIndicatorCreateDTO createDTO) { - return success(indicatorService.saveIndicator(createDTO)); - } - - @ApiOperation("根据ID级联删除:删除当前指标及其所有后代指标(子/孙级)") - @DeleteMapping("/{id}") - public AjaxResult removeIndicator(@PathVariable Long id) { - if (id == null) { - return AjaxResult.error("id不能为空"); - } - return toAjax(indicatorService.removeIndicator(id)); - } - - @ApiOperation("修改指标") - @PutMapping - public AjaxResult updateIndicator(@Valid @RequestBody AeIndicatorUpdateDTO updateDTO) { - return toAjax(indicatorService.updateIndicator(updateDTO)); - } - - @ApiOperation("获取指定parentId下指定level层级的指标") - @GetMapping("/getChildrenByParentIdWithLevelLimit") - public AjaxResult getChildrenByParentIdWithLevelLimit(@RequestParam Long parentId, @RequestParam Integer maxLevel, @RequestParam Integer type) { - return success(indicatorService.getChildrenByParentIdWithLevelLimit(parentId, maxLevel, type)); - } -} +package com.cmvr.web.controller.evaluation; + +import com.cmvr.common.core.controller.BaseController; +import com.cmvr.common.core.domain.AjaxResult; + +import com.cmvr.evaluation.model.dto.AeIndicatorCreateDTO; +import com.cmvr.evaluation.model.dto.AeIndicatorUpdateDTO; +import com.cmvr.evaluation.service.AeIndicatorService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; + +@Api(tags = "评价管理--指标库") +@RestController +@RequestMapping("/evaluate/indicator") +@RequiredArgsConstructor +public class AeIndicatorController extends BaseController { + + private final AeIndicatorService indicatorService; + + @ApiOperation("根据父id查询指标") + @GetMapping("/getIndicatorByParentId") + public AjaxResult getIndicatorByParentId(@RequestParam Long parentId, @RequestParam Integer type) { + if (parentId == null || type == null) { + return AjaxResult.error("参数不能为空"); + } + return success(indicatorService.selectIndicatorByParentId(parentId, type)); + } + + @ApiOperation("新增指标") + @PostMapping("/indicator/insert") + public AjaxResult insertIndicator(@Valid @RequestBody AeIndicatorCreateDTO createDTO) { + return success(indicatorService.saveIndicator(createDTO)); + } + + @ApiOperation("根据ID级联删除:删除当前指标及其所有后代指标(子/孙级)") + @DeleteMapping("/{id}") + public AjaxResult removeIndicator(@PathVariable Long id) { + if (id == null) { + return AjaxResult.error("id不能为空"); + } + return toAjax(indicatorService.removeIndicator(id)); + } + + @ApiOperation("修改指标") + @PutMapping + public AjaxResult updateIndicator(@Valid @RequestBody AeIndicatorUpdateDTO updateDTO) { + return toAjax(indicatorService.updateIndicator(updateDTO)); + } + + @ApiOperation("获取指定parentId下指定level层级的指标") + @GetMapping("/getChildrenByParentIdWithLevelLimit") + public AjaxResult getChildrenByParentIdWithLevelLimit(@RequestParam Long parentId, @RequestParam Integer maxLevel, @RequestParam Integer type) { + return success(indicatorService.getChildrenByParentIdWithLevelLimit(parentId, maxLevel, type)); + } +} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionAlarmController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionAlarmController.java index 37ec331..db9df1b 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionAlarmController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionAlarmController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.inspection; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionDetectionAlertController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionDetectionAlertController.java index cdbc476..b2d15ec 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionDetectionAlertController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionDetectionAlertController.java @@ -5,7 +5,7 @@ import com.cmvr.inspection.domain.dto.alert.AlertEnvelope; import com.cmvr.inspection.exception.DetectionAlertBadRequestException; import com.cmvr.inspection.service.IInspectionDetectionAlertService; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; +import tools.jackson.databind.ObjectMapper; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; @@ -18,8 +18,8 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionMapController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionMapController.java index 8652a24..f0503ac 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionMapController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionMapController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.inspection; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionResultController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionResultController.java index b4c96bf..3d2b39c 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionResultController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionResultController.java @@ -28,7 +28,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.util.List; /** diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionRobotController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionRobotController.java index 3253f03..993840d 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionRobotController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionRobotController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.inspection; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import cmvr.msgs.Agv; import com.cmvr.inspection.domain.vo.InspectionRobotVo; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskController.java index d5ffb7a..c144cbe 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.inspection; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskInstanceController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskInstanceController.java index f9a7b91..549be6a 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskInstanceController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionTaskInstanceController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.inspection; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import com.cmvr.inspection.domain.dto.InspectionTaskInstanceQuery; import io.swagger.annotations.Api; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionWaypointController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionWaypointController.java index 37e09a1..1d0f8aa 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionWaypointController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionWaypointController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.inspection; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/CacheController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/CacheController.java index c06f1ff..b1c6a5e 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/CacheController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/CacheController.java @@ -25,7 +25,7 @@ import com.cmvr.system.domain.SysCache; /** * 缓存监控 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/monitor/cache") @@ -45,6 +45,7 @@ public class CacheController caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); } + @SuppressWarnings("deprecation") @PreAuthorize("@ss.hasPermi('monitor:cache:list')") @GetMapping() public AjaxResult getInfo() throws Exception diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/ServerController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/ServerController.java index 022e2e9..e319ee8 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/ServerController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/ServerController.java @@ -10,7 +10,7 @@ import com.cmvr.framework.web.domain.Server; /** * 服务器监控 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/monitor/server") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysLogininforController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysLogininforController.java index edb6ee7..8f04910 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysLogininforController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysLogininforController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.monitor; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; @@ -23,7 +23,7 @@ import com.cmvr.system.service.ISysLogininforService; /** * 系统访问记录 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/monitor/logininfor") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysOperlogController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysOperlogController.java index 1fb1e56..f63fd65 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysOperlogController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysOperlogController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.monitor; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; @@ -22,7 +22,7 @@ import com.cmvr.system.service.ISysOperLogService; /** * 操作日志记录 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/monitor/operlog") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysUserOnlineController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysUserOnlineController.java index dab9a66..38968da 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysUserOnlineController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/monitor/SysUserOnlineController.java @@ -26,7 +26,7 @@ import com.cmvr.system.service.ISysUserOnlineService; /** * 在线用户监控 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/monitor/online") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/show/ShowIntelligentCockpitController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/show/ShowIntelligentCockpitController.java index 826494d..1c3f202 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/show/ShowIntelligentCockpitController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/show/ShowIntelligentCockpitController.java @@ -23,7 +23,7 @@ import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.io.IOException; @Api(tags = "演示--智能座舱") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysConfigController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysConfigController.java index 9fcfe74..649b704 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysConfigController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysConfigController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.system; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -25,7 +25,7 @@ import com.cmvr.system.service.ISysConfigService; /** * 参数配置 信息操作处理 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/config") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDeptController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDeptController.java index 14e915a..ca45262 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDeptController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDeptController.java @@ -1,6 +1,7 @@ package com.cmvr.web.controller.system; import java.util.List; +import java.util.Map; import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -25,7 +26,7 @@ import com.cmvr.system.service.ISysDeptService; /** * 部门信息 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/dept") @@ -110,6 +111,20 @@ public class SysDeptController extends BaseController return toAjax(deptService.updateDept(dept)); } + /** + * 保存部门排序 + */ + @PreAuthorize("@ss.hasPermi('system:dept:edit')") + @Log(title = "保存部门排序", businessType = BusinessType.UPDATE) + @PutMapping("/updateSort") + public AjaxResult updateSort(@RequestBody Map params) + { + String[] deptIds = params.get("deptIds").split(","); + String[] orderNums = params.get("orderNums").split(","); + deptService.updateDeptSort(deptIds, orderNums); + return success(); + } + /** * 删除部门 */ diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictDataController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictDataController.java index f251a15..a883c20 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictDataController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictDataController.java @@ -2,7 +2,7 @@ package com.cmvr.web.controller.system; import java.util.ArrayList; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -28,7 +28,7 @@ import com.cmvr.system.service.ISysDictTypeService; /** * 数据字典信息 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/dict/data") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictTypeController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictTypeController.java index 7814a06..64683a5 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictTypeController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysDictTypeController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.system; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -25,7 +25,7 @@ import com.cmvr.system.service.ISysDictTypeService; /** * 数据字典信息 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/dict/type") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysIndexController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysIndexController.java index a976eb0..e4ef701 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysIndexController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysIndexController.java @@ -1,22 +1,32 @@ package com.cmvr.web.controller.system; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.cmvr.common.config.CmvrIotConfig; +import com.cmvr.common.core.domain.AjaxResult; +import com.cmvr.common.core.domain.entity.SysUser; +import com.cmvr.common.utils.SecurityUtils; import com.cmvr.common.utils.StringUtils; +import com.cmvr.system.service.ISysUserService; /** * 首页 * - * @author cmvr-iot + * @author ruoyi */ @RestController public class SysIndexController { /** 系统基础配置 */ @Autowired - private CmvrIotConfig cmvrIotConfig; + private CmvrIotConfig ruoyiConfig; + + @Autowired + private ISysUserService userService; /** * 访问首页,提示语 @@ -24,6 +34,31 @@ public class SysIndexController @RequestMapping("/") public String index() { - return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", cmvrIotConfig.getName(), cmvrIotConfig.getVersion()); + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); + } + + /** + * 解锁屏幕 + */ + @PostMapping("/unlockscreen") + public AjaxResult unlockScreen(@RequestBody Map body) + { + String password = body.get("password"); + if (StringUtils.isEmpty(password)) + { + return AjaxResult.error("密码不能为空"); + } + String username = SecurityUtils.getUsername(); + SysUser user = userService.selectUserByUserName(username); + if (user == null) + { + return AjaxResult.error("服务器超时,请重新登录"); + } + if (!SecurityUtils.matchesPassword(password, user.getPassword())) + { + return AjaxResult.error("密码错误,请重新输入"); + } + + return AjaxResult.success("解锁成功"); } } diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysLoginController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysLoginController.java index ab57624..2e8dbfe 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysLoginController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysLoginController.java @@ -1,10 +1,8 @@ package com.cmvr.web.controller.system; +import java.util.Date; import java.util.List; import java.util.Set; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -16,18 +14,21 @@ import com.cmvr.common.core.domain.entity.SysMenu; import com.cmvr.common.core.domain.entity.SysUser; import com.cmvr.common.core.domain.model.LoginBody; import com.cmvr.common.core.domain.model.LoginUser; +import com.cmvr.common.core.text.Convert; +import com.cmvr.common.utils.DateUtils; import com.cmvr.common.utils.SecurityUtils; +import com.cmvr.common.utils.StringUtils; import com.cmvr.framework.web.service.SysLoginService; import com.cmvr.framework.web.service.SysPermissionService; import com.cmvr.framework.web.service.TokenService; +import com.cmvr.system.service.ISysConfigService; import com.cmvr.system.service.ISysMenuService; /** * 登录验证 * - * @author cmvr-iot + * @author ruoyi */ -@Api(tags = "通用--登录验证") @RestController public class SysLoginController { @@ -43,13 +44,15 @@ public class SysLoginController @Autowired private TokenService tokenService; + @Autowired + private ISysConfigService configService; + /** * 登录方法 * * @param loginBody 登录信息 * @return 结果 */ - @ApiOperation("登录") @PostMapping("/login") public AjaxResult login(@RequestBody LoginBody loginBody) { @@ -84,6 +87,9 @@ public class SysLoginController ajax.put("user", user); ajax.put("roles", roles); ajax.put("permissions", permissions); + ajax.put("pwdChrtype", getSysAccountChrtype()); + ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate())); + ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate())); return ajax; } @@ -99,4 +105,34 @@ public class SysLoginController List menus = menuService.selectMenuTreeByUserId(userId); return AjaxResult.success(menuService.buildMenus(menus)); } + + // 获取用户密码自定义配置规则 + public String getSysAccountChrtype() + { + return Convert.toStr(configService.selectConfigByKey("sys.account.chrtype"), "0"); + } + + // 检查初始密码是否提醒修改 + public boolean initPasswordIsModify(Date pwdUpdateDate) + { + Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify")); + return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null; + } + + // 检查密码是否过期 + public boolean passwordIsExpiration(Date pwdUpdateDate) + { + Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays")); + if (passwordValidateDays != null && passwordValidateDays > 0) + { + if (StringUtils.isNull(pwdUpdateDate)) + { + // 如果从未修改过初始密码,直接提醒过期 + return true; + } + Date nowDate = DateUtils.getNowDate(); + return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays; + } + return false; + } } diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysMenuController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysMenuController.java index a503820..8402d1a 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysMenuController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysMenuController.java @@ -1,6 +1,7 @@ package com.cmvr.web.controller.system; import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -24,7 +25,7 @@ import com.cmvr.system.service.ISysMenuService; /** * 菜单信息 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/menu") @@ -93,6 +94,10 @@ public class SysMenuController extends BaseController { return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); } + else if (!menuService.checkRouteConfigUnique(menu)) + { + return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); + } menu.setCreateBy(getUsername()); return toAjax(menuService.insertMenu(menu)); } @@ -117,10 +122,28 @@ public class SysMenuController extends BaseController { return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); } + else if (!menuService.checkRouteConfigUnique(menu)) + { + return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在"); + } menu.setUpdateBy(getUsername()); return toAjax(menuService.updateMenu(menu)); } + /** + * 保存菜单排序 + */ + @PreAuthorize("@ss.hasPermi('system:menu:edit')") + @Log(title = "保存菜单排序", businessType = BusinessType.UPDATE) + @PutMapping("/updateSort") + public AjaxResult updateSort(@RequestBody Map params) + { + String[] menuIds = params.get("menuIds").split(","); + String[] orderNums = params.get("orderNums").split(","); + menuService.updateMenuSort(menuIds, orderNums); + return success(); + } + /** * 删除菜单 */ @@ -139,4 +162,4 @@ public class SysMenuController extends BaseController } return toAjax(menuService.deleteMenuById(menuId)); } -} +} \ No newline at end of file diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysNoticeController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysNoticeController.java index d9d22a4..c45453a 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysNoticeController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysNoticeController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.cmvr.common.annotation.Log; import com.cmvr.common.core.controller.BaseController; @@ -18,12 +19,11 @@ import com.cmvr.common.core.domain.AjaxResult; import com.cmvr.common.core.page.TableDataInfo; import com.cmvr.common.enums.BusinessType; import com.cmvr.system.domain.SysNotice; +import com.cmvr.system.domain.SysNoticeRead; import com.cmvr.system.service.ISysNoticeService; /** - * 公告 信息操作处理 - * - * @author cmvr-iot + * 公告信息操作处理。 */ @RestController @RequestMapping("/system/notice") @@ -32,9 +32,6 @@ public class SysNoticeController extends BaseController @Autowired private ISysNoticeService noticeService; - /** - * 获取通知公告列表 - */ @PreAuthorize("@ss.hasPermi('system:notice:list')") @GetMapping("/list") public TableDataInfo list(SysNotice notice) @@ -44,9 +41,37 @@ public class SysNoticeController extends BaseController return getDataTable(list); } - /** - * 根据通知公告编号获取详细信息 - */ + @GetMapping("/listTop") + public AjaxResult listTop() + { + Long userId = getUserId(); + AjaxResult result = success(noticeService.selectNoticeTop(userId)); + result.put("unreadCount", noticeService.countUnreadNotice(userId)); + return result; + } + + @PostMapping("/markRead") + public AjaxResult markRead(@RequestParam Long noticeId) + { + noticeService.markNoticeRead(noticeId, getUserId()); + return success(); + } + + @PostMapping("/markReadAll") + public AjaxResult markReadAll(@RequestParam Long[] ids) + { + noticeService.markNoticeReadAll(ids, getUserId()); + return success(); + } + + @PreAuthorize("@ss.hasPermi('system:notice:list')") + @GetMapping("/readUsers/list") + public TableDataInfo readUsers(SysNoticeRead noticeRead) + { + startPage(); + return getDataTable(noticeService.selectNoticeReadUsers(noticeRead)); + } + @PreAuthorize("@ss.hasPermi('system:notice:query')") @GetMapping(value = "/{noticeId}") public AjaxResult getInfo(@PathVariable Long noticeId) @@ -54,9 +79,6 @@ public class SysNoticeController extends BaseController return success(noticeService.selectNoticeById(noticeId)); } - /** - * 新增通知公告 - */ @PreAuthorize("@ss.hasPermi('system:notice:add')") @Log(title = "通知公告", businessType = BusinessType.INSERT) @PostMapping @@ -66,9 +88,6 @@ public class SysNoticeController extends BaseController return toAjax(noticeService.insertNotice(notice)); } - /** - * 修改通知公告 - */ @PreAuthorize("@ss.hasPermi('system:notice:edit')") @Log(title = "通知公告", businessType = BusinessType.UPDATE) @PutMapping @@ -78,9 +97,6 @@ public class SysNoticeController extends BaseController return toAjax(noticeService.updateNotice(notice)); } - /** - * 删除通知公告 - */ @PreAuthorize("@ss.hasPermi('system:notice:remove')") @Log(title = "通知公告", businessType = BusinessType.DELETE) @DeleteMapping("/{noticeIds}") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysPostController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysPostController.java index bbb53bf..69cf05f 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysPostController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysPostController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.system; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -25,7 +25,7 @@ import com.cmvr.system.service.ISysPostService; /** * 岗位信息操作处理 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/post") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysProfileController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysProfileController.java index 2a77b9a..cd4f93c 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysProfileController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysProfileController.java @@ -17,9 +17,11 @@ import com.cmvr.common.core.domain.AjaxResult; import com.cmvr.common.core.domain.entity.SysUser; import com.cmvr.common.core.domain.model.LoginUser; import com.cmvr.common.enums.BusinessType; +import com.cmvr.common.utils.DateUtils; import com.cmvr.common.utils.SecurityUtils; import com.cmvr.common.utils.StringUtils; import com.cmvr.common.utils.file.FileUploadUtils; +import com.cmvr.common.utils.file.FileUtils; import com.cmvr.common.utils.file.MimeTypeUtils; import com.cmvr.framework.web.service.TokenService; import com.cmvr.system.service.ISysUserService; @@ -27,7 +29,7 @@ import com.cmvr.system.service.ISysUserService; /** * 个人信息 业务处理 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/user/profile") @@ -93,8 +95,9 @@ public class SysProfileController extends BaseController String oldPassword = params.get("oldPassword"); String newPassword = params.get("newPassword"); LoginUser loginUser = getLoginUser(); - String userName = loginUser.getUsername(); - String password = loginUser.getPassword(); + Long userId = loginUser.getUserId(); + SysUser user = userService.selectUserById(userId); + String password = user.getPassword(); if (!SecurityUtils.matchesPassword(oldPassword, password)) { return error("修改密码失败,旧密码错误"); @@ -104,9 +107,10 @@ public class SysProfileController extends BaseController return error("新密码不能与旧密码相同"); } newPassword = SecurityUtils.encryptPassword(newPassword); - if (userService.resetUserPwd(userName, newPassword) > 0) + if (userService.resetUserPwd(userId, newPassword) > 0) { - // 更新缓存用户密码 + // 更新缓存用户密码&密码最后更新时间 + loginUser.getUser().setPwdUpdateDate(DateUtils.getNowDate()); loginUser.getUser().setPassword(newPassword); tokenService.setLoginUser(loginUser); return success(); @@ -124,9 +128,14 @@ public class SysProfileController extends BaseController if (!file.isEmpty()) { LoginUser loginUser = getLoginUser(); - String avatar = FileUploadUtils.upload(CmvrIotConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); - if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) + String avatar = FileUploadUtils.upload(CmvrIotConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true); + if (userService.updateUserAvatar(loginUser.getUserId(), avatar)) { + String oldAvatar = loginUser.getUser().getAvatar(); + if (StringUtils.isNotEmpty(oldAvatar)) + { + FileUtils.deleteFile(CmvrIotConfig.getProfile() + FileUtils.stripPrefix(oldAvatar)); + } AjaxResult ajax = AjaxResult.success(); ajax.put("imgUrl", avatar); // 更新缓存用户头像 diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRegisterController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRegisterController.java index f1d887c..9ab8f7d 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRegisterController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRegisterController.java @@ -14,7 +14,7 @@ import com.cmvr.system.service.ISysConfigService; /** * 注册验证 * - * @author cmvr-iot + * @author ruoyi */ @RestController public class SysRegisterController extends BaseController diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRoleController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRoleController.java index b17e905..fad7532 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRoleController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysRoleController.java @@ -1,7 +1,7 @@ package com.cmvr.web.controller.system; import java.util.List; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -19,10 +19,8 @@ import com.cmvr.common.core.domain.AjaxResult; import com.cmvr.common.core.domain.entity.SysDept; import com.cmvr.common.core.domain.entity.SysRole; import com.cmvr.common.core.domain.entity.SysUser; -import com.cmvr.common.core.domain.model.LoginUser; import com.cmvr.common.core.page.TableDataInfo; import com.cmvr.common.enums.BusinessType; -import com.cmvr.common.utils.StringUtils; import com.cmvr.common.utils.poi.ExcelUtil; import com.cmvr.framework.web.service.SysPermissionService; import com.cmvr.framework.web.service.TokenService; @@ -34,7 +32,7 @@ import com.cmvr.system.service.ISysUserService; /** * 角色信息 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/role") @@ -128,14 +126,8 @@ public class SysRoleController extends BaseController if (roleService.updateRole(role) > 0) { - // 更新缓存用户权限 - LoginUser loginUser = getLoginUser(); - if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) - { - loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); - loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser())); - tokenService.setLoginUser(loginUser); - } + // 刷新所有持有该角色的在线用户权限 + tokenService.refreshPermissionByRoleId(role.getRoleId(), permissionService); return success(); } return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysUserController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysUserController.java index d82ce46..fe7db0e 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysUserController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/system/SysUserController.java @@ -2,7 +2,7 @@ package com.cmvr.web.controller.system; import java.util.List; import java.util.stream.Collectors; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -35,7 +35,7 @@ import com.cmvr.system.service.ISysUserService; /** * 用户信息 * - * @author cmvr-iot + * @author ruoyi */ @RestController @RequestMapping("/system/user") @@ -111,7 +111,7 @@ public class SysUserController extends BaseController ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); } List roles = roleService.selectRoleAll(); - ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); ajax.put("posts", postService.selectPostAll()); return ajax; } @@ -226,7 +226,7 @@ public class SysUserController extends BaseController SysUser user = userService.selectUserById(userId); List roles = roleService.selectRolesByUserId(userId); ajax.put("user", user); - ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); return ajax; } diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeDetectionItemController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeDetectionItemController.java index 81c9b5f..3c4a12a 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeDetectionItemController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeDetectionItemController.java @@ -15,7 +15,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.util.List; @Api(tags = "测试--检测项配置") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeFlowController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeFlowController.java index c43afe5..a1c46a7 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeFlowController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeFlowController.java @@ -30,8 +30,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.PreDestroy; -import javax.validation.Valid; +import jakarta.annotation.PreDestroy; +import jakarta.validation.Valid; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CancellationException; diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeTaskOrchestrationController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeTaskOrchestrationController.java index 5b35739..087674d 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeTaskOrchestrationController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/test/TeTaskOrchestrationController.java @@ -14,8 +14,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; import java.util.List; @Api(tags = "测试--任务编排") diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/CorpusInfoController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/CorpusInfoController.java index 54d23aa..4c58eaa 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/CorpusInfoController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/CorpusInfoController.java @@ -15,7 +15,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.util.Map; /** diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/TtsSynthesizeTaskController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/TtsSynthesizeTaskController.java index d144a83..7449952 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/TtsSynthesizeTaskController.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/tts/TtsSynthesizeTaskController.java @@ -18,7 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import java.util.List; /** diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/OpenApiConfig.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/OpenApiConfig.java new file mode 100644 index 0000000..139d788 --- /dev/null +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/OpenApiConfig.java @@ -0,0 +1,207 @@ +package com.cmvr.web.core.config; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; +import org.springdoc.core.models.GroupedOpenApi; +import org.springdoc.core.customizers.OpenApiCustomizer; +import org.springdoc.core.customizers.OperationCustomizer; +import org.springdoc.core.customizers.PropertyCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.MethodParameter; +import org.springframework.util.StringUtils; +import org.springframework.web.method.HandlerMethod; + +/** OpenAPI metadata, authorization and business-domain groups. */ +@Configuration +public class OpenApiConfig +{ + private static final String AUTHORIZATION = "Authorization"; + + @Bean + public OpenAPI cmvrOpenApi() + { + SecurityScheme bearerAuth = new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT"); + return new OpenAPI() + .info(new Info() + .title("CMVR IoT API") + .description("招商车研物联网平台接口文档") + .version("1.0.0")) + .components(new Components().addSecuritySchemes(AUTHORIZATION, bearerAuth)) + .addSecurityItem(new SecurityRequirement().addList(AUTHORIZATION)); + } + + @Bean + public GroupedOpenApi allApi() + { + return group("00-all", "全部接口", "/**"); + } + + private GroupedOpenApi group(String id, String displayName, String... paths) + { + return GroupedOpenApi.builder() + .group(id) + .displayName(displayName) + .pathsToMatch(paths) + // Keep the same visibility rule as the legacy Swagger Docket. + .addOpenApiMethodFilter(method -> method.isAnnotationPresent(ApiOperation.class)) + .addOperationCustomizer(legacySwaggerOperationCustomizer()) + .addOpenApiCustomizer(legacyTagOrderCustomizer()) + .build(); + } + + private OpenApiCustomizer legacyTagOrderCustomizer() + { + return openApi -> { + Set tagNames = new TreeSet<>(); + if (openApi.getPaths() != null) + { + openApi.getPaths().values().forEach(pathItem -> pathItem.readOperations().forEach(operation -> { + if (operation.getTags() != null) + { + tagNames.addAll(operation.getTags()); + } + })); + } + openApi.setTags(tagNames.stream() + .map(name -> new io.swagger.v3.oas.models.tags.Tag().name(name)) + .collect(Collectors.toList())); + }; + } + + @Bean + public OperationCustomizer legacySwaggerOperationCustomizer() + { + return this::customizeLegacyOperation; + } + + @Bean + public PropertyCustomizer legacySwaggerPropertyCustomizer() + { + return (schema, annotatedType) -> { + ApiModelProperty property = findAnnotation(annotatedType, ApiModelProperty.class); + if (property != null) + { + if (StringUtils.hasText(property.value())) + { + schema.setDescription(property.value()); + } + if (StringUtils.hasText(property.example())) + { + schema.setExample(property.example()); + } + } + return schema; + }; + } + + private Operation customizeLegacyOperation(Operation operation, HandlerMethod handlerMethod) + { + Api api = handlerMethod.getBeanType().getAnnotation(Api.class); + if (api != null) + { + List tags = Arrays.stream(api.tags()) + .filter(StringUtils::hasText) + .collect(Collectors.toList()); + if (tags.isEmpty() && StringUtils.hasText(api.value())) + { + tags.add(api.value()); + } + if (!tags.isEmpty()) + { + operation.setTags(tags); + } + } + + ApiOperation apiOperation = handlerMethod.getMethodAnnotation(ApiOperation.class); + if (apiOperation != null) + { + if (StringUtils.hasText(apiOperation.value())) + { + operation.setSummary(apiOperation.value()); + } + if (StringUtils.hasText(apiOperation.notes())) + { + operation.setDescription(apiOperation.notes()); + } + } + applyLegacyParameterDescriptions(operation, handlerMethod); + return operation; + } + + private void applyLegacyParameterDescriptions(Operation operation, HandlerMethod handlerMethod) + { + if (operation.getParameters() == null || operation.getParameters().isEmpty()) + { + return; + } + List parameters = operation.getParameters(); + int fallbackIndex = 0; + for (MethodParameter methodParameter : handlerMethod.getMethodParameters()) + { + ApiParam apiParam = methodParameter.getParameterAnnotation(ApiParam.class); + if (apiParam == null) + { + continue; + } + String parameterName = StringUtils.hasText(apiParam.name()) + ? apiParam.name() : methodParameter.getParameterName(); + Parameter parameter = parameters.stream() + .filter(item -> parameterName != null && parameterName.equals(item.getName())) + .findFirst() + .orElse(fallbackIndex < parameters.size() ? parameters.get(fallbackIndex++) : null); + if (parameter != null) + { + if (StringUtils.hasText(apiParam.value())) + { + parameter.setDescription(apiParam.value()); + } + if (apiParam.required()) + { + parameter.setRequired(true); + } + if (StringUtils.hasText(apiParam.example())) + { + parameter.setExample(apiParam.example()); + } + } + } + } + + private A findAnnotation(AnnotatedType annotatedType, Class annotationType) + { + Annotation[] annotations = annotatedType.getCtxAnnotations(); + if (annotations == null) + { + return null; + } + for (Annotation annotation : annotations) + { + if (annotationType.isInstance(annotation)) + { + return annotationType.cast(annotation); + } + } + return null; + } +} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/SwaggerConfig.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/SwaggerConfig.java deleted file mode 100644 index 2ffc7f0..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/SwaggerConfig.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.cmvr.web.core.config; - -import java.util.ArrayList; -import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import com.cmvr.common.config.CmvrIotConfig; -import com.cmvr.test.model.vo.inspection.InspectionAlarmRuleVO; -import com.cmvr.test.model.vo.inspection.InspectionManualReviewConfigVO; -import com.cmvr.test.model.vo.inspection.InspectionMediaVO; -import com.cmvr.test.model.vo.inspection.InspectionMeterRecognizeConfigVO; -import com.fasterxml.classmate.TypeResolver; -import io.swagger.annotations.ApiOperation; -import io.swagger.models.auth.In; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.service.ApiKey; -import springfox.documentation.service.AuthorizationScope; -import springfox.documentation.service.Contact; -import springfox.documentation.service.SecurityReference; -import springfox.documentation.service.SecurityScheme; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.contexts.SecurityContext; -import springfox.documentation.spring.web.plugins.Docket; - -/** - * Swagger2的接口配置 - * - * @author cmvr-iot - */ -@Configuration -public class SwaggerConfig -{ - /** 系统基础配置 */ - @Autowired - private CmvrIotConfig cmvrIotConfig; - - /** 用于将动态工作流payload对应的参数模型显式加入Swagger文档。 */ - @Autowired - private TypeResolver typeResolver; - - /** 是否开启swagger */ - @Value("${swagger.enabled}") - private boolean enabled; - - /** 设置请求的统一前缀 */ - @Value("${swagger.pathMapping}") - private String pathMapping; - - /** - * 创建API - */ - @Bean - public Docket createRestApi() - { - return new Docket(DocumentationType.OAS_30) - // 是否启用Swagger - .enable(enabled) - // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) - .apiInfo(apiInfo()) - // 设置哪些接口暴露给Swagger展示 - .select() - // 扫描所有有注解的api,用这种方式更灵活 - .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) - // 扫描指定包中的swagger注解 -// .apis(RequestHandlerSelectors.basePackage("com.cmvr.project.tool.swagger")) - // 扫描所有 .apis(RequestHandlerSelectors.any()) - .paths(PathSelectors.any()) - .build() - // 工作流单节点接口使用JSONObject作为payload,需显式注册巡检节点参数模型。 - .additionalModels( - typeResolver.resolve(InspectionMeterRecognizeConfigVO.class), - typeResolver.resolve(InspectionAlarmRuleVO.class), - typeResolver.resolve(InspectionManualReviewConfigVO.class), - typeResolver.resolve(InspectionMediaVO.class)) - /* 设置安全模式,swagger可以设置访问token */ - .securitySchemes(securitySchemes()) - .securityContexts(securityContexts()) - .pathMapping(pathMapping); - } - - /** - * 安全模式,这里指定token通过Authorization头请求头传递 - */ - private List securitySchemes() - { - List apiKeyList = new ArrayList(); - apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); - return apiKeyList; - } - - /** - * 安全上下文 - */ - private List securityContexts() - { - List securityContexts = new ArrayList<>(); - securityContexts.add( - SecurityContext.builder() - .securityReferences(defaultAuth()) - .operationSelector(o -> o.requestMappingPattern().matches("/.*")) - .build()); - return securityContexts; - } - - /** - * 默认的安全上引用 - */ - private List defaultAuth() - { - AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); - AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; - authorizationScopes[0] = authorizationScope; - List securityReferences = new ArrayList<>(); - securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); - return securityReferences; - } - - /** - * 添加摘要信息 - */ - private ApiInfo apiInfo() - { - // 用ApiInfoBuilder进行定制 - return new ApiInfoBuilder() - // 设置标题 - .title("标题:招商车研物联网平台管理系统_接口文档") - // 描述 - .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") - // 作者信息 - .contact(new Contact(cmvrIotConfig.getName(), null, null)) - // 版本 - .version("版本号:" + cmvrIotConfig.getVersion()) - .build(); - } -} diff --git a/cmvr-iot-admin/src/main/resources/application-dev.yml b/cmvr-iot-admin/src/main/resources/application-dev.yml index d2b704f..a48f8d4 100644 --- a/cmvr-iot-admin/src/main/resources/application-dev.yml +++ b/cmvr-iot-admin/src/main/resources/application-dev.yml @@ -68,7 +68,7 @@ spring: # 热部署开关 enabled: true # redis 配置 - redis: + data.redis: # 地址 host: 192.168.28.10 # 端口,默认为6379 @@ -136,4 +136,4 @@ flowise: # TTS外部接口配置 tts: external-api: - url: http://192.168.0.102:9003/generate_advanced_audio \ No newline at end of file + url: http://192.168.0.102:9003/generate_advanced_audio diff --git a/cmvr-iot-admin/src/main/resources/application-devbak.yml b/cmvr-iot-admin/src/main/resources/application-devbak.yml index 6ffa547..2cb75c4 100644 --- a/cmvr-iot-admin/src/main/resources/application-devbak.yml +++ b/cmvr-iot-admin/src/main/resources/application-devbak.yml @@ -68,7 +68,7 @@ spring: # 热部署开关 enabled: true # redis 配置 - redis: + data.redis: # 地址 host: 192.168.0.100 # 端口,默认为6379 @@ -131,4 +131,4 @@ flowise: start: http://192.168.0.108:3000/api/v1/prediction/f99329e9-b33d-437d-90ed-69eaa8a05418 abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/ query: http://192.168.0.108:3000/api/v1/executions/ - api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg \ No newline at end of file + api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg diff --git a/cmvr-iot-admin/src/main/resources/application-druid.yml b/cmvr-iot-admin/src/main/resources/application-druid.yml new file mode 100644 index 0000000..426a48a --- /dev/null +++ b/cmvr-iot-admin/src/main/resources/application-druid.yml @@ -0,0 +1,61 @@ +# 数据源配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + druid: + # 主库数据源 + master: + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root + password: password + # 从库数据源 + slave: + # 从数据源开关/默认关闭 + enabled: false + url: + username: + password: + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置连接超时时间 + connectTimeout: 30000 + # 配置网络超时时间 + socketTimeout: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + login-username: ruoyi + login-password: 123456 + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true \ No newline at end of file diff --git a/cmvr-iot-admin/src/main/resources/application-prod.yml b/cmvr-iot-admin/src/main/resources/application-prod.yml index 0ddd66d..83386b1 100644 --- a/cmvr-iot-admin/src/main/resources/application-prod.yml +++ b/cmvr-iot-admin/src/main/resources/application-prod.yml @@ -68,7 +68,7 @@ spring: # 热部署开关 enabled: true # redis 配置 - redis: + data.redis: # 地址 host: 192.168.28.10 # 端口,默认为6379 @@ -131,4 +131,4 @@ flowise: start: http://192.168.0.108:3000/api/v1/prediction/f99329e9-b33d-437d-90ed-69eaa8a05418 abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/ query: http://192.168.0.108:3000/api/v1/executions/ - api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg \ No newline at end of file + api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg diff --git a/cmvr-iot-admin/src/main/resources/application-prodbak.yml b/cmvr-iot-admin/src/main/resources/application-prodbak.yml index 0bc1cd7..f4ac900 100644 --- a/cmvr-iot-admin/src/main/resources/application-prodbak.yml +++ b/cmvr-iot-admin/src/main/resources/application-prodbak.yml @@ -68,7 +68,7 @@ spring: # 热部署开关 enabled: true # redis 配置 - redis: + data.redis: # 地址 host: redis # 端口,默认为6379 diff --git a/cmvr-iot-admin/src/main/resources/application-test.yml b/cmvr-iot-admin/src/main/resources/application-test.yml index 0ddd66d..83386b1 100644 --- a/cmvr-iot-admin/src/main/resources/application-test.yml +++ b/cmvr-iot-admin/src/main/resources/application-test.yml @@ -68,7 +68,7 @@ spring: # 热部署开关 enabled: true # redis 配置 - redis: + data.redis: # 地址 host: 192.168.28.10 # 端口,默认为6379 @@ -131,4 +131,4 @@ flowise: start: http://192.168.0.108:3000/api/v1/prediction/f99329e9-b33d-437d-90ed-69eaa8a05418 abort: http://192.168.0.108:3000/api/v1/chatmessage/abort/f99329e9-b33d-437d-90ed-69eaa8a05418/ query: http://192.168.0.108:3000/api/v1/executions/ - api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg \ No newline at end of file + api-key: pg61JW6W_GXyqmqSoURJ4mlSRrCMRzGLBJli_w3BFkg diff --git a/cmvr-iot-admin/src/main/resources/application.yml b/cmvr-iot-admin/src/main/resources/application.yml index a8f4a30..431a92d 100644 --- a/cmvr-iot-admin/src/main/resources/application.yml +++ b/cmvr-iot-admin/src/main/resources/application.yml @@ -48,6 +48,10 @@ user: # Spring配置 spring: + sql: + init: + mode: always + schema-locations: classpath:db/notice-schema.sql # 资源信息 messages: # 国际化资源文件路径 @@ -99,13 +103,15 @@ swagger: # 请求前缀 pathMapping: / knife4j: - # 开启屏蔽文档资源 + # 生产环境可开启屏蔽文档资源 production: false - # 是否开启Knife4j(swagger 增强版) + # 是否开启Knife4j增强界面 enable: true setting: language: zh-CN enableRequestCache: true + enableSwaggerModels: true + swaggerModelName: 数据模型 # 防止XSS攻击 xss: @@ -116,4 +122,34 @@ xss: # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/*,/device/*,/test/*,/api/* +# Integrated QUIC gateway and in-process node synchronization. +cmvr: + quic: + enabled: true + bind-host: 0.0.0.0 + port: 4433 + grpc-host-source: observed-source + alpn: cmvr-quic-edge/1 + allowed-node-ids: "" + tls: + certificate: "certs/quic-gateway.crt" + private-key: "certs/quic-gateway.key" + require-client-certificate: false + client-ca: "" + heartbeat-interval-ms: 5000 + heartbeat-timeout-ms: 15000 + idle-timeout-ms: 30000 + maximum-control-frame-bytes: 1048576 + datagram-queue-length: 1024 + maximum-frame-bytes: 8388608 + maximum-reassembly-bytes: 67108864 + maximum-reassembly-frames: 256 + reassembly-timeout-ms: 2000 + media-subscriber-queue-capacity: 64 +springdoc: + api-docs: + path: /v3/api-docs + swagger-ui: + enabled: true + path: /swagger-ui.html diff --git a/cmvr-iot-admin/src/main/resources/db/notice-schema.sql b/cmvr-iot-admin/src/main/resources/db/notice-schema.sql new file mode 100644 index 0000000..1b64fdf --- /dev/null +++ b/cmvr-iot-admin/src/main/resources/db/notice-schema.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS sys_notice_read ( + read_id BIGINT NOT NULL AUTO_INCREMENT, + notice_id INT NOT NULL, + user_id BIGINT NOT NULL, + read_time DATETIME NOT NULL, + PRIMARY KEY (read_id), + UNIQUE KEY uk_user_notice (user_id, notice_id), + KEY idx_notice_id (notice_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Notice read records'; diff --git a/cmvr-iot-aima/pom.xml b/cmvr-iot-aima/pom.xml index 93a13e6..f0ea957 100644 --- a/cmvr-iot-aima/pom.xml +++ b/cmvr-iot-aima/pom.xml @@ -6,7 +6,7 @@ com.cmvr cmvr-iot - 3.8.9 + 3.9.2 cmvr-iot-aima diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/IAimaTaskInstanceService.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/IAimaTaskInstanceService.java index 18ab065..13d6bc8 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/IAimaTaskInstanceService.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/IAimaTaskInstanceService.java @@ -2,7 +2,7 @@ package com.cmvr.aima.service; import java.util.List; -import com.baomidou.mybatisplus.extension.service.IService; +import com.baomidou.mybatisplus.spring.service.IService; import com.cmvr.aima.domain.AimaTaskInstance; import com.cmvr.aima.domain.dto.AimaTaskInstanceQuery; import com.cmvr.aima.domain.vo.AimaTaskInstanceVo; diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaAlarmServiceImpl.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaAlarmServiceImpl.java index 8c6d5a4..4b888cc 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaAlarmServiceImpl.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaAlarmServiceImpl.java @@ -2,7 +2,7 @@ package com.cmvr.aima.service.impl; import java.util.List; import java.util.UUID; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.cmvr.common.utils.DateUtils; diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaPhoneServiceImpl.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaPhoneServiceImpl.java index 78bd1e7..c434e89 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaPhoneServiceImpl.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaPhoneServiceImpl.java @@ -2,7 +2,7 @@ package com.cmvr.aima.service.impl; import java.util.List; import java.util.UUID; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.cmvr.common.utils.DateUtils; diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskInstanceServiceImpl.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskInstanceServiceImpl.java index 1b44478..7021296 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskInstanceServiceImpl.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskInstanceServiceImpl.java @@ -3,7 +3,7 @@ package com.cmvr.aima.service.impl; import java.util.List; import java.util.UUID; import com.alibaba.fastjson2.JSONObject; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import com.cmvr.aima.domain.dto.AimaTaskInstanceQuery; import com.cmvr.aima.domain.vo.AimaTaskInstanceVo; import com.cmvr.common.exception.ServiceException; diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskServiceImpl.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskServiceImpl.java index 7343db8..110d74e 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskServiceImpl.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTaskServiceImpl.java @@ -7,7 +7,7 @@ import java.util.UUID; import java.util.stream.Collectors; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import com.cmvr.aima.domain.AimaTaskTestCase; import com.cmvr.aima.domain.AimaTestCase; import com.cmvr.aima.domain.vo.AimaTaskVo; diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestCaseServiceImpl.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestCaseServiceImpl.java index 022de12..9ea72ff 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestCaseServiceImpl.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestCaseServiceImpl.java @@ -2,7 +2,7 @@ package com.cmvr.aima.service.impl; import java.util.List; import java.util.UUID; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import com.cmvr.aima.domain.vo.AimaTestCaseVo; import com.cmvr.test.model.domain.TeDetectionItem; import com.cmvr.test.service.ITeDetectionItemService; diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestLogServiceImpl.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestLogServiceImpl.java index 250f0b7..3107918 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestLogServiceImpl.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaTestLogServiceImpl.java @@ -2,7 +2,7 @@ package com.cmvr.aima.service.impl; import java.util.List; import java.util.UUID; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.cmvr.common.utils.DateUtils; diff --git a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaVehicleServiceImpl.java b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaVehicleServiceImpl.java index f9e9ae0..6f95c0d 100644 --- a/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaVehicleServiceImpl.java +++ b/cmvr-iot-aima/src/main/java/com/cmvr/aima/service/impl/AimaVehicleServiceImpl.java @@ -2,7 +2,7 @@ package com.cmvr.aima.service.impl; import java.util.List; import java.util.UUID; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.cmvr.common.utils.DateUtils; diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/pom.xml b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/pom.xml index 0ef6f9f..0d87ffb 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/pom.xml +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/pom.xml @@ -6,27 +6,30 @@ com.cmvr cmvr-iot-edge - 3.8.9 + 3.9.2 cmvr-iot-grpc-client cmvr-iot gRPC客户端 + + com.cmvr + cmvr-iot-quic-contract + com.cmvr cmvr-iot-grpc-lib - net.devh - grpc-client-spring-boot-starter - ${grpc-client.version} + io.grpc + grpc-netty-shaded com.google.protobuf protobuf-java - 3.25.5 + ${protobuf.version} diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/adapter/RobotAudioGrpcAdapter.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/adapter/RobotAudioGrpcAdapter.java index ab20267..0215f25 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/adapter/RobotAudioGrpcAdapter.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/adapter/RobotAudioGrpcAdapter.java @@ -17,7 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; -import javax.annotation.PreDestroy; +import jakarta.annotation.PreDestroy; import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentHashMap; diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcChannelCache.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcChannelCache.java index 01b0f5d..af264c1 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcChannelCache.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcChannelCache.java @@ -49,6 +49,17 @@ public class GrpcChannelCache { }); } + /** + * 终端主动上报的gRPC地址发生变化时立即关闭旧通道。 + * 下一次业务调用仍通过原有supplier创建ManagedChannel。 + */ + public void invalidate(String terminalId) { + ChannelWrapper wrapper = channelMap.remove(terminalId); + if (wrapper != null) { + wrapper.close(); + } + } + /** * 通道包装器(管理通道生命周期和访问时间) */ @@ -77,4 +88,4 @@ public class GrpcChannelCache { } } } -} \ No newline at end of file +} diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcServiceManager.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcServiceManager.java index 2ac235a..42d0660 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcServiceManager.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/manage/GrpcServiceManager.java @@ -12,7 +12,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.Map; import java.util.concurrent.*; import java.util.function.Function; @@ -110,6 +110,11 @@ public class GrpcServiceManager { grpcChannelCache.cleanExpiredChannels(); } + /** QUIC发现终端地址变化后,使指定终端的旧gRPC通道立即失效。 */ + public void invalidateTerminal(String terminalId) { + grpcChannelCache.invalidate(terminalId); + } + /** * gRPC客户端工厂类 */ diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/EdgeCommonVO.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/EdgeCommonVO.java index a3771c6..0f35058 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/EdgeCommonVO.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/EdgeCommonVO.java @@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; @Data @ApiModel("边缘系统通用VO") diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvMapNameVO.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvMapNameVO.java index 4099eae..187c178 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvMapNameVO.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvMapNameVO.java @@ -6,7 +6,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; /** * AGV 地图名称请求参数。 diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvNavigateToStationVO.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvNavigateToStationVO.java index 1ab2c78..70c7997 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvNavigateToStationVO.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvNavigateToStationVO.java @@ -6,7 +6,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; /** * AGV 导航到站点的请求参数。 diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvUploadMapVO.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvUploadMapVO.java index 38a079b..400ded4 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvUploadMapVO.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/agv/EdgeAgvUploadMapVO.java @@ -5,7 +5,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; /** * AGV 上传地图请求参数。 diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/arm/EdgeArmCalibrateZeroQVO.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/arm/EdgeArmCalibrateZeroQVO.java index a023803..c163b51 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/arm/EdgeArmCalibrateZeroQVO.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/arm/EdgeArmCalibrateZeroQVO.java @@ -6,7 +6,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; /** * 机械臂标定零点参数。 diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/speaker/EdgeSpeakerPlayAudioVO.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/speaker/EdgeSpeakerPlayAudioVO.java index 1f7e9ff..a370a8a 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/speaker/EdgeSpeakerPlayAudioVO.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/model/speaker/EdgeSpeakerPlayAudioVO.java @@ -5,7 +5,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; /** * 扬声器播放音频请求参数。 diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/quic/QuicGatewayNodeSyncService.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/quic/QuicGatewayNodeSyncService.java new file mode 100644 index 0000000..5ee3cec --- /dev/null +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/quic/QuicGatewayNodeSyncService.java @@ -0,0 +1,224 @@ +package com.cmvr.edge.client.quic; + +import com.cmvr.device.domain.DeDeviceTerminalConfig; +import com.cmvr.device.service.IDeDeviceTerminalConfigService; +import com.cmvr.edge.client.manage.GrpcServiceManager; +import com.cmvr.quic.contract.QuicEventBus; +import com.cmvr.quic.gateway.v1.NodeEvent; +import com.cmvr.quic.gateway.v1.NodeEventType; +import com.cmvr.quic.gateway.v1.NodeSnapshot; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** 直接订阅进程内 QUIC 节点事件,并同步已绑定终端的运行状态和 gRPC 地址。 */ +@Service +@RequiredArgsConstructor +public class QuicGatewayNodeSyncService { + + private static final Logger log = LoggerFactory.getLogger(QuicGatewayNodeSyncService.class); + private static final long HEARTBEAT_PERSIST_INTERVAL_MS = 15000L; + + private final IDeDeviceTerminalConfigService terminalConfigService; + private final GrpcServiceManager grpcServiceManager; + private final QuicEventBus quicEventBus; + + @Value("${cmvr.quic.enabled:false}") + private boolean enabled; + + /** observed-source 使用 QUIC 来源 IP;advertised 使用节点主动上报的 gRPC host。 */ + @Value("${cmvr.quic.grpc-host-source:observed-source}") + private String grpcHostSource; + + private final AtomicBoolean stopping = new AtomicBoolean(false); + private final AtomicBoolean grpcHostSourceWarningLogged = new AtomicBoolean(false); + private final Set unknownNodes = ConcurrentHashMap.newKeySet(); + private final Set grpcAddressMismatchNodes = ConcurrentHashMap.newKeySet(); + private final ConcurrentHashMap lastPersistedAt = new ConcurrentHashMap(); + private final ConcurrentHashMap synchronizedTerminals = + new ConcurrentHashMap(); + private ExecutorService eventExecutor; + private QuicEventBus.Subscription subscription; + + @PostConstruct + public void start() { + if (!enabled) { + log.info("QUIC 节点状态同步未启用"); + return; + } + eventExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable runnable) { + Thread thread = new Thread(runnable, "quic-node-sync"); + thread.setDaemon(true); + return thread; + } + }); + subscription = quicEventBus.watchNodes(true, this::enqueueEvent); + log.info("已通过进程内事件总线订阅 QUIC 节点事件"); + } + + private void enqueueEvent(final NodeEvent event) { + ExecutorService executor = eventExecutor; + if (stopping.get() || executor == null) { + return; + } + try { + executor.execute(new Runnable() { + @Override + public void run() { + handleEventSafely(event); + } + }); + } catch (RejectedExecutionException ignored) { + if (!stopping.get()) { + log.warn("QUIC 节点事件线程已停止,忽略事件,nodeId={}", event.getNode().getNodeId()); + } + } + } + + private void handleEventSafely(NodeEvent event) { + try { + syncNode(event); + } catch (RuntimeException error) { + log.error("同步 QUIC 终端状态失败,nodeId={},eventType={}", + event.getNode().getNodeId(), event.getType(), error); + } + } + + private void syncNode(NodeEvent event) { + NodeSnapshot node = event.getNode(); + if (node.getNodeId().isEmpty()) { + return; + } + DeDeviceTerminalConfig terminal = terminalConfigService.selectByQuicNodeId(node.getNodeId()); + if (terminal == null) { + if (unknownNodes.add(node.getNodeId())) { + log.warn("QUIC 节点尚未绑定平台终端,忽略运行状态同步,nodeId={},remoteIp={}", + node.getNodeId(), node.getObservedSourceIp()); + } + return; + } + unknownNodes.remove(node.getNodeId()); + + boolean offline = event.getType() == NodeEventType.NODE_EVENT_TYPE_OFFLINE || !node.getOnline(); + if (offline) { + synchronizedTerminals.remove(node.getNodeId()); + } else { + synchronizedTerminals.put(node.getNodeId(), terminal.getId()); + } + String grpcHost = offline ? null : resolveGrpcHost(node); + Long grpcPort = offline || node.getGrpcEndpoint().getPort() == 0 + ? null : Long.valueOf(node.getGrpcEndpoint().getPort()); + boolean endpointChanged = !offline && grpcHost != null && grpcPort != null + && (!grpcHost.equals(terminal.getHost()) || !grpcPort.equals(terminal.getPort())); + long now = System.currentTimeMillis(); + Long previousPersisted = lastPersistedAt.get(node.getNodeId()); + boolean immediate = event.getType() == NodeEventType.NODE_EVENT_TYPE_REGISTERED + || event.getType() == NodeEventType.NODE_EVENT_TYPE_OFFLINE || endpointChanged; + if (!immediate && previousPersisted != null + && now - previousPersisted.longValue() < HEARTBEAT_PERSIST_INTERVAL_MS) { + return; + } + + terminalConfigService.updateQuicRuntimeState(terminal.getId(), grpcHost, grpcPort, + node.getObservedSourceIp(), node.getSessionId(), node.getBootId(), + node.getSoftwareVersion(), offline ? "0" : "1", + new Date(event.getEventTimeUnixMs() == 0 ? now : event.getEventTimeUnixMs())); + lastPersistedAt.put(node.getNodeId(), now); + if (offline) { + lastPersistedAt.remove(node.getNodeId()); + } + if (endpointChanged || offline) { + grpcServiceManager.invalidateTerminal(terminal.getId()); + } + log.info("QUIC 终端状态已同步,terminalId={},nodeId={},online={},grpc={}:{}", + terminal.getId(), node.getNodeId(), !offline, + grpcHost == null ? terminal.getHost() : grpcHost, + grpcPort == null ? terminal.getPort() : grpcPort); + } + + private String resolveGrpcHost(NodeSnapshot node) { + String advertisedHost = emptyToNull(node.getGrpcEndpoint().getHost()); + if ("advertised".equalsIgnoreCase(grpcHostSource)) { + return advertisedHost; + } + if (!"observed-source".equalsIgnoreCase(grpcHostSource) + && grpcHostSourceWarningLogged.compareAndSet(false, true)) { + log.warn("未知的 QUIC gRPC 地址来源配置,按 observed-source 处理,value={}", grpcHostSource); + } + String observedHost = emptyToNull(node.getObservedSourceIp()); + if (observedHost == null) { + log.warn("QUIC 节点缺少来源 IP,回退到节点上报地址,nodeId={},advertisedHost={}", + node.getNodeId(), advertisedHost); + return advertisedHost; + } + if (advertisedHost != null && !observedHost.equals(advertisedHost) + && grpcAddressMismatchNodes.add(node.getNodeId())) { + log.info("QUIC 节点上报的 gRPC 地址与来源 IP 不同,使用来源 IP,nodeId={}," + + "observedHost={},advertisedHost={}", + node.getNodeId(), observedHost, advertisedHost); + } else if (observedHost.equals(advertisedHost)) { + grpcAddressMismatchNodes.remove(node.getNodeId()); + } + return observedHost; + } + + private void markSynchronizedTerminalsOffline() { + for (Map.Entry entry : synchronizedTerminals.entrySet()) { + try { + terminalConfigService.updateQuicRuntimeState(entry.getValue(), null, null, + null, null, null, null, "0", new Date()); + grpcServiceManager.invalidateTerminal(entry.getValue()); + } catch (RuntimeException error) { + log.error("标记 QUIC 终端离线失败,nodeId={},terminalId={}", + entry.getKey(), entry.getValue(), error); + } + } + synchronizedTerminals.clear(); + lastPersistedAt.clear(); + } + + private static String emptyToNull(String value) { + return value == null || value.trim().isEmpty() ? null : value.trim(); + } + + @PreDestroy + public void stop() { + if (!stopping.compareAndSet(false, true)) { + return; + } + QuicEventBus.Subscription currentSubscription = subscription; + if (currentSubscription != null) { + currentSubscription.close(); + } + ExecutorService executor = eventExecutor; + if (executor != null) { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException interrupted) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + markSynchronizedTerminalsOffline(); + } +} diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/AudioService.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/AudioService.java index ed7347b..c2cbe20 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/AudioService.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/AudioService.java @@ -4,9 +4,9 @@ import com.cmvr.common.utils.uuid.IdUtils; import com.cmvr.edge.client.adapter.RobotAudioGrpcAdapter; import com.cmvr.edge.client.adapter.RobotAudioGrpcAdapter.RobotAudioStream; import com.cmvr.edge.client.adapter.RobotAudioGrpcAdapter.RobotAudioStreamListener; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/webrtc/WebRtcAudioBridge.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/webrtc/WebRtcAudioBridge.java index 7eb2dd7..cabe5e5 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/webrtc/WebRtcAudioBridge.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/webrtc/WebRtcAudioBridge.java @@ -3,7 +3,7 @@ package com.cmvr.edge.client.webrtc; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.PreDestroy; +import jakarta.annotation.PreDestroy; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/pom.xml b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/pom.xml index b94de6f..6250b77 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/pom.xml +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib/pom.xml @@ -6,7 +6,7 @@ com.cmvr cmvr-iot-edge - 3.8.9 + 3.9.2 cmvr-iot-grpc-lib diff --git a/cmvr-iot-api/cmvr-iot-edge/pom.xml b/cmvr-iot-api/cmvr-iot-edge/pom.xml index 1fb241c..6b5e981 100644 --- a/cmvr-iot-api/cmvr-iot-edge/pom.xml +++ b/cmvr-iot-api/cmvr-iot-edge/pom.xml @@ -6,7 +6,7 @@ com.cmvr cmvr-iot-api - 3.8.9 + 3.9.2 cmvr-iot-edge diff --git a/cmvr-iot-api/cmvr-iot-llm/pom.xml b/cmvr-iot-api/cmvr-iot-llm/pom.xml index 67871a4..27b12a9 100644 --- a/cmvr-iot-api/cmvr-iot-llm/pom.xml +++ b/cmvr-iot-api/cmvr-iot-llm/pom.xml @@ -6,7 +6,7 @@ com.cmvr cmvr-iot-api - 3.8.9 + 3.9.2 cmvr-iot-llm diff --git a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentAdvancedVO.java b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentAdvancedVO.java index e478e18..64e16a5 100644 --- a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentAdvancedVO.java +++ b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentAdvancedVO.java @@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; @Data @ApiModel("智能体调用VO") diff --git a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentVO.java b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentVO.java index 728879d..82b5f14 100644 --- a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentVO.java +++ b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallAgentVO.java @@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; @Data @ApiModel("智能体调用VO") diff --git a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSAdvancedVO.java b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSAdvancedVO.java index 3b7ccdf..582ebd1 100644 --- a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSAdvancedVO.java +++ b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSAdvancedVO.java @@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; @Data @ApiModel("TTS调用VO") diff --git a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSVO.java b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSVO.java index d081a8a..b0c8d4d 100644 --- a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSVO.java +++ b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/model/CallTTSVO.java @@ -4,7 +4,7 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; @Data @ApiModel("TTS调用VO") diff --git a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/LlmChatService.java b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/LlmChatService.java index 8bc7a93..2fc2cb8 100644 --- a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/LlmChatService.java +++ b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/LlmChatService.java @@ -2,13 +2,13 @@ package com.cmvr.llm.util; import com.alibaba.fastjson2.JSONObject; import com.cmvr.llm.service.LLMAiTtsService; -import com.fasterxml.jackson.databind.ObjectMapper; +import tools.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.annotation.PreDestroy; +import jakarta.annotation.PreDestroy; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; diff --git a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/SseChatClient.java b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/SseChatClient.java index 3716e10..e445d20 100644 --- a/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/SseChatClient.java +++ b/cmvr-iot-api/cmvr-iot-llm/src/main/java/com/cmvr/llm/util/SseChatClient.java @@ -1,6 +1,6 @@ package com.cmvr.llm.util; -import com.fasterxml.jackson.databind.ObjectMapper; +import tools.jackson.databind.ObjectMapper; import okhttp3.*; import java.io.BufferedReader; diff --git a/cmvr-iot-api/pom.xml b/cmvr-iot-api/pom.xml index a592b44..07a1813 100644 --- a/cmvr-iot-api/pom.xml +++ b/cmvr-iot-api/pom.xml @@ -6,7 +6,7 @@ com.cmvr cmvr-iot - 3.8.9 + 3.9.2 cmvr-iot-api diff --git a/cmvr-iot-common/pom.xml b/cmvr-iot-common/pom.xml index 696bcf3..402119e 100644 --- a/cmvr-iot-common/pom.xml +++ b/cmvr-iot-common/pom.xml @@ -5,7 +5,7 @@ cmvr-iot com.cmvr - 3.8.9 + 3.9.2 4.0.0 @@ -55,7 +55,7 @@ - com.fasterxml.jackson.core + tools.jackson.core jackson-databind @@ -77,12 +77,6 @@ poi-ooxml - - - org.yaml - snakeyaml - - io.jsonwebtoken @@ -101,6 +95,11 @@ spring-boot-starter-data-redis + + org.springframework.boot + spring-boot-starter-cache + + org.apache.commons @@ -109,51 +108,54 @@ - eu.bitwalker - UserAgentUtils + nl.basjes.parse.useragent + yauaa - javax.servlet - javax.servlet-api + jakarta.servlet + jakarta.servlet-api - com.baomidou - mybatis-plus-boot-starter + mybatis-plus-spring-boot4-starter + + + com.baomidou + mybatis-plus-extension + + + com.baomidou + mybatis-plus-jsqlparser - - com.github.yulichang mybatis-plus-join-boot-starter - - org.projectlombok lombok - - cn.hutool hutool-all - - - - com.github.xiaoymin - knife4j-spring-boot-starter - - - io.minio minio + + org.yaml + snakeyaml + + + io.swagger + swagger-annotations + ${swagger.annotations.version} + + diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Anonymous.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Anonymous.java index 738d35f..8b96ef4 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Anonymous.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Anonymous.java @@ -9,7 +9,7 @@ import java.lang.annotation.Target; /** * 匿名访问不鉴权注解 * - * @author cmvrIot + * @author ruoyi */ @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataScope.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataScope.java index 9fb105c..46de2a5 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataScope.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataScope.java @@ -9,22 +9,32 @@ import java.lang.annotation.Target; /** * 数据权限过滤注解 * - * @author cmvrIot + * @author ruoyi */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataScope { + /** + * 用户表的别名 + */ + public String userAlias() default ""; + /** * 部门表的别名 */ public String deptAlias() default ""; /** - * 用户表的别名 + * 用户字段名 */ - public String userAlias() default ""; + public String userField() default "user_id"; + + /** + * 部门字段名 + */ + public String deptField() default "dept_id"; /** * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来 diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataSource.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataSource.java index 986d4bb..9e17276 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataSource.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/DataSource.java @@ -13,7 +13,7 @@ import com.cmvr.common.enums.DataSourceType; * * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 * - * @author cmvrIot + * @author ruoyi */ @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excel.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excel.java index 5a6be63..b28e12f 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excel.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excel.java @@ -12,7 +12,7 @@ import com.cmvr.common.utils.poi.ExcelHandlerAdapter; /** * 自定义导出Excel数据注解 * - * @author cmvrIot + * @author ruoyi */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @@ -56,6 +56,7 @@ public @interface Excel /** * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN */ + @SuppressWarnings("deprecation") public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; /** @@ -194,4 +195,4 @@ public @interface Excel return this.value; } } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excels.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excels.java index 98e9574..99e08a1 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excels.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Excels.java @@ -8,7 +8,7 @@ import java.lang.annotation.Target; /** * Excel注解集 * - * @author cmvrIot + * @author ruoyi */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Log.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Log.java index 0f6f4ce..7b3576a 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Log.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Log.java @@ -11,7 +11,7 @@ import com.cmvr.common.enums.OperatorType; /** * 自定义操作日志记录注解 * - * @author cmvrIot + * @author ruoyi * */ @Target({ ElementType.PARAMETER, ElementType.METHOD }) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RateLimiter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RateLimiter.java index a9595c2..a861b12 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RateLimiter.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RateLimiter.java @@ -11,7 +11,7 @@ import com.cmvr.common.enums.LimitType; /** * 限流注解 * - * @author cmvrIot + * @author ruoyi */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RepeatSubmit.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RepeatSubmit.java index 971f111..b0d6f2e 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RepeatSubmit.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/RepeatSubmit.java @@ -10,7 +10,7 @@ import java.lang.annotation.Target; /** * 自定义注解防止表单重复提交 * - * @author cmvrIot + * @author ruoyi * */ @Inherited diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Sensitive.java b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Sensitive.java index 8456fa6..e96f2e6 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Sensitive.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/annotation/Sensitive.java @@ -5,17 +5,17 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import tools.jackson.databind.annotation.JsonSerialize; import com.cmvr.common.config.serializer.SensitiveJsonSerializer; import com.cmvr.common.enums.DesensitizedType; /** * 数据脱敏注解 * - * @author cmvrIot + * @author ruoyi */ @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) +@Target({ ElementType.FIELD, ElementType.METHOD }) @JacksonAnnotationsInside @JsonSerialize(using = SensitiveJsonSerializer.class) public @interface Sensitive diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/config/serializer/SensitiveJsonSerializer.java b/cmvr-iot-common/src/main/java/com/cmvr/common/config/serializer/SensitiveJsonSerializer.java index 19a2532..8833767 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/config/serializer/SensitiveJsonSerializer.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/config/serializer/SensitiveJsonSerializer.java @@ -1,13 +1,13 @@ package com.cmvr.common.config.serializer; -import java.io.IOException; import java.util.Objects; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.BeanProperty; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonGenerator; +import tools.jackson.databind.BeanProperty; +import tools.jackson.databind.DatabindException; +import tools.jackson.databind.SerializationContext; +import tools.jackson.databind.ValueSerializer; +import tools.jackson.databind.ser.std.StdSerializer; import com.cmvr.common.annotation.Sensitive; import com.cmvr.common.core.domain.model.LoginUser; import com.cmvr.common.enums.DesensitizedType; @@ -16,16 +16,28 @@ import com.cmvr.common.utils.SecurityUtils; /** * 数据脱敏序列化过滤 * - * @author cmvrIot + * @author ruoyi */ -public class SensitiveJsonSerializer extends JsonSerializer implements ContextualSerializer +public class SensitiveJsonSerializer extends StdSerializer { - private DesensitizedType desensitizedType; + private final DesensitizedType desensitizedType; + + public SensitiveJsonSerializer() + { + super(String.class); + this.desensitizedType = null; + } + + public SensitiveJsonSerializer(DesensitizedType desensitizedType) + { + super(String.class); + this.desensitizedType = desensitizedType; + } @Override - public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException + public void serialize(String value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException { - if (desensitization()) + if (desensitizedType != null && desensitization()) { gen.writeString(desensitizedType.desensitizer().apply(value)); } @@ -36,16 +48,14 @@ public class SensitiveJsonSerializer extends JsonSerializer implements C } @Override - public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) - throws JsonMappingException + public ValueSerializer createContextual(SerializationContext ctxt, BeanProperty property) throws DatabindException { Sensitive annotation = property.getAnnotation(Sensitive.class); if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { - this.desensitizedType = annotation.desensitizedType(); - return this; + return new SensitiveJsonSerializer(annotation.desensitizedType()); } - return prov.findValueSerializer(property.getType(), property); + return ctxt.findValueSerializer(property.getType()); } /** diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/CacheConstants.java b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/CacheConstants.java index e2d39b1..1910311 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/CacheConstants.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/CacheConstants.java @@ -3,7 +3,7 @@ package com.cmvr.common.constant; /** * 缓存的key 常量 * - * @author cmvrIot + * @author ruoyi */ public class CacheConstants { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/Constants.java b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/Constants.java index ca8c366..cd6bb86 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/Constants.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/Constants.java @@ -6,7 +6,7 @@ import io.jsonwebtoken.Claims; /** * 通用常量信息 * - * @author cmvrIot + * @author ruoyi */ public class Constants { @@ -83,12 +83,12 @@ public class Constants /** * 角色权限分隔符 */ - public static final String ROLE_DELIMETER = ","; + public static final String ROLE_DELIMITER = ","; /** * 权限标识分隔符 */ - public static final String PERMISSION_DELIMETER = ","; + public static final String PERMISSION_DELIMITER = ","; /** * 验证码有效期(分钟) @@ -158,7 +158,7 @@ public class Constants /** * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全) */ - public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.cmvr" }; + public static final String[] JSON_WHITELIST_STR = { "com.cmvr" }; /** * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) @@ -170,4 +170,35 @@ public class Constants */ public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", "org.springframework", "org.apache", "com.cmvr.common.utils.file", "com.cmvr.common.config", "com.cmvr.generator" }; + + /** + * 部门相关常量 + */ + public static class Dept + { + /** + * 全部数据权限 + */ + public static final String DATA_SCOPE_ALL = "1"; + + /** + * 自定数据权限 + */ + public static final String DATA_SCOPE_CUSTOM = "2"; + + /** + * 部门数据权限 + */ + public static final String DATA_SCOPE_DEPT = "3"; + + /** + * 部门及以下数据权限 + */ + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; + + /** + * 仅本人数据权限 + */ + public static final String DATA_SCOPE_SELF = "5"; + } } diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/GenConstants.java b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/GenConstants.java index 62b646b..f15c4fb 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/GenConstants.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/GenConstants.java @@ -3,7 +3,7 @@ package com.cmvr.common.constant; /** * 代码生成通用常量 * - * @author cmvrIot + * @author ruoyi */ public class GenConstants { @@ -31,6 +31,9 @@ public class GenConstants /** 上级菜单名称字段 */ public static final String PARENT_MENU_NAME = "parentMenuName"; + /** 生成详情页开关 */ + public static final String GEN_VIEW = "genView"; + /** 数据库字符串类型 */ public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" }; diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/HttpStatus.java b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/HttpStatus.java index feea3ba..0121eb7 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/HttpStatus.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/HttpStatus.java @@ -3,7 +3,7 @@ package com.cmvr.common.constant; /** * 返回状态码 * - * @author cmvrIot + * @author ruoyi */ public class HttpStatus { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/ScheduleConstants.java b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/ScheduleConstants.java index 6df7c90..372f288 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/ScheduleConstants.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/ScheduleConstants.java @@ -3,7 +3,7 @@ package com.cmvr.common.constant; /** * 任务调度通用常量 * - * @author cmvrIot + * @author ruoyi */ public class ScheduleConstants { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/UserConstants.java b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/UserConstants.java index df05390..85e1fe6 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/constant/UserConstants.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/constant/UserConstants.java @@ -3,7 +3,7 @@ package com.cmvr.common.constant; /** * 用户常量信息 * - * @author cmvrIot + * @author ruoyi */ public class UserConstants { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/controller/BaseController.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/controller/BaseController.java index b9d6eb5..5f88523 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/controller/BaseController.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/controller/BaseController.java @@ -24,7 +24,7 @@ import com.cmvr.common.utils.sql.SqlUtil; /** * web层通用数据处理 * - * @author cmvrIot + * @author ruoyi */ public class BaseController { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/AjaxResult.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/AjaxResult.java index a97bc24..8e12296 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/AjaxResult.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/AjaxResult.java @@ -8,7 +8,7 @@ import com.cmvr.common.utils.StringUtils; /** * 操作消息提醒 * - * @author cmvrIot + * @author ruoyi */ public class AjaxResult extends HashMap { @@ -102,25 +102,16 @@ public class AjaxResult extends HashMap return new AjaxResult(HttpStatus.SUCCESS, msg, data); } - /** - * 返回成功消息 - * - * @param data 数据对象 - * @return 成功消息 - */ + /** Compatibility alias retained for existing CMVR REST controllers. */ public static AjaxResult ok(Object data) { - return new AjaxResult(HttpStatus.SUCCESS, "操作成功", data); + return success(data); } - /** - * 返回成功消息 - * - * @return 成功消息 - */ + /** Compatibility alias retained for existing CMVR REST controllers. */ public static AjaxResult ok() { - return new AjaxResult(HttpStatus.SUCCESS, "操作成功", null); + return success(); } /** diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/BaseEntity.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/BaseEntity.java index cb02509..7599067 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/BaseEntity.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/BaseEntity.java @@ -4,8 +4,6 @@ import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; - -import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -14,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; /** * Entity基类 * - * @author cmvrIot + * @author ruoyi */ public class BaseEntity implements Serializable { @@ -26,20 +24,16 @@ public class BaseEntity implements Serializable private String searchValue; /** 创建者 */ - @TableField(fill = FieldFill.INSERT) private String createBy; /** 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - @TableField(fill = FieldFill.INSERT) private Date createTime; /** 更新者 */ - @TableField(fill = FieldFill.UPDATE) private String updateBy; /** 更新时间 */ - @TableField(fill = FieldFill.UPDATE) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/R.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/R.java index 65b9423..da4dbfe 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/R.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/R.java @@ -6,7 +6,7 @@ import com.cmvr.common.constant.HttpStatus; /** * 响应信息主体 * - * @author cmvrIot + * @author ruoyi */ public class R implements Serializable { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeEntity.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeEntity.java index 3e12976..7d93ed5 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeEntity.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeEntity.java @@ -6,7 +6,7 @@ import java.util.List; /** * Tree基类 * - * @author cmvrIot + * @author ruoyi */ public class TreeEntity extends BaseEntity { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeSelect.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeSelect.java index 66bcd81..423040c 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeSelect.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/TreeSelect.java @@ -12,7 +12,7 @@ import com.cmvr.common.utils.StringUtils; /** * Treeselect树结构实体类 * - * @author cmvrIot + * @author ruoyi */ public class TreeSelect implements Serializable { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDept.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDept.java index bf7d01c..044f841 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDept.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDept.java @@ -2,10 +2,10 @@ package com.cmvr.common.core.domain.entity; import java.util.ArrayList; import java.util.List; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.cmvr.common.core.domain.BaseEntity; @@ -13,7 +13,7 @@ import com.cmvr.common.core.domain.BaseEntity; /** * 部门表 sys_dept * - * @author cmvrIot + * @author ruoyi */ public class SysDept extends BaseEntity { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictData.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictData.java index a2fadff..43f4dda 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictData.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictData.java @@ -1,7 +1,7 @@ package com.cmvr.common.core.domain.entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.cmvr.common.annotation.Excel; @@ -12,7 +12,7 @@ import com.cmvr.common.core.domain.BaseEntity; /** * 字典数据表 sys_dict_data * - * @author cmvrIot + * @author ruoyi */ public class SysDictData extends BaseEntity { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictType.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictType.java index a2f88e2..856bc1d 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictType.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysDictType.java @@ -1,8 +1,8 @@ package com.cmvr.common.core.domain.entity; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.cmvr.common.annotation.Excel; @@ -12,7 +12,7 @@ import com.cmvr.common.core.domain.BaseEntity; /** * 字典类型表 sys_dict_type * - * @author cmvrIot + * @author ruoyi */ public class SysDictType extends BaseEntity { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysMenu.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysMenu.java index b207e2c..4a6db9e 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysMenu.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysMenu.java @@ -2,9 +2,9 @@ package com.cmvr.common.core.domain.entity; import java.util.ArrayList; import java.util.List; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.cmvr.common.core.domain.BaseEntity; @@ -12,7 +12,7 @@ import com.cmvr.common.core.domain.BaseEntity; /** * 菜单权限表 sys_menu * - * @author cmvrIot + * @author ruoyi */ public class SysMenu extends BaseEntity { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysRole.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysRole.java index eb527ee..fa7992e 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysRole.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysRole.java @@ -1,9 +1,9 @@ package com.cmvr.common.core.domain.entity; import java.util.Set; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.cmvr.common.annotation.Excel; @@ -13,7 +13,7 @@ import com.cmvr.common.core.domain.BaseEntity; /** * 角色表 sys_role * - * @author cmvrIot + * @author ruoyi */ public class SysRole extends BaseEntity { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysUser.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysUser.java index 5074604..fd3e673 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysUser.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/entity/SysUser.java @@ -2,20 +2,23 @@ package com.cmvr.common.core.domain.entity; import java.util.Date; import java.util.List; -import javax.validation.constraints.*; +import jakarta.validation.constraints.*; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; import com.cmvr.common.annotation.Excel; import com.cmvr.common.annotation.Excel.ColumnType; import com.cmvr.common.annotation.Excel.Type; import com.cmvr.common.annotation.Excels; import com.cmvr.common.core.domain.BaseEntity; +import com.cmvr.common.utils.SecurityUtils; import com.cmvr.common.xss.Xss; /** * 用户对象 sys_user * - * @author cmvrIot + * @author ruoyi */ public class SysUser extends BaseEntity { @@ -55,8 +58,8 @@ public class SysUser extends BaseEntity /** 密码 */ private String password; - /** 帐号状态(0正常 1停用) */ - @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") + /** 账号状态(0正常 1停用) */ + @Excel(name = "账号状态", readConverterExp = "0=正常,1=停用") private String status; /** 删除标志(0代表存在 2代表删除) */ @@ -67,9 +70,13 @@ public class SysUser extends BaseEntity private String loginIp; /** 最后登录时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) private Date loginDate; + /** 密码最后更新时间 */ + private Date pwdUpdateDate; + /** 部门对象 */ @Excels({ @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), @@ -111,12 +118,7 @@ public class SysUser extends BaseEntity public boolean isAdmin() { - return isAdmin(this.userId); - } - - public static boolean isAdmin(Long userId) - { - return userId != null && 1L == userId; + return SecurityUtils.isAdmin(this.userId); } public Long getDeptId() @@ -197,6 +199,7 @@ public class SysUser extends BaseEntity this.avatar = avatar; } + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String getPassword() { return password; @@ -247,6 +250,16 @@ public class SysUser extends BaseEntity this.loginDate = loginDate; } + public Date getPwdUpdateDate() + { + return pwdUpdateDate; + } + + public void setPwdUpdateDate(Date pwdUpdateDate) + { + this.pwdUpdateDate = pwdUpdateDate; + } + public SysDept getDept() { return dept; @@ -313,6 +326,7 @@ public class SysUser extends BaseEntity .append("delFlag", getDelFlag()) .append("loginIp", getLoginIp()) .append("loginDate", getLoginDate()) + .append("pwdUpdateDate", getPwdUpdateDate()) .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) .append("updateBy", getUpdateBy()) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginBody.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginBody.java index de58e32..2a72e38 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginBody.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginBody.java @@ -3,7 +3,7 @@ package com.cmvr.common.core.domain.model; /** * 用户登录对象 * - * @author cmvrIot + * @author ruoyi */ public class LoginBody { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginUser.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginUser.java index 54f9cae..97573ad 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginUser.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/LoginUser.java @@ -1,16 +1,20 @@ package com.cmvr.common.core.domain.model; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; import com.alibaba.fastjson2.annotation.JSONField; import com.cmvr.common.core.domain.entity.SysUser; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import java.util.Collection; -import java.util.Set; /** * 登录用户身份权限 * - * @author cmvrIot + * @author ruoyi */ public class LoginUser implements UserDetails { @@ -259,8 +263,16 @@ public class LoginUser implements UserDetails } @Override + @JSONField(serialize = false) public Collection getAuthorities() { - return null; + if (permissions == null || permissions.isEmpty()) + { + return Collections.emptyList(); + } + return permissions.stream() + .filter(Objects::nonNull) + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); } } diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/RegisterBody.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/RegisterBody.java index 869bb50..960743a 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/RegisterBody.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/domain/model/RegisterBody.java @@ -3,7 +3,7 @@ package com.cmvr.common.core.domain.model; /** * 用户注册对象 * - * @author cmvrIot + * @author ruoyi */ public class RegisterBody extends LoginBody { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/PageDomain.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/PageDomain.java index 37e1d7a..0fef901 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/PageDomain.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/PageDomain.java @@ -5,7 +5,7 @@ import com.cmvr.common.utils.StringUtils; /** * 分页数据 * - * @author cmvrIot + * @author ruoyi */ public class PageDomain { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableDataInfo.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableDataInfo.java index 190fc2b..31c0950 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableDataInfo.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableDataInfo.java @@ -6,7 +6,7 @@ import java.util.List; /** * 表格分页数据对象 * - * @author cmvrIot + * @author ruoyi */ public class TableDataInfo implements Serializable { @@ -37,7 +37,7 @@ public class TableDataInfo implements Serializable * @param list 列表数据 * @param total 总记录数 */ - public TableDataInfo(List list, int total) + public TableDataInfo(List list, long total) { this.rows = list; this.total = total; diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableSupport.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableSupport.java index 5d8dbf3..bca6ae0 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableSupport.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/page/TableSupport.java @@ -6,7 +6,7 @@ import com.cmvr.common.utils.ServletUtils; /** * 表格数据处理 * - * @author cmvrIot + * @author ruoyi */ public class TableSupport { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/redis/RedisCache.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/redis/RedisCache.java index 8e82f56..5cc33fc 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/redis/RedisCache.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/redis/RedisCache.java @@ -16,7 +16,7 @@ import org.springframework.stereotype.Component; /** * spring redis 工具类 * - * @author cmvrIot + * @author ruoyi **/ @SuppressWarnings(value = { "unchecked", "rawtypes" }) @Component diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/CharsetKit.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/CharsetKit.java index 8495829..a0eeb48 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/CharsetKit.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/CharsetKit.java @@ -7,7 +7,7 @@ import com.cmvr.common.utils.StringUtils; /** * 字符集工具类 * - * @author cmvrIot + * @author ruoyi */ public class CharsetKit { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/Convert.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/Convert.java index 3247c8f..4576c12 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/Convert.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/Convert.java @@ -8,12 +8,11 @@ import java.nio.charset.Charset; import java.text.NumberFormat; import java.util.Set; import com.cmvr.common.utils.StringUtils; -import org.apache.commons.lang3.ArrayUtils; /** * 类型转换器 * - * @author cmvrIot + * @author ruoyi */ public class Convert { @@ -541,7 +540,7 @@ public class Convert /** * 转换为boolean
- * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * String支持的值为:true、false、yes、ok、no、1、0、是、否, 如果给定的值为空,或者转换失败,返回默认值
* 转换失败不会报错 * * @param value 被转换的值 @@ -570,10 +569,12 @@ public class Convert case "yes": case "ok": case "1": + case "是": return true; case "false": case "no": case "0": + case "否": return false; default: return defaultValue; @@ -796,14 +797,23 @@ public class Convert { return (String) obj; } - else if (obj instanceof byte[]) + else if (obj instanceof byte[] || obj instanceof Byte[]) { - return str((byte[]) obj, charset); - } - else if (obj instanceof Byte[]) - { - byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj); - return str(bytes, charset); + if (obj instanceof byte[]) + { + return str((byte[]) obj, charset); + } + else + { + Byte[] bytes = (Byte[]) obj; + int length = bytes.length; + byte[] dest = new byte[length]; + for (int i = 0; i < length; i++) + { + dest[i] = bytes[i]; + } + return str(dest, charset); + } } else if (obj instanceof ByteBuffer) { @@ -959,9 +969,7 @@ public class Convert c[i] = (char) (c[i] - 65248); } } - String returnString = new String(c); - - return returnString; + return new String(c); } /** diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/StrFormatter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/StrFormatter.java index 71ad6d0..e264c8d 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/StrFormatter.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/core/text/StrFormatter.java @@ -5,7 +5,7 @@ import com.cmvr.common.utils.StringUtils; /** * 字符串格式化 * - * @author cmvrIot + * @author ruoyi */ public class StrFormatter { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessStatus.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessStatus.java index 42e807a..815bf2d 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessStatus.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessStatus.java @@ -3,7 +3,7 @@ package com.cmvr.common.enums; /** * 操作状态 * - * @author cmvrIot + * @author ruoyi * */ public enum BusinessStatus diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessType.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessType.java index 5e2f4a3..2afa24f 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessType.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/BusinessType.java @@ -3,7 +3,7 @@ package com.cmvr.common.enums; /** * 业务操作类型 * - * @author cmvrIot + * @author ruoyi */ public enum BusinessType { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DataSourceType.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DataSourceType.java index a1b2184..bb1e673 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DataSourceType.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DataSourceType.java @@ -3,7 +3,7 @@ package com.cmvr.common.enums; /** * 数据源 * - * @author cmvrIot + * @author ruoyi */ public enum DataSourceType { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DesensitizedType.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DesensitizedType.java index c4021b6..61399cd 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DesensitizedType.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/DesensitizedType.java @@ -6,7 +6,7 @@ import com.cmvr.common.utils.DesensitizedUtil; /** * 脱敏类型 * - * @author cmvrIot + * @author ruoyi */ public enum DesensitizedType { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/HttpMethod.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/HttpMethod.java index de9d658..24dc7ed 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/HttpMethod.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/HttpMethod.java @@ -2,12 +2,12 @@ package com.cmvr.common.enums; import java.util.HashMap; import java.util.Map; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * 请求方式 * - * @author cmvrIot + * @author ruoyi */ public enum HttpMethod { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/LimitType.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/LimitType.java index 4ade7a4..9320d2a 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/LimitType.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/LimitType.java @@ -3,7 +3,7 @@ package com.cmvr.common.enums; /** * 限流类型 * - * @author cmvrIot + * @author ruoyi */ public enum LimitType diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/OperatorType.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/OperatorType.java index e0bc060..e0099d2 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/OperatorType.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/OperatorType.java @@ -3,7 +3,7 @@ package com.cmvr.common.enums; /** * 操作人类别 * - * @author cmvrIot + * @author ruoyi */ public enum OperatorType { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/UserStatus.java b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/UserStatus.java index 1718aa5..fb8a117 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/enums/UserStatus.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/enums/UserStatus.java @@ -3,7 +3,7 @@ package com.cmvr.common.enums; /** * 用户状态 * - * @author cmvrIot + * @author ruoyi */ public enum UserStatus { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/DemoModeException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/DemoModeException.java index 60d322e..8c477e5 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/DemoModeException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/DemoModeException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception; /** * 演示模式异常 * - * @author cmvrIot + * @author ruoyi */ public class DemoModeException extends RuntimeException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/GlobalException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/GlobalException.java index a4f2795..1f90dbf 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/GlobalException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/GlobalException.java @@ -3,55 +3,73 @@ package com.cmvr.common.exception; import cn.hutool.core.util.StrUtil; /** - * 全局自定义业务异常 + * 全局异常 + * + * @author ruoyi */ -public class GlobalException extends RuntimeException { +public class GlobalException extends RuntimeException +{ private static final long serialVersionUID = 1L; - /** 前端展示提示信息 */ + /** + * 错误提示 + */ private String message; - /** 后端详细错误信息(数据库/原始异常详情) */ + + /** + * 错误明细,内部调试错误 + * + * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ private String detailMessage; - // 空构造,序列化使用 - public GlobalException() { + /** + * 空构造方法,避免反序列化问题 + */ + public GlobalException() + { } - // 单纯提示信息 - public GlobalException(String message) { + public GlobalException(String message) + { this.message = message; } - // 占位符格式化提示 - public GlobalException(String template, Object... params) { + public GlobalException(String template, Object... params) + { this.message = StrUtil.format(template, params); } - // 【重点:支持 提示+原始异常】对应 throw new GlobalException("任务执行失败", e); - public GlobalException(String message, Throwable cause) { - super(cause); // 绑定原始异常栈,日志可打全堆栈 + public GlobalException(String message, Throwable cause) + { + super(cause); this.message = message; - if (cause != null) { + if (cause != null) + { this.detailMessage = cause.getMessage(); } } - public String getDetailMessage() { + public String getDetailMessage() + { return detailMessage; } - public GlobalException setDetailMessage(String detailMessage) { + public GlobalException setDetailMessage(String detailMessage) + { this.detailMessage = detailMessage; return this; } @Override - public String getMessage() { + public String getMessage() + { return message; } - public GlobalException setMessage(String message) { + public GlobalException setMessage(String message) + { this.message = message; return this; } -} \ No newline at end of file +} diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/ServiceException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/ServiceException.java index 802aec0..5daf4dc 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/ServiceException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/ServiceException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception; /** * 业务异常 * - * @author cmvrIot + * @author ruoyi */ public final class ServiceException extends RuntimeException { @@ -71,4 +71,4 @@ public final class ServiceException extends RuntimeException this.detailMessage = detailMessage; return this; } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/UtilException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/UtilException.java index 4fa4b54..abd1375 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/UtilException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/UtilException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception; /** * 工具类异常 * - * @author cmvrIot + * @author ruoyi */ public class UtilException extends RuntimeException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/base/BaseException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/base/BaseException.java index c95d5f7..29641f0 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/base/BaseException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/base/BaseException.java @@ -6,7 +6,7 @@ import com.cmvr.common.utils.StringUtils; /** * 基础异常 * - * @author cmvrIot + * @author ruoyi */ public class BaseException extends RuntimeException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileException.java index 29ea12e..1dac536 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileException.java @@ -5,7 +5,7 @@ import com.cmvr.common.exception.base.BaseException; /** * 文件信息异常类 * - * @author cmvrIot + * @author ruoyi */ public class FileException extends BaseException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileNameLengthLimitExceededException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileNameLengthLimitExceededException.java index aa55e88..17dce24 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileNameLengthLimitExceededException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileNameLengthLimitExceededException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.file; /** * 文件名称超长限制异常类 * - * @author cmvrIot + * @author ruoyi */ public class FileNameLengthLimitExceededException extends FileException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileSizeLimitExceededException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileSizeLimitExceededException.java index f3452a6..206c3f0 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileSizeLimitExceededException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileSizeLimitExceededException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.file; /** * 文件名大小限制异常类 * - * @author cmvrIot + * @author ruoyi */ public class FileSizeLimitExceededException extends FileException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileUploadException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileUploadException.java index 11b0eee..1d95e29 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileUploadException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/FileUploadException.java @@ -6,7 +6,7 @@ import java.io.PrintWriter; /** * 文件上传异常类 * - * @author cmvrIot + * @author ruoyi */ public class FileUploadException extends Exception { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/InvalidExtensionException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/InvalidExtensionException.java index 26fdaa4..bfe539e 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/InvalidExtensionException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/file/InvalidExtensionException.java @@ -3,9 +3,9 @@ package com.cmvr.common.exception.file; import java.util.Arrays; /** - * 文件上传 误异常类 + * 文件上传无效扩展名异常类 * - * @author cmvrIot + * @author ruoyi */ public class InvalidExtensionException extends FileUploadException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/job/TaskException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/job/TaskException.java index 4f2ae46..a38f991 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/job/TaskException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/job/TaskException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.job; /** * 计划策略异常 * - * @author cmvrIot + * @author ruoyi */ public class TaskException extends Exception { @@ -31,4 +31,4 @@ public class TaskException extends Exception { TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/BlackListException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/BlackListException.java index a50ab9d..0d2b0b4 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/BlackListException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/BlackListException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.user; /** * 黑名单IP异常类 * - * @author cmvrIot + * @author ruoyi */ public class BlackListException extends UserException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaException.java index ac28350..328d02a 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.user; /** * 验证码错误异常类 * - * @author cmvrIot + * @author ruoyi */ public class CaptchaException extends UserException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaExpireException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaExpireException.java index 18c8c30..4715695 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaExpireException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/CaptchaExpireException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.user; /** * 验证码失效异常类 * - * @author cmvrIot + * @author ruoyi */ public class CaptchaExpireException extends UserException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserException.java index d7fde75..dcb12a2 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserException.java @@ -5,7 +5,7 @@ import com.cmvr.common.exception.base.BaseException; /** * 用户信息异常类 * - * @author cmvrIot + * @author ruoyi */ public class UserException extends BaseException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserNotExistsException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserNotExistsException.java index 0fd825b..af3bd48 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserNotExistsException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserNotExistsException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.user; /** * 用户不存在异常类 * - * @author cmvrIot + * @author ruoyi */ public class UserNotExistsException extends UserException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordNotMatchException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordNotMatchException.java index 2669bac..e57b78c 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordNotMatchException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordNotMatchException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.user; /** * 用户密码不正确或不符合规范异常类 * - * @author cmvrIot + * @author ruoyi */ public class UserPasswordNotMatchException extends UserException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordRetryLimitExceedException.java b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordRetryLimitExceedException.java index 42ee8ab..69b0f37 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordRetryLimitExceedException.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/exception/user/UserPasswordRetryLimitExceedException.java @@ -3,7 +3,7 @@ package com.cmvr.common.exception.user; /** * 用户错误最大次数异常类 * - * @author cmvrIot + * @author ruoyi */ public class UserPasswordRetryLimitExceedException extends UserException { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/PropertyPreExcludeFilter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/PropertyPreExcludeFilter.java index 54ee7dd..9cea02f 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/PropertyPreExcludeFilter.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/PropertyPreExcludeFilter.java @@ -5,7 +5,7 @@ import com.alibaba.fastjson2.filter.SimplePropertyPreFilter; /** * 排除JSON敏感属性 * - * @author cmvrIot + * @author ruoyi */ public class PropertyPreExcludeFilter extends SimplePropertyPreFilter { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RefererFilter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RefererFilter.java new file mode 100644 index 0000000..1a84097 --- /dev/null +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RefererFilter.java @@ -0,0 +1,77 @@ +package com.cmvr.common.filter; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * 防盗链过滤器 + * + * @author ruoyi + */ +public class RefererFilter implements Filter +{ + /** + * 允许的域名列表 + */ + public List allowedDomains; + + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + String domains = filterConfig.getInitParameter("allowedDomains"); + this.allowedDomains = Arrays.asList(domains.split(",")); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException + { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + + String referer = req.getHeader("Referer"); + + // 如果Referer为空,拒绝访问 + if (referer == null || referer.isEmpty()) + { + resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer header is required"); + return; + } + + // 检查Referer是否在允许的域名列表中 + boolean allowed = false; + for (String domain : allowedDomains) + { + if (referer.contains(domain)) + { + allowed = true; + break; + } + } + + // 根据检查结果决定是否放行 + if (allowed) + { + chain.doFilter(request, response); + } + else + { + resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer '" + referer + "' is not allowed"); + } + } + + @Override + public void destroy() + { + + } +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatableFilter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatableFilter.java index 19cc575..f5b53a9 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatableFilter.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatableFilter.java @@ -1,20 +1,20 @@ package com.cmvr.common.filter; import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.MediaType; import com.cmvr.common.utils.StringUtils; /** * Repeatable 过滤器 * - * @author cmvrIot + * @author ruoyi */ public class RepeatableFilter implements Filter { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatedlyRequestWrapper.java b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatedlyRequestWrapper.java index f85f193..a29bd07 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatedlyRequestWrapper.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/RepeatedlyRequestWrapper.java @@ -4,18 +4,18 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; import com.cmvr.common.utils.http.HttpHelper; import com.cmvr.common.constant.Constants; /** * 构建可重复读取inputStream的request * - * @author cmvrIot + * @author ruoyi */ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssFilter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssFilter.java index ad99247..c6e16a4 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssFilter.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssFilter.java @@ -3,21 +3,21 @@ package com.cmvr.common.filter; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import com.cmvr.common.utils.StringUtils; import com.cmvr.common.enums.HttpMethod; /** * 防止XSS攻击的过滤器 * - * @author cmvrIot + * @author ruoyi */ public class XssFilter implements Filter { @@ -72,4 +72,4 @@ public class XssFilter implements Filter { } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssHttpServletRequestWrapper.java b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssHttpServletRequestWrapper.java index 5b599ec..b1fd1c6 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssHttpServletRequestWrapper.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/filter/XssHttpServletRequestWrapper.java @@ -2,10 +2,10 @@ package com.cmvr.common.filter; import java.io.ByteArrayInputStream; import java.io.IOException; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; import org.apache.commons.io.IOUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -15,7 +15,7 @@ import com.cmvr.common.utils.html.EscapeUtil; /** * XSS过滤处理 * - * @author cmvrIot + * @author ruoyi */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { @@ -108,4 +108,4 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper String header = super.getHeader(HttpHeaders.CONTENT_TYPE); return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Arith.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Arith.java index 42518d3..66ac6f2 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Arith.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Arith.java @@ -6,7 +6,7 @@ import java.math.RoundingMode; /** * 精确的浮点数运算 * - * @author cmvrIot + * @author ruoyi */ public class Arith { @@ -108,7 +108,6 @@ public class Arith "The scale must be a positive integer or zero"); } BigDecimal b = new BigDecimal(Double.toString(v)); - BigDecimal one = BigDecimal.ONE; - return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); + return b.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).doubleValue(); } } diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DateUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DateUtils.java index 4c185de..b40b5ee 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DateUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DateUtils.java @@ -14,8 +14,9 @@ import org.apache.commons.lang3.time.DateFormatUtils; /** * 时间工具类 * - * @author cmvrIot + * @author ruoyi */ +@SuppressWarnings("deprecation") public class DateUtils extends org.apache.commons.lang3.time.DateUtils { public static String YYYY = "yyyy"; diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DesensitizedUtil.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DesensitizedUtil.java index ec74906..6642e6c 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DesensitizedUtil.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DesensitizedUtil.java @@ -3,7 +3,7 @@ package com.cmvr.common.utils; /** * 脱敏工具类 * - * @author cmvrIot + * @author ruoyi */ public class DesensitizedUtil { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DictUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DictUtils.java index 5b23e9f..0e8b7ad 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DictUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/DictUtils.java @@ -1,7 +1,9 @@ package com.cmvr.common.utils; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.alibaba.fastjson2.JSONArray; import com.cmvr.common.constant.CacheConstants; import com.cmvr.common.core.domain.entity.SysDictData; @@ -11,7 +13,7 @@ import com.cmvr.common.utils.spring.SpringUtils; /** * 字典工具类 * - * @author cmvrIot + * @author ruoyi */ public class DictUtils { @@ -89,37 +91,25 @@ public class DictUtils */ public static String getDictLabel(String dictType, String dictValue, String separator) { - StringBuilder propertyString = new StringBuilder(); List datas = getDictCache(dictType); - if (StringUtils.isNull(datas)) + if (StringUtils.isNull(datas) || StringUtils.isEmpty(dictValue)) { return StringUtils.EMPTY; } - if (StringUtils.containsAny(separator, dictValue)) + Map dictMap = datas.stream().collect(HashMap::new, (map, dict) -> map.put(dict.getDictValue(), dict.getDictLabel()), Map::putAll); + if (!StringUtils.contains(dictValue, separator)) { - for (SysDictData dict : datas) + return dictMap.getOrDefault(dictValue, StringUtils.EMPTY); + } + StringBuilder labelBuilder = new StringBuilder(); + for (String seperatedValue : dictValue.split(separator)) + { + if (dictMap.containsKey(seperatedValue)) { - for (String value : dictValue.split(separator)) - { - if (value.equals(dict.getDictValue())) - { - propertyString.append(dict.getDictLabel()).append(separator); - break; - } - } + labelBuilder.append(dictMap.get(seperatedValue)).append(separator); } } - else - { - for (SysDictData dict : datas) - { - if (dictValue.equals(dict.getDictValue())) - { - return dict.getDictLabel(); - } - } - } - return StringUtils.stripEnd(propertyString.toString(), separator); + return StringUtils.removeEnd(labelBuilder.toString(), separator); } /** @@ -132,37 +122,25 @@ public class DictUtils */ public static String getDictValue(String dictType, String dictLabel, String separator) { - StringBuilder propertyString = new StringBuilder(); List datas = getDictCache(dictType); - if (StringUtils.isNull(datas)) + if (StringUtils.isNull(datas) || StringUtils.isEmpty(dictLabel)) { return StringUtils.EMPTY; } - if (StringUtils.containsAny(separator, dictLabel)) + Map dictMap = datas.stream().collect(HashMap::new, (map, dict) -> map.put(dict.getDictLabel(), dict.getDictValue()), Map::putAll); + if (!StringUtils.contains(dictLabel, separator)) { - for (SysDictData dict : datas) + return dictMap.getOrDefault(dictLabel, StringUtils.EMPTY); + } + StringBuilder valueBuilder = new StringBuilder(); + for (String seperatedValue : dictLabel.split(separator)) + { + if (dictMap.containsKey(seperatedValue)) { - for (String label : dictLabel.split(separator)) - { - if (label.equals(dict.getDictLabel())) - { - propertyString.append(dict.getDictValue()).append(separator); - break; - } - } + valueBuilder.append(dictMap.get(seperatedValue)).append(separator); } } - else - { - for (SysDictData dict : datas) - { - if (dictLabel.equals(dict.getDictLabel())) - { - return dict.getDictValue(); - } - } - } - return StringUtils.stripEnd(propertyString.toString(), separator); + return StringUtils.removeEnd(valueBuilder.toString(), separator); } /** diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ExceptionUtil.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ExceptionUtil.java index 7c41d30..b4a422e 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ExceptionUtil.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ExceptionUtil.java @@ -7,7 +7,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils; /** * 错误信息处理类。 * - * @author cmvrIot + * @author ruoyi */ public class ExceptionUtil { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/LogUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/LogUtils.java index 2b8356a..af6b0a0 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/LogUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/LogUtils.java @@ -3,7 +3,7 @@ package com.cmvr.common.utils; /** * 处理并记录日志文件 * - * @author cmvrIot + * @author ruoyi */ public class LogUtils { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/MessageUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/MessageUtils.java index da91754..9ea9ef3 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/MessageUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/MessageUtils.java @@ -7,7 +7,7 @@ import com.cmvr.common.utils.spring.SpringUtils; /** * 获取i18n资源文件 * - * @author cmvrIot + * @author ruoyi */ public class MessageUtils { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/PageUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/PageUtils.java index 8afb38e..517e8e3 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/PageUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/PageUtils.java @@ -8,7 +8,7 @@ import com.cmvr.common.utils.sql.SqlUtil; /** * 分页工具类 * - * @author cmvrIot + * @author ruoyi */ public class PageUtils extends PageHelper { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/SecurityUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/SecurityUtils.java index 6a7c257..85ee76c 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/SecurityUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/SecurityUtils.java @@ -16,7 +16,7 @@ import com.cmvr.common.exception.ServiceException; /** * 安全服务工具类 * - * @author cmvrIot + * @author ruoyi */ public class SecurityUtils { @@ -114,6 +114,16 @@ public class SecurityUtils return passwordEncoder.matches(rawPassword, encodedPassword); } + /** + * 是否为管理员 + * + * @return 结果 + */ + public static boolean isAdmin() + { + return isAdmin(getUserId()); + } + /** * 是否为管理员 * @@ -175,8 +185,4 @@ public class SecurityUtils .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role)); } - public static void setAuthentication(Authentication authentication) { - SecurityContextHolder.getContext().setAuthentication(authentication); - } - } diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ServletUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ServletUtils.java index 016170a..6e0a823 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ServletUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ServletUtils.java @@ -7,10 +7,10 @@ import java.net.URLEncoder; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -20,7 +20,7 @@ import com.cmvr.common.core.text.Convert; /** * 客户端工具类 * - * @author cmvrIot + * @author ruoyi */ public class ServletUtils { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/StringUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/StringUtils.java index fcf87c3..8b5bcba 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/StringUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/StringUtils.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.commons.lang3.Strings; import org.springframework.util.AntPathMatcher; import com.cmvr.common.constant.Constants; import com.cmvr.common.core.text.StrFormatter; @@ -13,8 +14,9 @@ import com.cmvr.common.core.text.StrFormatter; /** * 字符串工具类 * - * @author cmvrIot + * @author ruoyi */ +@SuppressWarnings("deprecation") public class StringUtils extends org.apache.commons.lang3.StringUtils { /** 空字符串 */ @@ -286,6 +288,32 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils return str.substring(start, end); } + /** + * 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串 + * + * @param str 要截取的字符串 + * @param open 起始字符串 + * @param close 结束字符串 + * @return 截取结果 + */ + public static String substringBetweenLast(final String str, final String open, final String close) + { + if (isEmpty(str) || isEmpty(open) || isEmpty(close)) + { + return NULLSTR; + } + final int start = str.indexOf(open); + if (start != INDEX_NOT_FOUND) + { + final int end = str.lastIndexOf(close); + if (end != INDEX_NOT_FOUND) + { + return str.substring(start + open.length(), end); + } + } + return NULLSTR; + } + /** * 判断是否为空,并且不是空白字符 * @@ -355,6 +383,18 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils return new HashSet(str2List(str, sep, true, false)); } + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @return list集合 + */ + public static final List str2List(String str, String sep) + { + return str2List(str, sep, true, false); + } + /** * 字符串转list * @@ -394,12 +434,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils return list; } + /** + * 检查子字符串是否存在 + * + * @param seq 检查的字符串 + * @param searchSeq 查找的字符串 + * @return 结果 + */ + public static boolean contains(final CharSequence seq, final CharSequence searchSeq) + { + return Strings.CS.contains(seq, searchSeq); + } + /** * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value * * @param collection 给定的集合 * @param array 给定的数组 - * @return boolean 结果 + * @return 结果 */ public static boolean containsAny(Collection collection, String... array) { @@ -420,6 +472,18 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } } + /** + * 判断是否包含给定数组中的任意一个。 + * + * @param cs 要判断的字符串 + * @param searchCharSequences 要判断的数组 + * @return 结果 + */ + public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) + { + return Strings.CS.containsAny(cs, searchCharSequences); + } + /** * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 * @@ -443,6 +507,163 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils return false; } + /** + * 检查是否包含要搜索的字符串,忽略大小写 + * + * @param str 要检查的字符串 + * @param searchStr 要查找的字符串 + * @return 如果包含要搜索的字符串(忽略大小写)则返回true,如果不包含或返回false + */ + public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) + { + return Strings.CI.contains(str, searchStr); + } + + /** + * 检查字符串是否以任意前缀开始 + * + * @param sequence 要检查的字符串 + * @param searchStrings 区分大小写的字符串前缀数组 + * @return 结果 + */ + public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) + { + return Strings.CS.startsWithAny(sequence, searchStrings); + } + + /** + * 不区分大小写地检查一个字符串是否以指定前缀开头。 + * + * @param str 待检查的字符串 + * @param 要查找的前缀 + * @return 结果 + */ + public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) + { + return Strings.CI.startsWith(str, prefix); + } + + /** + * 比较两个字符串是否相同 + * + * @param cs1 第一个字符串 + * @param cs2 第二个字符串 + * @return 如果给定对象与字符串相等,则返回 true;否则返回 false + */ + public static boolean equals(final CharSequence cs1, final CharSequence cs2) + { + return Strings.CS.equals(cs1, cs2); + } + + /** + * 替换字符串中所有匹配的字符 + * + * @param text 要搜索和替换的文本 + * @param searchString 要搜索的字符串 + * @param replacement 用于替换的字符串 + * @return 处理完所有替换后的文本 + */ + public static String replace(final String text, final String searchString, final String replacement) + { + return Strings.CS.replace(text, searchString, replacement); + } + + /** + * 仅当子字符串位于源字符串末尾时才将其移除,否则返回源字符串。 + * @param str 要搜索的源字符串 + * @param remove 要搜索并移除的字符串 + * @return 如果找到并移除了字符串,则返回移除后的子字符串 + */ + public static String removeEnd(final String str, final String remove) + { + return Strings.CS.removeEnd(str, remove); + } + + /** + * 查找字符串首次出现位置的索引 + * + * @param seq 要检查的字符串 + * @param searchSeq 要查找的字符串 + * @return 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1 + */ + public static int indexOf(final CharSequence seq, final CharSequence searchSeq) + { + return Strings.CS.indexOf(seq, searchSeq); + } + + /** + * 检查字符串是否以指定的后缀结尾 + * + * @param str 要检查的字符 + * @param suffix 要检查的后缀 + * @return 若参数与该字符串末尾相符 true;否则 false + */ + public static boolean endsWith(final CharSequence str, final CharSequence suffix) + { + return Strings.CS.endsWith(str, suffix); + } + + /** + * 将给定的字符串与数组进行比较 + * + * @param string 要比较的字符串 + * @param searchStrings 字符串数组 + * @return 如果字符串等于(区分大小写){@code searchStrings}中的任意其他元素,则返回true;如果{@code searchStrings}为null或不包含匹配项,则返回false + */ + public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) + { + return Strings.CS.equalsAny(string, searchStrings); + } + + /** + * 检查一个字符串是否以任意提供的区分大小写的后缀结尾。 + * + * @param sequence 要检查的字符串 + * @param searchStrings 要查找的区分大小写的字符串数组 + * @return 如果输入参数{@code sequence}为null且未提供任何{@code searchStrings},或者输入{@code sequence}以任意提供的区分大小写的{@code searchStrings}结尾,则返回{@code true}。 + */ + public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) + { + return Strings.CS.endsWithAny(sequence, searchStrings); + } + + /** + * 不区分大小写地检查字符序列是否以指定的后缀结尾 + * + * @param str 要检查的字符序列 + * @param suffix 要查找的后缀 + * @return 如果字符序列以该后缀结尾(不区分大小写),或两者均为{@code null},则返回{@code true} + */ + public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) + { + return Strings.CI.endsWith(str, suffix); + } + + /** + * 指定范围内查找字符串,忽略大小写 + * + * @param str 要检查的字符串 + * @param searchStr 要查找的字符串 + * @return 搜索字符串的第一个索引,如果未找到匹配项则返回 -1 + */ + public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) + { + return Strings.CI.indexOf(str, searchStr); + } + + /** + * Compares given {@code string} to a CharSequences vararg of {@code searchStrings}, + * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case. + * + * @param string to compare, may be {@code null}. + * @param searchStrings a vararg of strings, may be {@code null}. + * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings}; + */ + public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings) + { + return Strings.CI.equalsAny(string, searchStrings); + } + /** * 驼峰转下划线命名 */ @@ -514,6 +735,22 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils return false; } + /** + * 删除最后一个字符串 + * + * @param str 输入字符串 + * @param spit 以什么类型结尾的 + * @return 截取后的字符串 + */ + public static String lastStringDel(String str, String spit) + { + if (!StringUtils.isEmpty(str) && str.endsWith(spit)) + { + return str.subSequence(0, str.length() - 1).toString(); + } + return str; + } + /** * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld * @@ -681,4 +918,4 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } return sb.toString(); } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Threads.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Threads.java index 3713da2..05dc312 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Threads.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/Threads.java @@ -11,7 +11,7 @@ import org.slf4j.LoggerFactory; /** * 线程相关工具类. * - * @author cmvrIot + * @author ruoyi */ public class Threads { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanUtils.java index 8541109..ce3b0c1 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanUtils.java @@ -9,7 +9,7 @@ import java.util.regex.Pattern; /** * Bean 工具类 * - * @author cmvrIot + * @author ruoyi */ public class BeanUtils extends org.springframework.beans.BeanUtils { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanValidators.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanValidators.java index 4f24a78..57205cb 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanValidators.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/bean/BeanValidators.java @@ -1,14 +1,14 @@ package com.cmvr.common.utils.bean; import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validator; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; /** * bean对象属性验证 * - * @author cmvrIot + * @author ruoyi */ public class BeanValidators { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileTypeUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileTypeUtils.java index 8fb6325..5574d89 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileTypeUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileTypeUtils.java @@ -6,14 +6,14 @@ import org.apache.commons.lang3.StringUtils; /** * 文件类型工具类 * - * @author cmvrIot + * @author ruoyi */ public class FileTypeUtils { /** * 获取文件类型 *

- * 例如: cmvrIot.txt, 返回: txt + * 例如: ruoyi.txt, 返回: txt * * @param file 文件名 * @return 后缀(不含".") @@ -30,7 +30,7 @@ public class FileTypeUtils /** * 获取文件类型 *

- * 例如: cmvrIot.txt, 返回: txt + * 例如: ruoyi.txt, 返回: txt * * @param fileName 文件名 * @return 后缀(不含".") @@ -73,4 +73,4 @@ public class FileTypeUtils } return strFileExtendName; } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUploadUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUploadUtils.java index bb7c0b3..e2bae16 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUploadUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUploadUtils.java @@ -13,12 +13,13 @@ import com.cmvr.common.exception.file.FileSizeLimitExceededException; import com.cmvr.common.exception.file.InvalidExtensionException; import com.cmvr.common.utils.DateUtils; import com.cmvr.common.utils.StringUtils; +import com.cmvr.common.utils.uuid.IdUtils; import com.cmvr.common.utils.uuid.Seq; /** * 文件上传工具类 - * - * @author cmvr-iot + * + * @author ruoyi */ public class FileUploadUtils { @@ -102,15 +103,35 @@ public class FileUploadUtils throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { - int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); - if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) + return upload(baseDir, file, allowedExtension, false); + } + + /** + * 文件上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @param useCustomNaming 系统自定义文件名 + * @param allowedExtension 上传文件类型 + * @return 返回上传成功的文件名 + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileNameLengthLimitExceededException 文件名太长 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 + */ + public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension, boolean useCustomNaming) + throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, + InvalidExtensionException + { + int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length(); + if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } assertAllowed(file, allowedExtension); - String fileName = extractFilename(file); + String fileName = useCustomNaming ? uuidFilename(file) : extractFilename(file); String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); file.transferTo(Paths.get(absPath)); @@ -118,12 +139,19 @@ public class FileUploadUtils } /** - * 编码文件名 + * 编码文件名(日期格式目录 + 原文件名 + 序列值 + 后缀) */ public static final String extractFilename(MultipartFile file) { - return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), - FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); + return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); + } + + /** + * 编编码文件名(日期格式目录 + UUID + 后缀) + */ + public static final String uuidFilename(MultipartFile file) + { + return StringUtils.format("{}/{}.{}", DateUtils.datePath(), IdUtils.fastSimpleUUID(), getExtension(file)); } public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException @@ -216,7 +244,7 @@ public class FileUploadUtils /** * 获取文件名的后缀 - * + * * @param file 表单文件 * @return 后缀名 */ diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUtils.java index 8755beb..ed87b64 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/FileUtils.java @@ -9,20 +9,21 @@ import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; import com.cmvr.common.config.CmvrIotConfig; +import com.cmvr.common.constant.Constants; import com.cmvr.common.utils.DateUtils; import com.cmvr.common.utils.StringUtils; import com.cmvr.common.utils.uuid.IdUtils; -import org.apache.commons.io.FilenameUtils; /** * 文件处理工具类 * - * @author cmvrIot + * @author ruoyi */ public class FileUtils { @@ -103,6 +104,17 @@ public class FileUtils return FileUploadUtils.getPathFileName(uploadDir, pathName); } + /** + * 移除路径中的请求前缀片段 + * + * @param filePath 文件路径 + * @return 移除后的文件路径 + */ + public static String stripPrefix(String filePath) + { + return StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX); + } + /** * 删除文件 * @@ -256,7 +268,7 @@ public class FileUtils } /** - * 获取文件名称 /profile/upload/2022/04/16/cmvrIot.png -- cmvrIot.png + * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png * * @param fileName 路径名称 * @return 没有文件路径的名称 @@ -274,7 +286,7 @@ public class FileUtils } /** - * 获取不带后缀文件名称 /profile/upload/2022/04/16/cmvrIot.png -- cmvrIot + * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi * * @param fileName 路径名称 * @return 没有文件路径和后缀的名称 diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/ImageUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/ImageUtils.java index ce9c8ad..35df54c 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/ImageUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/ImageUtils.java @@ -16,7 +16,7 @@ import com.cmvr.common.utils.StringUtils; /** * 图片处理工具类 * - * @author cmvrIot + * @author ruoyi */ public class ImageUtils { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/MimeTypeUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/MimeTypeUtils.java index 70ade72..8310f91 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/MimeTypeUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/file/MimeTypeUtils.java @@ -3,7 +3,7 @@ package com.cmvr.common.utils.file; /** * 媒体类型工具类 * - * @author cmvrIot + * @author ruoyi */ public class MimeTypeUtils { @@ -30,7 +30,7 @@ public class MimeTypeUtils // 图片 "bmp", "gif", "jpg", "jpeg", "png", // word excel powerpoint - "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", // 压缩文件 "rar", "zip", "gz", "bz2", // 视频格式 diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/EscapeUtil.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/EscapeUtil.java index ac287a5..02477d1 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/EscapeUtil.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/EscapeUtil.java @@ -5,7 +5,7 @@ import com.cmvr.common.utils.StringUtils; /** * 转义和反转义工具类 * - * @author cmvrIot + * @author ruoyi */ public class EscapeUtil { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/HTMLFilter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/HTMLFilter.java index a638191..8622baa 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/HTMLFilter.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/html/HTMLFilter.java @@ -13,7 +13,7 @@ import java.util.regex.Pattern; /** * HTML过滤器,用于去除XSS漏洞隐患。 * - * @author cmvrIot + * @author ruoyi */ public final class HTMLFilter { @@ -567,4 +567,4 @@ public final class HTMLFilter { return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpHelper.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpHelper.java index 5a78e7c..e1458cd 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpHelper.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpHelper.java @@ -5,7 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import javax.servlet.ServletRequest; +import jakarta.servlet.ServletRequest; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory; /** * 通用http工具封装 * - * @author cmvrIot + * @author ruoyi */ public class HttpHelper { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpUtils.java index 784d138..2168a9e 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/HttpUtils.java @@ -1,6 +1,5 @@ package com.cmvr.common.utils.http; -import cn.hutool.json.JSONUtil; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -26,11 +25,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cmvr.common.constant.Constants; import com.cmvr.common.utils.StringUtils; +import org.springframework.http.MediaType; +import cn.hutool.json.JSONUtil; /** * 通用http发送方法 * - * @author cmvrIot + * @author ruoyi */ public class HttpUtils { @@ -130,6 +131,19 @@ public class HttpUtils * @return 所代表远程资源的响应结果 */ public static String sendPost(String url, String param) + { + return sendPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE); + } + + /** + * 向指定 URL 发送POST方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数 + * @param contentType 内容类型 + * @return 所代表远程资源的响应结果 + */ + public static String sendPost(String url, String param, String contentType) { PrintWriter out = null; BufferedReader in = null; @@ -143,7 +157,7 @@ public class HttpUtils conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); conn.setRequestProperty("Accept-Charset", "utf-8"); - conn.setRequestProperty("contentType", "utf-8"); + conn.setRequestProperty("Content-Type", contentType); conn.setDoOutput(true); conn.setDoInput(true); out = new PrintWriter(conn.getOutputStream()); @@ -195,6 +209,11 @@ public class HttpUtils } public static String sendSSLPost(String url, String param) + { + return sendSSLPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE); + } + + public static String sendSSLPost(String url, String param, String contentType) { StringBuilder result = new StringBuilder(); String urlNameString = url + "?" + param; @@ -209,7 +228,7 @@ public class HttpUtils conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); conn.setRequestProperty("Accept-Charset", "utf-8"); - conn.setRequestProperty("contentType", "utf-8"); + conn.setRequestProperty("Content-Type", contentType); conn.setDoOutput(true); conn.setDoInput(true); @@ -249,6 +268,54 @@ public class HttpUtils return result.toString(); } + public static byte[] sendPostReturnBytes(String url, Map params) + { + HttpURLConnection conn = null; + try + { + log.info("sendPostReturnBytes - {}", url); + conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setRequestMethod("POST"); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("Content-Type", "application/json;charset=utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setConnectTimeout(30000); + conn.setReadTimeout(60000); + try (OutputStream os = conn.getOutputStream()) + { + os.write(JSONUtil.toJsonStr(params).getBytes(StandardCharsets.UTF_8)); + } + int responseCode = conn.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK) + { + throw new IOException("HTTP error code: " + responseCode); + } + try (InputStream is = conn.getInputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream()) + { + byte[] buffer = new byte[4096]; + int length; + while ((length = is.read(buffer)) != -1) + { + output.write(buffer, 0, length); + } + return output.toByteArray(); + } + } + catch (IOException e) + { + throw new RuntimeException("调用外部服务失败: " + url, e); + } + finally + { + if (conn != null) + { + conn.disconnect(); + } + } + } + private static class TrustAnyTrustManager implements X509TrustManager { @Override @@ -276,90 +343,4 @@ public class HttpUtils return true; } } - - /** - * 向指定 URL 发送POST方法的请求,返回字节数组(用于接收文件流) - * - * @param url 发送请求的 URL - * @param params 请求参数 - * @return 所代表远程资源的响应结果(字节数组) - */ - public static byte[] sendPostReturnBytes(String url, Map params) - { - HttpURLConnection conn = null; - try - { - log.info("sendPostReturnBytes - {}", url); - URL realUrl = new URL(url); - conn = (HttpURLConnection) realUrl.openConnection(); - conn.setRequestMethod("POST"); - conn.setRequestProperty("accept", "*/*"); - conn.setRequestProperty("connection", "Keep-Alive"); - conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); - conn.setRequestProperty("Content-Type", "application/json;charset=utf-8"); - conn.setDoOutput(true); - conn.setDoInput(true); - conn.setConnectTimeout(30000); - conn.setReadTimeout(60000); - - // 发送请求参数 - String jsonParams = JSONUtil.toJsonStr(params); - try (OutputStream os = conn.getOutputStream()) - { - os.write(jsonParams.getBytes(StandardCharsets.UTF_8)); - os.flush(); - } - - // 读取响应 - int responseCode = conn.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) - { - try (InputStream is = conn.getInputStream(); - ByteArrayOutputStream baos = new ByteArrayOutputStream()) - { - byte[] buffer = new byte[1024]; - int len; - while ((len = is.read(buffer)) != -1) - { - baos.write(buffer, 0, len); - } - byte[] result = baos.toByteArray(); - log.info("recv bytes length: {}", result.length); - return result; - } - } - else - { - log.error("HTTP error code: {}", responseCode); - throw new RuntimeException("HTTP error code: " + responseCode); - } - } - catch (ConnectException e) - { - log.error("调用HttpUtils.sendPostReturnBytes ConnectException, url=" + url, e); - throw new RuntimeException("连接外部TTS服务失败", e); - } - catch (SocketTimeoutException e) - { - log.error("调用HttpUtils.sendPostReturnBytes SocketTimeoutException, url=" + url, e); - throw new RuntimeException("外部TTS服务超时", e); - } - catch (IOException e) - { - log.error("调用HttpUtils.sendPostReturnBytes IOException, url=" + url, e); - throw new RuntimeException("IO异常", e); - } - catch (Exception e) - { - log.error("调用HttpUtils.sendPostReturnBytes Exception, url=" + url, e); - throw new RuntimeException("调用外部TTS服务异常", e); - } - finally - { - if (conn != null) - { - conn.disconnect(); - } - } - } } diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/UserAgentUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/UserAgentUtils.java new file mode 100644 index 0000000..2ff3bdb --- /dev/null +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/http/UserAgentUtils.java @@ -0,0 +1,254 @@ +package com.cmvr.common.utils.http; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import com.cmvr.common.utils.StringUtils; +import nl.basjes.parse.useragent.UserAgent; +import nl.basjes.parse.useragent.UserAgentAnalyzer; + +/** + * UserAgent解析工具类 + * + * @author ruoyi + */ +public class UserAgentUtils +{ + public static final String UNKNOWN = ""; + + // 浏览器正则表达式模式 + private static final Pattern CHROME_PATTERN = Pattern.compile("Chrome/(\\d+)(?:\\.\\d+)*"); + private static final Pattern FIREFOX_PATTERN = Pattern.compile("Firefox/(\\d+)(?:\\.\\d+)*"); + private static final Pattern EDGE_PATTERN = Pattern.compile("Edg(?:e)?/(\\d+)(?:\\.\\d+)*"); + private static final Pattern SAFARI_PATTERN = Pattern.compile("Version/(\\d+)(?:\\.\\d+)*"); + private static final Pattern OPERA_PATTERN = Pattern.compile("Opera/(\\d+)(?:\\.\\d+)*"); + private static final Pattern IE_PATTERN = Pattern.compile("(?:MSIE |Trident/.*rv:)(\\d+)(?:\\.\\d+)*"); + private static final Pattern SAMSUNG_PATTERN = Pattern.compile("SamsungBrowser/(\\d+)(?:\\.\\d+)*"); + private static final Pattern UC_PATTERN = Pattern.compile("UCBrowser/(\\d+)(?:\\.\\d+)*"); + private static final Pattern QQ_PATTERN = Pattern.compile("QQBrowser/(\\d+)(?:\\.\\d+)*"); + private static final Pattern WECHAT_PATTERN = Pattern.compile("MicroMessenger/(\\d+)(?:\\.\\d+)*"); + private static final Pattern BAIDU_PATTERN = Pattern.compile("baidubrowser/(\\d+)(?:\\.\\d+)*"); + + // 操作系统正则表达式模式 + private static final Pattern WINDOWS_PATTERN = Pattern.compile("Windows NT (\\d+\\.\\d+)"); + private static final Pattern MACOS_PATTERN = Pattern.compile("Mac OS X (\\d+[_\\d]*)"); + private static final Pattern ANDROID_PATTERN = Pattern.compile("Android (\\d+)(?:\\.\\d+)*"); + private static final Pattern IOS_PATTERN = Pattern.compile("OS[\\s_](\\d+)(?:_\\d+)*"); + private static final Pattern LINUX_PATTERN = Pattern.compile("Linux"); + private static final Pattern CHROMEOS_PATTERN = Pattern.compile("CrOS"); + + private static final UserAgentAnalyzer userAgentAnalyzer = UserAgentAnalyzer + .newBuilder().hideMatcherLoadStats() + .withCache(5000) + .showMinimalVersion() + .withField(UserAgent.AGENT_NAME_VERSION) + .withField(UserAgent.OPERATING_SYSTEM_NAME_VERSION) + .build(); + + /** + * 获取客户端浏览器 + */ + public static String getBrowser(String userAgent) + { + UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent); + String agentNameVersion = iua.get(UserAgent.AGENT_NAME_VERSION).getValue(); + if (StringUtils.isBlank(agentNameVersion) || agentNameVersion.contains("??")) + { + return formatBrowser(userAgent); + } + return agentNameVersion; + } + + /** + * 获取客户端操作系统 + */ + public static String getOperatingSystem(String userAgent) + { + UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent); + String operatingSystemNameVersion = iua.get(UserAgent.OPERATING_SYSTEM_NAME_VERSION).getValue(); + if (StringUtils.isBlank(operatingSystemNameVersion) || operatingSystemNameVersion.contains("??")) + { + return formatOperatingSystem(userAgent); + } + return operatingSystemNameVersion; + } + + /** + * 全面浏览器检测 + */ + private static String formatBrowser(String browser) + { + // Chrome系列浏览器 + Matcher chromeMatcher = CHROME_PATTERN.matcher(browser); + if (chromeMatcher.find() && (browser.contains("Chrome") || browser.contains("CriOS"))) + { + return "Chrome" + chromeMatcher.group(1); + } + // Firefox + Matcher firefoxMatcher = FIREFOX_PATTERN.matcher(browser); + if (firefoxMatcher.find()) + { + return "Firefox" + firefoxMatcher.group(1); + } + // Edge浏览器 + Matcher edgeMatcher = EDGE_PATTERN.matcher(browser); + if (edgeMatcher.find()) + { + return "Edge" + edgeMatcher.group(1); + } + // Safari浏览器(需排除Chrome) + Matcher safariMatcher = SAFARI_PATTERN.matcher(browser); + if (safariMatcher.find() && !browser.contains("Chrome")) + { + return "Safari" + safariMatcher.group(1); + } + // 微信内置浏览器 + Matcher wechatMatcher = WECHAT_PATTERN.matcher(browser); + if (wechatMatcher.find()) + { + return "WeChat" + wechatMatcher.group(1); + } + // UC浏览器 + Matcher ucMatcher = UC_PATTERN.matcher(browser); + if (ucMatcher.find()) + { + return "UC Browser" + ucMatcher.group(1); + } + // QQ浏览器 + Matcher qqMatcher = QQ_PATTERN.matcher(browser); + if (qqMatcher.find()) + { + return "QQ Browser" + qqMatcher.group(1); + } + // 百度浏览器 + Matcher baiduMatcher = BAIDU_PATTERN.matcher(browser); + if (baiduMatcher.find()) + { + return "Baidu Browser" + baiduMatcher.group(1); + } + // Samsung浏览器 + Matcher samsungMatcher = SAMSUNG_PATTERN.matcher(browser); + if (samsungMatcher.find()) + { + return "Samsung Browser" + samsungMatcher.group(1); + } + // Opera浏览器 + Matcher operaMatcher = OPERA_PATTERN.matcher(browser); + if (operaMatcher.find()) + { + return "Opera" + operaMatcher.group(1); + } + // IE浏览器 + Matcher ieMatcher = IE_PATTERN.matcher(browser); + if (ieMatcher.find()) + { + return "Internet Explorer" + ieMatcher.group(1); + } + return UNKNOWN; + } + + /** + * 检测操作系统 + */ + private static String formatOperatingSystem(String operatingSystem) + { + // Windows系统 + Matcher windowsMatcher = WINDOWS_PATTERN.matcher(operatingSystem); + if (windowsMatcher.find()) + { + return "Windows" + getWindowsVersionDisplay(windowsMatcher.group(1)); + } + // macOS系统 + Matcher macMatcher = MACOS_PATTERN.matcher(operatingSystem); + if (macMatcher.find()) + { + String version = macMatcher.group(1).replace("_", "."); + return "macOS" + extractMajorVersion(version); + } + // Android系统 + Matcher androidMatcher = ANDROID_PATTERN.matcher(operatingSystem); + if (androidMatcher.find()) + { + return "Android" + extractMajorVersion(androidMatcher.group(1)); + } + // iOS系统 + Matcher iosMatcher = IOS_PATTERN.matcher(operatingSystem); + if (iosMatcher.find() && (operatingSystem.contains("iPhone") || operatingSystem.contains("iPad"))) + { + return "iOS" + extractMajorVersion(iosMatcher.group(1)); + } + // Linux系统 + if (LINUX_PATTERN.matcher(operatingSystem).find() && !operatingSystem.contains("Android")) + { + return "Linux"; + } + // Chrome OS + if (CHROMEOS_PATTERN.matcher(operatingSystem).find()) + { + return "Chrome OS"; + } + return UNKNOWN; + } + + /** + * 提取优化的主版本号 + */ + private static String extractMajorVersion(String fullVersion) + { + if (StringUtils.isEmpty(fullVersion)) + { + return StringUtils.EMPTY; + } + try + { + // 清理版本号中的非数字字符 + String cleanVersion = fullVersion.replaceAll("[^0-9.]", ""); + String[] parts = cleanVersion.split("\\."); + if (parts.length > 0) + { + String firstPart = parts[0]; + if (firstPart.matches("\\d+")) + { + int version = Integer.parseInt(firstPart); + + // 处理三位数版本号(如142 -> 14) + if (version >= 100) + { + return String.valueOf(version / 10); + } + return firstPart; + } + } + } + catch (NumberFormatException e) + { + // 版本号解析失败,返回原始值 + } + return fullVersion; + } + + /** + * Windows版本号显示优化 + */ + private static String getWindowsVersionDisplay(String version) + { + switch (version) + { + case "10.0": + return "10"; + case "6.3": + return "8.1"; + case "6.2": + return "8"; + case "6.1": + return "7"; + case "6.0": + return "Vista"; + case "5.1": + return "XP"; + case "5.0": + return "2000"; + default: + return extractMajorVersion(version); + } + } +} diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/AddressUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/AddressUtils.java index 7d7759f..4513936 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/AddressUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/AddressUtils.java @@ -12,14 +12,14 @@ import com.cmvr.common.utils.http.HttpUtils; /** * 获取地址类 * - * @author cmvrIot + * @author ruoyi */ public class AddressUtils { private static final Logger log = LoggerFactory.getLogger(AddressUtils.class); // IP地址查询 - public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; + public static final String IP_URL = "https://whois.pconline.com.cn/ipJson.jsp"; // 未知地址 public static final String UNKNOWN = "XX XX"; diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/IpUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/IpUtils.java index 7780d3e..59e8888 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/IpUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/ip/IpUtils.java @@ -2,14 +2,14 @@ package com.cmvr.common.utils.ip; import java.net.InetAddress; import java.net.UnknownHostException; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import com.cmvr.common.utils.ServletUtils; import com.cmvr.common.utils.StringUtils; /** * 获取IP方法 * - * @author cmvrIot + * @author ruoyi */ public class IpUtils { @@ -379,4 +379,4 @@ public class IpUtils } return false; } -} +} \ No newline at end of file diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelHandlerAdapter.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelHandlerAdapter.java index 0ea0a11..47fadb0 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelHandlerAdapter.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelHandlerAdapter.java @@ -6,7 +6,7 @@ import org.apache.poi.ss.usermodel.Workbook; /** * Excel数据格式处理适配器 * - * @author cmvrIot + * @author ruoyi */ public interface ExcelHandlerAdapter { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelSheet.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelSheet.java new file mode 100644 index 0000000..fb790bd --- /dev/null +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelSheet.java @@ -0,0 +1,85 @@ +package com.cmvr.common.utils.poi; + +import java.util.ArrayList; +import java.util.List; + +/** + * 多 Sheet 导出时的数据信息 + * + * 使用示例: + *

+ *   List> sheets = new ArrayList<>();
+ *   sheets.add(new ExcelSheet<>("参数数据", configList, Config.class, "参数信息"));
+ *   sheets.add(new ExcelSheet<>("岗位数据", postList, Post.class, "岗位信息"));
+ *   return ExcelUtil.exportMultiSheet(sheets);
+ * 
+ * + * @author ruoyi + */ +public class ExcelSheet +{ + /** Sheet 名称 */ + private String sheetName; + + /** 导出数据集合 */ + private List list; + + /** 数据对应的实体 Class */ + private Class clazz; + + /** Sheet 顶部大标题(可为空) */ + private String title; + + public ExcelSheet(String sheetName, List list, Class clazz) + { + this(sheetName, list, clazz, ""); + } + + public ExcelSheet(String sheetName, List list, Class clazz, String title) + { + this.sheetName = sheetName; + this.list = list != null ? list : new ArrayList<>(); + this.clazz = clazz; + this.title = title != null ? title : ""; + } + + public String getSheetName() + { + return sheetName; + } + + public List getList() + { + return list; + } + + public Class getClazz() + { + return clazz; + } + + public String getTitle() + { + return title; + } + + public void setSheetName(String sheetName) + { + this.sheetName = sheetName; + } + + public void setList(List list) + { + this.list = list; + } + + public void setClazz(Class clazz) + { + this.clazz = clazz; + } + + public void setTitle(String title) + { + this.title = title; + } +} diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelUtil.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelUtil.java index b232ad3..b12c71f 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelUtil.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/poi/ExcelUtil.java @@ -23,7 +23,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.reflect.FieldUtils; @@ -89,12 +89,14 @@ import com.cmvr.common.utils.reflect.ReflectUtils; /** * Excel相关处理 * - * @author cmvr-iot + * @author ruoyi */ public class ExcelUtil { private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + public static final String SEPARATOR = ","; + public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; @@ -104,6 +106,11 @@ public class ExcelUtil */ public Map sysDictMap = new HashMap(); + /** + * 单元格样式缓存 + */ + private Map cellStyleCache = new HashMap(); + /** * Excel sheet最大行数,默认65536 */ @@ -172,23 +179,18 @@ public class ExcelUtil /** * 对象的子列表方法 */ - private Method subMethod; + private Map subMethods; /** * 对象的子列表属性 */ - private List subFields; + private Map> subFieldsMap; /** * 统计列表 */ private Map statistics = new HashMap(); - /** - * 数字格式 - */ - private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); - /** * 实体对象 */ @@ -255,7 +257,10 @@ public class ExcelUtil int titleLastCol = this.fields.size() - 1; if (isSubList()) { - titleLastCol = titleLastCol + subFields.size() - 1; + for (List currentSubFields : subFieldsMap.values()) + { + titleLastCol = titleLastCol + currentSubFields.size() - 1; + } } Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); titleRow.setHeightInPoints(30); @@ -275,16 +280,17 @@ public class ExcelUtil { Row subRow = sheet.createRow(rownum); int column = 0; - int subFieldSize = subFields != null ? subFields.size() : 0; for (Object[] objects : fields) { Field field = (Field) objects[0]; Excel attr = (Excel) objects[1]; + CellStyle cellStyle = styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())); if (Collection.class.isAssignableFrom(field.getType())) { Cell cell = subRow.createCell(column); cell.setCellValue(attr.name()); - cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + cell.setCellStyle(cellStyle); + int subFieldSize = subFieldsMap != null ? subFieldsMap.get(field.getName()).size() : 0; if (subFieldSize > 1) { CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1); @@ -296,7 +302,7 @@ public class ExcelUtil { Cell cell = subRow.createCell(column++); cell.setCellValue(attr.name()); - cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + cell.setCellStyle(cellStyle); } } rownum++; @@ -360,7 +366,7 @@ public class ExcelUtil throw new IOException("文件sheet不存在"); } boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); - Map pictures; + Map> pictures = null; if (isXSSFWorkbook) { pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); @@ -377,7 +383,11 @@ public class ExcelUtil Map cellMap = new HashMap(); // 获取表头 Row heard = sheet.getRow(titleNum); - for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + if (heard == null) + { + throw new UtilException("文件标题行为空,请检查Excel文件格式"); + } + for (int i = 0; i < heard.getLastCellNum(); i++) { Cell cell = heard.getCell(i); if (StringUtils.isNotNull(cell)) @@ -385,10 +395,6 @@ public class ExcelUtil String value = this.getCellValue(heard, i).toString(); cellMap.put(value, i); } - else - { - cellMap.put(null, i); - } } // 有数据时才处理 得到类的所有field. List fields = this.getFields(); @@ -417,7 +423,7 @@ public class ExcelUtil Object val = this.getCellValue(row, entry.getKey()); // 如果不存在实例则新建. - entity = (entity == null ? clazz.newInstance() : entity); + entity = (entity == null ? clazz.getDeclaredConstructor().newInstance() : entity); // 从map中得到对应列的field. Field field = (Field) entry.getValue()[0]; Excel attr = (Excel) entry.getValue()[1]; @@ -426,7 +432,7 @@ public class ExcelUtil if (String.class == fieldType) { String s = Convert.toStr(val); - if (StringUtils.endsWith(s, ".0")) + if (s.matches("^\\d+\\.0$")) { val = StringUtils.substringBefore(s, ".0"); } @@ -504,16 +510,15 @@ public class ExcelUtil } else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) { - PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); - if (image == null) + StringBuilder propertyString = new StringBuilder(); + List images = pictures.get(row.getRowNum() + "_" + entry.getKey()); + for (PictureData picture : images) { - val = ""; - } - else - { - byte[] data = image.getData(); - val = FileUtils.writeImportBytes(data); + byte[] data = picture.getData(); + String fileName = FileUtils.writeImportBytes(data); + propertyString.append(fileName).append(SEPARATOR); } + val = StringUtils.stripEnd(propertyString.toString(), SEPARATOR); } ReflectUtils.invokeSetter(entity, propertyName, val); } @@ -580,6 +585,117 @@ public class ExcelUtil exportExcel(response); } + /** + * 多 Sheet 导出 —— 将多个不同类型的数据集合写入同一 Excel,直接输出到 HttpServletResponse + * + * @param response HTTP 响应 + * @param sheets Sheet 描述列表 + */ + public static void exportMultiSheet(HttpServletResponse response, List> sheets) + { + if (sheets == null || sheets.isEmpty()) + { + return; + } + SXSSFWorkbook wb = buildWorkbook(sheets); + try + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + wb.write(response.getOutputStream()); + } + catch (Exception e) + { + log.error("多Sheet导出Excel异常{}", e.getMessage()); + } + finally + { + IOUtils.closeQuietly(wb); + } + } + + /** + * 多 Sheet 导出 —— 将多个不同类型的数据集合写入同一 Excel,生成文件并返回下载地址 + * + * @param sheets Sheet 描述列表 + * @return AjaxResult(含文件下载地址) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static AjaxResult exportMultiSheet(List> sheets) + { + if (sheets == null || sheets.isEmpty()) + { + return AjaxResult.error("导出数据不能为空"); + } + SXSSFWorkbook wb = buildWorkbook(sheets); + OutputStream out = null; + try + { + ExcelUtil firstUtil = new ExcelUtil(sheets.get(0).getClazz()); + String filename = firstUtil.encodingFilename(sheets.get(0).getSheetName()); + out = new FileOutputStream(firstUtil.getAbsoluteFile(filename)); + wb.write(out); + return AjaxResult.success(filename); + } + catch (Exception e) + { + log.error("多Sheet导出Excel异常{}", e.getMessage()); + throw new UtilException("导出Excel失败,请联系网站管理员!"); + } + finally + { + IOUtils.closeQuietly(wb); + IOUtils.closeQuietly(out); + } + } + + /** + * 构建多 Sheet Workbook —— 创建 SXSSFWorkbook 并将所有 Sheet 数据写入 + * + * @param sheets Sheet 描述列表 + * @return 已写入所有 Sheet 数据的 SXSSFWorkbook + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static SXSSFWorkbook buildWorkbook(List> sheets) + { + SXSSFWorkbook wb = new SXSSFWorkbook(500); + for (ExcelSheet excelSheet : sheets) + { + ExcelUtil util = new ExcelUtil(excelSheet.getClazz()); + util.initWithWorkbook(wb, excelSheet.getList(), excelSheet.getSheetName(), excelSheet.getTitle()); + util.writeSheet(); + } + return wb; + } + + /** + * 使用外部传入的 Workbook 初始化(多 Sheet 导出专用) + * 与 init() 的区别:不新建 Workbook,而是在已有 wb 上追加新 Sheet + * + * @param wb 已有工作簿 + * @param list 数据集合 + * @param sheetName Sheet 名称 + * @param title 大标题(可为空) + */ + public void initWithWorkbook(SXSSFWorkbook wb, List list, String sheetName, String title) + { + if (list == null) + { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.title = title != null ? title : ""; + this.type = Type.EXPORT; + this.rownum = 0; + this.wb = wb; + this.sheet = wb.createSheet(sheetName); + createExcelField(); + this.styles = createStyles(wb); + createTitle(); + createSubHead(); + } + /** * 对list数据源将其里面的数据导入到excel表单 * @@ -701,7 +817,8 @@ public class ExcelUtil Excel excel = (Excel) os[1]; if (Collection.class.isAssignableFrom(field.getType())) { - for (Field subField : subFields) + List currentSubFields = subFieldsMap.get(field.getName()); + for (Field subField : currentSubFields) { Excel subExcel = subField.getAnnotation(Excel.class); this.createHeadCell(subExcel, row, column++); @@ -714,7 +831,7 @@ public class ExcelUtil } if (Type.EXPORT.equals(type)) { - fillExcelData(index, row); + fillExcelData(index); addStatisticsRow(); } } @@ -724,10 +841,9 @@ public class ExcelUtil * 填充excel数据 * * @param index 序号 - * @param row 单元格行 */ @SuppressWarnings("unchecked") - public void fillExcelData(int index, Row row) + public void fillExcelData(int index) { int startNo = index * sheetSize; int endNo = Math.min(startNo + sheetSize, list.size()); @@ -735,7 +851,7 @@ public class ExcelUtil for (int i = startNo; i < endNo; i++) { - row = sheet.createRow(currentRowNum); + Row row = sheet.createRow(currentRowNum); T vo = (T) list.get(i); int column = 0; int maxSubListSize = getCurrentMaxSubListSize(vo); @@ -748,6 +864,7 @@ public class ExcelUtil try { Collection subList = (Collection) getTargetValue(vo, field, excel); + List currentSubFields = subFieldsMap.get(field.getName()); if (subList != null && !subList.isEmpty()) { int subIndex = 0; @@ -760,15 +877,15 @@ public class ExcelUtil } int subColumn = column; - for (Field subField : subFields) + for (Field subField : currentSubFields) { Excel subExcel = subField.getAnnotation(Excel.class); addCell(subExcel, subRow, (T) subVo, subField, subColumn++); } subIndex++; } - column += subFields.size(); } + column += currentSubFields.size(); } catch (Exception e) { @@ -860,6 +977,7 @@ public class ExcelUtil style = wb.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setDataFormat(dataFormat.getFormat("######0.00")); Font totalFont = wb.createFont(); totalFont.setFontName("Arial"); totalFont.setFontHeightInPoints((short) 10); @@ -1037,12 +1155,15 @@ public class ExcelUtil else if (ColumnType.IMAGE == attr.cellType()) { ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); - String imagePath = Convert.toStr(value); - if (StringUtils.isNotEmpty(imagePath)) + String propertyValue = Convert.toStr(value); + if (StringUtils.isNotEmpty(propertyValue)) { - byte[] data = ImageUtils.getImage(imagePath); - getDrawingPatriarch(cell.getSheet()).createPicture(anchor, - cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + List imagePaths = StringUtils.str2List(propertyValue, SEPARATOR); + for (String imagePath : imagePaths) + { + byte[] data = ImageUtils.getImage(imagePath); + getDrawingPatriarch(cell.getSheet()).createPicture(anchor, cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } } } } @@ -1119,6 +1240,7 @@ public class ExcelUtil /** * 添加单元格 */ + @SuppressWarnings("deprecation") public Cell addCell(Excel attr, Row row, T vo, Field field, int column) { Cell cell = null; @@ -1131,7 +1253,7 @@ public class ExcelUtil { // 创建cell cell = row.createCell(column); - if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) + if (isSubListValue(vo) && getListCellValue(vo) > 1 && attr.needMerge()) { if (subMergedLastRowNum >= subMergedFirstRowNum) { @@ -1148,6 +1270,7 @@ public class ExcelUtil String dictType = attr.dictType(); if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) { + cell.setCellStyle(createCellStyle(cell.getCellStyle(), dateFormat)); cell.setCellValue(parseDateToStr(dateFormat, value)); } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) @@ -1186,6 +1309,28 @@ public class ExcelUtil return cell; } + /** + * 使用自定义格式,同时避免样式污染 + * + * @param cellStyle 从此样式复制 + * @param format 格式匹配的字符串 + * @return 格式化后CellStyle对象 + */ + private CellStyle createCellStyle(CellStyle cellStyle, String format) + { + String key = cellStyle.getIndex() + "|" + format; + CellStyle cached = cellStyleCache.get(key); + if (cached != null) + { + return cached; + } + CellStyle style = wb.createCellStyle(); + style.cloneStyleFrom(cellStyle); + style.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat(format)); + cellStyleCache.put(key, style); + return style; + } + /** * 设置 POI XSSFSheet 单元格提示或选择框 * @@ -1237,18 +1382,36 @@ public class ExcelUtil public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) { String hideSheetName = "combo_" + firstCol + "_" + endCol; - Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 - for (int i = 0; i < textlist.length; i++) + Sheet hideSheet = null; + String hideSheetDataName = hideSheetName + "_data"; + Name name = wb.getName(hideSheetDataName); + if (name != null) { - hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); + // 名称已存在,尝试从名称的引用中找到sheet名称 + String refersToFormula = name.getRefersToFormula(); + if (StringUtils.isNotEmpty(refersToFormula) && refersToFormula.contains("!")) + { + String sheetNameFromFormula = refersToFormula.substring(0, refersToFormula.indexOf("!")); + hideSheet = wb.getSheet(sheetNameFromFormula); + } } - // 创建名称,可被其他单元格引用 - Name name = wb.createName(); - name.setNameName(hideSheetName + "_data"); - name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); + + if (hideSheet == null) + { + hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 + for (int i = 0; i < textlist.length; i++) + { + hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); + } + // 创建名称,可被其他单元格引用 + name = wb.createName(); + name.setNameName(hideSheetDataName); + name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); + } + DataValidationHelper helper = sheet.getDataValidationHelper(); // 加载下拉列表内容 - DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data"); + DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetDataName); // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); // 数据有效性对象 @@ -1286,7 +1449,7 @@ public class ExcelUtil public static String convertByExp(String propertyValue, String converterExp, String separator) { StringBuilder propertyString = new StringBuilder(); - String[] convertSource = converterExp.split(","); + String[] convertSource = converterExp.split(SEPARATOR); for (String item : convertSource) { String[] itemArray = item.split("="); @@ -1323,7 +1486,7 @@ public class ExcelUtil public static String reverseByExp(String propertyValue, String converterExp, String separator) { StringBuilder propertyString = new StringBuilder(); - String[] convertSource = converterExp.split(","); + String[] convertSource = converterExp.split(SEPARATOR); for (String item : convertSource) { String[] itemArray = item.split("="); @@ -1386,7 +1549,7 @@ public class ExcelUtil { try { - Object instance = excel.handler().newInstance(); + Object instance = excel.handler().getDeclaredConstructor().newInstance(); Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class }); value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb); } @@ -1437,7 +1600,7 @@ public class ExcelUtil { cell = row.createCell(key); cell.setCellStyle(styles.get("total")); - cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + cell.setCellValue(statistics.get(key)); } statistics.clear(); } @@ -1448,8 +1611,7 @@ public class ExcelUtil */ public String encodingFilename(String filename) { - filename = UUID.randomUUID() + "_" + filename + ".xlsx"; - return filename; + return UUID.randomUUID() + "_" + filename + ".xlsx"; } /** @@ -1537,6 +1699,8 @@ public class ExcelUtil { List fields = new ArrayList(); List tempFields = new ArrayList<>(); + subFieldsMap = new HashMap<>(); + subMethods = new HashMap<>(); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); if (StringUtils.isNotEmpty(includeFields)) @@ -1584,10 +1748,11 @@ public class ExcelUtil } if (Collection.class.isAssignableFrom(field.getType())) { - subMethod = getSubMethod(field.getName(), clazz); + String fieldName = field.getName(); + subMethods.put(fieldName, getSubMethod(fieldName, clazz)); ParameterizedType pt = (ParameterizedType) field.getGenericType(); Class subClass = (Class) pt.getActualTypeArguments()[0]; - this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + subFieldsMap.put(fieldName, FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class)); } } @@ -1656,7 +1821,8 @@ public class ExcelUtil { this.sheet = wb.createSheet(); this.createTitle(); - wb.setSheetName(index, sheetName + index); + int actualIndex = wb.getSheetIndex(this.sheet); + wb.setSheetName(actualIndex, sheetName + index); } } @@ -1750,30 +1916,24 @@ public class ExcelUtil * @param workbook 工作簿对象 * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData */ - public static Map getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) + public static Map> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) { - Map sheetIndexPicMap = new HashMap(); + Map> sheetIndexPicMap = new HashMap<>(); List pictures = workbook.getAllPictures(); - if (!pictures.isEmpty()) + if (!pictures.isEmpty() && sheet.getDrawingPatriarch() != null) { for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) { - HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); if (shape instanceof HSSFPicture) { HSSFPicture pic = (HSSFPicture) shape; - int pictureIndex = pic.getPictureIndex() - 1; - HSSFPictureData picData = pictures.get(pictureIndex); + HSSFClientAnchor anchor = (HSSFClientAnchor) pic.getAnchor(); String picIndex = anchor.getRow1() + "_" + anchor.getCol1(); - sheetIndexPicMap.put(picIndex, picData); + sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData()); } } - return sheetIndexPicMap; - } - else - { - return sheetIndexPicMap; } + return sheetIndexPicMap; } /** @@ -1783,16 +1943,15 @@ public class ExcelUtil * @param workbook 工作簿对象 * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData */ - public static Map getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) + public static Map> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) { - Map sheetIndexPicMap = new HashMap(); + Map> sheetIndexPicMap = new HashMap<>(); for (POIXMLDocumentPart dr : sheet.getRelations()) { if (dr instanceof XSSFDrawing) { XSSFDrawing drawing = (XSSFDrawing) dr; - List shapes = drawing.getShapes(); - for (XSSFShape shape : shapes) + for (XSSFShape shape : drawing.getShapes()) { if (shape instanceof XSSFPicture) { @@ -1800,7 +1959,7 @@ public class ExcelUtil XSSFClientAnchor anchor = pic.getPreferredSize(); CTMarker ctMarker = anchor.getFrom(); String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); - sheetIndexPicMap.put(picIndex, pic.getPictureData()); + sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData()); } } } @@ -1846,7 +2005,7 @@ public class ExcelUtil */ public boolean isSubList() { - return StringUtils.isNotNull(subFields) && subFields.size() > 0; + return !StringUtils.isEmpty(subFieldsMap); } /** @@ -1854,24 +2013,32 @@ public class ExcelUtil */ public boolean isSubListValue(T vo) { - return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0; + return !StringUtils.isEmpty(subFieldsMap) && getListCellValue(vo) > 0; } /** * 获取集合的值 */ - public Collection getListCellValue(Object obj) + public int getListCellValue(Object obj) { - Object value; + Collection value; + int max = 0; try { - value = subMethod.invoke(obj, new Object[] {}); + for (String s : subMethods.keySet()) + { + value = (Collection) subMethods.get(s).invoke(obj); + if (value.size() > max) + { + max = value.size(); + } + } } catch (Exception e) { - return new ArrayList(); + return 0; } - return (Collection) value; + return max; } /** diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/reflect/ReflectUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/reflect/ReflectUtils.java index 16cfe03..c3ec418 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/reflect/ReflectUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/reflect/ReflectUtils.java @@ -7,18 +7,18 @@ import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Date; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.poi.ss.usermodel.DateUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cmvr.common.core.text.Convert; import com.cmvr.common.utils.DateUtils; +import com.cmvr.common.utils.StringUtils; /** * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. * - * @author cmvrIot + * @author ruoyi */ @SuppressWarnings("rawtypes") public class ReflectUtils @@ -310,6 +310,7 @@ public class ReflectUtils /** * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ + @SuppressWarnings("deprecation") public static void makeAccessible(Method method) { if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) @@ -322,6 +323,7 @@ public class ReflectUtils /** * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ + @SuppressWarnings("deprecation") public static void makeAccessible(Field field) { if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Base64.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Base64.java index c87960a..1cd185d 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Base64.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Base64.java @@ -3,7 +3,7 @@ package com.cmvr.common.utils.sign; /** * Base64工具类 * - * @author cmvrIot + * @author ruoyi */ public final class Base64 { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Md5Utils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Md5Utils.java index 170e602..1b91b21 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Md5Utils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sign/Md5Utils.java @@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory; /** * Md5加密方法 * - * @author cmvrIot + * @author ruoyi */ public class Md5Utils { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/spring/SpringUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/spring/SpringUtils.java index 4d40194..1d5398b 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/spring/SpringUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/spring/SpringUtils.java @@ -1,5 +1,6 @@ package com.cmvr.common.utils.spring; +import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.AopContext; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -13,7 +14,7 @@ import com.cmvr.common.utils.StringUtils; /** * spring工具类 方便在非spring管理环境中获取bean * - * @author cmvrIot + * @author ruoyi */ @Component public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware @@ -120,7 +121,12 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC @SuppressWarnings("unchecked") public static T getAopProxy(T invoker) { - return (T) AopContext.currentProxy(); + Object proxy = AopContext.currentProxy(); + if (((Advised) proxy).getTargetSource().getTargetClass() == invoker.getClass()) + { + return (T) proxy; + } + return invoker; } /** diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sql/SqlUtil.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sql/SqlUtil.java index daa9c85..5251c47 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sql/SqlUtil.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/sql/SqlUtil.java @@ -6,14 +6,14 @@ import com.cmvr.common.utils.StringUtils; /** * sql操作工具类 * - * @author cmvrIot + * @author ruoyi */ public class SqlUtil { /** * 定义常用的 sql关键字 */ - public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()"; + public static String SQL_REGEX = "\u000B|%0A|and |extractvalue|updatexml|sleep|information_schema|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()"; /** * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) @@ -58,12 +58,13 @@ public class SqlUtil { return; } + String normalizedValue = value.replaceAll("\\p{Z}|\\s", ""); String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); for (String sqlKeyword : sqlKeywords) { - if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) + if (StringUtils.indexOfIgnoreCase(normalizedValue, sqlKeyword) > -1) { - throw new UtilException("参数存在SQL注入风险"); + throw new UtilException("请求参数包含敏感关键词'" + sqlKeyword + "',可能存在安全风险"); } } } diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/IdUtils.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/IdUtils.java index c494a3e..95677ef 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/IdUtils.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/IdUtils.java @@ -3,7 +3,7 @@ package com.cmvr.common.utils.uuid; /** * ID生成器工具类 * - * @author cmvrIot + * @author ruoyi */ public class IdUtils { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/Seq.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/Seq.java index c2b35e6..1b4d124 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/Seq.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/Seq.java @@ -5,7 +5,7 @@ import com.cmvr.common.utils.DateUtils; import com.cmvr.common.utils.StringUtils; /** - * @author cmvrIot 序列生成类 + * @author ruoyi 序列生成类 */ public class Seq { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/UUID.java b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/UUID.java index b7650fe..8cd06ee 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/UUID.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/utils/uuid/UUID.java @@ -10,7 +10,7 @@ import com.cmvr.common.exception.UtilException; /** * 提供通用唯一识别码(universally unique identifier)(UUID)实现 * - * @author cmvrIot + * @author ruoyi */ public final class UUID implements java.io.Serializable, Comparable { diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/xss/Xss.java b/cmvr-iot-common/src/main/java/com/cmvr/common/xss/Xss.java index 2784863..faea558 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/xss/Xss.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/xss/Xss.java @@ -1,7 +1,7 @@ package com.cmvr.common.xss; -import javax.validation.Constraint; -import javax.validation.Payload; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -10,7 +10,7 @@ import java.lang.annotation.Target; /** * 自定义xss校验注解 * - * @author cmvrIot + * @author ruoyi */ @Retention(RetentionPolicy.RUNTIME) @Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER }) diff --git a/cmvr-iot-common/src/main/java/com/cmvr/common/xss/XssValidator.java b/cmvr-iot-common/src/main/java/com/cmvr/common/xss/XssValidator.java index 7c68c90..6601bfb 100644 --- a/cmvr-iot-common/src/main/java/com/cmvr/common/xss/XssValidator.java +++ b/cmvr-iot-common/src/main/java/com/cmvr/common/xss/XssValidator.java @@ -1,15 +1,15 @@ package com.cmvr.common.xss; import com.cmvr.common.utils.StringUtils; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 自定义xss校验注解实现 * - * @author cmvrIot + * @author ruoyi */ public class XssValidator implements ConstraintValidator { @@ -36,4 +36,4 @@ public class XssValidator implements ConstraintValidator } return pattern.matcher(sHtml).matches(); } -} +} \ No newline at end of file diff --git a/cmvr-iot-device/pom.xml b/cmvr-iot-device/pom.xml index 344f455..ef55fb4 100644 --- a/cmvr-iot-device/pom.xml +++ b/cmvr-iot-device/pom.xml @@ -6,7 +6,7 @@ com.cmvr cmvr-iot - 3.8.9 + 3.9.2 cmvr-iot-device diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceTerminalConfig.java b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceTerminalConfig.java index 9905ae1..5f41236 100644 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceTerminalConfig.java +++ b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceTerminalConfig.java @@ -12,6 +12,8 @@ import org.apache.commons.lang3.builder.ToStringStyle; import com.cmvr.common.annotation.Excel; import com.cmvr.common.core.domain.BaseEntity; +import java.util.Date; + /** * 设备终端配置对象 de_device_terminal_config * @@ -61,4 +63,33 @@ public class DeDeviceTerminalConfig extends BaseEntity @ApiModelProperty("说明") private String description; + /** QUIC终端主动注册时使用的稳定节点ID,人工绑定后不可与其他终端重复。 */ + @Excel(name = "QUIC节点ID") + @ApiModelProperty("QUIC节点ID") + private String quicNodeId; + + /** Gateway从已认证QUIC连接中观察到的源IP。 */ + @ApiModelProperty("QUIC连接源IP") + private String quicObservedIp; + + /** 当前QUIC注册会话ID。 */ + @ApiModelProperty("QUIC会话ID") + private String quicSessionId; + + /** 终端本次操作系统启动ID。 */ + @ApiModelProperty("QUIC终端启动ID") + private String quicBootId; + + /** cmvr-es上报的软件版本。 */ + @ApiModelProperty("终端软件版本") + private String quicSoftwareVersion; + + /** QUIC在线状态:0离线,1在线;与原有status启停字段相互独立。 */ + @ApiModelProperty("QUIC在线状态:0离线,1在线") + private String quicOnlineStatus; + + /** 最近一次收到有效QUIC心跳或注册事件的时间。 */ + @ApiModelProperty("最近QUIC心跳时间") + private Date quicLastHeartbeatTime; + } diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceTerminalConfigMapper.java b/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceTerminalConfigMapper.java index c9d5da1..2a5437e 100644 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceTerminalConfigMapper.java +++ b/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceTerminalConfigMapper.java @@ -5,6 +5,9 @@ import java.util.List; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.cmvr.device.domain.DeDeviceTerminalConfig; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; /** * 设备终端配置Mapper接口 @@ -23,6 +26,22 @@ public interface DeDeviceTerminalConfigMapper extends BaseMapper + + + + + + + - select id, create_by, create_time, update_by, update_time, remake, name, host, port, status, description from de_device_terminal_config + select id, create_by, create_time, update_by, update_time, remake, name, host, port, status, description, + quic_node_id, quic_observed_ip, quic_session_id, quic_boot_id, quic_software_version, + quic_online_status, quic_last_heartbeat_time + from de_device_terminal_config + +