可正常启动
This commit is contained in:
parent
7df3b9b36b
commit
a17f1971bb
@ -1,89 +1,29 @@
|
|||||||
您是Java编程、Spring Boot、Spring Framework、Maven、JUnit和相关Java技术的专家,你深思熟虑,给出细致入微的答案,并且善于推理。你细心地提供准确、真实、周到的答案,是一个推理天才。
|
- 作为Java编程、Spring Boot、Spring Framework、Maven、JUnit和相关Java技术专家,需要实现企业应用级别的高性能管理框架
|
||||||
需要实现的是企业应用级别的管理框架,需要具有高性能、
|
|
||||||
|
|
||||||
### 严格遵循的要求
|
### 严格遵循要求
|
||||||
- 首先,一步一步地思考——详细描述你在伪代码中构建什么的计划。
|
- 首先一步一步思考,详细描述伪代码构建计划,确认后再写代码
|
||||||
- 确认,然后写代码!
|
- 遵循正确、最佳实践、DRY原则、无错误、功能齐全的代码编写原则
|
||||||
- 始终编写正确、最佳实践、DRY原则(不要重复自己)、无错误、功能齐全且可工作的代码,还应与下面代码实施指南中列出的规则保持一致。
|
- 专注于简单易读的代码实现,确保代码完整性
|
||||||
- 专注于简单易读的代码,而不是高性能。
|
- 包含所有必需的导入包,确保关键组件正确命名
|
||||||
- 完全实现所有要求的功能。
|
- 如遇不确定答案或不知道答案,应明确说明而非猜测
|
||||||
- 不要留下待办事项、占位符或缺失的部分。
|
- 可提出合理化建议,但需等待确认
|
||||||
- 确保代码完整!彻底确认。
|
- 对新设计的实体类、字段、方法添加注释,实际逻辑需要逻辑注释
|
||||||
- 包括所有必需的导入的包,并确保关键组件的正确命名。
|
- 新增或者修改数据库表需在V1.0.0__init_schema.sql、V1.0.1__init_data.sql中补充表结构和初始化数据,不要随意删除。
|
||||||
- 如果你认为可能没有正确答案,你就说出来。
|
|
||||||
- 如果你不知道答案,就说出来,而不是猜测。
|
|
||||||
- 可以提出合理化的建议,但是需要等待是否可以。
|
|
||||||
- 对于新设计的实体类、字段、方法都要写注释,对于实际的逻辑要有逻辑注释。
|
|
||||||
- 写了新的数据库表,应该在V1.0.0__init_schema.sql、V1.0.1__init_data.sql补充数据库表和初始化数据。
|
|
||||||
- 编写代码前,先查看一下V1.0.0__init_schema.sql、V1.0.1__init_data.sql表结构,再进行编写。
|
|
||||||
# Deploy Ease Platform 开发规范
|
|
||||||
|
|
||||||
### 包结构说明
|
### 包结构规范
|
||||||
- 框架包路径
|
- 框架包路径(com.qqchen.deploy.backend.framework):包含annotation、api、audit、controller等多个子包
|
||||||
com.qqchen.deploy.backend.framework
|
- 业务包路径(com.qqchen.deploy.backend):包含api、controller、converter、entity等多个子包
|
||||||
com.qqchen.deploy.backend.framework.annotation 注解实现
|
|
||||||
com.qqchen.deploy.backend.framework.api api相关
|
|
||||||
com.qqchen.deploy.backend.framework.audit 审计
|
|
||||||
com.qqchen.deploy.backend.framework.controller BaseController
|
|
||||||
com.qqchen.deploy.backend.framework.converter BaseConverter
|
|
||||||
com.qqchen.deploy.backend.framework.domain 聚合(AggregateRoot、Entity所有的实体类都继承Entity)
|
|
||||||
com.qqchen.deploy.backend.framework.dto DTO(BaseDTO、BaseResponse)
|
|
||||||
com.qqchen.deploy.backend.framework.enums 枚举
|
|
||||||
com.qqchen.deploy.backend.framework.exception 异常
|
|
||||||
com.qqchen.deploy.backend.framework.handler 全局异常拦截
|
|
||||||
com.qqchen.deploy.backend.framework.query 接口请求入参(BaseQuery、DateRange、Range)
|
|
||||||
com.qqchen.deploy.backend.framework.repository IBaseRepository
|
|
||||||
com.qqchen.deploy.backend.framework.security JWT
|
|
||||||
com.qqchen.deploy.backend.framework.service IBaseService
|
|
||||||
com.qqchen.deploy.backend.framework.service.impl BaseServiceImpl
|
|
||||||
- 业务包路径
|
|
||||||
com.qqchen.deploy.backend.api 三方接口
|
|
||||||
com.qqchen.deploy.backend.controller 二方接口
|
|
||||||
com.qqchen.deploy.backend.converter 转换器
|
|
||||||
com.qqchen.deploy.backend.entity 数据库实体类
|
|
||||||
com.qqchen.deploy.backend.integration 第三方系统对接
|
|
||||||
com.qqchen.deploy.backend.model
|
|
||||||
com.qqchen.deploy.backend.model.dto 存放所有DTO对象
|
|
||||||
com.qqchen.deploy.backend.model.query 配套page、list接口使用
|
|
||||||
com.qqchen.deploy.backend.model.request 接口入参(复杂业务场景使用)
|
|
||||||
com.qqchen.deploy.backend.model.response 接口出参(复杂业务场景使用)
|
|
||||||
|
|
||||||
### DTO设计规范
|
### 数据对象规范
|
||||||
- 简单CRUD场景使用统一的DTO,无需额外的Request/Response对象
|
- DTO设计:简单CRUD使用统一DTO,复杂场景使用专门Request/Response,继承BaseDTO获取基础字段
|
||||||
- 以下场景需要使用专门的Request/Response:
|
- 验证规则:使用Jakarta Validation注解,支持自定义验证注解和分组验证
|
||||||
1. 复杂的业务场景(如用户注册、登录)
|
- 对象转换:使用MapStruct进行转换,继承BaseConverter,显式声明特殊映射
|
||||||
2. 有特殊验证需求的接口
|
|
||||||
3. 入参和出参差异较大的接口
|
|
||||||
4. 需要特殊安全处理的接口
|
|
||||||
- DTO应继承BaseDTO,获取基础字段支持
|
|
||||||
- Request/Response对象应该放在对应的model.request和model.response包中
|
|
||||||
|
|
||||||
### 验证规范
|
|
||||||
- DTO字段验证:
|
|
||||||
1. 使用Jakarta Validation注解
|
|
||||||
2. 自定义验证注解
|
|
||||||
3. 分组验证
|
|
||||||
- 示例:
|
|
||||||
```java
|
|
||||||
@Data
|
|
||||||
public class ExternalSystemDTO extends BaseDTO {
|
|
||||||
@NotBlank(message = "系统名称不能为空")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@NotNull(message = "系统类型不能为空")
|
|
||||||
private SystemType type;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Service层规范
|
### Service层规范
|
||||||
- 简单CRUD场景直接继承BaseServiceImpl即可
|
- 简单CRUD继承BaseServiceImpl,复杂业务需定义专门接口和实现,包含事务控制和异常处理
|
||||||
- 复杂业务场景需要:
|
- 使用@Transactional注解控制事务,合理设置事务传播机制和隔离级别
|
||||||
1. 定义业务接口方法
|
- 实现乐观锁(@Version)或悲观锁(findByIdWithLock)进行并发控制
|
||||||
2. 实现具体的业务逻辑
|
- 示例
|
||||||
3. 处理业务异常
|
|
||||||
4. 添加事务控制
|
|
||||||
- 示例:
|
|
||||||
```java
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@ServiceType(DATABASE)
|
@ServiceType(DATABASE)
|
||||||
@ -96,44 +36,12 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
|||||||
// 业务实现
|
// 业务实现
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
### 查询规范
|
|
||||||
- 简单查询使用BaseQuery
|
|
||||||
- 复杂查询需要:
|
|
||||||
1. 继承BaseQuery
|
|
||||||
2. 使用@QueryField注解标注查询字段
|
|
||||||
3. 指定查询类型
|
|
||||||
- 示例:
|
|
||||||
```java
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class ExternalSystemQuery extends BaseQuery {
|
|
||||||
@QueryField(field = "name", type = QueryType.LIKE)
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@QueryField(field = "type")
|
|
||||||
private SystemType type;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 异常处理规范
|
|
||||||
- 业务异常应承BusinessException
|
|
||||||
- 使用ResponseCode定义错误码
|
|
||||||
- 在messages.properties中定义错误消息
|
|
||||||
- 通过GlobalExceptionHandler统一处理异常
|
|
||||||
- 示例:
|
|
||||||
```java
|
|
||||||
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_DISABLED);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Controller层规范
|
### Controller层规范
|
||||||
- REST FULL接口使用框架BaseController
|
- REST接口使用BaseController,三方接口命名为模块名ApiController,二方接口为模块名Controller
|
||||||
- 新增接口命名规范:
|
- 返回值com.qqchen.deploy.backend.framework.api.Response<T>
|
||||||
- 三方接口:模块名ApiController(如:ExternalSystemApiController)
|
- 统一使用GlobalExceptionHandler处理异常
|
||||||
- 二方接口:模块名Controller(如:ExternalSystemController)
|
|
||||||
- 示例:
|
- 示例:
|
||||||
```java
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/external-system")
|
@RequestMapping("/api/v1/external-system")
|
||||||
@ -141,19 +49,16 @@ throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_DISABLED);
|
|||||||
public class ExternalSystemApiController extends BaseController<ExternalSystem, ExternalSystemDTO, Long, ExternalSystemQuery> {
|
public class ExternalSystemApiController extends BaseController<ExternalSystem, ExternalSystemDTO, Long, ExternalSystemQuery> {
|
||||||
// 特定业务方法实现
|
// 特定业务方法实现
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
### Repository层规范
|
### Repository层规范
|
||||||
- 继承IBaseRepository
|
- 继承IBaseRepository,定义特定查询方法
|
||||||
- 定义特定的查询方法
|
- 使用JPA命名规范定义查询方法
|
||||||
|
- 复杂查询使用@Query注解
|
||||||
- 示例:
|
- 示例:
|
||||||
```java
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface IExternalSystemRepository extends IBaseRepository<ExternalSystem, Long> {
|
public interface IExternalSystemRepository extends IBaseRepository<ExternalSystem, Long> {
|
||||||
boolean existsByNameAndDeletedFalse(String name);
|
boolean existsByNameAndDeletedFalse(String name);
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
### Converter规范
|
### Converter规范
|
||||||
- 继承BaseConverter,遵循以下规则:
|
- 继承BaseConverter,遵循以下规则:
|
||||||
1. 简单场景(字段完全匹配)示例:
|
1. 简单场景(字段完全匹配)示例:
|
||||||
@ -172,354 +77,52 @@ public interface IExternalSystemRepository extends IBaseRepository<ExternalSyste
|
|||||||
UserDTO toDto(User entity);
|
UserDTO toDto(User entity);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
### 枚举规范
|
||||||
|
- 新增加枚举应添加到com.qqchen.deploy.backend.enums,后缀以Enum结尾
|
||||||
|
- 增加枚举时,不要修改现有没有,只追加即可
|
||||||
|
|
||||||
### 测试规范
|
### 异常规范
|
||||||
- Service层测试:
|
- 异常分为系统异常应继承SystemException和业务异常应承BusinessException,使用ResponseCode定义错误码,在messages.properties中定义错误消息
|
||||||
1. 使用@SpringBootTest
|
- 示例
|
||||||
2. 使用@MockBean模拟依赖
|
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_DISABLED);
|
||||||
3. 测试所有业务场景
|
|
||||||
- Controller层测试:
|
|
||||||
1. 使用@WebMvcTest或@SpringBootTest + @AutoConfigureMockMvc
|
|
||||||
2. 使用MockMvc测试接口
|
|
||||||
3. 测试所有接口路径
|
|
||||||
- Repository层测试:
|
|
||||||
1. 使用@DataJpaTest
|
|
||||||
2. 测试所有查询方法
|
|
||||||
|
|
||||||
### 文档规范
|
|
||||||
- 类注释:说明类的用途、作者、版本
|
|
||||||
- 方法注释:说明参数、返回值、异常
|
|
||||||
- 业务方法注释:说明业务规则
|
|
||||||
- API文档:使用Swagger注解
|
|
||||||
|
|
||||||
### 命名规范
|
### 命名规范
|
||||||
- 使用PascalCase作为类名(例,UserController、OrderService)
|
- 类名使用PascalCase(UserController、OrderService)
|
||||||
- 使用camelCase作为方法和变量名(例如,findUserById、isOrderValid)
|
- 方法和变量名使用camelCase(findUserById、isOrderValid)
|
||||||
- 对常量使用ALL_CAPS(例如,MAX_RETRY_ATTEMPTS、DEFAULT_PAGE_SIZE)
|
- 常量使用ALL_CAPS(MAX_RETRY_ATTEMPTS、DEFAULT_PAGE_SIZE)
|
||||||
- service、repository接口类需要以I开头,service实现类无需使用I开头但尾部需要Impl结尾
|
- Service、Repository接口类以I开头,实现类需要Impl结尾
|
||||||
|
|
||||||
### 数据库规范
|
### 数据库规范
|
||||||
- 使用Flyway进行数据库版本控制
|
- 使用Flyway进行版本控制,新表结构写入V1.0.0__init_schema.sql,初始数据写入V1.0.1__init_data.sql
|
||||||
- 新增表结构写入V1.0.0__init_schema.sql
|
- 表名和字段名使用下划线命名法(sys_user, create_time)
|
||||||
- 新增初始数据写入V1.0.1__init_data.sql
|
|
||||||
- 表名使用下划线命名法(例如:sys_user, sys_role)
|
|
||||||
- 字段名使用下划线命名法(例如:create_time, update_by)
|
|
||||||
- 必须包含基础字段:id, create_time, create_by, update_time, update_by, version, deleted
|
- 必须包含基础字段:id, create_time, create_by, update_time, update_by, version, deleted
|
||||||
|
|
||||||
### 国际化规范
|
|
||||||
- 使用ResponseCode进行异常码定义
|
|
||||||
- 在messages.properties中定义中文消息
|
|
||||||
- 在messages_en_US.properties中定义英文消息
|
|
||||||
- 在messages_zh_CN.properties中定义中文繁体消息
|
|
||||||
|
|
||||||
### 文档维护规范
|
|
||||||
- README.md文件维护规则:
|
|
||||||
1. 接口变更必须同步更新README.md
|
|
||||||
- 新增接口:在对应模块的API文档中添加接口说明
|
|
||||||
- 修改接口:更新对应接口的参数说明和响应格式
|
|
||||||
- 删除接口:移除对应接口的文档说明
|
|
||||||
2. 接口文档格式要求:
|
|
||||||
```http
|
|
||||||
[HTTP方法] [接口路径]
|
|
||||||
|
|
||||||
请求参数:
|
|
||||||
{
|
|
||||||
"参数1": "值1", // 参数说明(是否必填)
|
|
||||||
"参数2": "值2" // 参数说明(是否必填)
|
|
||||||
}
|
|
||||||
|
|
||||||
响应结果:
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"code": 200,
|
|
||||||
"message": "操作成功",
|
|
||||||
"data": {
|
|
||||||
// 响应数据结构
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
3. 功能清单维护:
|
|
||||||
- 新增功能:在"已实现功能"章节添加功能说明
|
|
||||||
- 修改功能:更新对应功能的描述
|
|
||||||
- 删除功能:移除对应功能说明
|
|
||||||
4. 文档结构规范:
|
|
||||||
- 功能描述必须清晰准确
|
|
||||||
- 使用markdown格式化文档
|
|
||||||
- 保持文档层级结构一致
|
|
||||||
- 使用统一的示例格式
|
|
||||||
|
|
||||||
### 错误码规范
|
### 错误码规范
|
||||||
- 错误码分类:
|
- 系统级错误(1xxx):1000-1099通用系统错误,1100-1199依赖注入错误,1200-1299数据库错误
|
||||||
1. 系统级错误(1xxx)
|
- 业务级错误(2xxx):2000-2099通用业务错误,2100-2199角色相关,2200-2299 JWT相关等
|
||||||
- 1000-1099:通用系统错误
|
- 错误码命名使用大写字母和下划线,采用"模块_操作_错误"命名方式
|
||||||
- 1100-1199:依赖注入错误
|
|
||||||
- 1200-1299:数据库错误
|
|
||||||
2. 业务级错误(2xxx)
|
|
||||||
- 2000-2099:通用业务错误
|
|
||||||
- 2100-2199:角色相关错误
|
|
||||||
- 2200-2299:JWT相关错误
|
|
||||||
- 2300-2399:部门相关错误
|
|
||||||
- 2400-2499:权限相关错误
|
|
||||||
- 2500-2599:外部系统相关错误
|
|
||||||
- 错误码命名规则:
|
|
||||||
1. 使用大写字母和下划线
|
|
||||||
2. 采用`模块_操作_错误`的命名方式
|
|
||||||
3. 在ResponseCode枚举类中定义
|
|
||||||
- 错误信息规范:
|
|
||||||
1. 在messages.properties中定义错误信息
|
|
||||||
2. 错误信息要简洁明了
|
|
||||||
3. 包含问题描述和可能的解决方案
|
|
||||||
4. 支持国际化
|
|
||||||
|
|
||||||
### 接口安全规范
|
|
||||||
- JWT Token规范:
|
|
||||||
1. Token结构:
|
|
||||||
- Header:包含算法信息
|
|
||||||
- Payload:包含用户信息和权限信息
|
|
||||||
- Signature:使用密钥签名
|
|
||||||
2. Token有效期:
|
|
||||||
- Access Token:2小时
|
|
||||||
- Refresh Token:7天
|
|
||||||
3. Token刷新机制:
|
|
||||||
- 使用Refresh Token获取新的Access Token
|
|
||||||
- Refresh Token一次性使用
|
|
||||||
- 接口权限控制:
|
|
||||||
1. 使用@PreAuthorize注解控制接口访问权限
|
|
||||||
2. 使用@Secured注解控制方法级别权限
|
|
||||||
3. 实现自定义权限评估器
|
|
||||||
- 敏感数据处理:
|
|
||||||
1. 密码等敏感信息必须加密存储
|
|
||||||
2. 使用AES加密传输敏感数据
|
|
||||||
3. 日志中不得打印敏感信息
|
|
||||||
4. 接口返回时脱敏处理
|
|
||||||
|
|
||||||
### 代码审查规范
|
|
||||||
- 审查重点:
|
|
||||||
1. 代码质量:
|
|
||||||
- 代码是否符合编码规范
|
|
||||||
- 是否存在重复代码
|
|
||||||
- 是否有性能问题
|
|
||||||
2. 业务逻辑:
|
|
||||||
- 业务流程是否正确
|
|
||||||
- 异常处理是否完善
|
|
||||||
- 边界条件是否考虑
|
|
||||||
3. 安全性:
|
|
||||||
- 是否存在安全漏洞
|
|
||||||
- 敏感数据是否安全处理
|
|
||||||
- 权限控制是否正确
|
|
||||||
4. 测试覆盖:
|
|
||||||
- 单元测试是否完整
|
|
||||||
- 是否覆盖关键路径
|
|
||||||
- 是否包含边界测试
|
|
||||||
- 审查流程:
|
|
||||||
1. 提交前自查
|
|
||||||
2. 提交Pull Request
|
|
||||||
3. 代码评审
|
|
||||||
4. 修改完善
|
|
||||||
5. 评审通过
|
|
||||||
- 审查标准:
|
|
||||||
1. 代码实现是否满足需求
|
|
||||||
2. 是否符合开发规范
|
|
||||||
3. 是否有充分的测试覆盖
|
|
||||||
4. 文档是否同步更新
|
|
||||||
|
|
||||||
### 缓存使用规范
|
### 缓存使用规范
|
||||||
- 缓存注解:
|
- 使用@Cacheable(查询)、@CachePut(更新)、@CacheEvict(删除)注解
|
||||||
1. @Cacheable:适用于查询操作
|
- 缓存Key格式:模块:业务:标识,如user:info:1
|
||||||
2. @CachePut:适用于更新操作
|
- 根据业务场景选择缓存策略:Cache Aside、Write Through、Write Back
|
||||||
3. @CacheEvict:适用于删除操作
|
|
||||||
4. @Caching:组合多个缓存操作
|
|
||||||
- 缓存Key:
|
|
||||||
1. 格式:`模块:业务:标识`
|
|
||||||
2. 示例:`user:info:1`
|
|
||||||
3. 避免特殊字符
|
|
||||||
4. 长度控制在200以内
|
|
||||||
- 缓存策略:
|
|
||||||
1. 读多写少用Cache Aside
|
|
||||||
2. 写多读少用Write Through
|
|
||||||
3. 高一致性用Write Back
|
|
||||||
- 示例:
|
|
||||||
```java
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@ServiceType(DATABASE)
|
|
||||||
public class UserServiceImpl extends BaseServiceImpl<User, UserDTO, Long> implements IUserService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IUserRepository userRepository;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private UserConverter userConverter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Cacheable(value = "user", key = "#id")
|
|
||||||
public UserDTO findById(Long id) {
|
|
||||||
User user = userRepository.findById(id)
|
|
||||||
.orElseThrow(() -> new BusinessException(ResponseCode.USER_NOT_FOUND));
|
|
||||||
return userConverter.toDto(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
@CacheEvict(value = "user", key = "#id")
|
|
||||||
public void delete(Long id) {
|
|
||||||
User user = findEntityById(id);
|
|
||||||
user.setDeleted(true);
|
|
||||||
userRepository.save(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 分层设计规范
|
|
||||||
- Controller层:
|
|
||||||
1. REST接口设计
|
|
||||||
2. 参数校验
|
|
||||||
3. 权限控制
|
|
||||||
4. 响应封装
|
|
||||||
- Service层:
|
|
||||||
1. 业务逻辑处理
|
|
||||||
2. 事务控制
|
|
||||||
3. 缓存处理
|
|
||||||
4. 并发控制
|
|
||||||
- Repository层:
|
|
||||||
1. 数据访问
|
|
||||||
2. 查询优化
|
|
||||||
3. 持久化操作
|
|
||||||
|
|
||||||
### 数据对象规范
|
|
||||||
- DTO设计:
|
|
||||||
1. 简单CRUD场景使用统一DTO
|
|
||||||
2. 复杂业务场景使用专门的Request/Response
|
|
||||||
3. 继承BaseDTO获取基础字段
|
|
||||||
- 验证规则:
|
|
||||||
1. 使用Jakarta Validation注解
|
|
||||||
2. 自定义验证注解
|
|
||||||
3. 分组验证
|
|
||||||
- 对象转换:
|
|
||||||
1. 使用MapStruct进行对象转换
|
|
||||||
2. 继承BaseConverter
|
|
||||||
3. 显式声明特殊映射
|
|
||||||
|
|
||||||
### 业务处理规范
|
|
||||||
- 事务管理:
|
|
||||||
1. 声明式事务(@Transactional)
|
|
||||||
2. 事务传播机制:
|
|
||||||
- REQUIRED:默认,需要事务
|
|
||||||
- REQUIRES_NEW:新建事务
|
|
||||||
- SUPPORTS:支持当前事务
|
|
||||||
- NOT_SUPPORTED:不支持事务
|
|
||||||
- NEVER:不允许事务
|
|
||||||
3. 事务隔离级别:
|
|
||||||
- READ_COMMITTED:默认
|
|
||||||
- REPEATABLE_READ:需要时使用
|
|
||||||
- 并发控制:
|
|
||||||
1. 乐观锁:
|
|
||||||
- 使用@Version注解
|
|
||||||
- 实现重试机制
|
|
||||||
2. 悲观锁:
|
|
||||||
- findByIdWithLock方法
|
|
||||||
- 限定锁范围和时间
|
|
||||||
3. 分布式锁:
|
|
||||||
- 使用Redis实现
|
|
||||||
- 设置超时时间
|
|
||||||
- 防止死锁
|
|
||||||
- 缓存策略:
|
|
||||||
1. 缓存注解使用:
|
|
||||||
- @Cacheable:查询
|
|
||||||
- @CachePut:更新
|
|
||||||
- @CacheEvict:删除
|
|
||||||
2. 缓存Key规范:
|
|
||||||
- 格式:模块:业务:标识
|
|
||||||
- 避免特殊字符
|
|
||||||
3. 缓存更新策略:
|
|
||||||
- Cache Aside
|
|
||||||
- Write Through
|
|
||||||
- Write Back
|
|
||||||
|
|
||||||
### 安全规范
|
### 安全规范
|
||||||
- 认证授权:
|
- JWT Token包含Header(算法)、Payload(用户信息)、Signature(签名)
|
||||||
1. JWT Token结构和有效期
|
- Access Token有效期2小时,Refresh Token有效期7天
|
||||||
2. 权限注解使用
|
- 敏感数据加密存储和传输,日志和接口返回需脱敏
|
||||||
3. 自定义权限评估
|
|
||||||
- 敏感信息:
|
|
||||||
1. 密码加密存储
|
|
||||||
2. 传输数据加密
|
|
||||||
3. 日志脱敏处理
|
|
||||||
4. 接口参数脱敏
|
|
||||||
- 接口防护:
|
|
||||||
1. 参数校验
|
|
||||||
2. SQL注入防护
|
|
||||||
3. XSS防护
|
|
||||||
4. CSRF防护
|
|
||||||
|
|
||||||
### 异常处理规范
|
|
||||||
- 异常分类:
|
|
||||||
1. 业务异常(BusinessException)
|
|
||||||
2. 系统异常(SystemException)
|
|
||||||
3. 参数异常(ValidationException)
|
|
||||||
- 错误码:
|
|
||||||
1. 系统级错误(1xxx)
|
|
||||||
2. 业务级错误(2xxx)
|
|
||||||
3. 第三方错误(3xxx)
|
|
||||||
- 异常处理:
|
|
||||||
1. 统一异常处理器
|
|
||||||
2. 错误信息国际化
|
|
||||||
3. 异常日志记录
|
|
||||||
|
|
||||||
### 日志规范
|
|
||||||
- 日志级别:
|
|
||||||
1. ERROR:系统错误、业务异常
|
|
||||||
2. WARN:潜在问题警告
|
|
||||||
3. INFO:重要业务操作
|
|
||||||
4. DEBUG:调试信息
|
|
||||||
- 日志内容:
|
|
||||||
1. 操作人信息
|
|
||||||
2. 业务模块
|
|
||||||
3. 操作类型
|
|
||||||
4. 关键参数
|
|
||||||
- 日志脱敏:
|
|
||||||
1. 密码信息
|
|
||||||
2. 个人隐私
|
|
||||||
3. 敏感配置
|
|
||||||
|
|
||||||
### 文档规范
|
|
||||||
- 代码注释:
|
|
||||||
1. 类注释:用途、作者、版本
|
|
||||||
2. 方法注释:参数、返回值、异常
|
|
||||||
3. 业务注释:业务规则、处理逻辑
|
|
||||||
- API文档:
|
|
||||||
1. 使用Swagger注解
|
|
||||||
2. 接口说明完整
|
|
||||||
3. 参数说明清晰
|
|
||||||
- README维护:
|
|
||||||
1. 功能清单及时更新
|
|
||||||
2. 接口文档同步修改
|
|
||||||
3. 环境配置说明
|
|
||||||
|
|
||||||
### 测试规范
|
### 测试规范
|
||||||
- 单元测试:
|
- Service层:使用@SpringBootTest和@MockBean,测试所有业务场景
|
||||||
1. Service层业务测试
|
- Controller层:使用@WebMvcTest或MockMvc,测试所有接口路径
|
||||||
2. 重要工具类测试
|
- Repository层:使用@DataJpaTest,测试所有查询方法
|
||||||
3. 边界条件测试
|
|
||||||
- 集成测试:
|
### 文档规范
|
||||||
1. Controller层接口测试
|
- 类注释:说明用途、作者、版本
|
||||||
2. 数据库操作测试
|
- 方法注释:说明参数、返回值、异常
|
||||||
3. 缓存操作测试
|
- API文档:使用Swagger注解,保持文档同步更新
|
||||||
- 测试原则:
|
|
||||||
1. 测试覆盖率要求
|
|
||||||
2. 测试数据隔离
|
|
||||||
3. 测试用例完整性
|
|
||||||
|
|
||||||
### 性能优化规范
|
### 性能优化规范
|
||||||
- 数据库优化:
|
- 数据库优化:索引设计、SQL优化、分页查询
|
||||||
1. 索引设计
|
- 代码优化:循环优化、集合操作、字符串处理
|
||||||
2. SQL优化
|
- 缓存优化:合理设置缓存粒度、更新策略、防止缓存穿透
|
||||||
3. 分页查询
|
|
||||||
- 代码优化:
|
|
||||||
1. 循环优化
|
|
||||||
2. 集合操作
|
|
||||||
3. 字符串处理
|
|
||||||
- 缓存优化:
|
|
||||||
1. 缓存粒度
|
|
||||||
2. 缓存更新
|
|
||||||
3. 缓存穿透处理
|
|
||||||
516
backend/.cursorrules1
Normal file
516
backend/.cursorrules1
Normal file
@ -0,0 +1,516 @@
|
|||||||
|
您是Java编程、Spring Boot、Spring Framework、Maven、JUnit和相关Java技术的专家,你深思熟虑,给出细致入微的答案,并且善于推理。你细心地提供准确、真实、周到的答案,是一个推理天才。
|
||||||
|
需要实现的是企业应用级别的管理框架,需要具有高性能。
|
||||||
|
|
||||||
|
### 严格遵循的要求
|
||||||
|
- 首先,一步一步地思考——详细描述你在伪代码中构建什么的计划。
|
||||||
|
- 确认,然后写代码!
|
||||||
|
- 始终编写正确、最佳实践、DRY原则(不要重复自己)、无错误、功能齐全且可工作的代码,还应与下面代码实施指南中列出的规则保持一致。
|
||||||
|
- 专注于简单易读的代码,而不是高性能。
|
||||||
|
- 完全实现所有要求的功能。
|
||||||
|
- 不要留下待办事项、占位符或缺失的部分。
|
||||||
|
- 确保代码完整!彻底确认。
|
||||||
|
- 包括所有必需的导入的包,并确保关键组件的正确命名。
|
||||||
|
- 如果你认为可能没有正确答案,你就说出来。
|
||||||
|
- 如果你不知道答案,就说出来,而不是猜测。
|
||||||
|
- 可以提出合理化的建议,但是需要等待是否可以。
|
||||||
|
- 对于新设计的实体类、字段、方法都要写注释,对于实际的逻辑要有逻辑注释。
|
||||||
|
- 写了新的数据库表,应该在V1.0.0__init_schema.sql、V1.0.1__init_data.sql补充数据库表和初始化数据。
|
||||||
|
- 编写代码前,先查看一下V1.0.0__init_schema.sql、V1.0.1__init_data.sql表结构,再进行编写。
|
||||||
|
# Deploy Ease Platform 开发规范
|
||||||
|
|
||||||
|
### 包结构说明
|
||||||
|
- 框架包路径
|
||||||
|
com.qqchen.deploy.backend.framework
|
||||||
|
com.qqchen.deploy.backend.framework.annotation 注解实现
|
||||||
|
com.qqchen.deploy.backend.framework.api api相关
|
||||||
|
com.qqchen.deploy.backend.framework.audit 审计
|
||||||
|
com.qqchen.deploy.backend.framework.controller BaseController
|
||||||
|
com.qqchen.deploy.backend.framework.converter BaseConverter
|
||||||
|
com.qqchen.deploy.backend.framework.domain 聚合(AggregateRoot、Entity所有的实体类都继承Entity)
|
||||||
|
com.qqchen.deploy.backend.framework.dto DTO(BaseDTO、BaseResponse)
|
||||||
|
com.qqchen.deploy.backend.framework.enums 枚举 框架枚举写在这个包下
|
||||||
|
com.qqchen.deploy.backend.framework.exception 异常
|
||||||
|
com.qqchen.deploy.backend.framework.handler 全局异常拦截
|
||||||
|
com.qqchen.deploy.backend.framework.query 接口请求入参(BaseQuery、DateRange、Range)
|
||||||
|
com.qqchen.deploy.backend.framework.repository IBaseRepository
|
||||||
|
com.qqchen.deploy.backend.framework.security JWT
|
||||||
|
com.qqchen.deploy.backend.framework.service IBaseService
|
||||||
|
com.qqchen.deploy.backend.framework.service.impl BaseServiceImpl
|
||||||
|
- 业务包路径
|
||||||
|
com.qqchen.deploy.backend.api 三方接口
|
||||||
|
com.qqchen.deploy.backend.controller 二方接口
|
||||||
|
com.qqchen.deploy.backend.converter 转换器
|
||||||
|
com.qqchen.deploy.backend.entity 数据库实体类
|
||||||
|
com.qqchen.deploy.backend.integration 第三方系统对接
|
||||||
|
com.qqchen.deploy.backend.enums 实体类枚举、业务枚举统一卸载这个包下
|
||||||
|
com.qqchen.deploy.backend.model
|
||||||
|
com.qqchen.deploy.backend.model.dto 存放所有DTO对象
|
||||||
|
com.qqchen.deploy.backend.model.query 配套page、list接口使用
|
||||||
|
com.qqchen.deploy.backend.model.request 接口入参(复杂业务场景使用)
|
||||||
|
com.qqchen.deploy.backend.model.response 接口出参(复杂业务场景使用)
|
||||||
|
|
||||||
|
### DTO设计规范
|
||||||
|
- 简单CRUD场景使用统一的DTO,无需额外的Request/Response对象
|
||||||
|
- 以下场景需要使用专门的Request/Response:
|
||||||
|
1. 复杂的业务场景(如用户注册、登录)
|
||||||
|
2. 有特殊验证需求的接口
|
||||||
|
3. 入参和出参差异较大的接口
|
||||||
|
4. 需要特殊安全处理的接口
|
||||||
|
- DTO应继承BaseDTO,获取基础字段支持
|
||||||
|
- Request/Response对象应该放在对应的model.request和model.response包中
|
||||||
|
|
||||||
|
### 验证规范
|
||||||
|
- DTO字段验证:
|
||||||
|
1. 使用Jakarta Validation注解
|
||||||
|
2. 自定义验证注解
|
||||||
|
3. 分组验证
|
||||||
|
- 示例:
|
||||||
|
```java
|
||||||
|
@Data
|
||||||
|
public class ExternalSystemDTO extends BaseDTO {
|
||||||
|
@NotBlank(message = "系统名称不能为空")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@NotNull(message = "系统类型不能为空")
|
||||||
|
private SystemType type;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### 数据对象规范
|
||||||
|
- DTO设计:
|
||||||
|
1. 简单CRUD场景使用统一DTO
|
||||||
|
2. 复杂业务场景使用专门的Request/Response
|
||||||
|
3. 继承BaseDTO获取基础字段
|
||||||
|
- 验证规则:
|
||||||
|
1. 使用Jakarta Validation注解
|
||||||
|
2. 自定义验证注解
|
||||||
|
3. 分组验证
|
||||||
|
- 对象转换:
|
||||||
|
1. 使用MapStruct进行对象转换
|
||||||
|
2. 继承BaseConverter
|
||||||
|
3. 显式声明特殊映射
|
||||||
|
|
||||||
|
### Service层规范
|
||||||
|
- 简单CRUD场景直接继承BaseServiceImpl即可
|
||||||
|
- 复杂业务场景需要:
|
||||||
|
1. 定义业务接口方法
|
||||||
|
2. 实现具体的业务逻辑
|
||||||
|
3. 处理业务异常
|
||||||
|
4. 添加事务控制
|
||||||
|
- 示例:
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@ServiceType(DATABASE)
|
||||||
|
public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, ExternalSystemDTO, Long>
|
||||||
|
implements IExternalSystemService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public boolean testConnection(Long id) {
|
||||||
|
// 业务实现
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查询规范
|
||||||
|
- 简单查询使用BaseQuery
|
||||||
|
- 复杂查询需要:
|
||||||
|
1. 继承BaseQuery
|
||||||
|
2. 使用@QueryField注解标注查询字段
|
||||||
|
3. 指定查询类型
|
||||||
|
- 示例:
|
||||||
|
```java
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class ExternalSystemQuery extends BaseQuery {
|
||||||
|
@QueryField(field = "name", type = QueryType.LIKE)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@QueryField(field = "type")
|
||||||
|
private SystemType type;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 异常处理规范
|
||||||
|
- 业务异常应承BusinessException
|
||||||
|
- 使用ResponseCode定义错误码
|
||||||
|
- 在messages.properties中定义错误消息
|
||||||
|
- 通过GlobalExceptionHandler统一处理异常
|
||||||
|
- 示例:
|
||||||
|
```java
|
||||||
|
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_DISABLED);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Controller层规范
|
||||||
|
- REST FULL接口使用框架BaseController
|
||||||
|
- 新增接口命名规范:
|
||||||
|
- 三方接口:模块名ApiController(如:ExternalSystemApiController)
|
||||||
|
- 二方接口:模块名Controller(如:ExternalSystemController)
|
||||||
|
- 示例:
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/external-system")
|
||||||
|
@Tag(name = "外部系统管理", description = "外部系统管理相关接口")
|
||||||
|
public class ExternalSystemApiController extends BaseController<ExternalSystem, ExternalSystemDTO, Long, ExternalSystemQuery> {
|
||||||
|
// 特定业务方法实现
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Repository层规范
|
||||||
|
- 继承IBaseRepository
|
||||||
|
- 定义特定的查询方法
|
||||||
|
- 示例:
|
||||||
|
```java
|
||||||
|
@Repository
|
||||||
|
public interface IExternalSystemRepository extends IBaseRepository<ExternalSystem, Long> {
|
||||||
|
boolean existsByNameAndDeletedFalse(String name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Converter规范
|
||||||
|
- 继承BaseConverter,遵循以下规则:
|
||||||
|
1. 简单场景(字段完全匹配)示例:
|
||||||
|
```java
|
||||||
|
@Mapper(config = BaseConverter.class)
|
||||||
|
public interface ExternalSystemConverter extends BaseConverter<ExternalSystem, ExternalSystemDTO> {
|
||||||
|
// 字段完全匹配时无需额外配置
|
||||||
|
}
|
||||||
|
```
|
||||||
|
2. 复杂场景(需要特殊映射)示例:
|
||||||
|
```java
|
||||||
|
@Mapper(config = BaseConverter.class)
|
||||||
|
public interface UserConverter extends BaseConverter<User, UserDTO> {
|
||||||
|
@Mapping(target = "departmentId", source = "department.id")
|
||||||
|
@Mapping(target = "departmentName", source = "department.name")
|
||||||
|
UserDTO toDto(User entity);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 测试规范
|
||||||
|
- Service层测试:
|
||||||
|
1. 使用@SpringBootTest
|
||||||
|
2. 使用@MockBean模拟依赖
|
||||||
|
3. 测试所有业务场景
|
||||||
|
- Controller层测试:
|
||||||
|
1. 使用@WebMvcTest或@SpringBootTest + @AutoConfigureMockMvc
|
||||||
|
2. 使用MockMvc测试接口
|
||||||
|
3. 测试所有接口路径
|
||||||
|
- Repository层测试:
|
||||||
|
1. 使用@DataJpaTest
|
||||||
|
2. 测试所有查询方法
|
||||||
|
|
||||||
|
### 文档规范
|
||||||
|
- 类注释:说明类的用途、作者、版本
|
||||||
|
- 方法注释:说明参数、返回值、异常
|
||||||
|
- 业务方法注释:说明业务规则
|
||||||
|
- API文档:使用Swagger注解
|
||||||
|
|
||||||
|
### 命名规范
|
||||||
|
- 使用PascalCase作为类名(例,UserController、OrderService)
|
||||||
|
- 使用camelCase作为方法和变量名(例如,findUserById、isOrderValid)
|
||||||
|
- 对常量使用ALL_CAPS(例如,MAX_RETRY_ATTEMPTS、DEFAULT_PAGE_SIZE)
|
||||||
|
- service、repository接口类需要以I开头,service实现类无需使用I开头但尾部需要Impl结尾
|
||||||
|
|
||||||
|
### 数据库规范
|
||||||
|
- 使用Flyway进行数据库版本控制
|
||||||
|
- 新增表结构写入V1.0.0__init_schema.sql
|
||||||
|
- 新增初始数据写入V1.0.1__init_data.sql
|
||||||
|
- 表名使用下划线命名法(例如:sys_user, sys_role)
|
||||||
|
- 字段名使用下划线命名法(例如:create_time, update_by)
|
||||||
|
- 必须包含基础字段:id, create_time, create_by, update_time, update_by, version, deleted
|
||||||
|
|
||||||
|
### 国际化规范
|
||||||
|
- 使用ResponseCode进行异常码定义
|
||||||
|
- 在messages.properties中定义中文消息、messages_en_US.properties中定义英文消息、在messages_zh_CN.properties中定义中文消息
|
||||||
|
|
||||||
|
### 文档维护规范
|
||||||
|
- README.md文件维护规则:
|
||||||
|
1. 接口变更必须同步更新README.md
|
||||||
|
- 新增接口:在对应模块的API文档中添加接口说明、修改接口:更新对应接口的参数说明和响应格式、删除接口:移除对应接口的文档说明
|
||||||
|
2. 接口文档格式要求:
|
||||||
|
```http
|
||||||
|
[HTTP方法] [接口路径]
|
||||||
|
|
||||||
|
请求参数:
|
||||||
|
{
|
||||||
|
"参数1": "值1", // 参数说明(是否必填)
|
||||||
|
"参数2": "值2" // 参数说明(是否必填)
|
||||||
|
}
|
||||||
|
|
||||||
|
响应结果:
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"code": 200,
|
||||||
|
"message": "操作成功",
|
||||||
|
"data": {
|
||||||
|
// 响应数据结构
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. 功能清单维护:
|
||||||
|
- 新增功能:在"已实现功能"章节添加功能说明;修改功能:更新对应功能的描述;删除功能:移除对应功能说明
|
||||||
|
4. 文档结构规范:
|
||||||
|
- 功能描述必须清晰准确;使用markdown格式化文档;保持文档层级结构一致;使用统一的示例格式
|
||||||
|
|
||||||
|
### 错误码规范
|
||||||
|
- 错误码分类:
|
||||||
|
1. 系统级错误(1xxx)
|
||||||
|
- 1000-1099:通用系统错误
|
||||||
|
- 1100-1199:依赖注入错误
|
||||||
|
- 1200-1299:数据库错误
|
||||||
|
2. 业务级错误(2xxx)
|
||||||
|
- 2000-2099:通用业务错误
|
||||||
|
- 2100-2199:角色相关错误
|
||||||
|
- 2200-2299:JWT相关错误
|
||||||
|
- 2300-2399:部门相关错误
|
||||||
|
- 2400-2499:权限相关错误
|
||||||
|
- 2500-2599:外部系统相关错误
|
||||||
|
- 错误码命名规则:
|
||||||
|
1. 使用大写字母和下划线
|
||||||
|
2. 采用`模块_操作_错误`的命名方式
|
||||||
|
3. 在ResponseCode枚举类中定义
|
||||||
|
- 错误信息规范:
|
||||||
|
1. 在messages.properties中定义错误信息
|
||||||
|
2. 错误信息要简洁明了
|
||||||
|
3. 包含问题描述和可能的解决方案
|
||||||
|
4. 支持国际化
|
||||||
|
|
||||||
|
### 接口安全规范
|
||||||
|
- JWT Token规范:
|
||||||
|
1. Token结构:
|
||||||
|
- Header:包含算法信息
|
||||||
|
- Payload:包含用户信息和权限信息
|
||||||
|
- Signature:使用密钥签名
|
||||||
|
2. Token有效期:
|
||||||
|
- Access Token:2小时
|
||||||
|
- Refresh Token:7天
|
||||||
|
3. Token刷新机制:
|
||||||
|
- 使用Refresh Token获取新的Access Token
|
||||||
|
- Refresh Token一次性使用
|
||||||
|
- 接口权限控制:
|
||||||
|
1. 使用@PreAuthorize注解控制接口访问权限
|
||||||
|
2. 使用@Secured注解控制方法级别权限
|
||||||
|
3. 实现自定义权限评估器
|
||||||
|
- 敏感数据处理:
|
||||||
|
1. 密码等敏感信息必须加密存储
|
||||||
|
2. 使用AES加密传输敏感数据
|
||||||
|
3. 日志中不得打印敏感信息
|
||||||
|
4. 接口返回时脱敏处理
|
||||||
|
|
||||||
|
### 代码审查规范
|
||||||
|
- 审查重点:
|
||||||
|
1. 代码质量:
|
||||||
|
- 代码是否符合编码规范
|
||||||
|
- 是否存在重复代码
|
||||||
|
- 是否有性能问题
|
||||||
|
2. 业务逻辑:
|
||||||
|
- 业务流程是否正确
|
||||||
|
- 异常处理是否完善
|
||||||
|
- 边界条件是否考虑
|
||||||
|
3. 安全性:
|
||||||
|
- 是否存在安全漏洞
|
||||||
|
- 敏感数据是否安全处理
|
||||||
|
- 权限控制是否正确
|
||||||
|
4. 测试覆盖:
|
||||||
|
- 单元测试是否完整
|
||||||
|
- 是否覆盖关键路径
|
||||||
|
- 是否包含边界测试
|
||||||
|
- 审查流程:
|
||||||
|
1. 提交前自查
|
||||||
|
2. 提交Pull Request
|
||||||
|
3. 代码评审
|
||||||
|
4. 修改完善
|
||||||
|
5. 评审通过
|
||||||
|
- 审查标准:
|
||||||
|
1. 代码实现是否满足需求
|
||||||
|
2. 是否符合开发规范
|
||||||
|
3. 是否有充分的测试覆盖
|
||||||
|
4. 文档是否同步更新
|
||||||
|
|
||||||
|
### 缓存使用规范
|
||||||
|
- 缓存注解:
|
||||||
|
1. @Cacheable:适用于查询操作
|
||||||
|
2. @CachePut:适用于更新操作
|
||||||
|
3. @CacheEvict:适用于删除操作
|
||||||
|
4. @Caching:组合多个缓存操作
|
||||||
|
- 缓存Key:
|
||||||
|
1. 格式:`模块:业务:标识`
|
||||||
|
2. 示例:`user:info:1`
|
||||||
|
3. 避免特殊字符
|
||||||
|
4. 长度控制在200以内
|
||||||
|
- 缓存策略:
|
||||||
|
1. 读多写少用Cache Aside
|
||||||
|
2. 写多读少用Write Through
|
||||||
|
3. 高一致性用Write Back
|
||||||
|
- 示例:
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@ServiceType(DATABASE)
|
||||||
|
public class UserServiceImpl extends BaseServiceImpl<User, UserDTO, Long> implements IUserService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IUserRepository userRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserConverter userConverter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Cacheable(value = "user", key = "#id")
|
||||||
|
public UserDTO findById(Long id) {
|
||||||
|
User user = userRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new BusinessException(ResponseCode.USER_NOT_FOUND));
|
||||||
|
return userConverter.toDto(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@CacheEvict(value = "user", key = "#id")
|
||||||
|
public void delete(Long id) {
|
||||||
|
User user = findEntityById(id);
|
||||||
|
user.setDeleted(true);
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 分层设计规范
|
||||||
|
- Controller层:
|
||||||
|
1. REST接口设计
|
||||||
|
2. 参数校验
|
||||||
|
3. 权限控制
|
||||||
|
4. 响应封装
|
||||||
|
- Service层:
|
||||||
|
1. 业务逻辑处理
|
||||||
|
2. 事务控制
|
||||||
|
3. 缓存处理
|
||||||
|
4. 并发控制
|
||||||
|
- Repository层:
|
||||||
|
1. 数据访问
|
||||||
|
2. 查询优化
|
||||||
|
3. 持久化操作
|
||||||
|
|
||||||
|
### 业务处理规范
|
||||||
|
- 事务管理:
|
||||||
|
1. 声明式事务(@Transactional)
|
||||||
|
2. 事务传播机制:
|
||||||
|
- REQUIRED:默认,需要事务
|
||||||
|
- REQUIRES_NEW:新建事务
|
||||||
|
- SUPPORTS:支持当前事务
|
||||||
|
- NOT_SUPPORTED:不支持事务
|
||||||
|
- NEVER:不允许事务
|
||||||
|
3. 事务隔离级别:
|
||||||
|
- READ_COMMITTED:默认
|
||||||
|
- REPEATABLE_READ:需要时使用
|
||||||
|
- 并发控制:
|
||||||
|
1. 乐观锁:
|
||||||
|
- 使用@Version注解
|
||||||
|
- 实现重试机制
|
||||||
|
2. 悲观锁:
|
||||||
|
- findByIdWithLock方法
|
||||||
|
- 限定锁范围和时间
|
||||||
|
3. 分布式锁:
|
||||||
|
- 使用Redis实现
|
||||||
|
- 设置超时时间
|
||||||
|
- 防止死锁
|
||||||
|
- 缓存策略:
|
||||||
|
1. 缓存注解使用:
|
||||||
|
- @Cacheable:查询
|
||||||
|
- @CachePut:更新
|
||||||
|
- @CacheEvict:删除
|
||||||
|
2. 缓存Key规范:
|
||||||
|
- 格式:模块:业务:标识
|
||||||
|
- 避免特殊字符
|
||||||
|
3. 缓存更新策略:
|
||||||
|
- Cache Aside
|
||||||
|
- Write Through
|
||||||
|
- Write Back
|
||||||
|
|
||||||
|
### 安全规范
|
||||||
|
- 认证授权:
|
||||||
|
1. JWT Token结构和有效期
|
||||||
|
2. 权限注解使用
|
||||||
|
3. 自定义权限评估
|
||||||
|
- 敏感信息:
|
||||||
|
1. 密码加密存储
|
||||||
|
2. 传输数据加密
|
||||||
|
3. 日志脱敏处理
|
||||||
|
4. 接口参数脱敏
|
||||||
|
- 接口防护:
|
||||||
|
1. 参数校验
|
||||||
|
2. SQL注入防护
|
||||||
|
3. XSS防护
|
||||||
|
4. CSRF防护
|
||||||
|
|
||||||
|
### 异常处理规范
|
||||||
|
- 异常分类:
|
||||||
|
1. 业务异常(BusinessException)
|
||||||
|
2. 系统异常(SystemException)
|
||||||
|
3. 参数异常(ValidationException)
|
||||||
|
- 错误码:
|
||||||
|
1. 系统级错误(1xxx)
|
||||||
|
2. 业务级错误(2xxx)
|
||||||
|
3. 第三方错误(3xxx)
|
||||||
|
- 异常处理:
|
||||||
|
1. 统一异常处理器
|
||||||
|
2. 错误信息国际化
|
||||||
|
3. 异常日志记录
|
||||||
|
|
||||||
|
### 日志规范
|
||||||
|
- 日志级别:
|
||||||
|
1. ERROR:系统错误、业务异常
|
||||||
|
2. WARN:潜在问题警告
|
||||||
|
3. INFO:重要业务操作
|
||||||
|
4. DEBUG:调试信息
|
||||||
|
- 日志内容:
|
||||||
|
1. 操作人信息
|
||||||
|
2. 业务模块
|
||||||
|
3. 操作类型
|
||||||
|
4. 关键参数
|
||||||
|
- 日志脱敏:
|
||||||
|
1. 密码信息
|
||||||
|
2. 个人隐私
|
||||||
|
3. 敏感配置
|
||||||
|
|
||||||
|
### 文档规范
|
||||||
|
- 代码注释:
|
||||||
|
1. 类注释:用途、作者、版本
|
||||||
|
2. 方法注释:参数、返回值、异常
|
||||||
|
3. 业务注释:业务规则、处理逻辑
|
||||||
|
- API文档:
|
||||||
|
1. 使用Swagger注解
|
||||||
|
2. 接口说明完整
|
||||||
|
3. 参数说明清晰
|
||||||
|
- README维护:
|
||||||
|
1. 功能清单及时更新
|
||||||
|
2. 接口文档同步修改
|
||||||
|
3. 环境配置说明
|
||||||
|
|
||||||
|
### 测试规范
|
||||||
|
- 单元测试:
|
||||||
|
1. Service层业务测试
|
||||||
|
2. 重要工具类测试
|
||||||
|
3. 边界条件测试
|
||||||
|
- 集成测试:
|
||||||
|
1. Controller层接口测试
|
||||||
|
2. 数据库操作测试
|
||||||
|
3. 缓存操作测试
|
||||||
|
- 测试原则:
|
||||||
|
1. 测试覆盖率要求
|
||||||
|
2. 测试数据隔离
|
||||||
|
3. 测试用例完整性
|
||||||
|
|
||||||
|
### 性能优化规范
|
||||||
|
- 数据库优化:
|
||||||
|
1. 索引设计
|
||||||
|
2. SQL优化
|
||||||
|
3. 分页查询
|
||||||
|
- 代码优化:
|
||||||
|
1. 循环优化
|
||||||
|
2. 集合操作
|
||||||
|
3. 字符串处理
|
||||||
|
- 缓存优化:
|
||||||
|
1. 缓存粒度
|
||||||
|
2. 缓存更新
|
||||||
|
3. 缓存穿透处理
|
||||||
@ -772,7 +772,7 @@ POST /api/v1/permission
|
|||||||
- 详细的接口文档
|
- 详细的接口文档
|
||||||
- 规范的代码注释
|
- 规范的代码注释
|
||||||
|
|
||||||
详细规范请参考:[后端开发规范](.cursorrules)
|
详细规范请参考:[后端开发规范](.cursorrules1)
|
||||||
|
|
||||||
### 前端开发规范
|
### 前端开发规范
|
||||||
- 统一的接口调用方式
|
- 统一的接口调用方式
|
||||||
|
|||||||
@ -12,10 +12,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
package com.qqchen.deploy.backend.entity;
|
package com.qqchen.deploy.backend.entity;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemAuthTypeEnum;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemSyncStatusEnum;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
@ -26,7 +29,7 @@ public class ExternalSystem extends Entity<Long> {
|
|||||||
*/
|
*/
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private SystemType type;
|
private ExternalSystemTypeEnum type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统访问地址
|
* 系统访问地址
|
||||||
@ -51,11 +54,11 @@ public class ExternalSystem extends Entity<Long> {
|
|||||||
private Boolean enabled = true;
|
private Boolean enabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证方式:BASIC/TOKEN/OAUTH<EFBFBD><EFBFBD>
|
* 认证方式:BASIC/TOKEN/OAUTH
|
||||||
*/
|
*/
|
||||||
@Column(name = "auth_type", nullable = false)
|
@Column(name = "auth_type", nullable = false)
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private AuthType authType;
|
private ExternalSystemAuthTypeEnum authType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户名
|
* 用户名
|
||||||
@ -77,7 +80,7 @@ public class ExternalSystem extends Entity<Long> {
|
|||||||
*/
|
*/
|
||||||
@Column(name = "sync_status")
|
@Column(name = "sync_status")
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private SyncStatus syncStatus;
|
private ExternalSystemSyncStatusEnum syncStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 最后同步时间
|
* 最后同步时间
|
||||||
@ -97,30 +100,5 @@ public class ExternalSystem extends Entity<Long> {
|
|||||||
@Column(columnDefinition = "JSON")
|
@Column(columnDefinition = "JSON")
|
||||||
private String config;
|
private String config;
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统类型枚举
|
|
||||||
*/
|
|
||||||
public enum SystemType {
|
|
||||||
JENKINS,
|
|
||||||
GIT,
|
|
||||||
ZENTAO
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证类型枚举
|
|
||||||
*/
|
|
||||||
public enum AuthType {
|
|
||||||
BASIC,
|
|
||||||
TOKEN,
|
|
||||||
OAUTH
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步状态枚举
|
|
||||||
*/
|
|
||||||
public enum SyncStatus {
|
|
||||||
SUCCESS,
|
|
||||||
FAILED,
|
|
||||||
RUNNING
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.qqchen.deploy.backend.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证类型枚举
|
||||||
|
*/
|
||||||
|
public enum ExternalSystemAuthTypeEnum {
|
||||||
|
BASIC,
|
||||||
|
TOKEN,
|
||||||
|
OAUTH
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package com.qqchen.deploy.backend.enums;
|
||||||
|
|
||||||
|
public enum ExternalSystemSyncStatusEnum {
|
||||||
|
SUCCESS,
|
||||||
|
FAILED,
|
||||||
|
RUNNING
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.qqchen.deploy.backend.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统类型枚举
|
||||||
|
*/
|
||||||
|
public enum ExternalSystemTypeEnum {
|
||||||
|
JENKINS,
|
||||||
|
GIT,
|
||||||
|
ZENTAO
|
||||||
|
}
|
||||||
@ -66,6 +66,7 @@ public enum ResponseCode {
|
|||||||
PERMISSION_ASSIGN_FAILED(2404, "permission.assign.failed"),
|
PERMISSION_ASSIGN_FAILED(2404, "permission.assign.failed"),
|
||||||
|
|
||||||
// 第三方系统相关错误码 (2500-2599)
|
// 第三方系统相关错误码 (2500-2599)
|
||||||
|
EXTERNAL_SYSTEM_NOT_FOUND(2505, "external.system.not.found"),
|
||||||
EXTERNAL_SYSTEM_NAME_EXISTS(2500, "external.system.name.exists"),
|
EXTERNAL_SYSTEM_NAME_EXISTS(2500, "external.system.name.exists"),
|
||||||
EXTERNAL_SYSTEM_TYPE_URL_EXISTS(2501, "external.system.type.url.exists"),
|
EXTERNAL_SYSTEM_TYPE_URL_EXISTS(2501, "external.system.type.url.exists"),
|
||||||
EXTERNAL_SYSTEM_DISABLED(2502, "external.system.disabled"),
|
EXTERNAL_SYSTEM_DISABLED(2502, "external.system.disabled"),
|
||||||
|
|||||||
@ -14,4 +14,5 @@ public class BusinessException extends BaseException {
|
|||||||
public BusinessException(ResponseCode errorCode, Object[] args) {
|
public BusinessException(ResponseCode errorCode, Object[] args) {
|
||||||
super(errorCode, args);
|
super(errorCode, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package com.qqchen.deploy.backend.integration;
|
package com.qqchen.deploy.backend.integration;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 第三方系统集成接口
|
* 第三方系统集成接口
|
||||||
@ -26,5 +27,5 @@ public interface IExternalSystemIntegration {
|
|||||||
*
|
*
|
||||||
* @return 系统类型
|
* @return 系统类型
|
||||||
*/
|
*/
|
||||||
ExternalSystem.SystemType getSystemType();
|
ExternalSystemTypeEnum getSystemType();
|
||||||
}
|
}
|
||||||
@ -1,79 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.integration;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.integration.client.IJenkinsClient;
|
|
||||||
import com.qqchen.deploy.backend.integration.dto.JenkinsBuildDTO;
|
|
||||||
import com.qqchen.deploy.backend.integration.dto.JenkinsConnectionDTO;
|
|
||||||
import feign.FeignException;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Slf4j
|
|
||||||
public class JenkinsService {
|
|
||||||
|
|
||||||
// @Resource
|
|
||||||
// private final IJenkinsClient jenkinsClient;
|
|
||||||
//
|
|
||||||
// public boolean testConnection(JenkinsConnectionDTO config) {
|
|
||||||
// try {
|
|
||||||
// String authHeader = createAuthHeader(config.getUsername(), config.getPassword());
|
|
||||||
// jenkinsClient.testConnection(authHeader);
|
|
||||||
// log.info("Jenkins连接测试成功");
|
|
||||||
// return true;
|
|
||||||
// } catch (FeignException.Unauthorized e) {
|
|
||||||
// log.error("Jenkins连接测试失败: 认证失败");
|
|
||||||
// return false;
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("Jenkins连接测试失败: {}", e.getMessage());
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public BuildInfo getBuildInfo(JenkinsConnectionDTO config, String jobName, Integer buildNumber) {
|
|
||||||
// try {
|
|
||||||
// String authHeader = createAuthHeader(config.getUsername(), config.getPassword());
|
|
||||||
// JenkinsBuildDTO jenkinsBuild = jenkinsClient.getBuildInfo(authHeader, jobName, buildNumber);
|
|
||||||
// return convertToBuildInfo(jenkinsBuild);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("获取Jenkins构建信息失败: {}", e.getMessage());
|
|
||||||
// throw new RuntimeException("Failed to get build info", e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private String createAuthHeader(String username, String password) {
|
|
||||||
// String auth = username + ":" + password;
|
|
||||||
// return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private BuildInfo convertToBuildInfo(JenkinsBuildDTO dto) {
|
|
||||||
// BuildInfo buildInfo = new BuildInfo();
|
|
||||||
// buildInfo.setJobName(dto.getJobName());
|
|
||||||
// buildInfo.setBuildNumber(dto.getBuildNumber());
|
|
||||||
// buildInfo.setBuildUrl(dto.getUrl());
|
|
||||||
// buildInfo.setBuildTime(LocalDateTime.ofInstant(
|
|
||||||
// Instant.ofEpochMilli(dto.getTimestamp()),
|
|
||||||
// ZoneId.systemDefault()
|
|
||||||
// ));
|
|
||||||
//
|
|
||||||
// // 转换构建状态
|
|
||||||
// buildInfo.setStatus(convertBuildStatus(dto.getResult(), dto.getStatus()));
|
|
||||||
//
|
|
||||||
// return buildInfo;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private BuildInfo.BuildStatus convertBuildStatus(String result, String status) {
|
|
||||||
// if ("IN_PROGRESS".equals(status)) {
|
|
||||||
// return BuildInfo.BuildStatus.IN_PROGRESS;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return switch (result) {
|
|
||||||
// case "SUCCESS" -> BuildInfo.BuildStatus.SUCCESS;
|
|
||||||
// case "FAILURE" -> BuildInfo.BuildStatus.FAILURE;
|
|
||||||
// case "ABORTED" -> BuildInfo.BuildStatus.CANCELLED;
|
|
||||||
// default -> throw new IllegalStateException("Unknown build status: " + result);
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.integration.client;
|
|
||||||
|
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestHeader;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@FeignClient(name = "jenkins-service", url = "#{null}") // 动态URL
|
|
||||||
public interface IJenkinsClient {
|
|
||||||
|
|
||||||
@GetMapping("/api/json")
|
|
||||||
Map<String, Object> testConnection(
|
|
||||||
@RequestHeader("Authorization") String authorization
|
|
||||||
);
|
|
||||||
|
|
||||||
@PostMapping("/job/{jobName}/build")
|
|
||||||
void triggerBuild(
|
|
||||||
@RequestHeader("Authorization") String authorization,
|
|
||||||
@PathVariable("jobName") String jobName
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.integration.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Component
|
|
||||||
public class JenkinsProperties {
|
|
||||||
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
public String getBasicAuth() {
|
|
||||||
String auth = username + ":" + password;
|
|
||||||
return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.integration.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class BuildInfo {
|
|
||||||
private String jobName;
|
|
||||||
|
|
||||||
private Integer buildNumber;
|
|
||||||
|
|
||||||
private BuildStatus status;
|
|
||||||
|
|
||||||
private LocalDateTime buildTime;
|
|
||||||
|
|
||||||
private String buildUrl;
|
|
||||||
|
|
||||||
public enum BuildStatus {
|
|
||||||
SUCCESS, FAILURE, IN_PROGRESS, CANCELLED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.integration.dto;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.framework.integration.dto.ThirdPartyDTO;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class JenkinsBuildDTO implements ThirdPartyDTO {
|
|
||||||
|
|
||||||
private String jobName;
|
|
||||||
|
|
||||||
private Integer buildNumber;
|
|
||||||
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
private String result;
|
|
||||||
|
|
||||||
private Long timestamp;
|
|
||||||
|
|
||||||
private String url;
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.integration.dto;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.framework.integration.dto.ThirdPartyDTO;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class JenkinsConnectionDTO implements ThirdPartyDTO {
|
|
||||||
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
private String password;
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.integration.enums;
|
|
||||||
|
|
||||||
public enum JenkinsBuildStatus {
|
|
||||||
SUCCESS, FAILURE, IN_PROGRESS, CANCELLED
|
|
||||||
}
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package com.qqchen.deploy.backend.integration.impl;
|
package com.qqchen.deploy.backend.integration.impl;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.integration.IExternalSystemIntegration;
|
import com.qqchen.deploy.backend.integration.IExternalSystemIntegration;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
@ -43,7 +44,7 @@ public class GitIntegration implements IExternalSystemIntegration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExternalSystem.SystemType getSystemType() {
|
public ExternalSystemTypeEnum getSystemType() {
|
||||||
return ExternalSystem.SystemType.GIT;
|
return ExternalSystemTypeEnum.GIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
package com.qqchen.deploy.backend.integration.impl;
|
package com.qqchen.deploy.backend.integration.impl;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemAuthTypeEnum;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.integration.IExternalSystemIntegration;
|
import com.qqchen.deploy.backend.integration.IExternalSystemIntegration;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.*;
|
import org.springframework.http.*;
|
||||||
@ -9,6 +11,10 @@ import org.springframework.web.client.RestTemplate;
|
|||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import static com.qqchen.deploy.backend.enums.ExternalSystemAuthTypeEnum.BASIC;
|
||||||
|
import static com.qqchen.deploy.backend.enums.ExternalSystemAuthTypeEnum.OAUTH;
|
||||||
|
import static com.qqchen.deploy.backend.enums.ExternalSystemAuthTypeEnum.TOKEN;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class JenkinsIntegration implements IExternalSystemIntegration {
|
public class JenkinsIntegration implements IExternalSystemIntegration {
|
||||||
@ -51,7 +57,7 @@ public class JenkinsIntegration implements IExternalSystemIntegration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExternalSystem.SystemType getSystemType() {
|
public ExternalSystemTypeEnum getSystemType() {
|
||||||
return ExternalSystem.SystemType.JENKINS;
|
return ExternalSystemTypeEnum.JENKINS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package com.qqchen.deploy.backend.model;
|
package com.qqchen.deploy.backend.model;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem.SystemType;
|
import com.qqchen.deploy.backend.enums.ExternalSystemAuthTypeEnum;
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem.AuthType;
|
import com.qqchen.deploy.backend.enums.ExternalSystemSyncStatusEnum;
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem.SyncStatus;
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@ -19,7 +19,7 @@ public class ExternalSystemDTO extends BaseDTO {
|
|||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@NotNull(message = "系统类型不能为空")
|
@NotNull(message = "系统类型不能为空")
|
||||||
private SystemType type;
|
private ExternalSystemTypeEnum type;
|
||||||
|
|
||||||
@NotBlank(message = "系统访问地址不能为空")
|
@NotBlank(message = "系统访问地址不能为空")
|
||||||
private String url;
|
private String url;
|
||||||
@ -31,7 +31,7 @@ public class ExternalSystemDTO extends BaseDTO {
|
|||||||
private Boolean enabled = true;
|
private Boolean enabled = true;
|
||||||
|
|
||||||
@NotNull(message = "认证方式不能为空")
|
@NotNull(message = "认证方式不能为空")
|
||||||
private AuthType authType;
|
private ExternalSystemAuthTypeEnum authType;
|
||||||
|
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ public class ExternalSystemDTO extends BaseDTO {
|
|||||||
|
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
private SyncStatus syncStatus;
|
private ExternalSystemSyncStatusEnum syncStatus;
|
||||||
|
|
||||||
private LocalDateTime lastSyncTime;
|
private LocalDateTime lastSyncTime;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.qqchen.deploy.backend.model.query;
|
package com.qqchen.deploy.backend.model.query;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem.SystemType;
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.framework.annotation.QueryField;
|
import com.qqchen.deploy.backend.framework.annotation.QueryField;
|
||||||
import com.qqchen.deploy.backend.framework.enums.QueryType;
|
import com.qqchen.deploy.backend.framework.enums.QueryType;
|
||||||
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
||||||
@ -25,7 +25,7 @@ public class ExternalSystemQuery extends BaseQuery {
|
|||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@QueryField(field = "type")
|
@QueryField(field = "type")
|
||||||
private SystemType type;
|
private ExternalSystemTypeEnum type;
|
||||||
|
|
||||||
@QueryField(field = "enabled")
|
@QueryField(field = "enabled")
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.qqchen.deploy.backend.repository;
|
package com.qqchen.deploy.backend.repository;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ public interface IExternalSystemRepository extends IBaseRepository<ExternalSyste
|
|||||||
/**
|
/**
|
||||||
* 检查系统类型和URL组合是否存在
|
* 检查系统类型和URL组合是否存在
|
||||||
*/
|
*/
|
||||||
boolean existsByTypeAndUrlAndDeletedFalse(ExternalSystem.SystemType type, String url);
|
boolean existsByTypeAndUrlAndDeletedFalse(ExternalSystemTypeEnum type, String url);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询所有未删除的系统,按排序字段排序
|
* 查询所有未删除的系统,按排序字段排序
|
||||||
|
|||||||
@ -1,132 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.service;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.RepositoryGroup;
|
|
||||||
import com.qqchen.deploy.backend.entity.RepositoryProject;
|
|
||||||
import com.qqchen.deploy.backend.entity.RepositoryBranch;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositoryGroupDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositoryProjectDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositoryBranchDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositorySyncStatusDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositorySyncTaskDTO;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 版本控制仓库服务接口
|
|
||||||
* 提供代码仓库的组织结构、项目和分支的管理功能,以及与外部版本控制系统的数据同步功能
|
|
||||||
*
|
|
||||||
* @author QQchen
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
public interface IRepositoryVersionControlService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定外部系统的仓库组列表
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @return 仓库组列表,按排序号升序排列
|
|
||||||
*/
|
|
||||||
List<RepositoryGroupDTO> listGroups(Long externalSystemId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定的仓库组信息
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @param groupId 仓库组ID
|
|
||||||
* @return 仓库组信息
|
|
||||||
* @throws com.qqchen.deploy.backend.framework.exception.BusinessException 当仓库组不存在时抛出异常
|
|
||||||
*/
|
|
||||||
RepositoryGroupDTO getGroup(Long externalSystemId, Long groupId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步指定外部系统的仓库组数据
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
*/
|
|
||||||
void syncGroups(Long externalSystemId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定仓库组下的项目列表
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @param groupId 仓库组ID
|
|
||||||
* @return 项目列表,按排序号升序排列
|
|
||||||
*/
|
|
||||||
List<RepositoryProjectDTO> listProjects(Long externalSystemId, Long groupId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定的项目信息
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @param projectId 项目ID
|
|
||||||
* @return 项目信息
|
|
||||||
* @throws com.qqchen.deploy.backend.framework.exception.BusinessException 当项目不存在时抛出异常
|
|
||||||
*/
|
|
||||||
RepositoryProjectDTO getProject(Long externalSystemId, Long projectId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步指定仓库组下的项目数据
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @param groupId 仓库组ID
|
|
||||||
*/
|
|
||||||
void syncProjects(Long externalSystemId, Long groupId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定项目的分支列表
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @param projectId 项目ID
|
|
||||||
* @return 分支列表
|
|
||||||
*/
|
|
||||||
List<RepositoryBranchDTO> listBranches(Long externalSystemId, Long projectId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定的分支信息
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @param projectId 项目ID
|
|
||||||
* @param branchName 分支名称
|
|
||||||
* @return 分支信息
|
|
||||||
* @throws com.qqchen.deploy.backend.framework.exception.BusinessException 当分支不存在时抛出异常
|
|
||||||
*/
|
|
||||||
RepositoryBranchDTO getBranch(Long externalSystemId, Long projectId, String branchName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步指定项目的分支数据
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @param projectId 项目ID
|
|
||||||
*/
|
|
||||||
void syncBranches(Long externalSystemId, Long projectId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步指定外部系统的所有数据(同步组、项目、分支)
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
*/
|
|
||||||
void syncAll(Long externalSystemId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步同步指定外部系统的所有数据
|
|
||||||
*
|
|
||||||
* @param externalSystemId 外部系统ID
|
|
||||||
* @return 同步任务ID
|
|
||||||
*/
|
|
||||||
Long asyncSyncAll(Long externalSystemId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取同步任务状态
|
|
||||||
*
|
|
||||||
* @param historyId 同步历史ID
|
|
||||||
* @return 同步状态信息
|
|
||||||
*/
|
|
||||||
RepositorySyncStatusDTO getSyncStatus(Long historyId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取正在运行的同步任务列表
|
|
||||||
*
|
|
||||||
* @return 运行中的同步任务列表
|
|
||||||
*/
|
|
||||||
List<RepositorySyncTaskDTO> getRunningSyncs();
|
|
||||||
}
|
|
||||||
@ -1,6 +1,9 @@
|
|||||||
package com.qqchen.deploy.backend.service.impl;
|
package com.qqchen.deploy.backend.service.impl;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemAuthTypeEnum;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemSyncStatusEnum;
|
||||||
|
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||||
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
||||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
@ -47,7 +50,7 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
|||||||
@Resource
|
@Resource
|
||||||
private List<IExternalSystemIntegration> systemIntegrations;
|
private List<IExternalSystemIntegration> systemIntegrations;
|
||||||
|
|
||||||
private Map<ExternalSystem.SystemType, IExternalSystemIntegration> integrationMap;
|
private Map<ExternalSystemTypeEnum, IExternalSystemIntegration> integrationMap;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
@ -87,8 +90,8 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
|||||||
* @param dto 外部系统DTO
|
* @param dto 外部系统DTO
|
||||||
*/
|
*/
|
||||||
private void validateGitAuth(ExternalSystemDTO dto) {
|
private void validateGitAuth(ExternalSystemDTO dto) {
|
||||||
if (dto.getType() == ExternalSystem.SystemType.GIT) {
|
if (dto.getType() == ExternalSystemTypeEnum.GIT) {
|
||||||
if (dto.getAuthType() != ExternalSystem.AuthType.TOKEN) {
|
if (dto.getAuthType() != ExternalSystemAuthTypeEnum.TOKEN) {
|
||||||
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_GIT_AUTH_TYPE_ERROR);
|
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_GIT_AUTH_TYPE_ERROR);
|
||||||
}
|
}
|
||||||
if (StringUtils.isBlank(dto.getToken())) {
|
if (StringUtils.isBlank(dto.getToken())) {
|
||||||
@ -127,7 +130,7 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
system.setSyncStatus(ExternalSystem.SyncStatus.RUNNING);
|
system.setSyncStatus(ExternalSystemSyncStatusEnum.RUNNING);
|
||||||
externalSystemRepository.save(system);
|
externalSystemRepository.save(system);
|
||||||
|
|
||||||
// TODO: 根据不同的系统类型调用不同的同步方法
|
// TODO: 根据不同的系统类型调用不同的同步方法
|
||||||
@ -137,10 +140,10 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
|||||||
case ZENTAO -> syncZentaoData(system);
|
case ZENTAO -> syncZentaoData(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
system.setSyncStatus(ExternalSystem.SyncStatus.SUCCESS);
|
system.setSyncStatus(ExternalSystemSyncStatusEnum.SUCCESS);
|
||||||
system.setLastSyncTime(LocalDateTime.now());
|
system.setLastSyncTime(LocalDateTime.now());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
system.setSyncStatus(ExternalSystem.SyncStatus.FAILED);
|
system.setSyncStatus(ExternalSystemSyncStatusEnum.FAILED);
|
||||||
log.error("Sync data failed for external system: {}", system.getName(), e);
|
log.error("Sync data failed for external system: {}", system.getName(), e);
|
||||||
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_SYNC_FAILED);
|
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_SYNC_FAILED);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -1,145 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.service.impl;
|
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.entity.RepositoryGroup;
|
|
||||||
import com.qqchen.deploy.backend.entity.RepositoryProject;
|
|
||||||
import com.qqchen.deploy.backend.entity.RepositoryBranch;
|
|
||||||
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
|
||||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositoryGroupDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositoryProjectDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositoryBranchDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositorySyncStatusDTO;
|
|
||||||
import com.qqchen.deploy.backend.model.dto.RepositorySyncTaskDTO;
|
|
||||||
import com.qqchen.deploy.backend.repository.IRepositoryGroupRepository;
|
|
||||||
import com.qqchen.deploy.backend.repository.IRepositoryProjectRepository;
|
|
||||||
import com.qqchen.deploy.backend.repository.IRepositoryBranchRepository;
|
|
||||||
import com.qqchen.deploy.backend.service.IRepositoryVersionControlService;
|
|
||||||
import com.qqchen.deploy.backend.converter.RepositoryConverter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 版本控制仓库服务实现类
|
|
||||||
* 用于管理代码仓库的组织结构、项目和分支,支持与外部版本控制系统(如GitLab)的数据同步
|
|
||||||
*
|
|
||||||
* @author QQchen
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@ServiceType(ServiceType.Type.DATABASE)
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class RepositoryVersionControlServiceImpl implements IRepositoryVersionControlService {
|
|
||||||
|
|
||||||
private final IRepositoryGroupRepository groupRepository;
|
|
||||||
private final IRepositoryProjectRepository projectRepository;
|
|
||||||
private final IRepositoryBranchRepository branchRepository;
|
|
||||||
private final RepositoryConverter repositoryConverter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RepositoryGroupDTO> listGroups(Long externalSystemId) {
|
|
||||||
log.debug("获取仓库组列表, externalSystemId: {}", externalSystemId);
|
|
||||||
return groupRepository.findByExternalSystemIdAndDeletedFalseOrderBySortAsc(externalSystemId)
|
|
||||||
.stream()
|
|
||||||
.map(repositoryConverter::toDto)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RepositoryGroupDTO getGroup(Long externalSystemId, Long groupId) {
|
|
||||||
log.debug("获取仓库组信息, externalSystemId: {}, groupId: {}", externalSystemId, groupId);
|
|
||||||
RepositoryGroup group = groupRepository.findByExternalSystemIdAndGroupId(externalSystemId, groupId)
|
|
||||||
.orElseThrow(() -> new BusinessException(ResponseCode.REPOSITORY_GROUP_NOT_FOUND));
|
|
||||||
return repositoryConverter.toDto(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void syncGroups(Long externalSystemId) {
|
|
||||||
log.info("开始同步仓库组数据, externalSystemId: {}", externalSystemId);
|
|
||||||
// TODO: 实现仓库组同步逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RepositoryProjectDTO> listProjects(Long externalSystemId, Long groupId) {
|
|
||||||
log.debug("获取项目列表, externalSystemId: {}, groupId: {}", externalSystemId, groupId);
|
|
||||||
return projectRepository.findByExternalSystemIdAndGroupIdAndDeletedFalseOrderBySortAsc(externalSystemId, groupId)
|
|
||||||
.stream()
|
|
||||||
.map(repositoryConverter::toDto)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RepositoryProjectDTO getProject(Long externalSystemId, Long projectId) {
|
|
||||||
log.debug("获取项目信息, externalSystemId: {}, projectId: {}", externalSystemId, projectId);
|
|
||||||
RepositoryProject project = projectRepository.findByExternalSystemIdAndProjectId(externalSystemId, projectId)
|
|
||||||
.orElseThrow(() -> new BusinessException(ResponseCode.REPOSITORY_PROJECT_NOT_FOUND));
|
|
||||||
return repositoryConverter.toDto(project);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void syncProjects(Long externalSystemId, Long groupId) {
|
|
||||||
log.info("开始同步项目数据, externalSystemId: {}, groupId: {}", externalSystemId, groupId);
|
|
||||||
// TODO: 实现项目同步逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RepositoryBranchDTO> listBranches(Long externalSystemId, Long projectId) {
|
|
||||||
log.debug("获取分支列表, externalSystemId: {}, projectId: {}", externalSystemId, projectId);
|
|
||||||
return branchRepository.findByExternalSystemIdAndProjectIdAndDeletedFalse(externalSystemId, projectId)
|
|
||||||
.stream()
|
|
||||||
.map(repositoryConverter::toDto)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RepositoryBranchDTO getBranch(Long externalSystemId, Long projectId, String branchName) {
|
|
||||||
log.debug("获取分支信息, externalSystemId: {}, projectId: {}, branchName: {}",
|
|
||||||
externalSystemId, projectId, branchName);
|
|
||||||
RepositoryBranch branch = branchRepository.findByExternalSystemIdAndProjectIdAndName(externalSystemId, projectId, branchName)
|
|
||||||
.orElseThrow(() -> new BusinessException(ResponseCode.REPOSITORY_BRANCH_NOT_FOUND));
|
|
||||||
return repositoryConverter.toDto(branch);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void syncBranches(Long externalSystemId, Long projectId) {
|
|
||||||
log.info("开始同步分支数据, externalSystemId: {}, projectId: {}", externalSystemId, projectId);
|
|
||||||
// TODO: 实现分支同步逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void syncAll(Long externalSystemId) {
|
|
||||||
log.info("开始全量同步数据, externalSystemId: {}", externalSystemId);
|
|
||||||
// TODO: 实现全量同步逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long asyncSyncAll(Long externalSystemId) {
|
|
||||||
log.info("开始异步全量同步数据, externalSystemId: {}", externalSystemId);
|
|
||||||
// TODO: 实现异步全量同步逻辑
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RepositorySyncStatusDTO getSyncStatus(Long historyId) {
|
|
||||||
log.debug("获取同步状态, historyId: {}", historyId);
|
|
||||||
// TODO: 实现获取同步状态逻辑
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RepositorySyncTaskDTO> getRunningSyncs() {
|
|
||||||
log.debug("获取运行中的同步任务列表");
|
|
||||||
// TODO: 实现获取运行中的同步任务列表逻辑
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -56,7 +56,7 @@ INSERT INTO sys_role (id, create_time, code, name, type, description, sort)
|
|||||||
VALUES
|
VALUES
|
||||||
(1, NOW(), 'SUPER_ADMIN', '超级管理员', 1, '系统超级管理员,拥有所有权限', 1),
|
(1, NOW(), 'SUPER_ADMIN', '超级管理员', 1, '系统超级管理员,拥有所有权限', 1),
|
||||||
(2, NOW(), 'SYSTEM_ADMIN', '系统管理员', 1, '系统管理员,拥有大部分系统管理权限', 2),
|
(2, NOW(), 'SYSTEM_ADMIN', '系统管理员', 1, '系统管理员,拥有大部分系统管理权限', 2),
|
||||||
(3, NOW(), 'COMMON_USER', '普通用户', 2, '普通用户,仅拥有基本操作权限', 3);
|
(3, NOW(), 'COMMON_USER', '普通用户', 2, '普通用<EFBFBD><EFBFBD>,仅拥有基本操作权限', 3);
|
||||||
|
|
||||||
-- 初始化角色标签
|
-- 初始化角色标签
|
||||||
INSERT INTO sys_role_tag (id, create_time, name, color)
|
INSERT INTO sys_role_tag (id, create_time, name, color)
|
||||||
@ -145,4 +145,9 @@ INSERT INTO sys_external_system (
|
|||||||
'GitLab测试环境', 'GIT', 'http://gitlab.test.com', '测试环境GitLab服务器', 2, 1,
|
'GitLab测试环境', 'GIT', 'http://gitlab.test.com', '测试环境GitLab服务器', 2, 1,
|
||||||
'TOKEN', NULL, NULL, 'test-token',
|
'TOKEN', NULL, NULL, 'test-token',
|
||||||
'SUCCESS', '2023-12-01 00:00:00', '2023-12-01 00:00:00', '{}'
|
'SUCCESS', '2023-12-01 00:00:00', '2023-12-01 00:00:00', '{}'
|
||||||
|
), (
|
||||||
|
3, 'admin', '2024-12-03 10:35:58.932966', 0, 'admin', '2024-12-03 10:35:58.932966', 0,
|
||||||
|
'链宇GIT', 'GIT', 'http://119.3.203.210:8088/', NULL, 1, 1,
|
||||||
|
'TOKEN', NULL, NULL, 'cNSud7D1GmYQKEMco7s5',
|
||||||
|
NULL, NULL, NULL, '{}'
|
||||||
);
|
);
|
||||||
@ -12,7 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@ -38,7 +37,7 @@ class ExternalSystemServiceImplTest {
|
|||||||
system = new ExternalSystem();
|
system = new ExternalSystem();
|
||||||
system.setId(1L);
|
system.setId(1L);
|
||||||
system.setName("测试Jenkins");
|
system.setName("测试Jenkins");
|
||||||
system.setType(ExternalSystem.SystemType.JENKINS);
|
system.setType(ExternalSystem.ExternalSystemSystemType.JENKINS);
|
||||||
system.setUrl("http://jenkins.test.com");
|
system.setUrl("http://jenkins.test.com");
|
||||||
system.setAuthType(ExternalSystem.AuthType.BASIC);
|
system.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||||
system.setUsername("admin");
|
system.setUsername("admin");
|
||||||
@ -48,7 +47,7 @@ class ExternalSystemServiceImplTest {
|
|||||||
|
|
||||||
systemDTO = new ExternalSystemDTO();
|
systemDTO = new ExternalSystemDTO();
|
||||||
systemDTO.setName("测试Jenkins");
|
systemDTO.setName("测试Jenkins");
|
||||||
systemDTO.setType(ExternalSystem.SystemType.JENKINS);
|
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.JENKINS);
|
||||||
systemDTO.setUrl("http://jenkins.test.com");
|
systemDTO.setUrl("http://jenkins.test.com");
|
||||||
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||||
systemDTO.setUsername("admin");
|
systemDTO.setUsername("admin");
|
||||||
@ -149,7 +148,7 @@ class ExternalSystemServiceImplTest {
|
|||||||
@Test
|
@Test
|
||||||
void validateUniqueConstraints_WhenGitWithoutToken_ShouldThrowException() {
|
void validateUniqueConstraints_WhenGitWithoutToken_ShouldThrowException() {
|
||||||
// 准备数据
|
// 准备数据
|
||||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||||
systemDTO.setAuthType(ExternalSystem.AuthType.TOKEN);
|
systemDTO.setAuthType(ExternalSystem.AuthType.TOKEN);
|
||||||
systemDTO.setToken(null);
|
systemDTO.setToken(null);
|
||||||
|
|
||||||
@ -167,7 +166,7 @@ class ExternalSystemServiceImplTest {
|
|||||||
@Test
|
@Test
|
||||||
void validateUniqueConstraints_WhenGitWithWrongAuthType_ShouldThrowException() {
|
void validateUniqueConstraints_WhenGitWithWrongAuthType_ShouldThrowException() {
|
||||||
// 准备数据
|
// 准备数据
|
||||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||||
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||||
|
|
||||||
// Mock
|
// Mock
|
||||||
@ -184,7 +183,7 @@ class ExternalSystemServiceImplTest {
|
|||||||
@Test
|
@Test
|
||||||
void update_WhenGitWithoutToken_ShouldThrowException() {
|
void update_WhenGitWithoutToken_ShouldThrowException() {
|
||||||
// 准备数据
|
// 准备数据
|
||||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||||
systemDTO.setAuthType(ExternalSystem.AuthType.TOKEN);
|
systemDTO.setAuthType(ExternalSystem.AuthType.TOKEN);
|
||||||
systemDTO.setToken(null);
|
systemDTO.setToken(null);
|
||||||
|
|
||||||
@ -197,7 +196,7 @@ class ExternalSystemServiceImplTest {
|
|||||||
@Test
|
@Test
|
||||||
void update_WhenGitWithWrongAuthType_ShouldThrowException() {
|
void update_WhenGitWithWrongAuthType_ShouldThrowException() {
|
||||||
// 准备数据
|
// 准备数据
|
||||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||||
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||||
|
|
||||||
// 验证
|
// 验证
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user