集成必要性功能

This commit is contained in:
2026-03-12 16:25:24 +08:00
parent 5708f80091
commit f0649cb888
201 changed files with 303 additions and 19897 deletions

View File

@@ -1,4 +0,0 @@
/**
* 针对 infra 模块的 api 包
*/
package com.njcn.rdms.framework.common.biz.infra;

View File

@@ -1,6 +1,6 @@
package com.njcn.rdms.framework.common.biz.infra.logger;
package com.njcn.rdms.framework.common.biz.system.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.enums.RpcConstants;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -11,11 +11,11 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = RpcConstants.INFRA_NAME)
@FeignClient(name = RpcConstants.SYSTEM_NAME)
@Tag(name = "RPC 服务 - API 访问日志")
public interface ApiAccessLogCommonApi {
String PREFIX = RpcConstants.INFRA_PREFIX + "/api-access-log";
String PREFIX = RpcConstants.SYSTEM_PREFIX + "/api-access-log";
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建 API 访问日志")

View File

@@ -1,6 +1,6 @@
package com.njcn.rdms.framework.common.biz.infra.logger;
package com.njcn.rdms.framework.common.biz.system.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.enums.RpcConstants;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -11,11 +11,11 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = RpcConstants.INFRA_NAME)
@FeignClient(name = RpcConstants.SYSTEM_NAME)
@Tag(name = "RPC 服务 - API 异常日志")
public interface ApiErrorLogCommonApi {
String PREFIX = RpcConstants.INFRA_PREFIX + "/api-error-log";
String PREFIX = RpcConstants.SYSTEM_PREFIX + "/api-error-log";
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建 API 异常日志")

View File

@@ -1,4 +1,4 @@
package com.njcn.rdms.framework.common.biz.infra.logger.dto;
package com.njcn.rdms.framework.common.biz.system.logger.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

View File

@@ -1,4 +1,4 @@
package com.njcn.rdms.framework.common.biz.infra.logger.dto;
package com.njcn.rdms.framework.common.biz.system.logger.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

View File

@@ -26,15 +26,5 @@ public interface RpcConstants {
*/
String SYSTEM_PREFIX = RPC_API_PREFIX + "/system";
/**
* infra 服务名
*
* 注意,需要保证和 spring.application.name 保持一致
*/
String INFRA_NAME = "rdms-infra-server";
/**
* infra 服务的前缀
*/
String INFRA_PREFIX = RPC_API_PREFIX + "/infra";
}

View File

@@ -1,4 +1,4 @@
# MQ 改造方案(评审稿)
# MQ 改造方案(评审稿)
## 1. 背景与目标
你当前的业务策略是:
@@ -26,16 +26,13 @@
当前 `rdms-spring-boot-starter-mq` 的真实情况:
1. Redis 能力最完整包含模板、监听器抽象、Stream 补偿与清理任务。
2. RabbitMQ 只有 `MessageConverter` 级别自动配置,未形成统一收发抽象。
3. RocketMQ、Kafka 在该 starter 中没有对应自动配置主链路,实际接入主要在 WebSocket 模块。
当前 `rdms-system` 默认配置:
1. `rdms.websocket.sender-type: local`,即默认并未走 MQ 分发链路。
## 3. 改造原则
1. 先配置统一,再接口统一,最后再清理非主路径。
2. 任何阶段都必须可回滚,且回滚只改配置不改代码。
3. 保持 Rabbit/Kafka 包路径存在,避免一次性大删导致历史分支合并困难。
4. 先让 WebSocket 场景打通可切换,再考虑扩展到业务 MQ。
## 4. 目标架构(落地后)
统一引入配置:
@@ -44,10 +41,8 @@
统一行为:
1. 单体环境配 `redis`
2. 微服务环境配 `rocketmq`
3. WebSocket `sender-type` 跟随 `rdms.mq.type`,避免双配置。
建议方式:
1. `rdms.websocket.sender-type: ${rdms.mq.type}`
## 4.1 配置矩阵(最小可运行)
@@ -56,8 +51,6 @@
rdms:
mq:
type: redis
websocket:
sender-type: ${rdms.mq.type}
spring:
data:
@@ -71,8 +64,6 @@ spring:
rdms:
mq:
type: rocketmq
websocket:
sender-type: ${rdms.mq.type}
rocketmq:
name-server: 127.0.0.1:9876
@@ -102,7 +93,6 @@ rocketmq:
实施项:
1. 新增配置项 `rdms.mq.type`,默认值 `redis`
2. 修改环境配置,使 `rdms.websocket.sender-type` 引用 `rdms.mq.type`
3. 本阶段不删除 Rabbit/Kafka 代码,不变更包结构。
收益:
@@ -110,7 +100,6 @@ rocketmq:
2. 不触碰核心业务逻辑,风险最低。
回滚:
1.`rdms.websocket.sender-type` 改回固定值即可。
## 阶段 B中风险接口统一
目标:抽象统一 MQ 发送接口,减少业务对具体中间件的耦合。
@@ -119,7 +108,6 @@ rocketmq:
1. 新增统一接口,例如 `UnifiedMqSender`
2. 提供 `RedisMqSender``RocketMqSender` 两个实现。
3.`@ConditionalOnProperty` 根据 `rdms.mq.type` 注入唯一实现。
4. 在 WebSocket 发送链路优先替换为统一接口调用。
5. 统一消息契约,至少包含标准消息头:
`msgId``bizKey``timestamp``producer``traceId``version`
@@ -149,7 +137,6 @@ rocketmq:
## 6. 影响面评估
主要影响模块:
1. `rdms-framework/rdms-spring-boot-starter-mq`
2. `rdms-framework/rdms-spring-boot-starter-websocket`
3. `rdms-system/rdms-system-boot` 配置文件
主要风险点:
@@ -182,7 +169,6 @@ rocketmq:
## 7. 验收清单(每阶段都要过)
1. 单体环境 `rdms.mq.type=redis` 可启动、可发送、可消费。
2. 微服务环境 `rdms.mq.type=rocketmq` 可启动、可发送、可消费。
3. WebSocket 在两种模式下都能完成跨实例消息投递。
4. 关键链路日志可定位发送端与消费端。
5. 切换只改配置,不改代码。
6. 回滚路径已验证。
@@ -224,7 +210,6 @@ rocketmq:
3. 关键业务出现重复消费副作用。
回滚动作:
1. 只回滚 `rdms.mq.type``rdms.websocket.sender-type` 配置。
2. 不回滚代码,确保恢复路径最短。
## 9. 当前建议

View File

@@ -52,7 +52,6 @@ Redis 相关能力分成两类:
### 6. 多 MQ 的真实边界
虽然模块描述写了支持 Redis / RocketMQ / RabbitMQ / Kafka
但本 starter 的自动配置主要是 Redis + Rabbit。
RocketMQ / Kafka 的业务化接入在 `rdms-spring-boot-starter-websocket` 里有更完整示例。
## 自动配置入口
`META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`:
@@ -78,13 +77,6 @@ RocketMQ / Kafka 的业务化接入在 `rdms-spring-boot-starter-websocket` 里
2. 先按第 2 节使用 `Pub/Sub`(这是项目里最常见路径)。
3. 需要可恢复消费时,再按第 3 节接入 `Stream`
WebSocket 场景建议:
1. 多实例广播: `rdms.websocket.sender-type: redis`
2. 单机部署: 保持 `rdms.websocket.sender-type: local`
说明:
1. 只要存在 `AbstractRedisChannelMessageListener` Bean框架会自动注册 Redis 监听容器。
## 2. 使用 Redis Pub/Sub广播
适用场景: 通知广播、在线会话广播、对可靠性要求不高但强调实时性。
@@ -232,13 +224,6 @@ public class DemoRedisMessageInterceptor implements RedisMessageInterceptor {
1. Redis Stream 要求 Redis 版本 >= 5.0
2. 只有存在 Stream 监听器时,重投/清理定时任务才会生效
## 与 WebSocket 的关系
`rdms-spring-boot-starter-websocket` 直接复用本模块能力:
1. `sender-type=redis` 时使用 `RedisMQTemplate` + `AbstractRedisChannelMessageListener`
2. `sender-type=rabbitmq/rocketmq/kafka` 时切换到对应中间件实现
你可以参考 websocket 模块作为本模块的落地样板。
## 当前已知注意点
1. `AbstractRedisStreamMessageListener` 有一个 `(streamKey, group)` 构造器,内部把 `messageType` 置空;而消费反序列化仍依赖 `messageType`
建议优先使用无参构造路径(即泛型推断消息类型的默认方式)。

View File

@@ -519,7 +519,13 @@ public Long createUser(UserSaveReqVO reqVO) {
token 的签发和存储仍在系统服务等其他模块。
2. 当前跨服务透传的是 `login-user`,不是原始 token
所以下游服务能识别当前用户,不等于它一直拿着原始 `Authorization`
所以下游服务能识别当前用户,不等于它一直拿着原始 `Authorization`
3. 单体部署(不经过网关)建议在入口层剥离 `login-user` 请求头,避免外部伪造登录态
- Nginx 示例:
```nginx
# 去除客户端伪造的 login-user 头
proxy_set_header login-user "";
```
3. 不加 `@PreAuthorize` 不代表匿名可访问
默认仍然需要登录,只是不会进一步做权限点校验。

View File

@@ -2,7 +2,7 @@ package com.njcn.rdms.framework.apilog.config;
import com.njcn.rdms.framework.apilog.core.filter.ApiAccessLogFilter;
import com.njcn.rdms.framework.apilog.core.interceptor.ApiAccessLogInterceptor;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.enums.WebFilterOrderEnum;
import com.njcn.rdms.framework.web.config.RdmsWebAutoConfiguration;
import com.njcn.rdms.framework.web.config.WebProperties;

View File

@@ -1,7 +1,7 @@
package com.njcn.rdms.framework.apilog.config;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;

View File

@@ -10,8 +10,8 @@ import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.njcn.rdms.framework.apilog.core.annotation.ApiAccessLog;
import com.njcn.rdms.framework.apilog.core.enums.OperateTypeEnum;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.json.JsonUtils;

View File

@@ -2,7 +2,7 @@ package com.njcn.rdms.framework.web.config;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.enums.WebFilterOrderEnum;
import com.njcn.rdms.framework.web.core.filter.CacheRequestBodyFilter;
import com.njcn.rdms.framework.web.core.handler.GlobalExceptionHandler;

View File

@@ -7,8 +7,8 @@ import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.exception.ServiceException;
import com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;

View File

@@ -1,21 +1,21 @@
# rdms-spring-boot-starter-websocket
# rdms-spring-boot-starter-websocket
## 1. 模块定位
`rdms-spring-boot-starter-websocket` 是 WebSocket 基础设施模块,用于统一处理连接、会话管理、消息分发与消息发送,并支持多节点场景下的广播投递
`rdms-spring-boot-starter-websocket` 是 WebSocket 基础设施模块,用于统一处理连接、会话管理、消息分发与消息发送。
模块聚合的核心能力:
- WebSocket 自动装配与路径注册
- 登录用户绑定与会话管理
- JSON 消息协议与监听器分发
- 消息发送与多节点广播
- 消息发送
## 2. 设计思路
- 统一 JSON 消息协议(`type` + `content`),通过 `type` 分发到对应监听器,降低业务耦合。
- 通过 `WebSocketSessionManager` 统一管理会话,支持按用户类型/用户编号/会话 ID 进行推送。
- 通过可插拔 `sender-type` 支持单机与多节点广播local/redis/rocketmq/rabbitmq/kafka
- 通过本地发送器支持单机消息推送
- 与安全体系结合,在握手阶段写入 `LoginUser`,便于后续鉴权与定向发送。
## 3. 功能模块
@@ -28,7 +28,7 @@
- 注册握手拦截器(默认 `LoginUserHandshakeInterceptor`
- 注册 `WebSocketSessionManager`
- 放行 WebSocket 路径的安全校验
- 注册消息发送器(按 `sender-type`
- 注册消息发送器
### 3.2 JSON 消息协议
@@ -69,14 +69,7 @@
消息会被封装为统一的 `JsonWebSocketMessage` 后发送。
### 3.5 多节点广播
`sender-type` 支持以下类型:
- `local`:单机直连(默认)
- `redis` / `rocketmq` / `rabbitmq` / `kafka`:通过 MQ 广播到各实例,再由各实例推送到本机会话
### 3.6 登录用户绑定
### 3.5 登录用户绑定
握手阶段会读取当前登录用户并写入 WebSocket Session
@@ -102,13 +95,11 @@ rdms:
websocket:
enable: true
path: /ws
sender-type: local
```
说明:
- `path` 默认 `/ws`
- `sender-type` 默认 `local`
- `enable` 默认 `true`
### 4.3 连接方式
@@ -148,49 +139,4 @@ public void push(Long userId, NoticeDTO notice) {
}
```
### 4.6 多节点广播配置示例
Redis
```yaml
rdms:
websocket:
sender-type: redis
```
RocketMQ
```yaml
rdms:
websocket:
sender-type: rocketmq
sender-rocketmq:
topic: ws-topic
consumer-group: ws-group
```
Kafka
```yaml
rdms:
websocket:
sender-type: kafka
sender-kafka:
topic: ws-topic
consumer-group: ws-group
```
RabbitMQ
```yaml
rdms:
websocket:
sender-type: rabbitmq
sender-rabbitmq:
exchange: ws-exchange
queue: ws-queue
```
注意:
- 使用 MQ 模式时,请确保对应 MQ 客户端依赖与连接配置已就绪。

View File

@@ -39,28 +39,6 @@
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>com.njcn</groupId>
<artifactId>rdms-spring-boot-starter-mq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
</project>

144
rdms-gateway/README.md Normal file
View File

@@ -0,0 +1,144 @@
# rdms-gateway
## 1. 模块定位
`rdms-gateway` 是 API 服务网关模块,基于 Spring Cloud GatewayWebFlux实现负责统一入口的路由转发、鉴权透传、跨域处理、访问日志、灰度/标签负载与全局异常处理。
## 2. 设计思路
- 通过网关统一处理横切能力,业务服务只关注业务逻辑。
- 鉴权只做“解析 + 透传”,是否需要登录交给后端服务判定。
- 灰度/标签负载通过自定义 `grayLb://` 方案实现。
- 访问日志默认打印到日志,后续可扩展为落库。
## 3. 功能模块
### 3.1 路由与文档聚合
- 路由配置集中在 `application.yaml``spring.cloud.gateway.server.webflux.routes`
- Knife4j Gateway 负责聚合各服务的 OpenAPI 文档。
### 3.2 Token 鉴权透传
`TokenAuthenticationFilter` 负责:
-`Authorization` 解析 Token
- 远程校验 Token 有效性
- 校验通过后将 `login-user` 头透传给后端
- 不阻断请求,是否需要登录由后端服务决定
### 3.3 跨域处理
`CorsFilter` 统一放行跨域请求,并处理 OPTIONS 预检请求。
### 3.4 访问日志
`AccessLogFilter` 记录:
- 请求路径、方法、参数、Body、Headers
- 响应体、响应码
- 耗时、用户信息
当前实现是打印到日志(控制台/文件),可扩展为落库。
### 3.5 灰度/标签负载
灰度发布Gray/Canary是指新旧版本并行运行只让一小部分请求先进入新版本验证稳定后再逐步扩大流量最终全量切换。
在本项目中,灰度不是按“百分比随机分流”,而是**按请求头定向路由**
- 请求头 `version` 用于匹配实例 `metadata.version`
- 请求头 `tag` 用于匹配实例 `metadata.tag`
- 如果匹配不到目标实例,会回退到全量实例
- 最终按 Nacos 权重随机选择实例
`grayLb://` + `GrayLoadBalancer` 规则:
- header `version` 匹配实例 metadata `version`
- header `tag` 匹配实例 metadata `tag`
- 无匹配时回落到全量实例
注意:
- 不带 `tag` 的请求会优先过滤掉带 `tag` 的实例,避免测试/灰度实例被默认流量命中
- 灰度发布依赖请求头控制路由范围,需要由网关或内部调用方注入 `version/tag`,避免外部随意绕路
### 3.6 全局异常
`GlobalExceptionHandler` 将异常统一翻译为 `CommonResult` 返回。
### 3.7 Jackson 一致性
`GatewayJacksonAutoConfiguration` 统一 JSON 序列化策略时间戳、Long -> Number 等)。
## 4. 开发人员上手
### 4.1 路由配置示例
```yaml
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: system-admin-api
uri: grayLb://rdms-system-server
predicates:
- Path=/admin-api/system/**
filters:
- RewritePath=/admin-api/system/v3/api-docs, /v3/api-docs
```
### 4.2 鉴权透传
前端携带:
```
Authorization: Bearer <token>
tenant-id: <tenantId>
```
网关校验成功后,会透传 `login-user` 给后端服务。
### 4.3 灰度/标签路由
请求头示例:
```
version: 1.0.0
tag: dev
```
服务实例需要在注册中心 metadata 中配置对应 `version/tag`
### 4.4 WebSocket 路由
```yaml
- id: system-websocket
uri: grayLb://rdms-system-server
predicates:
- Path=/system/ws/**
```
### 4.5 文档聚合示例
```yaml
knife4j:
gateway:
enabled: true
routes:
- name: system-server
service-name: rdms-system-server
url: /admin-api/system/v3/api-docs
```
## 5. 关键类索引
- 入口:`src/main/java/com/njcn/rdms/gateway/GatewayServerApplication.java`
- 路由配置:`src/main/resources/application.yaml`
- 鉴权:`src/main/java/com/njcn/rdms/gateway/filter/security/TokenAuthenticationFilter.java`
- 灰度:`src/main/java/com/njcn/rdms/gateway/filter/grey/GrayLoadBalancer.java`
- 访问日志:`src/main/java/com/njcn/rdms/gateway/filter/logging/AccessLogFilter.java`
- 跨域:`src/main/java/com/njcn/rdms/gateway/filter/cors/CorsFilter.java`
- 全局异常:`src/main/java/com/njcn/rdms/gateway/handler/GlobalExceptionHandler.java`

View File

@@ -55,7 +55,7 @@ public class GrayReactiveLoadBalancerClientFilter implements GlobalFilter, Order
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
// 修改 by 灿能源码:将 lb 替换成 grayLb表示灰度负载均衡
// 修改:将 lb 替换成 grayLb表示灰度负载均衡
if (url == null || (!"grayLb".equals(url.getScheme()) && !"grayLb".equals(schemePrefix))) {
return chain.filter(exchange);
}
@@ -121,7 +121,7 @@ public class GrayReactiveLoadBalancerClientFilter implements GlobalFilter, Order
private Mono<Response<ServiceInstance>> choose(Request<RequestDataContext> lbRequest, String serviceId,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors) {
// 修改 by 灿能源码:直接创建 GrayLoadBalancer 对象
// 修改:直接创建 GrayLoadBalancer 对象
GrayLoadBalancer loadBalancer = new GrayLoadBalancer(
clientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class), serviceId);
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));

View File

@@ -76,9 +76,6 @@ knife4j:
- name: system-server
service-name: rdms-system-server
url: /admin-api/system/v3/api-docs
- name: infra-server
service-name: infra-server
url: /admin-api/infra/v3/api-docs
- name: bpm-server
service-name: bpm-server
url: /admin-api/bpm/v3/api-docs
@@ -87,4 +84,4 @@ knife4j:
rdms:
info:
version: 1.0.0
version: 1.0.0

View File

@@ -1,4 +1,3 @@
灿能源码 http://www.iocoder.cn
Application Version: ${rdms.info.version}
Spring Boot Version: ${spring-boot.version}

View File

@@ -0,0 +1,57 @@
# rdms-system-api
**概述**
本模块定义了 System系统模块对其他模块开放的公共 RPC API 面。它是一个纯 API 的 jar 包:包含 Feign 客户端接口、请求/响应 DTO以及枚举/常量。不包含 controller 或 service 的实现。
**这里包含什么**
- 位于 `com.njcn.rdms.module.system.api.*` 下的 Feign 客户端接口
- 位于 `com.njcn.rdms.module.system.api.*.dto` 下的 DTO
- 位于 `com.njcn.rdms.module.system.enums.*` 下的系统枚举和常量
**API 分组**
- `config``ConfigApi`,用于根据 key 读取配置值
- `dept``DeptApi``PostApi`,用于部门与岗位数据及校验
- `dict``DictDataApi`,用于字典数据校验(继承 `DictDataCommonApi`
- `file``FileApi`,用于文件创建与预签名 URL
- `logger``LoginLogApi``OperateLogApi`(继承 `OperateLogCommonApi`
- `notify``NotifyMessageSendApi`,用于站内消息发送
- `permission``PermissionApi`(继承 `PermissionCommonApi`)以及 `RoleApi`
- `user``AdminUserApi`,用于管理员用户查询与校验
- `websocket``WebSocketSenderApi`,用于推送 WebSocket 消息
**关键常量**
- `ApiConstants.NAME = "system-server"`(必须与 system 服务的 `spring.application.name` 保持一致)
- `ApiConstants.PREFIX = "/rpc-api/system"`
- `ApiConstants.VERSION = "1.0.0"`
**用法**
1. 在调用方模块中添加依赖。
```xml
<dependency>
<groupId>com.njcn</groupId>
<artifactId>rdms-system-api</artifactId>
</dependency>
```
2. 在调用方服务中启用 Feign 客户端扫描。
```java
@EnableFeignClients(basePackages = "com.njcn.rdms.module.system.api")
```
3. 注入并调用 API 接口。
```java
@Resource
private AdminUserApi adminUserApi;
public AdminUserRespDTO loadUser(Long id) {
return adminUserApi.getUser(id).getCheckedData();
}
```
**备注**
- 所有方法都返回 `CommonResult<T>`。按需使用 `getCheckedData()``checkError()`
- 有些 API 提供了默认的辅助方法(例如 `FileApi.createFile(...)``WebSocketSenderApi.send(...)`)。
- `DictDataApi``OperateLogApi``PermissionApi` 继承了来自 `rdms-framework` 的通用 RPC 接口。

View File

@@ -24,7 +24,7 @@ public class LoginLogCreateReqDTO {
private Integer userType;
@Schema(description = "用户账号", example = "rdms")
@Size(max = 30, message = "用户账号长度不能超过30个字符")
private String username; // 不再强制校验 username 非空,因为 Member 社交登录时,此时暂时没有 username(mobile
private String username; // 不再强制校验 username 非空,兼容无 username 的登录场景
@Schema(description = "登录结果,参见 LoginResultEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "登录结果不能为空")

View File

@@ -1,28 +0,0 @@
package com.njcn.rdms.module.system.api.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
import com.njcn.rdms.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - 邮件发送")
public interface MailSendApi {
String PREFIX = ApiConstants.PREFIX + "/mail/send";
@PostMapping(PREFIX + "/send-single-admin")
@Operation(summary = "发送单条邮件给 Admin 用户", description = "在 mail 为空时,使用 userId 加载对应 Admin 的邮箱")
CommonResult<Long> sendSingleMailToAdmin(@Valid @RequestBody MailSendSingleToUserReqDTO reqDTO);
@PostMapping(PREFIX + "/send-single-member")
@Operation(summary = "发送单条邮件给 Member 用户", description = "在 mail 为空时,使用 userId 加载对应 Member 的邮箱")
CommonResult<Long> sendSingleMailToMember(@Valid @RequestBody MailSendSingleToUserReqDTO reqDTO);
}

View File

@@ -1,55 +0,0 @@
package com.njcn.rdms.module.system.api.mail.dto;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.File;
import java.util.List;
import java.util.Map;
/**
* 邮件发送 Request DTO
*
* @author hongawen
*/
@Data
public class MailSendSingleToUserReqDTO {
/**
* 用户编号
*
* 如果非空,则加载对应用户的邮箱,添加到 {@link #toMails} 中
*/
private Long userId;
/**
* 收件邮箱
*/
private List<@Email String> toMails;
/**
* 抄送邮箱
*/
private List<@Email String> ccMails;
/**
* 密送邮箱
*/
private List<@Email String> bccMails;
/**
* 邮件模板编号
*/
@NotNull(message = "邮件模板编号不能为空")
private String templateCode;
/**
* 邮件模板参数
*/
private Map<String, Object> templateParams;
/**
* 附件
*/
private File[] attachments;
}

View File

@@ -13,7 +13,6 @@ public interface ErrorCodeConstants {
ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_002_000_000, "登录失败,账号密码不正确");
ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_002_000_001, "登录失败,账号被禁用");
ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_004, "验证码不正确,原因:{}");
ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "未绑定账号,需要进行绑定");
ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在");
ErrorCode AUTH_REGISTER_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_008, "验证码不正确,原因:{}");
@@ -115,19 +114,6 @@ public interface ErrorCodeConstants {
ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "名字为【{}】的租户套餐已被禁用");
ErrorCode TENANT_PACKAGE_NAME_DUPLICATE = new ErrorCode(1_002_016_003, "已经存在该名字的租户套餐");
// ========== 社交用户 1-002-018-000 ==========
ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}");
ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "获得小程序订阅消息模版失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR = new ErrorCode(1_002_018_203, "发送小程序订阅消息失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_UPLOAD_SHIPPING_INFO_ERROR = new ErrorCode(1_002_018_204, "上传微信小程序发货信息失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_ORDER_NOTIFY_CONFIRM_RECEIVE_ERROR = new ErrorCode(1_002_018_205, "上传微信小程序订单收货信息失败");
ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "社交客户端不存在");
ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置");
// ========== OAuth2 客户端 1-002-020-000 =========
ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在");
ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在");
@@ -146,18 +132,6 @@ public interface ErrorCodeConstants {
ErrorCode OAUTH2_CODE_NOT_EXISTS = new ErrorCode(1_002_022_000, "code 不存在");
ErrorCode OAUTH2_CODE_EXPIRE = new ErrorCode(1_002_022_001, "code 已过期");
// ========== 邮箱账号 1-002-023-000 ==========
ErrorCode MAIL_ACCOUNT_NOT_EXISTS = new ErrorCode(1_002_023_000, "邮箱账号不存在");
ErrorCode MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS = new ErrorCode(1_002_023_001, "无法删除,该邮箱账号还有邮件模板");
// ========== 邮件模版 1-002-024-000 ==========
ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_024_000, "邮件模版不存在");
ErrorCode MAIL_TEMPLATE_CODE_EXISTS = new ErrorCode(1_002_024_001, "邮件模版 code({}) 已存在");
// ========== 邮件发送 1-002-025-000 ==========
ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_025_000, "模板参数({})缺失");
ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1_002_025_001, "邮箱不存在");
// ========== 站内信模版 1-002-026-000 ==========
ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_026_000, "站内信模版不存在");
ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_026_001, "已经存在编码为【{}】的站内信模板");
@@ -194,28 +168,10 @@ public interface ErrorCodeConstants {
ErrorCode FILE_NOT_EXISTS = new ErrorCode(1_001_003_001, "文件不存在");
ErrorCode FILE_IS_EMPTY = new ErrorCode(1_001_003_002, "文件为空");
// ========== 代码生成器 1-001-004-000 ==========
ErrorCode CODEGEN_TABLE_EXISTS = new ErrorCode(1_001_004_002, "表定义已经存在");
ErrorCode CODEGEN_IMPORT_TABLE_NULL = new ErrorCode(1_001_004_001, "导入的表不存在");
ErrorCode CODEGEN_IMPORT_COLUMNS_NULL = new ErrorCode(1_001_004_002, "导入的字段不存在");
ErrorCode CODEGEN_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_004, "表定义不存在");
ErrorCode CODEGEN_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_005, "字段义不存在");
ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1_001_004_006, "同步的字段不存在");
ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1_001_004_007, "同步失败,不存在改变");
ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1_001_004_008, "数据库的表注释未填写");
ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1_001_004_009, "数据库的表字段({})注释未填写");
ErrorCode CODEGEN_MASTER_TABLE_NOT_EXISTS = new ErrorCode(1_001_004_010, "主表(id={})定义不存在,请检查");
ErrorCode CODEGEN_SUB_COLUMN_NOT_EXISTS = new ErrorCode(1_001_004_011, "子表的字段(id={})不存在,请检查");
ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE = new ErrorCode(1_001_004_012, "主表生成代码失败,原因:它没有子表");
// ========== 文件配置 1-001-006-000 ==========
ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_006_000, "文件配置不存在");
ErrorCode FILE_CONFIG_DELETE_FAIL_MASTER = new ErrorCode(1_001_006_001, "该文件配置不允许删除,原因:它是主配置,删除会导致无法上传文件");
// ========== 数据源配置 1-001-007-000 ==========
ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_007_000, "数据源配置不存在");
ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1_001_007_001, "数据源配置不正确,无法进行连接");
// ========== 学生 1-001-201-000 ==========
ErrorCode DEMO01_CONTACT_NOT_EXISTS = new ErrorCode(1_001_201_000, "示例联系人不存在");
ErrorCode DEMO02_CATEGORY_NOT_EXISTS = new ErrorCode(1_001_201_001, "示例分类不存在");

View File

@@ -1,29 +0,0 @@
package com.njcn.rdms.module.system.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成器的字段 HTML 展示枚举
*/
@AllArgsConstructor
@Getter
public enum CodegenColumnHtmlTypeEnum {
INPUT("input"), // 文本框
TEXTAREA("textarea"), // 文本域
SELECT("select"), // 下拉框
RADIO("radio"), // 单选框
CHECKBOX("checkbox"), // 复选框
DATETIME("datetime"), // 日期控件
IMAGE_UPLOAD("imageUpload"), // 上传图片
FILE_UPLOAD("fileUpload"), // 上传文件
EDITOR("editor"), // 富文本控件
;
/**
* 条件
*/
private final String type;
}

View File

@@ -1,27 +0,0 @@
package com.njcn.rdms.module.system.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成器的字段过滤条件枚举
*/
@AllArgsConstructor
@Getter
public enum CodegenColumnListConditionEnum {
EQ("="),
NE("!="),
GT(">"),
GTE(">="),
LT("<"),
LTE("<="),
LIKE("LIKE"),
BETWEEN("BETWEEN");
/**
* 条件
*/
private final String condition;
}

View File

@@ -1,35 +0,0 @@
package com.njcn.rdms.module.system.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成的前端类型枚举
*
* @author hongawen
*/
@AllArgsConstructor
@Getter
public enum CodegenFrontTypeEnum {
VUE2_ELEMENT_UI(10), // Vue2 Element UI 标准模版
VUE3_ELEMENT_PLUS(20), // Vue3 Element Plus 标准模版
VUE3_VBEN2_ANTD_SCHEMA(30), // Vue3 VBEN2 + ANTD + Schema 模版
VUE3_VBEN5_ANTD_SCHEMA(40), // Vue3 VBEN5 + ANTD + schema 模版
VUE3_VBEN5_ANTD_GENERAL(41), // Vue3 VBEN5 + ANTD 标准模版
VUE3_VBEN5_EP_SCHEMA(50), // Vue3 VBEN5 + EP + schema 模版
VUE3_VBEN5_EP_GENERAL(51), // Vue3 VBEN5 + EP 标准模版
VUE3_ADMIN_UNIAPP_WOT(60), // Vue3 Admin + Uniapp + WOT 标准模版
;
/**
* 类型
*/
private final Integer type;
}

View File

@@ -1,41 +0,0 @@
package com.njcn.rdms.module.system.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
import static cn.hutool.core.util.ArrayUtil.firstMatch;
/**
* 代码生成的场景枚举
*
* @author hongawen
*/
@AllArgsConstructor
@Getter
public enum CodegenSceneEnum {
ADMIN(1, "管理后台", "admin", ""),
APP(2, "用户 APP", "app", "App");
/**
* 场景
*/
private final Integer scene;
/**
* 场景名
*/
private final String name;
/**
* 基础包名
*/
private final String basePackage;
/**
* Controller 和 VO 类的前缀
*/
private final String prefixClass;
public static CodegenSceneEnum valueOf(Integer scene) {
return firstMatch(sceneEnum -> sceneEnum.getScene().equals(scene), values());
}
}

View File

@@ -1,53 +0,0 @@
package com.njcn.rdms.module.system.enums.codegen;
import com.njcn.rdms.framework.common.util.object.ObjectUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
/**
* 代码生成模板类型
*
* @author hongawen
*/
@AllArgsConstructor
@Getter
public enum CodegenTemplateTypeEnum {
ONE(1), // 单表(增删改查)
TREE(2), // 树表(增删改查)
MASTER_NORMAL(10), // 主子表 - 主表 - 普通模式
MASTER_ERP(11), // 主子表 - 主表 - ERP 模式
MASTER_INNER(12), // 主子表 - 主表 - 内嵌模式
SUB(15), // 主子表 - 子表
;
/**
* 类型
*/
private final Integer type;
/**
* 是否为主表
*
* @param type 类型
* @return 是否主表
*/
public static boolean isMaster(Integer type) {
return ObjectUtils.equalsAny(type,
MASTER_NORMAL.type, MASTER_ERP.type, MASTER_INNER.type);
}
/**
* 是否为树表
*
* @param type 类型
* @return 是否树表
*/
public static boolean isTree(Integer type) {
return Objects.equals(type, TREE.type);
}
}

View File

@@ -1,30 +0,0 @@
package com.njcn.rdms.module.system.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成的 VO 类型枚举
*
* 目前的作用Controller 新增、修改、响应时,使用 VO 还是 DO
* 注意:不包括 Controller 的分页参数!
*
* @author hongawen
*/
@AllArgsConstructor
@Getter
public enum CodegenVOTypeEnum {
VO(10, "VO"),
DO(20, "DO");
/**
* 场景
*/
private final Integer type;
/**
* 场景名
*/
private final String name;
}

View File

@@ -11,7 +11,6 @@ import lombok.Getter;
public enum LoginLogTypeEnum {
LOGIN_USERNAME(100), // 使用账号登录
LOGIN_SOCIAL(101), // 使用社交登录
LOGIN_MOBILE(103), // 使用手机登陆
LOGIN_SMS(104), // 使用短信登陆

View File

@@ -1,24 +0,0 @@
package com.njcn.rdms.module.system.enums.mail;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 邮件的发送状态枚举
*
* @author hongawen
* @since 2022/4/10 13:39
*/
@Getter
@AllArgsConstructor
public enum MailSendStatusEnum {
INIT(0), // 初始化
SUCCESS(10), // 发送成功
FAILURE(20), // 发送失败
IGNORE(30), // 忽略,即不发送
;
private final int status;
}

View File

@@ -49,10 +49,6 @@
<groupId>com.njcn</groupId>
<artifactId>rdms-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId> <!-- 代码生成器,使用它解析表结构 -->
</dependency>
<dependency>
<groupId>com.njcn</groupId>
@@ -104,28 +100,12 @@
<artifactId>rdms-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId> <!-- 实现代码生成 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.anji-plus</groupId>
<artifactId>captcha-spring-boot-starter</artifactId> <!-- 验证码,一般用于登录使用 -->
</dependency>
<dependency>
<groupId>org.dromara.hutool</groupId>
<artifactId>hutool-extra</artifactId> <!-- 邮件 -->
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->

View File

@@ -1,7 +1,7 @@
package com.njcn.rdms.module.system.api.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.ApiAccessLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiAccessLogCreateReqDTO;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.service.logger.ApiAccessLogService;
import jakarta.annotation.Resource;

View File

@@ -1,7 +1,7 @@
package com.njcn.rdms.module.system.api.logger;
import com.njcn.rdms.framework.common.biz.infra.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.infra.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.biz.system.logger.ApiErrorLogCommonApi;
import com.njcn.rdms.framework.common.biz.system.logger.dto.ApiErrorLogCreateReqDTO;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.service.logger.ApiErrorLogService;
import jakarta.annotation.Resource;

View File

@@ -1,33 +0,0 @@
package com.njcn.rdms.module.system.api.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.api.mail.dto.MailSendSingleToUserReqDTO;
import com.njcn.rdms.module.system.service.mail.MailSendService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
public class MailSendApiImpl implements MailSendApi {
@Resource
private MailSendService mailSendService;
@Override
public CommonResult<Long> sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) {
return success(mailSendService.sendSingleMailToAdmin(reqDTO.getUserId(),
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams(), reqDTO.getAttachments()));
}
@Override
public CommonResult<Long> sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) {
return success(mailSendService.sendSingleMailToMember(reqDTO.getUserId(),
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
reqDTO.getTemplateCode(), reqDTO.getTemplateParams(), reqDTO.getAttachments()));
}
}

View File

@@ -1,160 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ZipUtil;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenCreateListReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenDetailRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenPreviewRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenUpdateReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTableRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.DatabaseTableRespVO;
import com.njcn.rdms.module.system.convert.codegen.CodegenConvert;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenColumnDO;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenTableDO;
import com.njcn.rdms.module.system.service.codegen.CodegenService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.getLoginUserNickname;
import static com.njcn.rdms.module.system.framework.file.core.utils.FileTypeUtils.writeAttachment;
@Tag(name = "管理后台 - 代码生成器")
@RestController
@RequestMapping("/infra/codegen")
@Validated
public class CodegenController {
@Resource
private CodegenService codegenService;
@GetMapping("/db/table/list")
@Operation(summary = "获得数据库自带的表定义列表", description = "会过滤掉已经导入 Codegen 的表")
@Parameters({
@Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1"),
@Parameter(name = "name", description = "表名,模糊匹配", example = "rdms"),
@Parameter(name = "comment", description = "描述,模糊匹配", example = "灿能")
})
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<List<DatabaseTableRespVO>> getDatabaseTableList(
@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId,
@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "comment", required = false) String comment) {
return success(codegenService.getDatabaseTableList(dataSourceConfigId, name, comment));
}
@GetMapping("/table/list")
@Operation(summary = "获得表定义列表")
@Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) {
List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId);
return success(BeanUtils.toBean(list, CodegenTableRespVO.class));
}
@GetMapping("/table/page")
@Operation(summary = "获得表定义分页")
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class));
}
@GetMapping("/detail")
@Operation(summary = "获得表和字段的明细")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
CodegenTableDO table = codegenService.getCodegenTable(tableId);
List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
// 拼装返回
return success(CodegenConvert.INSTANCE.convert(table, columns));
}
@Operation(summary = "基于数据库的表结构,创建代码生成器的表和字段定义")
@PostMapping("/create-list")
@PreAuthorize("@ss.hasPermission('infra:codegen:create')")
public CommonResult<List<Long>> createCodegenList(@Valid @RequestBody CodegenCreateListReqVO reqVO) {
return success(codegenService.createCodegenList(getLoginUserNickname(), reqVO));
}
@Operation(summary = "更新数据库的表和字段定义")
@PutMapping("/update")
@PreAuthorize("@ss.hasPermission('infra:codegen:update')")
public CommonResult<Boolean> updateCodegen(@Valid @RequestBody CodegenUpdateReqVO updateReqVO) {
codegenService.updateCodegen(updateReqVO);
return success(true);
}
@Operation(summary = "基于数据库的表结构,同步数据库的表和字段定义")
@PutMapping("/sync-from-db")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:update')")
public CommonResult<Boolean> syncCodegenFromDB(@RequestParam("tableId") Long tableId) {
codegenService.syncCodegenFromDB(tableId);
return success(true);
}
@Operation(summary = "删除数据库的表和字段定义")
@DeleteMapping("/delete")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:delete')")
public CommonResult<Boolean> deleteCodegen(@RequestParam("tableId") Long tableId) {
codegenService.deleteCodegen(tableId);
return success(true);
}
@Operation(summary = "批量删除数据库的表和字段定义")
@DeleteMapping("/delete-list")
@Parameter(name = "tableIds", description = "表编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:codegen:delete')")
public CommonResult<Boolean> deleteCodegenList(@RequestParam("tableIds") List<Long> tableIds) {
codegenService.deleteCodegenList(tableIds);
return success(true);
}
@Operation(summary = "预览生成代码")
@GetMapping("/preview")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:preview')")
public CommonResult<List<CodegenPreviewRespVO>> previewCodegen(@RequestParam("tableId") Long tableId) {
Map<String, String> codes = codegenService.generationCodes(tableId);
return success(CodegenConvert.INSTANCE.convert(codes));
}
@Operation(summary = "下载生成代码")
@GetMapping("/download")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:download')")
public void downloadCodegen(@RequestParam("tableId") Long tableId,
HttpServletResponse response) throws IOException {
// 生成代码
Map<String, String> codes = codegenService.generationCodes(tableId);
// 构建 zip 包
String[] paths = codes.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = codes.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipUtil.zip(outputStream, paths, ins);
// 输出
writeAttachment(response, "codegen.zip", outputStream.toByteArray());
}
}

View File

@@ -1,21 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 基于数据库的表结构,创建代码生成器的表和字段定义 Request VO")
@Data
public class CodegenCreateListReqVO {
@Schema(description = "数据源配置的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "数据源配置的编号不能为空")
private Long dataSourceConfigId;
@Schema(description = "表名数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2, 3]")
@NotNull(message = "表名数组不能为空")
private List<String> tableNames;
}

View File

@@ -1,20 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.column.CodegenColumnRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTableRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 代码生成表和字段的明细 Response VO")
@Data
public class CodegenDetailRespVO {
@Schema(description = "表定义")
private CodegenTableRespVO table;
@Schema(description = "字段定义")
private List<CodegenColumnRespVO> columns;
}

View File

@@ -1,16 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 代码生成预览 Response VO注意每个文件都是一个该对象")
@Data
public class CodegenPreviewRespVO {
@Schema(description = "文件路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "java/com.njcn.rdms/adminserver/modules/system/controller/test/SysTestDemoController.java")
private String filePath;
@Schema(description = "代码", requiredMode = Schema.RequiredMode.REQUIRED, example = "Hello World")
private String code;
}

View File

@@ -1,24 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTableSaveReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 代码生成表和字段的修改 Request VO")
@Data
public class CodegenUpdateReqVO {
@Valid // 校验内嵌的字段
@NotNull(message = "表定义不能为空")
private CodegenTableSaveReqVO table;
@Valid // 校验内嵌的字段
@NotNull(message = "字段定义不能为空")
private List<CodegenColumnSaveReqVO> columns;
}

View File

@@ -1,69 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.column;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 代码生成字段定义 Response VO")
@Data
public class CodegenColumnRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long tableId;
@Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
private String columnName;
@Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
private String dataType;
@Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
private String columnComment;
@Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean nullable;
@Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean primaryKey;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer ordinalPosition;
@Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
private String javaType;
@Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
private String javaField;
@Schema(description = "字典类型", example = "sys_gender")
private String dictType;
@Schema(description = "数据示例", example = "1024")
private String example;
@Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean createOperation;
@Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean updateOperation;
@Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean listOperation;
@Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
private String listOperationCondition;
@Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean listOperationResult;
@Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
private String htmlType;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -1,80 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.column;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO")
@Data
public class CodegenColumnSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "表编号不能为空")
private Long tableId;
@Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
@NotNull(message = "字段名不能为空")
private String columnName;
@Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
@NotNull(message = "字段类型不能为空")
private String dataType;
@Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
@NotNull(message = "字段描述不能为空")
private String columnComment;
@Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否允许为空不能为空")
private Boolean nullable;
@Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
@NotNull(message = "是否主键不能为空")
private Boolean primaryKey;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@NotNull(message = "排序不能为空")
private Integer ordinalPosition;
@Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
@NotNull(message = "Java 属性类型不能为空")
private String javaType;
@Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
@NotNull(message = "Java 属性名不能为空")
private String javaField;
@Schema(description = "字典类型", example = "sys_gender")
private String dictType;
@Schema(description = "数据示例", example = "1024")
private String example;
@Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否为 Create 创建操作的字段不能为空")
private Boolean createOperation;
@Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
@NotNull(message = "是否为 Update 更新操作的字段不能为空")
private Boolean updateOperation;
@Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否为 List 查询操作的字段不能为空")
private Boolean listOperation;
@Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
@NotNull(message = "List 查询操作的条件类型不能为空")
private String listOperationCondition;
@Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否为 List 查询操作的返回字段不能为空")
private Boolean listOperationResult;
@Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
@NotNull(message = "显示类型不能为空")
private String htmlType;
}

View File

@@ -1,29 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 表定义分页 Request VO")
@Data
public class CodegenTablePageReqVO extends PageParam {
@Schema(description = "表名称,模糊匹配", example = "rdms")
private String tableName;
@Schema(description = "表描述,模糊匹配", example = "灿能")
private String tableComment;
@Schema(description = "实体,模糊匹配", example = "Rdms")
private String className;
@Schema(description = "创建时间", example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -1,72 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 代码生成表定义 Response VO")
@Data
public class CodegenTableRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer scene;
@Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
private String tableName;
@Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
private String tableComment;
@Schema(description = "备注", example = "我是备注")
private String remark;
@Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
private String moduleName;
@Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
private String businessName;
@Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
private String className;
@Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
private String classComment;
@Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
private String author;
@Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer templateType;
@Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private Integer frontType;
@Schema(description = "父菜单编号", example = "1024")
private Long parentMenuId;
@Schema(description = "主表的编号", example = "2048")
private Long masterTableId;
@Schema(description = "子表关联主表的字段编号", example = "4096")
private Long subJoinColumnId;
@Schema(description = "主表与子表是否一对多", example = "4096")
private Boolean subJoinMany;
@Schema(description = "树表的父字段编号", example = "8192")
private Long treeParentColumnId;
@Schema(description = "树表的名字字段编号", example = "16384")
private Long treeNameColumnId;
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Integer dataSourceConfigId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime updateTime;
}

View File

@@ -1,99 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.njcn.rdms.module.system.enums.codegen.CodegenSceneEnum;
import com.njcn.rdms.module.system.enums.codegen.CodegenTemplateTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO")
@Data
public class CodegenTableSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "导入类型不能为空")
private Integer scene;
@Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@NotNull(message = "表名称不能为空")
private String tableName;
@Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能")
@NotNull(message = "表描述不能为空")
private String tableComment;
@Schema(description = "备注", example = "我是备注")
private String remark;
@Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
@NotNull(message = "模块名不能为空")
private String moduleName;
@Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
@NotNull(message = "业务名不能为空")
private String businessName;
@Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
@NotNull(message = "类名称不能为空")
private String className;
@Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
@NotNull(message = "类描述不能为空")
private String classComment;
@Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
@NotNull(message = "作者不能为空")
private String author;
@Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "模板类型不能为空")
private Integer templateType;
@Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
@NotNull(message = "前端类型不能为空")
private Integer frontType;
@Schema(description = "父菜单编号", example = "1024")
private Long parentMenuId;
@Schema(description = "主表的编号", example = "2048")
private Long masterTableId;
@Schema(description = "子表关联主表的字段编号", example = "4096")
private Long subJoinColumnId;
@Schema(description = "主表与子表是否一对多", example = "4096")
private Boolean subJoinMany;
@Schema(description = "树表的父字段编号", example = "8192")
private Long treeParentColumnId;
@Schema(description = "树表的名字字段编号", example = "16384")
private Long treeNameColumnId;
@AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
@JsonIgnore
public boolean isParentMenuIdValid() {
// 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的
return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
|| getParentMenuId() != null;
}
@AssertTrue(message = "关联的父表信息不全")
@JsonIgnore
public boolean isSubValid() {
return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
|| (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany));
}
@AssertTrue(message = "关联的树表信息不全")
@JsonIgnore
public boolean isTreeValid() {
return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE)
|| (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId));
}
}

View File

@@ -1,16 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.codegen.vo.table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 数据库的表定义 Response VO")
@Data
public class DatabaseTableRespVO {
@Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yuanma")
private String name;
@Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "灿能源码")
private String comment;
}

View File

@@ -31,7 +31,7 @@ import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 参数配置")
@RestController
@RequestMapping("/infra/config")
@RequestMapping("/system/config")
@Validated
public class ConfigController {
@@ -40,14 +40,14 @@ public class ConfigController {
@PostMapping("/create")
@Operation(summary = "创建参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:create')")
@PreAuthorize("@ss.hasPermission('system:config:create')")
public CommonResult<Long> createConfig(@Valid @RequestBody ConfigSaveReqVO createReqVO) {
return success(configService.createConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:update')")
@PreAuthorize("@ss.hasPermission('system:config:update')")
public CommonResult<Boolean> updateConfig(@Valid @RequestBody ConfigSaveReqVO updateReqVO) {
configService.updateConfig(updateReqVO);
return success(true);
@@ -56,7 +56,7 @@ public class ConfigController {
@DeleteMapping("/delete")
@Operation(summary = "删除参数配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:config:delete')")
@PreAuthorize("@ss.hasPermission('system:config:delete')")
public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
configService.deleteConfig(id);
return success(true);
@@ -65,7 +65,7 @@ public class ConfigController {
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除参数配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:config:delete')")
@PreAuthorize("@ss.hasPermission('system:config:delete')")
public CommonResult<Boolean> deleteConfigList(@RequestParam("ids") List<Long> ids) {
configService.deleteConfigList(ids);
return success(true);
@@ -74,7 +74,7 @@ public class ConfigController {
@GetMapping(value = "/get")
@Operation(summary = "获得参数配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:config:query')")
@PreAuthorize("@ss.hasPermission('system:config:query')")
public CommonResult<ConfigRespVO> getConfig(@RequestParam("id") Long id) {
return success(ConfigConvert.INSTANCE.convert(configService.getConfig(id)));
}
@@ -95,7 +95,7 @@ public class ConfigController {
@GetMapping("/page")
@Operation(summary = "获取参数配置分页")
@PreAuthorize("@ss.hasPermission('infra:config:query')")
@PreAuthorize("@ss.hasPermission('system:config:query')")
public CommonResult<PageResult<ConfigRespVO>> getConfigPage(@Valid ConfigPageReqVO pageReqVO) {
PageResult<ConfigDO> page = configService.getConfigPage(pageReqVO);
return success(ConfigConvert.INSTANCE.convertPage(page));
@@ -103,7 +103,7 @@ public class ConfigController {
@GetMapping("/export-excel")
@Operation(summary = "导出参数配置")
@PreAuthorize("@ss.hasPermission('infra:config:export')")
@PreAuthorize("@ss.hasPermission('system:config:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportConfig(ConfigPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
@@ -115,3 +115,4 @@ public class ConfigController {
}
}

View File

@@ -1,81 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.db;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.db.vo.DataSourceConfigRespVO;
import com.njcn.rdms.module.system.controller.admin.db.vo.DataSourceConfigSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.db.DataSourceConfigDO;
import com.njcn.rdms.module.system.service.db.DataSourceConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 数据源配置")
@RestController
@RequestMapping("/infra/data-source-config")
@Validated
public class DataSourceConfigController {
@Resource
private DataSourceConfigService dataSourceConfigService;
@PostMapping("/create")
@Operation(summary = "创建数据源配置")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:create')")
public CommonResult<Long> createDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO createReqVO) {
return success(dataSourceConfigService.createDataSourceConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新数据源配置")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:update')")
public CommonResult<Boolean> updateDataSourceConfig(@Valid @RequestBody DataSourceConfigSaveReqVO updateReqVO) {
dataSourceConfigService.updateDataSourceConfig(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除数据源配置")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')")
public CommonResult<Boolean> deleteDataSourceConfig(@RequestParam("id") Long id) {
dataSourceConfigService.deleteDataSourceConfig(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除数据源配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:data-source-config:delete')")
public CommonResult<Boolean> deleteDataSourceConfigList(@RequestParam("ids") List<Long> ids) {
dataSourceConfigService.deleteDataSourceConfigList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得数据源配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:query')")
public CommonResult<DataSourceConfigRespVO> getDataSourceConfig(@RequestParam("id") Long id) {
DataSourceConfigDO config = dataSourceConfigService.getDataSourceConfig(id);
return success(BeanUtils.toBean(config, DataSourceConfigRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获得数据源配置列表")
@PreAuthorize("@ss.hasPermission('infra:data-source-config:query')")
public CommonResult<List<DataSourceConfigRespVO>> getDataSourceConfigList() {
List<DataSourceConfigDO> list = dataSourceConfigService.getDataSourceConfigList();
return success(BeanUtils.toBean(list, DataSourceConfigRespVO.class));
}
}

View File

@@ -1,27 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.db.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 数据源配置 Response VO")
@Data
public class DataSourceConfigRespVO {
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
private String name;
@Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro")
private String url;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root")
private String username;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -1,30 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.db.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 数据源配置创建/修改 Request VO")
@Data
public class DataSourceConfigSaveReqVO {
@Schema(description = "主键编号", example = "1024")
private Long id;
@Schema(description = "数据源名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
@NotNull(message = "数据源名称不能为空")
private String name;
@Schema(description = "数据源连接", requiredMode = Schema.RequiredMode.REQUIRED, example = "jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro")
@NotNull(message = "数据源连接不能为空")
private String url;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "root")
@NotNull(message = "用户名不能为空")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@NotNull(message = "密码不能为空")
private String password;
}

View File

@@ -1,5 +1,5 @@
### 请求 /infra/file-config/create 接口 => 成功
POST {{baseUrl}}/infra/file-config/create
### 请求 /system/file-config/create 接口 => 成功
POST {{baseUrl}}/system/file-config/create
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
@@ -18,8 +18,8 @@ Authorization: Bearer {{token}}
}
}
### 请求 /infra/file-config/update 接口 => 成功
PUT {{baseUrl}}/infra/file-config/update
### 请求 /system/file-config/update 接口 => 成功
PUT {{baseUrl}}/system/file-config/update
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}
@@ -38,8 +38,9 @@ Authorization: Bearer {{token}}
}
}
### 请求 /infra/file-config/test 接口 => 成功
GET {{baseUrl}}/infra/file-config/test?id=2
### 请求 /system/file-config/test 接口 => 成功
GET {{baseUrl}}/system/file-config/test?id=2
Content-Type: application/json
tenant-id: {{adminTenantId}}
Authorization: Bearer {{token}}

View File

@@ -23,7 +23,7 @@ import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 文件配置")
@RestController
@RequestMapping("/infra/file-config")
@RequestMapping("/system/file-config")
@Validated
public class FileConfigController {
@@ -32,14 +32,14 @@ public class FileConfigController {
@PostMapping("/create")
@Operation(summary = "创建文件配置")
@PreAuthorize("@ss.hasPermission('infra:file-config:create')")
@PreAuthorize("@ss.hasPermission('system:file-config:create')")
public CommonResult<Long> createFileConfig(@Valid @RequestBody FileConfigSaveReqVO createReqVO) {
return success(fileConfigService.createFileConfig(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新文件配置")
@PreAuthorize("@ss.hasPermission('infra:file-config:update')")
@PreAuthorize("@ss.hasPermission('system:file-config:update')")
public CommonResult<Boolean> updateFileConfig(@Valid @RequestBody FileConfigSaveReqVO updateReqVO) {
fileConfigService.updateFileConfig(updateReqVO);
return success(true);
@@ -47,7 +47,7 @@ public class FileConfigController {
@PutMapping("/update-master")
@Operation(summary = "更新文件配置为 Master")
@PreAuthorize("@ss.hasPermission('infra:file-config:update')")
@PreAuthorize("@ss.hasPermission('system:file-config:update')")
public CommonResult<Boolean> updateFileConfigMaster(@RequestParam("id") Long id) {
fileConfigService.updateFileConfigMaster(id);
return success(true);
@@ -56,7 +56,7 @@ public class FileConfigController {
@DeleteMapping("/delete")
@Operation(summary = "删除文件配置")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file-config:delete')")
@PreAuthorize("@ss.hasPermission('system:file-config:delete')")
public CommonResult<Boolean> deleteFileConfig(@RequestParam("id") Long id) {
fileConfigService.deleteFileConfig(id);
return success(true);
@@ -65,7 +65,7 @@ public class FileConfigController {
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除文件配置")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:file-config:delete')")
@PreAuthorize("@ss.hasPermission('system:file-config:delete')")
public CommonResult<Boolean> deleteFileConfigList(@RequestParam("ids") List<Long> ids) {
fileConfigService.deleteFileConfigList(ids);
return success(true);
@@ -74,7 +74,7 @@ public class FileConfigController {
@GetMapping("/get")
@Operation(summary = "获得文件配置")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
public CommonResult<FileConfigRespVO> getFileConfig(@RequestParam("id") Long id) {
FileConfigDO config = fileConfigService.getFileConfig(id);
return success(BeanUtils.toBean(config, FileConfigRespVO.class));
@@ -82,7 +82,7 @@ public class FileConfigController {
@GetMapping("/page")
@Operation(summary = "获得文件配置分页")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
public CommonResult<PageResult<FileConfigRespVO>> getFileConfigPage(@Valid FileConfigPageReqVO pageVO) {
PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(pageVO);
return success(BeanUtils.toBean(pageResult, FileConfigRespVO.class));
@@ -90,9 +90,10 @@ public class FileConfigController {
@GetMapping("/test")
@Operation(summary = "测试文件配置是否正确")
@PreAuthorize("@ss.hasPermission('infra:file-config:query')")
@PreAuthorize("@ss.hasPermission('system:file-config:query')")
public CommonResult<String> testFileConfig(@RequestParam("id") Long id) throws Exception {
String url = fileConfigService.testFileConfig(id);
return success(url);
}
}

View File

@@ -34,7 +34,7 @@ import static com.njcn.rdms.module.system.framework.file.core.utils.FileTypeUtil
@Tag(name = "管理后台 - 文件存储")
@RestController
@RequestMapping("/infra/file")
@RequestMapping("/system/file")
@Validated
@Slf4j
public class FileController {
@@ -74,7 +74,7 @@ public class FileController {
@GetMapping("/get")
@Operation(summary = "获得文件")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:query')")
@PreAuthorize("@ss.hasPermission('system:file:query')")
public CommonResult<FileRespVO> getFile(@RequestParam("id") Long id) {
return success(BeanUtils.toBean(fileService.getFile(id), FileRespVO.class));
}
@@ -82,7 +82,7 @@ public class FileController {
@DeleteMapping("/delete")
@Operation(summary = "删除文件")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:delete')")
@PreAuthorize("@ss.hasPermission('system:file:delete')")
public CommonResult<Boolean> deleteFile(@RequestParam("id") Long id) throws Exception {
fileService.deleteFile(id);
return success(true);
@@ -91,7 +91,7 @@ public class FileController {
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除文件")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('infra:file:delete')")
@PreAuthorize("@ss.hasPermission('system:file:delete')")
public CommonResult<Boolean> deleteFileList(@RequestParam("ids") List<Long> ids) throws Exception {
fileService.deleteFileList(ids);
return success(true);
@@ -127,10 +127,11 @@ public class FileController {
@GetMapping("/page")
@Operation(summary = "获得文件分页")
@PreAuthorize("@ss.hasPermission('infra:file:query')")
@PreAuthorize("@ss.hasPermission('system:file:query')")
public CommonResult<PageResult<FileRespVO>> getFilePage(@Valid FilePageReqVO pageVO) {
PageResult<FileDO> pageResult = fileService.getFilePage(pageVO);
return success(BeanUtils.toBean(pageResult, FileRespVO.class));
}
}

View File

@@ -31,7 +31,7 @@ import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - API 访问日志")
@RestController
@RequestMapping("/infra/api-access-log")
@RequestMapping("/system/api-access-log")
@Validated
public class ApiAccessLogController {
@@ -41,7 +41,7 @@ public class ApiAccessLogController {
@GetMapping("/get")
@Operation(summary = "获得 API 访问日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-access-log:query')")
public CommonResult<ApiAccessLogRespVO> getApiAccessLog(@RequestParam("id") Long id) {
ApiAccessLogDO apiAccessLog = apiAccessLogService.getApiAccessLog(id);
return success(BeanUtils.toBean(apiAccessLog, ApiAccessLogRespVO.class));
@@ -49,7 +49,7 @@ public class ApiAccessLogController {
@GetMapping("/page")
@Operation(summary = "获得API 访问日志分页")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-access-log:query')")
public CommonResult<PageResult<ApiAccessLogRespVO>> getApiAccessLogPage(@Valid ApiAccessLogPageReqVO pageReqVO) {
PageResult<ApiAccessLogDO> pageResult = apiAccessLogService.getApiAccessLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ApiAccessLogRespVO.class));
@@ -57,7 +57,7 @@ public class ApiAccessLogController {
@GetMapping("/export-excel")
@Operation(summary = "导出API 访问日志 Excel")
@PreAuthorize("@ss.hasPermission('infra:api-access-log:export')")
@PreAuthorize("@ss.hasPermission('system:api-access-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportApiAccessLogExcel(@Valid ApiAccessLogPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
@@ -69,3 +69,4 @@ public class ApiAccessLogController {
}
}

View File

@@ -30,7 +30,7 @@ import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.
@Tag(name = "管理后台 - API 错误日志")
@RestController
@RequestMapping("/infra/api-error-log")
@RequestMapping("/system/api-error-log")
@Validated
public class ApiErrorLogController {
@@ -43,7 +43,7 @@ public class ApiErrorLogController {
@Parameter(name = "id", description = "编号", required = true, example = "1024"),
@Parameter(name = "processStatus", description = "处理状态", required = true, example = "1")
})
@PreAuthorize("@ss.hasPermission('infra:api-error-log:update-status')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:update-status')")
public CommonResult<Boolean> updateApiErrorLogProcess(@RequestParam("id") Long id,
@RequestParam("processStatus") Integer processStatus) {
apiErrorLogService.updateApiErrorLogProcess(id, processStatus, getLoginUserId());
@@ -53,7 +53,7 @@ public class ApiErrorLogController {
@GetMapping("/get")
@Operation(summary = "获得 API 错误日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:query')")
public CommonResult<ApiErrorLogRespVO> getApiErrorLog(@RequestParam("id") Long id) {
ApiErrorLogDO apiErrorLog = apiErrorLogService.getApiErrorLog(id);
return success(BeanUtils.toBean(apiErrorLog, ApiErrorLogRespVO.class));
@@ -61,7 +61,7 @@ public class ApiErrorLogController {
@GetMapping("/page")
@Operation(summary = "获得 API 错误日志分页")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:query')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:query')")
public CommonResult<PageResult<ApiErrorLogRespVO>> getApiErrorLogPage(@Valid ApiErrorLogPageReqVO pageReqVO) {
PageResult<ApiErrorLogDO> pageResult = apiErrorLogService.getApiErrorLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, ApiErrorLogRespVO.class));
@@ -69,7 +69,7 @@ public class ApiErrorLogController {
@GetMapping("/export-excel")
@Operation(summary = "导出 API 错误日志 Excel")
@PreAuthorize("@ss.hasPermission('infra:api-error-log:export')")
@PreAuthorize("@ss.hasPermission('system:api-error-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportApiErrorLogExcel(@Valid ApiErrorLogPageReqVO exportReqVO,
HttpServletResponse response) throws IOException {
@@ -81,3 +81,4 @@ public class ApiErrorLogController {
}
}

View File

@@ -89,7 +89,7 @@ public class ApiAccessLogRespVO {
@ExcelProperty("结果码")
private Integer resultCode;
@Schema(description = "结果提示", example = "灿能源码,牛逼!")
@Schema(description = "结果提示", example = "灿能,牛逼!")
@ExcelProperty("结果提示")
private String resultMsg;

View File

@@ -1,90 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountRespVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountSaveReqVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountSimpleRespVO;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailAccountDO;
import com.njcn.rdms.module.system.service.mail.MailAccountService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 邮箱账号")
@RestController
@RequestMapping("/system/mail-account")
public class MailAccountController {
@Resource
private MailAccountService mailAccountService;
@PostMapping("/create")
@Operation(summary = "创建邮箱账号")
@PreAuthorize("@ss.hasPermission('system:mail-account:create')")
public CommonResult<Long> createMailAccount(@Valid @RequestBody MailAccountSaveReqVO createReqVO) {
return success(mailAccountService.createMailAccount(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改邮箱账号")
@PreAuthorize("@ss.hasPermission('system:mail-account:update')")
public CommonResult<Boolean> updateMailAccount(@Valid @RequestBody MailAccountSaveReqVO updateReqVO) {
mailAccountService.updateMailAccount(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除邮箱账号")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:mail-account:delete')")
public CommonResult<Boolean> deleteMailAccount(@RequestParam Long id) {
mailAccountService.deleteMailAccount(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除邮箱账号")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('system:mail-account:delete')")
public CommonResult<Boolean> deleteMailAccountList(@RequestParam("ids") List<Long> ids) {
mailAccountService.deleteMailAccountList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得邮箱账号")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-account:query')")
public CommonResult<MailAccountRespVO> getMailAccount(@RequestParam("id") Long id) {
MailAccountDO account = mailAccountService.getMailAccount(id);
return success(BeanUtils.toBean(account, MailAccountRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得邮箱账号分页")
@PreAuthorize("@ss.hasPermission('system:mail-account:query')")
public CommonResult<PageResult<MailAccountRespVO>> getMailAccountPage(@Valid MailAccountPageReqVO pageReqVO) {
PageResult<MailAccountDO> pageResult = mailAccountService.getMailAccountPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, MailAccountRespVO.class));
}
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(summary = "获得邮箱账号精简列表")
public CommonResult<List<MailAccountSimpleRespVO>> getSimpleMailAccountList() {
List<MailAccountDO> list = mailAccountService.getMailAccountList();
return success(BeanUtils.toBean(list, MailAccountSimpleRespVO.class));
}
}

View File

@@ -1,49 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
import com.njcn.rdms.module.system.controller.admin.mail.vo.log.MailLogRespVO;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailLogDO;
import com.njcn.rdms.module.system.service.mail.MailLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 邮件日志")
@RestController
@RequestMapping("/system/mail-log")
public class MailLogController {
@Resource
private MailLogService mailLogService;
@GetMapping("/page")
@Operation(summary = "获得邮箱日志分页")
@PreAuthorize("@ss.hasPermission('system:mail-log:query')")
public CommonResult<PageResult<MailLogRespVO>> getMailLogPage(@Valid MailLogPageReqVO pageVO) {
PageResult<MailLogDO> pageResult = mailLogService.getMailLogPage(pageVO);
return success(BeanUtils.toBean(pageResult, MailLogRespVO.class));
}
@GetMapping("/get")
@Operation(summary = "获得邮箱日志")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-log:query')")
public CommonResult<MailLogRespVO> getMailTemplate(@RequestParam("id") Long id) {
MailLogDO log = mailLogService.getMailLog(id);
return success(BeanUtils.toBean(log, MailLogRespVO.class));
}
}

View File

@@ -1,14 +0,0 @@
### 请求 /system/mail-template/send-mail 接口 => 成功
POST {{baseUrl}}/system/mail-template/send-mail
Authorization: Bearer {{token}}
Content-Type: application/json
tenant-id: {{adminTenantId}}
{
"templateCode": "test_01",
"mail": "7685413@qq.com",
"templateParams": {
"key01": "value01",
"key02": "value02"
}
}

View File

@@ -1,99 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.mail.vo.template.*;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailTemplateDO;
import com.njcn.rdms.module.system.service.mail.MailSendService;
import com.njcn.rdms.module.system.service.mail.MailTemplateService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
import static com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Tag(name = "管理后台 - 邮件模版")
@RestController
@RequestMapping("/system/mail-template")
public class MailTemplateController {
@Resource
private MailTemplateService mailTempleService;
@Resource
private MailSendService mailSendService;
@PostMapping("/create")
@Operation(summary = "创建邮件模版")
@PreAuthorize("@ss.hasPermission('system:mail-template:create')")
public CommonResult<Long> createMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO createReqVO){
return success(mailTempleService.createMailTemplate(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "修改邮件模版")
@PreAuthorize("@ss.hasPermission('system:mail-template:update')")
public CommonResult<Boolean> updateMailTemplate(@Valid @RequestBody MailTemplateSaveReqVO updateReqVO){
mailTempleService.updateMailTemplate(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除邮件模版")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-template:delete')")
public CommonResult<Boolean> deleteMailTemplate(@RequestParam("id") Long id) {
mailTempleService.deleteMailTemplate(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Operation(summary = "批量删除邮件模版")
@Parameter(name = "ids", description = "编号列表", required = true)
@PreAuthorize("@ss.hasPermission('system:mail-template:delete')")
public CommonResult<Boolean> deleteMailTemplateList(@RequestParam("ids") List<Long> ids) {
mailTempleService.deleteMailTemplateList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得邮件模版")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:mail-template:query')")
public CommonResult<MailTemplateRespVO> getMailTemplate(@RequestParam("id") Long id) {
MailTemplateDO template = mailTempleService.getMailTemplate(id);
return success(BeanUtils.toBean(template, MailTemplateRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得邮件模版分页")
@PreAuthorize("@ss.hasPermission('system:mail-template:query')")
public CommonResult<PageResult<MailTemplateRespVO>> getMailTemplatePage(@Valid MailTemplatePageReqVO pageReqVO) {
PageResult<MailTemplateDO> pageResult = mailTempleService.getMailTemplatePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, MailTemplateRespVO.class));
}
@GetMapping({"/list-all-simple", "simple-list"})
@Operation(summary = "获得邮件模版精简列表")
public CommonResult<List<MailTemplateSimpleRespVO>> getSimpleTemplateList() {
List<MailTemplateDO> list = mailTempleService.getMailTemplateList();
return success(BeanUtils.toBean(list, MailTemplateSimpleRespVO.class));
}
@PostMapping("/send-mail")
@Operation(summary = "发送邮件")
@PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
return success(mailSendService.sendSingleMailToAdmin(getLoginUserId(),
sendReqVO.getToMails(), sendReqVO.getCcMails(), sendReqVO.getBccMails(),
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
}
}

View File

@@ -1,21 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 邮箱账号分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MailAccountPageReqVO extends PageParam {
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdmsyuanma@123.com")
private String mail;
@Schema(description = "用户名" , requiredMode = Schema.RequiredMode.REQUIRED , example = "rdms")
private String username;
}

View File

@@ -1,39 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 邮箱账号 Response VO")
@Data
public class MailAccountRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdmsyuanma@123.com")
private String mail;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
private String password;
@Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn")
private String host;
@Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
private Integer port;
@Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean sslEnable;
@Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean starttlsEnable;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -1,44 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 邮箱账号创建/修改 Request VO")
@Data
public class MailAccountSaveReqVO {
@Schema(description = "编号", example = "1024")
private Long id;
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdmsyuanma@123.com")
@NotNull(message = "邮箱不能为空")
@Email(message = "必须是 Email 格式")
private String mail;
@Schema(description = "用户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms")
@NotNull(message = "用户名不能为空")
private String username;
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
@NotNull(message = "密码必填")
private String password;
@Schema(description = "SMTP 服务器域名", requiredMode = Schema.RequiredMode.REQUIRED, example = "www.iocoder.cn")
@NotNull(message = "SMTP 服务器域名不能为空")
private String host;
@Schema(description = "SMTP 服务器端口", requiredMode = Schema.RequiredMode.REQUIRED, example = "80")
@NotNull(message = "SMTP 服务器端口不能为空")
private Integer port;
@Schema(description = "是否开启 ssl", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否开启 ssl 必填")
private Boolean sslEnable;
@Schema(description = "是否开启 starttls", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否开启 starttls 必填")
private Boolean starttlsEnable;
}

View File

@@ -1,16 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.account;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 邮箱账号的精简 Response VO")
@Data
public class MailAccountSimpleRespVO {
@Schema(description = "邮箱编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "768541388@qq.com")
private String mail;
}

View File

@@ -1,42 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.log;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 邮箱日志分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MailLogPageReqVO extends PageParam {
@Schema(description = "用户编号", example = "30883")
private Long userId;
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2")
private Integer userType;
@Schema(description = "接收邮箱地址,模糊匹配", example = "76854@qq.com")
private String toMail;
@Schema(description = "邮箱账号编号", example = "18107")
private Long accountId;
@Schema(description = "模板编号", example = "5678")
private Long templateId;
@Schema(description = "发送状态,参见 MailSendStatusEnum 枚举", example = "1")
private Integer sendStatus;
@Schema(description = "发送时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] sendTime;
}

View File

@@ -1,71 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.log;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Schema(description = "管理后台 - 邮件日志 Response VO")
@Data
public class MailLogRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31020")
private Long id;
@Schema(description = "用户编号", example = "30883")
private Long userId;
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2")
private Byte userType;
@Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user1@example.com, user2@example.com")
private List<String> toMails;
@Schema(description = "抄送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user3@example.com, user4@example.com")
private List<String> ccMails;
@Schema(description = "密送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user5@example.com, user6@example.com")
private List<String> bccMails;
@Schema(description = "邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107")
private Long accountId;
@Schema(description = "发送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "85757@qq.com")
private String fromMail;
@Schema(description = "模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5678")
private Long templateId;
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
private String templateCode;
@Schema(description = "模版发送人名称", example = "李四")
private String templateNickname;
@Schema(description = "邮件标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试标题")
private String templateTitle;
@Schema(description = "邮件内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试内容")
private String templateContent;
@Schema(description = "邮件参数", requiredMode = Schema.RequiredMode.REQUIRED)
private Map<String, Object> templateParams;
@Schema(description = "发送状态,参见 MailSendStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Byte sendStatus;
@Schema(description = "发送时间")
private LocalDateTime sendTime;
@Schema(description = "发送返回的消息 ID", example = "28568")
private String sendMessageId;
@Schema(description = "发送异常")
private String sendException;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -1,36 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.template;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.njcn.rdms.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 邮件模版分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MailTemplatePageReqVO extends PageParam {
@Schema(description = "状态,参见 CommonStatusEnum 枚举", example = "1")
private Integer status;
@Schema(description = "标识,模糊匹配", example = "code_1024")
private String code;
@Schema(description = "名称,模糊匹配", example = "芋头")
private String name;
@Schema(description = "账号编号", example = "2048")
private Long accountId;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -1,46 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.template;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 邮件末班 Response VO")
@Data
public class MailTemplateRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试名字")
private String name;
@Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
private String code;
@Schema(description = "发送的邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long accountId;
@Schema(description = "发送人名称", example = "芋头")
private String nickname;
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "注册成功")
private String title;
@Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,注册成功啦")
private String content;
@Schema(description = "参数数组", example = "name,code")
private List<String> params;
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
@Schema(description = "备注", example = "奥特曼")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -1,46 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.template;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@Schema(description = "管理后台 - 邮件模版创建/修改 Request VO")
@Data
public class MailTemplateSaveReqVO {
@Schema(description = "编号", example = "1024")
private Long id;
@Schema(description = "模版名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试名字")
@NotNull(message = "名称不能为空")
private String name;
@Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "test")
@NotNull(message = "模版编号不能为空")
private String code;
@Schema(description = "发送的邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "发送的邮箱账号编号不能为空")
private Long accountId;
@Schema(description = "发送人名称", example = "芋头")
private String nickname;
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "注册成功")
@NotEmpty(message = "标题不能为空")
private String title;
@Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,注册成功啦")
@NotEmpty(message = "内容不能为空")
private String content;
@Schema(description = "状态,参见 CommonStatusEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
private Integer status;
@Schema(description = "备注", example = "奥特曼")
private String remark;
}

View File

@@ -1,32 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.template;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
@Schema(description = "管理后台 - 邮件发送 Req VO")
@Data
public class MailTemplateSendReqVO {
@Schema(description = "接收邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user1@example.com, user2@example.com]")
@NotEmpty(message = "接收邮箱不能为空")
private List<String> toMails;
@Schema(description = "抄送邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user3@example.com, user4@example.com]")
private List<String> ccMails;
@Schema(description = "密送邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user5@example.com, user6@example.com]")
private List<String> bccMails;
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
@NotNull(message = "模板编码不能为空")
private String templateCode;
@Schema(description = "模板参数")
private Map<String, Object> templateParams;
}

View File

@@ -1,16 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.mail.vo.template;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 邮件模版的精简 Response VO")
@Data
public class MailTemplateSimpleRespVO {
@Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "模版名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "哒哒哒")
private String name;
}

View File

@@ -1,4 +1,5 @@
### 请求 /infra/redis/get-monitor-info 接口 => 成功
GET {{baseUrl}}/infra/redis/get-monitor-info
### 请求 /system/redis/get-monitor-info 接口 => 成功
GET {{baseUrl}}/system/redis/get-monitor-info
Authorization: Bearer {{token}}
tenant-id: {{adminTenantId}}

View File

@@ -20,7 +20,7 @@ import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - Redis 监控")
@RestController
@RequestMapping("/infra/redis")
@RequestMapping("/system/redis")
public class RedisController {
@Resource
@@ -28,7 +28,7 @@ public class RedisController {
@GetMapping("/get-monitor-info")
@Operation(summary = "获得 Redis 监控信息")
@PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')")
@PreAuthorize("@ss.hasPermission('system:redis:get-monitor-info')")
public CommonResult<RedisMonitorRespVO> getRedisMonitorInfo() {
// 获得 Redis 统计信息
Properties info = stringRedisTemplate.execute((RedisCallback<Properties>) RedisServerCommands::info);
@@ -41,3 +41,4 @@ public class RedisController {
}
}

View File

@@ -1,20 +0,0 @@
### 请求 /system/social-client/send-subscribe-message 接口 => 发送测试订阅消息
POST {{baseUrl}}/system/social-client/send-subscribe-message
Authorization: Bearer {{token}}
Content-Type: application/json
#Authorization: Bearer test100
tenant-id: {{adminTenantId}}
{
"userId": 247,
"userType": 1,
"socialType": 34,
"templateTitle": "充值成功通知",
"page": "",
"messages": {
"character_string1":"5616122165165",
"amount2":"1000.00",
"time3":"2024-01-01 10:10:10",
"phrase4": "充值成功"
}
}

View File

@@ -1,83 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.socail;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
import com.njcn.rdms.module.system.controller.admin.socail.vo.client.SocialClientRespVO;
import com.njcn.rdms.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.social.SocialClientDO;
import com.njcn.rdms.module.system.service.social.SocialClientService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 社交客户端")
@RestController
@RequestMapping("/system/social-client")
@Validated
public class SocialClientController {
@Resource
private SocialClientService socialClientService;
@PostMapping("/create")
@Operation(summary = "创建社交客户端")
@PreAuthorize("@ss.hasPermission('system:social-client:create')")
public CommonResult<Long> createSocialClient(@Valid @RequestBody SocialClientSaveReqVO createReqVO) {
return success(socialClientService.createSocialClient(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新社交客户端")
@PreAuthorize("@ss.hasPermission('system:social-client:update')")
public CommonResult<Boolean> updateSocialClient(@Valid @RequestBody SocialClientSaveReqVO updateReqVO) {
socialClientService.updateSocialClient(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除社交客户端")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:social-client:delete')")
public CommonResult<Boolean> deleteSocialClient(@RequestParam("id") Long id) {
socialClientService.deleteSocialClient(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Parameter(name = "ids", description = "编号列表", required = true)
@Operation(summary = "批量删除社交客户端")
@PreAuthorize("@ss.hasPermission('system:social-client:delete')")
public CommonResult<Boolean> deleteSocialClientList(@RequestParam("ids") List<Long> ids) {
socialClientService.deleteSocialClientList(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得社交客户端")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:social-client:query')")
public CommonResult<SocialClientRespVO> getSocialClient(@RequestParam("id") Long id) {
SocialClientDO client = socialClientService.getSocialClient(id);
return success(BeanUtils.toBean(client, SocialClientRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得社交客户端分页")
@PreAuthorize("@ss.hasPermission('system:social-client:query')")
public CommonResult<PageResult<SocialClientRespVO>> getSocialClientPage(@Valid SocialClientPageReqVO pageVO) {
PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(pageVO);
return success(BeanUtils.toBean(pageResult, SocialClientRespVO.class));
}
}

View File

@@ -1,30 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.socail.vo.client;
import com.njcn.rdms.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 社交客户端分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SocialClientPageReqVO extends PageParam {
@Schema(description = "应用名", example = "rdms商城")
private String name;
@Schema(description = "社交平台的类型", example = "31")
private Integer socialType;
@Schema(description = "用户类型", example = "2")
private Integer userType;
@Schema(description = "客户端编号", example = "145442115")
private String clientId;
@Schema(description = "状态", example = "1")
private Integer status;
}

View File

@@ -1,42 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.socail.vo.client;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 社交客户端 Response VO")
@Data
public class SocialClientRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27162")
private Long id;
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms商城")
private String name;
@Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "31")
private Integer socialType;
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer userType;
@Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "wwd411c69a39ad2e54")
private String clientId;
@Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter")
private String clientSecret;
@Schema(description = "授权方的网页应用编号", example = "2000045")
private String agentId;
@Schema(description = "publicKey 公钥", example = "2000045")
private String publicKey;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@@ -1,50 +0,0 @@
package com.njcn.rdms.module.system.controller.admin.socail.vo.client;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.enums.UserTypeEnum;
import com.njcn.rdms.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
@Schema(description = "管理后台 - 社交客户端创建/修改 Request VO")
@Data
public class SocialClientSaveReqVO {
@Schema(description = "编号", example = "27162")
private Long id;
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "rdms商城")
@NotNull(message = "应用名不能为空")
private String name;
@Schema(description = "社交平台的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "31")
@NotNull(message = "社交平台的类型不能为空")
private Integer socialType;
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "用户类型不能为空")
@InEnum(UserTypeEnum.class)
private Integer userType;
@Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "wwd411c69a39ad2e54")
@NotNull(message = "客户端编号不能为空")
private String clientId;
@Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "peter")
@NotNull(message = "客户端密钥不能为空")
private String clientSecret;
@Schema(description = "授权方的网页应用编号", example = "2000045")
private String agentId;
@Schema(description = "publicKey 公钥", example = "2000045")
private String publicKey;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态不能为空")
@InEnum(CommonStatusEnum.class)
private Integer status;
}

View File

@@ -23,7 +23,7 @@ import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "用户 App - 文件存储")
@RestController
@RequestMapping("/infra/file")
@RequestMapping("/system/file")
@Validated
@Slf4j
public class AppFileController {
@@ -63,3 +63,4 @@ public class AppFileController {
}
}

View File

@@ -1,68 +0,0 @@
package com.njcn.rdms.module.system.convert.codegen;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.njcn.rdms.framework.common.util.collection.CollectionUtils;
import com.njcn.rdms.framework.common.util.object.BeanUtils;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenDetailRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.CodegenPreviewRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.column.CodegenColumnRespVO;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTableRespVO;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenColumnDO;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenTableDO;
import org.apache.ibatis.type.JdbcType;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
@Mapper
public interface CodegenConvert {
CodegenConvert INSTANCE = Mappers.getMapper(CodegenConvert.class);
// ========== TableInfo 相关 ==========
@Mappings({
@Mapping(source = "name", target = "tableName"),
@Mapping(source = "comment", target = "tableComment"),
})
CodegenTableDO convert(TableInfo bean);
List<CodegenColumnDO> convertList(List<TableField> list);
@Mappings({
@Mapping(source = "name", target = "columnName"),
@Mapping(source = "metaInfo.jdbcType", target = "dataType", qualifiedByName = "getDataType"),
@Mapping(source = "comment", target = "columnComment"),
@Mapping(source = "metaInfo.nullable", target = "nullable"),
@Mapping(source = "keyFlag", target = "primaryKey"),
@Mapping(source = "columnType.type", target = "javaType"),
@Mapping(source = "propertyName", target = "javaField"),
})
CodegenColumnDO convert(TableField bean);
@Named("getDataType")
default String getDataType(JdbcType jdbcType) {
return jdbcType.name();
}
// ========== 其它 ==========
default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) {
CodegenDetailRespVO respVO = new CodegenDetailRespVO();
respVO.setTable(BeanUtils.toBean(table, CodegenTableRespVO.class));
respVO.setColumns(BeanUtils.toBean(columns, CodegenColumnRespVO.class));
return respVO;
}
default List<CodegenPreviewRespVO> convert(Map<String, String> codes) {
return CollectionUtils.convertList(codes.entrySet(),
entry -> new CodegenPreviewRespVO().setFilePath(entry.getKey()).setCode(entry.getValue()));
}
}

View File

@@ -1,133 +0,0 @@
package com.njcn.rdms.module.system.dal.dataobject.codegen;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.njcn.rdms.module.system.enums.codegen.CodegenColumnHtmlTypeEnum;
import com.njcn.rdms.module.system.enums.codegen.CodegenColumnListConditionEnum;
import lombok.Data;
/**
* 代码生成 column 字段定义
*
* @author hongawen
*/
@TableName(value = "infra_codegen_column", autoResultMap = true)
@KeySequence("infra_codegen_column_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
public class CodegenColumnDO extends BaseDO {
/**
* ID 编号
*/
@TableId
private Long id;
/**
* 表编号
* <p>
* 关联 {@link CodegenTableDO#getId()}
*/
private Long tableId;
// ========== 表相关字段 ==========
/**
* 字段名
*
* 关联 {@link TableField#getName()}
*/
private String columnName;
/**
* 数据库字段类型
*
* 关联 {@link TableField.MetaInfo#getJdbcType()}
*/
private String dataType;
/**
* 字段描述
*
* 关联 {@link TableField#getComment()}
*/
private String columnComment;
/**
* 是否允许为空
*
* 关联 {@link TableField.MetaInfo#isNullable()}
*/
private Boolean nullable;
/**
* 是否主键
*
* 关联 {@link TableField#isKeyFlag()}
*/
private Boolean primaryKey;
/**
* 排序
*/
private Integer ordinalPosition;
// ========== Java 相关字段 ==========
/**
* Java 属性类型
*
* 例如说 String、Boolean 等等
*
* 关联 {@link TableField#getColumnType()}
*/
private String javaType;
/**
* Java 属性名
*
* 关联 {@link TableField#getPropertyName()}
*/
private String javaField;
/**
* 字典类型
* <p>
* 关联 DictTypeDO 的 type 属性
*/
private String dictType;
/**
* 数据示例,主要用于生成 Swagger 注解的 example 字段
*/
private String example;
// ========== CRUD 相关字段 ==========
/**
* 是否为 Create 创建操作的字段
*/
private Boolean createOperation;
/**
* 是否为 Update 更新操作的字段
*/
private Boolean updateOperation;
/**
* 是否为 List 查询操作的字段
*/
private Boolean listOperation;
/**
* List 查询操作的条件类型
* <p>
* 枚举 {@link CodegenColumnListConditionEnum}
*/
private String listOperationCondition;
/**
* 是否为 List 查询操作的返回字段
*/
private Boolean listOperationResult;
// ========== UI 相关字段 ==========
/**
* 显示类型
* <p>
* 枚举 {@link CodegenColumnHtmlTypeEnum}
*/
private String htmlType;
}

View File

@@ -1,155 +0,0 @@
package com.njcn.rdms.module.system.dal.dataobject.codegen;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.njcn.rdms.module.system.dal.dataobject.db.DataSourceConfigDO;
import com.njcn.rdms.module.system.enums.codegen.CodegenFrontTypeEnum;
import com.njcn.rdms.module.system.enums.codegen.CodegenSceneEnum;
import com.njcn.rdms.module.system.enums.codegen.CodegenTemplateTypeEnum;
import lombok.Data;
/**
* 代码生成 table 表定义
*
* @author hongawen
*/
@TableName(value = "infra_codegen_table", autoResultMap = true)
@KeySequence("infra_codegen_table_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
public class CodegenTableDO extends BaseDO {
/**
* ID 编号
*/
@TableId
private Long id;
/**
* 数据源编号
*
* 关联 {@link DataSourceConfigDO#getId()}
*/
private Long dataSourceConfigId;
/**
* 生成场景
*
* 枚举 {@link CodegenSceneEnum}
*/
private Integer scene;
// ========== 表相关字段 ==========
/**
* 表名称
*
* 关联 {@link TableInfo#getName()}
*/
private String tableName;
/**
* 表描述
*
* 关联 {@link TableInfo#getComment()}
*/
private String tableComment;
/**
* 备注
*/
private String remark;
// ========== 类相关字段 ==========
/**
* 模块名,即一级目录
*
* 例如说system、infra、tool 等等
*/
private String moduleName;
/**
* 业务名,即二级目录
*
* 例如说user、permission、dict 等等
*/
private String businessName;
/**
* 类名称(首字母大写)
*
* 例如说SysUser、SysMenu、SysDictData 等等
*/
private String className;
/**
* 类描述
*/
private String classComment;
/**
* 作者
*/
private String author;
// ========== 生成相关字段 ==========
/**
* 模板类型
*
* 枚举 {@link CodegenTemplateTypeEnum}
*/
private Integer templateType;
/**
* 代码生成的前端类型
*
* 枚举 {@link CodegenFrontTypeEnum}
*/
private Integer frontType;
// ========== 菜单相关字段 ==========
/**
* 父菜单编号
*
* 关联 MenuDO 的 id 属性
*/
private Long parentMenuId;
// ========== 主子表相关字段 ==========
/**
* 主表的编号
*
* 关联 {@link CodegenTableDO#getId()}
*/
private Long masterTableId;
/**
* 【自己】子表关联主表的字段编号
*
* 关联 {@link CodegenColumnDO#getId()}
*/
private Long subJoinColumnId;
/**
* 主表与子表是否一对多
*
* true一对多
* false一对一
*/
private Boolean subJoinMany;
// ========== 树表相关字段 ==========
/**
* 树表的父字段编号
*
* 关联 {@link CodegenColumnDO#getId()}
*/
private Long treeParentColumnId;
/**
* 树表的名字字段编号
*
* 名字的用途新增或修改时select 框展示的字段
*
* 关联 {@link CodegenColumnDO#getId()}
*/
private Long treeNameColumnId;
}

View File

@@ -1,49 +0,0 @@
package com.njcn.rdms.module.system.dal.dataobject.db;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.njcn.rdms.framework.mybatis.core.type.EncryptTypeHandler;
import lombok.Data;
/**
* 数据源配置
*
* @author hongawen
*/
@TableName(value = "infra_data_source_config", autoResultMap = true)
@KeySequence("infra_data_source_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
public class DataSourceConfigDO extends BaseDO {
/**
* 主键编号 - Master 数据源
*/
public static final Long ID_MASTER = 0L;
/**
* 主键编号
*/
private Long id;
/**
* 连接名
*/
private String name;
/**
* 数据源连接
*/
private String url;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
@TableField(typeHandler = EncryptTypeHandler.class)
private String password;
}

View File

@@ -1,61 +0,0 @@
package com.njcn.rdms.module.system.dal.dataobject.mail;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 邮箱账号 DO
*
* 用途:配置发送邮箱的账号
*
* @author hongawen
*
*/
@TableName(value = "system_mail_account", autoResultMap = true)
@KeySequence("system_mail_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class MailAccountDO extends BaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 邮箱
*/
private String mail;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* SMTP 服务器域名
*/
private String host;
/**
* SMTP 服务器端口
*/
private Integer port;
/**
* 是否开启 SSL
*/
private Boolean sslEnable;
/**
* 是否开启 STARTTLS
*/
private Boolean starttlsEnable;
}

View File

@@ -1,139 +0,0 @@
package com.njcn.rdms.module.system.dal.dataobject.mail;
import com.njcn.rdms.framework.common.enums.UserTypeEnum;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.njcn.rdms.framework.mybatis.core.type.StringListTypeHandler;
import com.njcn.rdms.module.system.enums.mail.MailSendStatusEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 邮箱日志 DO
* 记录每一次邮件的发送
*
* @author hongawen
*
*/
@TableName(value = "system_mail_log", autoResultMap = true)
@KeySequence("system_mail_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MailLogDO extends BaseDO implements Serializable {
/**
* 日志编号,自增
*/
private Long id;
/**
* 用户编码
*/
private Long userId;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 接收邮箱地址
*/
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> toMails;
/**
* 接收邮箱地址
*/
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> ccMails;
/**
* 密送邮箱地址
*/
@TableField(typeHandler = StringListTypeHandler.class)
private List<String> bccMails;
/**
* 邮箱账号编号
*
* 关联 {@link MailAccountDO#getId()}
*/
private Long accountId;
/**
* 发送邮箱地址
*
* 冗余 {@link MailAccountDO#getMail()}
*/
private String fromMail;
// ========= 模板相关字段 =========
/**
* 模版编号
*
* 关联 {@link MailTemplateDO#getId()}
*/
private Long templateId;
/**
* 模版编码
*
* 冗余 {@link MailTemplateDO#getCode()}
*/
private String templateCode;
/**
* 模版发送人名称
*
* 冗余 {@link MailTemplateDO#getNickname()}
*/
private String templateNickname;
/**
* 模版标题
*/
private String templateTitle;
/**
* 模版内容
*
* 基于 {@link MailTemplateDO#getContent()} 格式化后的内容
*/
private String templateContent;
/**
* 模版参数
*
* 基于 {@link MailTemplateDO#getParams()} 输入后的参数
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> templateParams;
// ========= 发送相关字段 =========
/**
* 发送状态
*
* 枚举 {@link MailSendStatusEnum}
*/
private Integer sendStatus;
/**
* 发送时间
*/
private LocalDateTime sendTime;
/**
* 发送返回的消息 ID
*/
private String sendMessageId;
/**
* 发送异常
*/
private String sendException;
}

View File

@@ -1,75 +0,0 @@
package com.njcn.rdms.module.system.dal.dataobject.mail;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 邮件模版 DO
*
* @author hongawen
*
*/
@TableName(value = "system_mail_template", autoResultMap = true)
@KeySequence("system_mail_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
public class MailTemplateDO extends BaseDO {
/**
* 主键
*/
private Long id;
/**
* 模版名称
*/
private String name;
/**
* 模版编号
*/
private String code;
/**
* 发送的邮箱账号编号
*
* 关联 {@link MailAccountDO#getId()}
*/
private Long accountId;
/**
* 发送人名称
*/
private String nickname;
/**
* 标题
*/
private String title;
/**
* 内容
*/
private String content;
/**
* 参数数组(自动根据内容生成)
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> params;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 备注
*/
private String remark;
}

View File

@@ -1,56 +0,0 @@
package com.njcn.rdms.module.system.dal.dataobject.social;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.enums.UserTypeEnum;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 社交客户端 DO
*
* @author hongawen
*/
@TableName(value = "system_social_client", autoResultMap = true)
@KeySequence("system_social_client_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SocialClientDO extends BaseDO {
@TableId
private Long id;
/** 应用名 */
private String name;
/**
* 社交类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer socialType;
/**
* 用户类型
*
* 枚举 {@link UserTypeEnum}
*/
private Integer userType;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/** 客户端 id */
private String clientId;
/** 客户端 Secret */
private String clientSecret;
/** 代理编号 */
private String agentId;
/** publicKey 公钥 */
private String publicKey;
}

View File

@@ -1,29 +0,0 @@
package com.njcn.rdms.module.system.dal.mysql.codegen;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenColumnDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface CodegenColumnMapper extends BaseMapperX<CodegenColumnDO> {
default List<CodegenColumnDO> selectListByTableId(Long tableId) {
return selectList(new LambdaQueryWrapperX<CodegenColumnDO>()
.eq(CodegenColumnDO::getTableId, tableId)
.orderByAsc(CodegenColumnDO::getOrdinalPosition));
}
default void deleteListByTableId(Long tableId) {
delete(CodegenColumnDO::getTableId, tableId);
}
default void deleteListByTableId(Collection<Long> tableIds) {
delete(new LambdaQueryWrapperX<CodegenColumnDO>()
.in(CodegenColumnDO::getTableId, tableIds));
}
}

View File

@@ -1,39 +0,0 @@
package com.njcn.rdms.module.system.dal.mysql.codegen;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.system.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import com.njcn.rdms.module.system.dal.dataobject.codegen.CodegenTableDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface CodegenTableMapper extends BaseMapperX<CodegenTableDO> {
default CodegenTableDO selectByTableNameAndDataSourceConfigId(String tableName, Long dataSourceConfigId) {
return selectOne(CodegenTableDO::getTableName, tableName,
CodegenTableDO::getDataSourceConfigId, dataSourceConfigId);
}
default PageResult<CodegenTableDO> selectPage(CodegenTablePageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<CodegenTableDO>()
.likeIfPresent(CodegenTableDO::getTableName, pageReqVO.getTableName())
.likeIfPresent(CodegenTableDO::getTableComment, pageReqVO.getTableComment())
.likeIfPresent(CodegenTableDO::getClassName, pageReqVO.getClassName())
.betweenIfPresent(CodegenTableDO::getCreateTime, pageReqVO.getCreateTime())
.orderByDesc(CodegenTableDO::getUpdateTime)
);
}
default List<CodegenTableDO> selectListByDataSourceConfigId(Long dataSourceConfigId) {
return selectList(CodegenTableDO::getDataSourceConfigId, dataSourceConfigId);
}
default List<CodegenTableDO> selectListByTemplateTypeAndMasterTableId(Integer templateType, Long masterTableId) {
return selectList(CodegenTableDO::getTemplateType, templateType,
CodegenTableDO::getMasterTableId, masterTableId);
}
}

View File

@@ -1,14 +0,0 @@
package com.njcn.rdms.module.system.dal.mysql.db;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.module.system.dal.dataobject.db.DataSourceConfigDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 数据源配置 Mapper
*
* @author hongawen
*/
@Mapper
public interface DataSourceConfigMapper extends BaseMapperX<DataSourceConfigDO> {
}

View File

@@ -1,20 +0,0 @@
package com.njcn.rdms.module.system.dal.mysql.mail;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.system.controller.admin.mail.vo.account.MailAccountPageReqVO;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailAccountDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MailAccountMapper extends BaseMapperX<MailAccountDO> {
default PageResult<MailAccountDO> selectPage(MailAccountPageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<MailAccountDO>()
.likeIfPresent(MailAccountDO::getMail, pageReqVO.getMail())
.likeIfPresent(MailAccountDO::getUsername , pageReqVO.getUsername())
.orderByDesc(MailAccountDO::getId));
}
}

View File

@@ -1,28 +0,0 @@
package com.njcn.rdms.module.system.dal.mysql.mail;
import cn.hutool.core.util.StrUtil;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.framework.mybatis.core.util.MyBatisUtils;
import com.njcn.rdms.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailLogDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MailLogMapper extends BaseMapperX<MailLogDO> {
default PageResult<MailLogDO> selectPage(MailLogPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<MailLogDO>()
.eqIfPresent(MailLogDO::getUserId, reqVO.getUserId())
.eqIfPresent(MailLogDO::getUserType, reqVO.getUserType())
.eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId())
.eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId())
.eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus())
.betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime())
.apply(StrUtil.isNotBlank(reqVO.getToMail()),
MyBatisUtils.findInSet("to_mails", reqVO.getToMail()))
.orderByDesc(MailLogDO::getId));
}
}

View File

@@ -1,31 +0,0 @@
package com.njcn.rdms.module.system.dal.mysql.mail;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO;
import com.njcn.rdms.module.system.dal.dataobject.mail.MailTemplateDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MailTemplateMapper extends BaseMapperX<MailTemplateDO> {
default PageResult<MailTemplateDO> selectPage(MailTemplatePageReqVO pageReqVO){
return selectPage(pageReqVO , new LambdaQueryWrapperX<MailTemplateDO>()
.eqIfPresent(MailTemplateDO::getStatus, pageReqVO.getStatus())
.likeIfPresent(MailTemplateDO::getCode, pageReqVO.getCode())
.likeIfPresent(MailTemplateDO::getName, pageReqVO.getName())
.eqIfPresent(MailTemplateDO::getAccountId, pageReqVO.getAccountId())
.betweenIfPresent(MailTemplateDO::getCreateTime, pageReqVO.getCreateTime())
.orderByDesc(MailTemplateDO::getId));
}
default Long selectCountByAccountId(Long accountId) {
return selectCount(MailTemplateDO::getAccountId, accountId);
}
default MailTemplateDO selectByCode(String code) {
return selectOne(MailTemplateDO::getCode, code);
}
}

View File

@@ -1,28 +0,0 @@
package com.njcn.rdms.module.system.dal.mysql.social;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
import com.njcn.rdms.module.system.dal.dataobject.social.SocialClientDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SocialClientMapper extends BaseMapperX<SocialClientDO> {
default SocialClientDO selectBySocialTypeAndUserType(Integer socialType, Integer userType) {
return selectOne(SocialClientDO::getSocialType, socialType,
SocialClientDO::getUserType, userType);
}
default PageResult<SocialClientDO> selectPage(SocialClientPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<SocialClientDO>()
.likeIfPresent(SocialClientDO::getName, reqVO.getName())
.eqIfPresent(SocialClientDO::getSocialType, reqVO.getSocialType())
.eqIfPresent(SocialClientDO::getUserType, reqVO.getUserType())
.likeIfPresent(SocialClientDO::getClientId, reqVO.getClientId())
.eqIfPresent(SocialClientDO::getStatus, reqVO.getStatus())
.orderByDesc(SocialClientDO::getId));
}
}

View File

@@ -27,8 +27,4 @@ public interface RedisKeyConstants {
String NOTIFY_TEMPLATE = "notify_template";
String MAIL_ACCOUNT = "mail_account";
String MAIL_TEMPLATE = "mail_template";
}

View File

@@ -1,9 +0,0 @@
package com.njcn.rdms.module.system.framework.codegen.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(CodegenProperties.class)
public class CodegenConfiguration {
}

View File

@@ -1,58 +0,0 @@
package com.njcn.rdms.module.system.framework.codegen.config;
import com.njcn.rdms.module.system.enums.codegen.CodegenFrontTypeEnum;
import com.njcn.rdms.module.system.enums.codegen.CodegenVOTypeEnum;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import java.util.Collection;
@ConfigurationProperties(prefix = "rdms.codegen")
@Validated
@Data
public class CodegenProperties {
/**
* 生成的 Java 代码的基础包
*/
@NotNull(message = "Java 代码的基础包不能为空")
private String basePackage;
/**
* 数据库名数组
*/
@NotEmpty(message = "数据库不能为空")
private Collection<String> dbSchemas;
/**
* 代码生成的前端类型(默认)
*
* 枚举 {@link CodegenFrontTypeEnum#getType()}
*/
@NotNull(message = "代码生成的前端类型不能为空")
private Integer frontType;
/**
* 代码生成的 VO 类型
*
* 枚举 {@link CodegenVOTypeEnum#getType()}
*/
@NotNull(message = "代码生成的 VO 类型不能为空")
private Integer voType;
/**
* 是否生成批量删除接口
*/
@NotNull(message = "是否生成批量删除接口不能为空")
private Boolean deleteBatchEnable;
/**
* 是否生成单元测试
*/
@NotNull(message = "是否生成单元测试不能为空")
private Boolean unitTestEnable;
}

View File

@@ -1,4 +0,0 @@
/**
* 代码生成器
*/
package com.njcn.rdms.module.system.framework.codegen;

Some files were not shown because too many files have changed in this diff Show More