From 2c2d6c3d265b76b09a15e4ce139164f9bb6fa127 Mon Sep 17 00:00:00 2001 From: lzh Date: Sun, 5 Apr 2026 16:48:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(video):=20=E6=96=B0=E5=BB=BA=20viewsh-modu?= =?UTF-8?q?le-video=20=E6=9C=8D=E5=8A=A1=E6=A8=A1=E5=9D=97=E9=AA=A8?= =?UTF-8?q?=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增视频管理模块,用于后续迁移 WVP-Platform(GB28181 视频监控平台)。 - viewsh-module-video-api: 契约层(Feign RPC 接口、枚举、错误码) - viewsh-module-video-server: 业务层(端口 48093) - 网关路由: video-admin-api / video-app-api - SecurityConfiguration: 放行 Swagger/Actuator/Druid/RPC Co-Authored-By: Claude Sonnet 4.6 (1M context) --- pom.xml | 1 + .../src/main/resources/application.yaml | 16 + viewsh-module-video/pom.xml | 25 + .../viewsh-module-video-api/pom.xml | 61 ++ .../viewsh/module/video/api/package-info.java | 4 + .../module/video/enums/ApiConstants.java | 21 + .../video/enums/ErrorCodeConstants.java | 15 + .../viewsh-module-video-server/pom.xml | 138 +++ .../module/video/VideoServerApplication.java | 16 + .../config/SecurityConfiguration.java | 39 + .../src/main/resources/application-local.yaml | 123 +++ .../src/main/resources/application.yaml | 122 +++ .../src/main/resources/logback-spring.xml | 43 + 新建服务 yudao-cloud 开发指南.md | 862 ++++++++++++++++++ 14 files changed, 1486 insertions(+) create mode 100644 viewsh-module-video/pom.xml create mode 100644 viewsh-module-video/viewsh-module-video-api/pom.xml create mode 100644 viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/api/package-info.java create mode 100644 viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ApiConstants.java create mode 100644 viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ErrorCodeConstants.java create mode 100644 viewsh-module-video/viewsh-module-video-server/pom.xml create mode 100644 viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/VideoServerApplication.java create mode 100644 viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/framework/security/config/SecurityConfiguration.java create mode 100644 viewsh-module-video/viewsh-module-video-server/src/main/resources/application-local.yaml create mode 100644 viewsh-module-video/viewsh-module-video-server/src/main/resources/application.yaml create mode 100644 viewsh-module-video/viewsh-module-video-server/src/main/resources/logback-spring.xml create mode 100644 新建服务 yudao-cloud 开发指南.md diff --git a/pom.xml b/pom.xml index 916e1a05..5f163070 100644 --- a/pom.xml +++ b/pom.xml @@ -27,6 +27,7 @@ viewsh-module-iot viewsh-module-ops + viewsh-module-video ${project.artifactId} diff --git a/viewsh-gateway/src/main/resources/application.yaml b/viewsh-gateway/src/main/resources/application.yaml index a4941c76..77ca8df5 100644 --- a/viewsh-gateway/src/main/resources/application.yaml +++ b/viewsh-gateway/src/main/resources/application.yaml @@ -212,6 +212,19 @@ spring: uri: grayLb://ops-server predicates: - Path=/open-api/ops/** + ## video-server 服务 + - id: video-admin-api # 路由的编号 + uri: grayLb://video-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/video/** + filters: + - RewritePath=/admin-api/video/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + - id: video-app-api # 路由的编号 + uri: grayLb://video-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/video/** + filters: + - RewritePath=/app-api/video/v3/api-docs, /v3/api-docs x-forwarded: prefix-enabled: false # 避免 Swagger 重复带上额外的 /admin-api/system 前缀 @@ -272,6 +285,9 @@ knife4j: - name: ops-server service-name: ops-server url: /admin-api/ops/v3/api-docs + - name: video-server + service-name: video-server + url: /admin-api/video/v3/api-docs --- #################### 芋道相关配置 #################### diff --git a/viewsh-module-video/pom.xml b/viewsh-module-video/pom.xml new file mode 100644 index 00000000..cd279278 --- /dev/null +++ b/viewsh-module-video/pom.xml @@ -0,0 +1,25 @@ + + + + viewsh + com.viewsh + ${revision} + + 4.0.0 + + viewsh-module-video + pom + + + viewsh-module-video-api + viewsh-module-video-server + + + ${project.artifactId} + + video 模块,主要实现摄像头管理、视频流管理、录像回放、NVR 对接等功能。 + + + diff --git a/viewsh-module-video/viewsh-module-video-api/pom.xml b/viewsh-module-video/viewsh-module-video-api/pom.xml new file mode 100644 index 00000000..55076d18 --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-api/pom.xml @@ -0,0 +1,61 @@ + + + + viewsh-module-video + com.viewsh + ${revision} + + 4.0.0 + viewsh-module-video-api + jar + + ${project.artifactId} + + video 模块 API,暴露给其它模块调用 + + + + + com.viewsh + viewsh-common + + + + + org.springframework + spring-web + provided + + + + + com.fasterxml.jackson.core + jackson-databind + provided + + + + + org.springframework.boot + spring-boot-starter-validation + true + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + provided + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + true + + + + diff --git a/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/api/package-info.java b/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/api/package-info.java new file mode 100644 index 00000000..22946e18 --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/api/package-info.java @@ -0,0 +1,4 @@ +/** + * video 模块 API,暴露给其它模块调用 + */ +package com.viewsh.module.video.api; diff --git a/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ApiConstants.java b/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ApiConstants.java new file mode 100644 index 00000000..5901b2b9 --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ApiConstants.java @@ -0,0 +1,21 @@ +package com.viewsh.module.video.enums; + +import com.viewsh.framework.common.enums.RpcConstants; + +/** + * API 相关的枚举 + */ +public class ApiConstants { + + /** + * 服务名 + * + * 注意,需要保证和 spring.application.name 保持一致 + */ + public static final String NAME = "video-server"; + + public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/video"; + + public static final String VERSION = "1.0.0"; + +} diff --git a/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ErrorCodeConstants.java b/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ErrorCodeConstants.java new file mode 100644 index 00000000..075e733f --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-api/src/main/java/com/viewsh/module/video/enums/ErrorCodeConstants.java @@ -0,0 +1,15 @@ +package com.viewsh.module.video.enums; + +import com.viewsh.framework.common.exception.ErrorCode; + +/** + * video 错误码枚举类 + * + * video 系统,使用 1-060-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 摄像头相关 1-060-001-000 ============ + ErrorCode CAMERA_NOT_EXISTS = new ErrorCode(1_060_001_000, "摄像头不存在"); + +} diff --git a/viewsh-module-video/viewsh-module-video-server/pom.xml b/viewsh-module-video/viewsh-module-video-server/pom.xml new file mode 100644 index 00000000..2a4b51e1 --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-server/pom.xml @@ -0,0 +1,138 @@ + + + + viewsh-module-video + com.viewsh + ${revision} + + 4.0.0 + jar + + viewsh-module-video-server + + ${project.artifactId} + + video 模块,主要实现摄像头管理、视频流管理、录像回放、NVR 对接等功能。 + + + + + + com.viewsh + viewsh-spring-boot-starter-env + + + + + com.viewsh + viewsh-module-system-api + ${revision} + + + com.viewsh + viewsh-module-iot-api + ${revision} + + + com.viewsh + viewsh-module-video-api + ${revision} + + + + + com.viewsh + viewsh-spring-boot-starter-biz-tenant + + + + + com.viewsh + viewsh-spring-boot-starter-web + + + com.viewsh + viewsh-spring-boot-starter-security + + + + + com.viewsh + viewsh-spring-boot-starter-mybatis + + + com.viewsh + viewsh-spring-boot-starter-redis + + + + + com.viewsh + viewsh-spring-boot-starter-rpc + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + com.viewsh + viewsh-spring-boot-starter-job + + + + + com.viewsh + viewsh-spring-boot-starter-mq + + + + + com.viewsh + viewsh-spring-boot-starter-test + + + + + com.viewsh + viewsh-spring-boot-starter-monitor + + + + + com.viewsh + viewsh-spring-boot-starter-excel + + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + diff --git a/viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/VideoServerApplication.java b/viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/VideoServerApplication.java new file mode 100644 index 00000000..7314f13b --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/VideoServerApplication.java @@ -0,0 +1,16 @@ +package com.viewsh.module.video; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Video 视频模块的启动类 + */ +@SpringBootApplication +public class VideoServerApplication { + + public static void main(String[] args) { + SpringApplication.run(VideoServerApplication.class, args); + } + +} diff --git a/viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/framework/security/config/SecurityConfiguration.java b/viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/framework/security/config/SecurityConfiguration.java new file mode 100644 index 00000000..d5bc7fe0 --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-server/src/main/java/com/viewsh/module/video/framework/security/config/SecurityConfiguration.java @@ -0,0 +1,39 @@ +package com.viewsh.module.video.framework.security.config; + +import com.viewsh.framework.security.config.AuthorizeRequestsCustomizer; +import com.viewsh.module.video.enums.ApiConstants; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; + +/** + * Video 模块的 Security 配置 + */ +@Configuration("videoSecurityConfiguration") +public class SecurityConfiguration { + + @Bean("videoAuthorizeRequestsCustomizer") + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry registry) { + // Swagger 接口文档 + registry.requestMatchers("/v3/api-docs/**").permitAll() + .requestMatchers("/webjars/**").permitAll() + .requestMatchers("/swagger-ui").permitAll() + .requestMatchers("/swagger-ui/**").permitAll(); + // Spring Boot Actuator 的安全配置 + registry.requestMatchers("/actuator").anonymous() + .requestMatchers("/actuator/**").anonymous(); + // Druid 监控 + registry.requestMatchers("/druid/**").anonymous(); + // RPC 服务的安全配置 + registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); + } + + }; + } + +} diff --git a/viewsh-module-video/viewsh-module-video-server/src/main/resources/application-local.yaml b/viewsh-module-video/viewsh-module-video-server/src/main/resources/application-local.yaml new file mode 100644 index 00000000..b191dfeb --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-server/src/main/resources/application-local.yaml @@ -0,0 +1,123 @@ +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 124.222.218.198:8848 # Nacos 服务器地址 + username: nacos # Nacos 账号 + password: 9oDxX~}e7DeP # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + metadata: + version: 1.0.0 # 服务实例的版本号,可用于灰度发布 + server-identity: nacosAuthKey # 身份验证密钥键 + server-identity-key: 8fG4s7J2kL9pQ3dR6xT1vZ0bW5nC8mE7hY2jU4qA0rS9tV6wB3fD1gH5kL8pN2 # 密钥值 + token: Z1xC9vT6pM3qL7rF2sW8bH0kD5nJ4aY9eV6uG1oR3tB8mN2wQ7cK5xS0jP4hL1 # 身份验证令牌 + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + +--- #################### 数据库相关配置 #################### +spring: + # 数据源配置项 + autoconfigure: + exclude: + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 1 # 初始连接数 + min-idle: 1 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 60000 # 配置获取连接等待超时的时间,单位:毫秒(1 分钟) + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒(1 分钟) + min-evictable-idle-time-millis: 600000 # 配置一个连接在池中最小生存的时间,单位:毫秒(10 分钟) + max-evictable-idle-time-millis: 1800000 # 配置一个连接在池中最大生存的时间,单位:毫秒(30 分钟) + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + pool-prepared-statements: true # 是否开启 PreparedStatement 缓存 + max-pool-prepared-statement-per-connection-size: 20 # 每个连接缓存的 PreparedStatement 数量 + primary: master + datasource: + master: + url: jdbc:mysql://${MYSQL_HOST:124.222.218.198}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:aiot-platform}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + username: ${MYSQL_USERNAME:root} + password: ${MYSQL_PASSWORD:65p^VTPi9Qd+} + slave: # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://${MYSQL_HOST:124.222.218.198}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:aiot-platform}?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true + username: ${MYSQL_USERNAME:root} + password: ${MYSQL_PASSWORD:65p^VTPi9Qd+} + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + data: + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +--- #################### MQ 消息队列相关配置 #################### + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + enabled: false # 是否开启调度中心,默认为 true 开启 + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + username: admin + password: admin + +# 日志文件配置 +logging: + level: + # 配置自己写的 MyBatis Mapper 打印日志 + com.viewsh.module.video.dal.mysql: debug + org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 diff --git a/viewsh-module-video/viewsh-module-video-server/src/main/resources/application.yaml b/viewsh-module-video/viewsh-module-video-server/src/main/resources/application.yaml new file mode 100644 index 00000000..dcd5f6eb --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-server/src/main/resources/application.yaml @@ -0,0 +1,122 @@ +spring: + application: + name: video-server + + profiles: + active: local + + main: + allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 + allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务 + + config: + import: + - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置 + - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置 + + # Servlet 配置 + servlet: + # 文件上传相关配置项 + multipart: + max-file-size: 16MB # 单个文件大小 + max-request-size: 32MB # 设置总上传的文件大小 + + # Jackson 配置项 + jackson: + serialization: + write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳 + write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401 + write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳 + fail-on-empty-beans: false # 允许序列化无属性的 Bean + + # Cache 配置项 + cache: + type: REDIS + redis: + time-to-live: 1h # 设置过期时间为 1 小时 + +server: + port: 48093 + +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +--- #################### 接口文档配置 #################### + +springdoc: + api-docs: + enabled: true # 1. 是否开启 Swagger 接文档的元数据 + path: /v3/api-docs + swagger-ui: + enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面 + path: /swagger-ui + default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 + +knife4j: + enable: true + setting: + language: zh_cn + +# MyBatis Plus 的配置项 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + global-config: + db-config: + id-type: NONE # "智能"模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + banner: false # 关闭控制台的 Banner 打印 + type-aliases-package: ${viewsh.info.base-package}.dal.dataobject + encryptor: + password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成 + +mybatis-plus-join: + banner: false # 关闭控制台的 Banner 打印 + +# Spring Data Redis 配置 +spring: + data: + redis: + repositories: + enabled: false # 项目未使用到 Spring Data Redis 的 Repository,所以直接禁用,保证启动速度 + +# VO 转换(数据翻译)相关 +easy-trans: + is-enable-global: false # 【默认禁用,对性能确认压力大】启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口 + +--- #################### RPC 远程调用相关配置 #################### + +--- #################### 消息队列相关 #################### + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + executor: + appname: ${spring.application.name} # 执行器 AppName + logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径 + accessToken: default_token # 执行器通讯TOKEN + +--- #################### 芋道相关配置 #################### + +viewsh: + info: + version: 1.0.0 + base-package: com.viewsh.module.video + web: + admin-ui: + url: http://dashboard.viewsh.iocoder.cn # Admin 管理后台 UI 的地址 + xss: + enable: false + exclude-urls: + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + swagger: + title: 视频管理后台 + description: 提供摄像头管理、视频流管理等功能 + version: ${viewsh.info.version} + tenant: # 多租户相关配置项 + enable: true + +debug: false diff --git a/viewsh-module-video/viewsh-module-video-server/src/main/resources/logback-spring.xml b/viewsh-module-video/viewsh-module-video-server/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..918d69d8 --- /dev/null +++ b/viewsh-module-video/viewsh-module-video-server/src/main/resources/logback-spring.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + + + ${FILE_LOG_PATTERN} + + + ${LOG_FILE} + + + ${LOG_FILE}.%d{yyyy-MM-dd}.%i.log + 30 + 10MB + + + + + 0 + 512 + + + + + + + + + + diff --git a/新建服务 yudao-cloud 开发指南.md b/新建服务 yudao-cloud 开发指南.md new file mode 100644 index 00000000..bf4c13a6 --- /dev/null +++ b/新建服务 yudao-cloud 开发指南.md @@ -0,0 +1,862 @@ +--- +title: "新建服务 | yudao-cloud 开发指南" +source: "https://cloud.iocoder.cn/module-new/#%F0%9F%91%8D-%E7%9B%B8%E5%85%B3%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B" +author: + - "[[芋道源码]]" +published: +created: 2026-04-05 +description: "RuoYi-Vue 全新 Cloud 版本,优化重构所有功能。基于 Spring Cloud Alibaba + MyBatis Plus + Vue & Element 实现的后台管理系统 + 微信小程序,支持 RBAC 动态权限、数据权限、SaaS 多租户、Activiti + Flowable 工作流、三方登录、支付、短信、商城等功能。" +tags: + - "clippings" +--- +## 新建服务 + +本章节,将介绍如何新建名字为 `yudao-module-demo` 的示例服务,并添加 RESTful API 接口。 + +虽然内容看起来比较长,是因为艿艿写的比较详细,大量截图,保姆级教程!其实只有 6 个步骤,保持耐心,跟着艿艿一点点来。🙂 完成之后,你会对整个 [项目结构](https://cloud.iocoder.cn/project-intro/) 有更充分的了解。 + +## 👍 相关视频教程 + +- [从零开始 06:如何 5 分钟,创建一个新模块?](https://t.zsxq.com/07EUrZrNV) 【该视频是 Boot 单体版,Cloud 待录制】 + +疑问:如果新建的服务,想要独立的 Git 仓库,怎么办? + +参见 [https://t.zsxq.com/LQKZh](https://t.zsxq.com/LQKZh) 帖子! + +## 1\. 新建 Maven 模块 + +### 1.1 新建 demo 模块 + +① 选择 File -> New -> Module 菜单,如下图所示: + +![打开 New Module](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97%E8%8F%9C%E5%8D%95.png) + +② 选择 Maven 类型,选择父模块为 `yudao` ,输入名字为 `yudao-module-demo` ,并点击 Create 按钮,如下图所示: + +![填写 Module 信息](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E5%A1%AB%E5%86%99Module%E4%BF%A1%E6%81%AFCloud.png) + +③ 打开 `yudao-module-demo` 模块,删除 src 文件,如下图所示: + +![删除多余的文件](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E5%88%A0%E9%99%A4%E5%A4%9A%E4%BD%99%E6%96%87%E4%BB%B6Boot.png) + +④ 打开 `yudao-module-demo` 模块的 `pom.xml` 文件,修改内容如下: + +提示 + +`` 部分,只是注释,不需要写到 XML 中。 + +```xml + + + + yudao + cn.iocoder.cloud + ${revision} + + 4.0.0 + + yudao-module-demo + pom + + ${project.artifactId} + + demo 模块,主要实现 XXX、YYY、ZZZ 等功能。 + + + +``` + +### 1.2 新建 demo-api 子模块 + +① 新建 `yudao-module-demo-api` 子模块,整个过程和“新建 demo 模块”是基本一致的,如下图所示: + +![填写 API Module 信息](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E5%A1%AB%E5%86%99Maven%E4%BE%9D%E8%B5%96Cloud-API.png) + +② 打开 `yudao-module-demo-api` 模块的 `pom.xml` 文件,修改内容如下: + +```xml + + + + yudao-module-demo + cn.iocoder.cloud + ${revision} + + 4.0.0 + yudao-module-demo-api + jar + + ${project.artifactId} + + demo 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.cloud + yudao-common + + + + +``` + +③ 【可选】新建 `cn.iocoder.yudao.module.demo` **基础** 包,其中 `demo` 为模块名。之后,新建 `api` 和 `enums` 包。如下图所示: + +![新建 API 基础包](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E6%96%B0%E5%BB%BA%E5%9F%BA%E7%A1%80%E5%8C%85Cloud-API.png) + +### 1.3 新建 demo-server 子模块 + +① 新建 `yudao-module-demo-server` 子模块,整个过程和“新建 demo 模块”是基本一致的,如下图所示: + +![填写 Server Module 信息](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E5%A1%AB%E5%86%99Maven%E4%BE%9D%E8%B5%96Cloud-Server.png) + +② 打开 `yudao-module-demo-server` 模块的 `pom.xml` 文件,修改成内容如下: + +```xml + + + + yudao-module-demo + cn.iocoder.cloud + ${revision} + + 4.0.0 + jar + + yudao-module-demo-server + + ${project.artifactId} + + demo 模块,主要实现 XXX、YYY、ZZZ 等功能。 + + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-env + + + + + cn.iocoder.cloud + yudao-module-system-api + ${revision} + + + cn.iocoder.cloud + yudao-module-infra-api + ${revision} + + + + cn.iocoder.cloud + yudao-module-demo-api + ${revision} + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-biz-data-permission + + + cn.iocoder.cloud + yudao-spring-boot-starter-biz-tenant + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-web + + + + cn.iocoder.cloud + yudao-spring-boot-starter-security + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-mybatis + + + + cn.iocoder.cloud + yudao-spring-boot-starter-redis + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-rpc + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-job + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-mq + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-test + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-excel + + + + + cn.iocoder.cloud + yudao-spring-boot-starter-monitor + + + + + + ${project.artifactId} + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + +``` + +③ 打开 Maven 菜单,点击刷新按钮,让引入的 Maven 依赖生效。如下图所示: + +![刷新 Maven 依赖](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E5%88%B7%E6%96%B0Maven%E4%BE%9D%E8%B5%96.png) + +④ 新建 `cn.iocoder.yudao.module.demo` **基础** 包,其中 `demo` 为模块名。之后,新建 `controller.admin` 和 `controller.app` 等包。如下图所示: + +![新建 Server 基础包](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E6%96%B0%E5%BB%BA%E5%9F%BA%E7%A1%80%E5%8C%85Cloud-Server.png) + +⑤ 新建安全配置 SecurityConfiguration 类。代码如下: + +```java +package cn.iocoder.yudao.module.demo.framework.security.config; + +import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; +import cn.iocoder.yudao.module.infra.enums.ApiConstants; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer; + +/** + * Demo 模块的 Security 配置 + */ +@Configuration(proxyBeanMethods = false) +public class SecurityConfiguration { + + @Bean + public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { + return new AuthorizeRequestsCustomizer() { + + @Override + public void customize(AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry registry) { + // Swagger 接口文档 + registry.requestMatchers("/v3/api-docs/**").permitAll() + .requestMatchers("/webjars/**").permitAll() + .requestMatchers("/swagger-ui").permitAll() + .requestMatchers("/swagger-ui/**").permitAll(); + // Druid 监控 + registry.requestMatchers("/druid/**").permitAll(); + // Spring Boot Actuator 的安全配置 + registry.requestMatchers("/actuator").permitAll() + .requestMatchers("/actuator/**").permitAll(); + // RPC 服务的安全配置 + registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); + } + + }; + } + +} +``` + +⑥ 新建 DemoServerApplication 启动类。代码如下: + +```java +package cn.iocoder.yudao.module.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 项目的启动类 + * + * @author 芋道源码 + */ +@SpringBootApplication +public class DemoServerApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoServerApplication.class, args); + } + +} +``` + +⑦ 在 `resources` 目录下,新建配置文件。如下图所示: + +![新建配置文件](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E6%96%B0%E5%BB%BA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6Cloud.png) + +其中 `application.yaml` 的配置如下: + +```yaml +spring: + application: + name: demo-server + + profiles: + active: local + + main: + allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。 + allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务 + + config: + import: + - optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置 + - optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置 + + # Servlet 配置 + servlet: + # 文件上传相关配置项 + multipart: + max-file-size: 16MB # 单个文件大小 + max-request-size: 32MB # 设置总上传的文件大小 + + # Jackson 配置项 + jackson: + serialization: + write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳 + write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401 + write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳 + fail-on-empty-beans: false # 允许序列化无属性的 Bean + + # Cache 配置项 + cache: + type: REDIS + redis: + time-to-live: 1h # 设置过期时间为 1 小时 + +server: + port: 48099 + +logging: + file: + name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径 + +--- #################### 接口文档配置 #################### + +springdoc: + api-docs: + enabled: true # 1. 是否开启 Swagger 接文档的元数据 + path: /v3/api-docs + swagger-ui: + enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面 + path: /swagger-ui.html + default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档 + +knife4j: + enable: true # 2.2 是否开启 Swagger 文档的 Knife4j UI 界面 + setting: + language: zh_cn + +# MyBatis Plus 的配置项 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + global-config: + db-config: + id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。 + # id-type: AUTO # 自增 ID,适合 MySQL 等直接自增的数据库 + # id-type: INPUT # 用户输入 ID,适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库 + # id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解 + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + banner: false # 关闭控制台的 Banner 打印 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject + encryptor: + password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成 + +mybatis-plus-join: + banner: false # 关闭控制台的 Banner 打印 + +# VO 转换(数据翻译)相关 +easy-trans: + is-enable-global: false # 【默认禁用,对性能确认压力大】启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口 + +--- #################### RPC 远程调用相关配置 #################### + +--- #################### MQ 消息队列相关配置 #################### + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + executor: + appname: ${spring.application.name} # 执行器 AppName + logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径 + accessToken: default_token # 执行器通讯TOKEN + +--- #################### 芋道相关配置 #################### + +yudao: + info: + version: 1.0.0 + base-package: cn.iocoder.yudao.module.demo + web: + admin-ui: + url: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址 + xss: + enable: false + exclude-urls: # 如下两个 url,仅仅是为了演示,去掉配置也没关系 + - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 + - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 + swagger: + title: 管理后台 + description: 提供管理员管理的所有功能 + version: ${yudao.info.version} + tenant: # 多租户相关配置项 + enable: true + +debug: false +``` +- `spring.application.name` 配置项:可以改成你想要的服务名。 +- `server.port` 配置项:可以改成你想要的端口号。 +- `yudao.info.version.base-package` 配置项:可以改成你的项目的基准包名。 + +其中 `application-local.yaml` 的配置如下: + +```yaml +--- #################### 注册中心 + 配置中心相关配置 #################### + +spring: + cloud: + nacos: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + username: # Nacos 账号 + password: # Nacos 密码 + discovery: # 【配置中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + metadata: + version: 1.0.0 # 服务实例的版本号,可用于灰度发布 + config: # 【注册中心】配置项 + namespace: dev # 命名空间。这里使用 dev 开发环境 + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + +--- #################### 数据库相关配置 #################### +spring: + # 数据源配置项 + autoconfigure: + # noinspection SpringBootApplicationYaml + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + stat-view-servlet: + enabled: true + allow: # 设置白名单,不填则允许所有访问 + url-pattern: /druid/* + login-username: # 控制台管理用户名和密码 + login-password: + filter: + stat: + enabled: true + log-slow-sql: true # 慢 SQL 记录 + slow-sql-millis: 100 + merge-sql: true + wall: + config: + multi-statement-allow: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 1 # 初始连接数 + min-idle: 1 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 60000 # 配置获取连接等待超时的时间,单位:毫秒(1 分钟) + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒(1 分钟) + min-evictable-idle-time-millis: 600000 # 配置一个连接在池中最小生存的时间,单位:毫秒(10 分钟) + max-evictable-idle-time-millis: 1800000 # 配置一个连接在池中最大生存的时间,单位:毫秒(30 分钟) + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + pool-prepared-statements: true # 是否开启 PreparedStatement 缓存 + max-pool-prepared-statement-per-connection-size: 20 # 每个连接缓存的 PreparedStatement 数量 + primary: master + datasource: + master: + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 + # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 + # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 + # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro # SQLServer 连接的示例 + # url: jdbc:dm://10.211.55.4:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 + username: root + password: 123456 + # username: sa # SQL Server 连接的示例 + # password: JSm:g(*%lU4ZAkz06cd52KqT3)i1?H7W # SQL Server 连接的示例 + # username: SYSDBA # DM 连接的示例 + # password: SYSDBA # DM 连接的示例 + slave: # 模拟从库,可根据自己需要修改 + lazy: true # 开启懒加载,保证启动速度 + url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 +# password: 123456 # 密码,建议生产环境开启 + +--- #################### MQ 消息队列相关配置 #################### + +--- #################### 定时任务相关配置 #################### + +xxl: + job: + admin: + addresses: http://127.0.0.1:9090/xxl-job-admin # 调度中心部署跟地址 + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项 +lock4j: + acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒 + expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒 + +--- #################### 监控相关配置 #################### + +# Actuator 监控端点的配置项 +management: + endpoints: + web: + base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +# Spring Boot Admin 配置项 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + instance: + service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME] + username: admin + password: admin + +# 日志文件配置 +logging: + level: + # 配置自己写的 MyBatis Mapper 打印日志 + cn.iocoder.yudao.module.demo.dal.mysql: debug + org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 + +--- #################### 芋道相关配置 #################### + +# 芋道配置项,设置当前项目所有自定义的配置 +yudao: + env: # 多环境的配置项 + tag: ${HOSTNAME} + security: + mock-enable: true + access-log: # 访问日志的配置项 + enable: false +``` +- `logging.level.cn.iocoder.yudao.module.demo.dal.mysql` 配置项:可以改成你的项目的基准包名。 + +其中 `logback-spring.xml` 的配置如下: + +```xml + + + + + + + + + +       + + + ${PATTERN_DEFAULT} + + + + + + + + + + ${PATTERN_DEFAULT} + + + + ${LOG_FILE} + + + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} + + + + + + 0 + + 256 + + + + + + + + ${PATTERN_DEFAULT} + + + + + + + + + + + + + + + + + + + + + + +``` + +## 2\. 新建 RESTful API 接口 + +① 在 `controller.admin` 包,新建一个 DemoTestController 类,并新建一个 `/demo/test/get` 接口。代码如下: + +```java +package cn.iocoder.yudao.module.demo.controller.admin; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - Test") +@RestController +@RequestMapping("/demo/test") +@Validated +public class DemoTestController { + + // 这个构造方法,只是方便大家,验证 Controller 有生效 + public DemoTestController() { + System.out.println(getClass() + "生效啦!!!"); + } + + @GetMapping("/get") + @Operation(summary = "获取 test 信息") + public CommonResult get() { + return success("true"); + } + +} +``` + +**注意** , `/demo` 是该模块所有 RESTful API 的基础路径, `/test` 是 Test 功能的基础路径。 + +② 在 `controller.app` 包,新建一个 AppDemoTestController 类,并新建一个 `/demo/test/get` 接口。代码如下: + +```java +package cn.iocoder.yudao.module.demo.controller.app; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "用户 App - Test") +@RestController +@RequestMapping("/demo/test") +@Validated +public class AppDemoTestController { + + // 这个构造方法,只是方便大家,验证 Controller 有生效 + public AppDemoTestController() { + System.out.println(getClass() + "生效啦!!!"); + } + + @GetMapping("/get") + @Operation(summary = "获取 test 信息") + public CommonResult get() { + return success("true"); + } + +} +``` + +在 Controller 的命名上,额外增加 **App** 作为前缀,一方面区分是管理后台还是用户 App 的 Controller,另一方面避免 Spring Bean 的名字冲突。 + +可能你会奇怪,这里我们定义了两个 `/demo/test/get` 接口,会不会存在重复导致冲突呢?答案,当然是并不会。原因是: + +- `controller.admin` 包下的接口,默认会增加 `/admin-api` ,即最终的访问地址是 `/admin-api/demo/test/get` +- `controller.app` 包下的接口,默认会增加 `/app-api` ,即最终的访问地址是 `/app-api/demo/test/get` + +## 3\. 启动 demo 服务 + +① 运行 SystemServerApplication 类,将 `system` 服务启动。(原因,需要使用 system 服务进行 token 认证) + +② 运行 DemoServerApplication 类,将新建的 `demo` 服务进行启动。启动完成后,可以看到如下日志: + +```bash +class cn.iocoder.yudao.module.demo.controller.admin.DemoTestController生效啦!!! +class cn.iocoder.yudao.module.demo.controller.app.AppDemoTestController生效啦!!! +``` + +## 4\. 测试接口 + +使用浏览器打开 [http://127.0.0.1:48099/doc.html](http://127.0.0.1:48099/doc.html) 地址,进入该服务的 Swagger 接口文档。 + +① 打开“管理后台 - Test”接口,进行 `/admin-api/demo/test/get` 接口的调试,如下图所示: + +![测试 接口](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E6%B5%8B%E8%AF%95Admin%E6%8E%A5%E5%8F%A3Cloud.png) + +② 打开“用户 App - Test”接口,进行 `/app-api/demo/test/get` 接口的调试,如下图所示: + +![测试 接口](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E6%B5%8B%E8%AF%95App%E6%8E%A5%E5%8F%A3Cloud.png) + +## 5\. 网关配置 + +① 打开 `yudao-gateway` 网关项目的 `application.yaml` 配置文件,增加 `demo` 服务的路由配置。代码如下: + +![网关路由配置](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E7%BD%91%E5%85%B3%E8%B7%AF%E7%94%B1%E9%85%8D%E7%BD%AECloud.png) + +友情提示:图中的 /v2/ 都改成 /v3/,或者以下面的文字为准!!! + +```yaml +- id: demo-admin-api # 路由的编号 + uri: grayLb://demo-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/demo/** + filters: + - RewritePath=/admin-api/demo/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v2/api-docs + - id: demo-app-api # 路由的编号 + uri: grayLb://demo-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/app-api/demo/** + filters: + - RewritePath=/app-api/demo/v3/api-docs, /v3/api-docs +``` +```yaml +- name: demo-server + service-name: demo-server + url: /admin-api/demo/v3/api-docs +``` + +另外, `master-jdk` 版本,使用的是 spring cloud 2025+ 版本,它多一层 `spring.cloud.gateway.server.webflux.routers` ,而不是 `spring.cloud.gateway.routers` !!! + +② 运行 GatewayServerApplication 类,将 `gateway` 网关服务启动。 + +③ 使用浏览器打开 [http://127.0.0.1:48080/doc.html](http://127.0.0.1:48080/doc.html) 地址,进入网关的 Swagger 接口文档。然后,选择 `demo-server` 服务,即可进行 `/admin-api/demo/test/get` 和 `/app-api/demo/test/get` 接口的调试,如下图所示: + +![网关 Swagger 接口文档](https://cloud.iocoder.cn/img/%E5%90%8E%E7%AB%AF%E6%89%8B%E5%86%8C/%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97/%E7%BD%91%E5%85%B3Swagger%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3.png) + +## 6\. 补充说明 + +### 6.1 访问接口返回 404? + +请检查,你新建的模块的 `package` 包名是不是在 `cn.iocoder.yudao.module` 下! + +如果不是,修改模块的 ServerApplication 类,增加新建的模块的 `package` 包名。例如说: + +```java +@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}.server", "${yudao.info.base-package}.module", + "xxx.yyy.zzz"}) // xxx.yyy.zzz 是你新建的模块的 \`package\` 包名 +``` + +### 6.2 MyBatis 日志 + +如果你希望新模块的 MyBatis 查询会打印 SQL 日志,需要在 `logging.level` 配置对应的 Logger。如下图所示: + +### 6.3 如何自定义 API 前缀 + +### 6.4 每个模块,独立工程 + +- [https://t.zsxq.com/73b2Q](https://t.zsxq.com/73b2Q) \ No newline at end of file