可正常启动
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原则(不要重复自己)、无错误、功能齐全且可工作的代码,还应与下面代码实施指南中列出的规则保持一致。
|
||||
- 专注于简单易读的代码,而不是高性能。
|
||||
- 完全实现所有要求的功能。
|
||||
- 不要留下待办事项、占位符或缺失的部分。
|
||||
- 确保代码完整!彻底确认。
|
||||
- 包括所有必需的导入的包,并确保关键组件的正确命名。
|
||||
- 如果你认为可能没有正确答案,你就说出来。
|
||||
- 如果你不知道答案,就说出来,而不是猜测。
|
||||
- 可以提出合理化的建议,但是需要等待是否可以。
|
||||
- 对于新设计的实体类、字段、方法都要写注释,对于实际的逻辑要有逻辑注释。
|
||||
- 写了新的数据库表,应该在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 开发规范
|
||||
### 严格遵循要求
|
||||
- 首先一步一步思考,详细描述伪代码构建计划,确认后再写代码
|
||||
- 遵循正确、最佳实践、DRY原则、无错误、功能齐全的代码编写原则
|
||||
- 专注于简单易读的代码实现,确保代码完整性
|
||||
- 包含所有必需的导入包,确保关键组件正确命名
|
||||
- 如遇不确定答案或不知道答案,应明确说明而非猜测
|
||||
- 可提出合理化建议,但需等待确认
|
||||
- 对新设计的实体类、字段、方法添加注释,实际逻辑需要逻辑注释
|
||||
- 新增或者修改数据库表需在V1.0.0__init_schema.sql、V1.0.1__init_data.sql中补充表结构和初始化数据,不要随意删除。
|
||||
|
||||
### 包结构说明
|
||||
- 框架包路径
|
||||
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.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 接口出参(复杂业务场景使用)
|
||||
### 包结构规范
|
||||
- 框架包路径(com.qqchen.deploy.backend.framework):包含annotation、api、audit、controller等多个子包
|
||||
- 业务包路径(com.qqchen.deploy.backend):包含api、controller、converter、entity等多个子包
|
||||
|
||||
### 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设计:简单CRUD使用统一DTO,复杂场景使用专门Request/Response,继承BaseDTO获取基础字段
|
||||
- 验证规则:使用Jakarta Validation注解,支持自定义验证注解和分组验证
|
||||
- 对象转换:使用MapStruct进行转换,继承BaseConverter,显式声明特殊映射
|
||||
|
||||
### Service层规范
|
||||
- 简单CRUD场景直接继承BaseServiceImpl即可
|
||||
- 复杂业务场景需要:
|
||||
1. 定义业务接口方法
|
||||
2. 实现具体的业务逻辑
|
||||
3. 处理业务异常
|
||||
4. 添加事务控制
|
||||
- 示例:
|
||||
```java
|
||||
- 简单CRUD继承BaseServiceImpl,复杂业务需定义专门接口和实现,包含事务控制和异常处理
|
||||
- 使用@Transactional注解控制事务,合理设置事务传播机制和隔离级别
|
||||
- 实现乐观锁(@Version)或悲观锁(findByIdWithLock)进行并发控制
|
||||
- 示例
|
||||
@Slf4j
|
||||
@Service
|
||||
@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层规范
|
||||
- REST FULL接口使用框架BaseController
|
||||
- 新增接口命名规范:
|
||||
- 三方接口:模块名ApiController(如:ExternalSystemApiController)
|
||||
- 二方接口:模块名Controller(如:ExternalSystemController)
|
||||
- REST接口使用BaseController,三方接口命名为模块名ApiController,二方接口为模块名Controller
|
||||
- 返回值com.qqchen.deploy.backend.framework.api.Response<T>
|
||||
- 统一使用GlobalExceptionHandler处理异常
|
||||
- 示例:
|
||||
```java
|
||||
@Slf4j
|
||||
@RestController
|
||||
@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> {
|
||||
// 特定业务方法实现
|
||||
}
|
||||
```
|
||||
|
||||
### Repository层规范
|
||||
- 继承IBaseRepository
|
||||
- 定义特定的查询方法
|
||||
- 继承IBaseRepository,定义特定查询方法
|
||||
- 使用JPA命名规范定义查询方法
|
||||
- 复杂查询使用@Query注解
|
||||
- 示例:
|
||||
```java
|
||||
@Repository
|
||||
public interface IExternalSystemRepository extends IBaseRepository<ExternalSystem, Long> {
|
||||
boolean existsByNameAndDeletedFalse(String name);
|
||||
}
|
||||
```
|
||||
|
||||
### Converter规范
|
||||
- 继承BaseConverter,遵循以下规则:
|
||||
1. 简单场景(字段完全匹配)示例:
|
||||
@ -172,354 +77,52 @@ public interface IExternalSystemRepository extends IBaseRepository<ExternalSyste
|
||||
UserDTO toDto(User entity);
|
||||
}
|
||||
```
|
||||
### 枚举规范
|
||||
- 新增加枚举应添加到com.qqchen.deploy.backend.enums,后缀以Enum结尾
|
||||
- 增加枚举时,不要修改现有没有,只追加即可
|
||||
|
||||
### 测试规范
|
||||
- Service层测试:
|
||||
1. 使用@SpringBootTest
|
||||
2. 使用@MockBean模拟依赖
|
||||
3. 测试所有业务场景
|
||||
- Controller层测试:
|
||||
1. 使用@WebMvcTest或@SpringBootTest + @AutoConfigureMockMvc
|
||||
2. 使用MockMvc测试接口
|
||||
3. 测试所有接口路径
|
||||
- Repository层测试:
|
||||
1. 使用@DataJpaTest
|
||||
2. 测试所有查询方法
|
||||
|
||||
### 文档规范
|
||||
- 类注释:说明类的用途、作者、版本
|
||||
- 方法注释:说明参数、返回值、异常
|
||||
- 业务方法注释:说明业务规则
|
||||
- API文档:使用Swagger注解
|
||||
### 异常规范
|
||||
- 异常分为系统异常应继承SystemException和业务异常应承BusinessException,使用ResponseCode定义错误码,在messages.properties中定义错误消息
|
||||
- 示例
|
||||
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_DISABLED);
|
||||
|
||||
### 命名规范
|
||||
- 使用PascalCase作为类名(例,UserController、OrderService)
|
||||
- 使用camelCase作为方法和变量名(例如,findUserById、isOrderValid)
|
||||
- 对常量使用ALL_CAPS(例如,MAX_RETRY_ATTEMPTS、DEFAULT_PAGE_SIZE)
|
||||
- service、repository接口类需要以I开头,service实现类无需使用I开头但尾部需要Impl结尾
|
||||
- 类名使用PascalCase(UserController、OrderService)
|
||||
- 方法和变量名使用camelCase(findUserById、isOrderValid)
|
||||
- 常量使用ALL_CAPS(MAX_RETRY_ATTEMPTS、DEFAULT_PAGE_SIZE)
|
||||
- Service、Repository接口类以I开头,实现类需要Impl结尾
|
||||
|
||||
### 数据库规范
|
||||
- 使用Flyway进行数据库版本控制
|
||||
- 新增表结构写入V1.0.0__init_schema.sql
|
||||
- 新增初始数据写入V1.0.1__init_data.sql
|
||||
- 表名使用下划线命名法(例如:sys_user, sys_role)
|
||||
- 字段名使用下划线命名法(例如:create_time, update_by)
|
||||
- 使用Flyway进行版本控制,新表结构写入V1.0.0__init_schema.sql,初始数据写入V1.0.1__init_data.sql
|
||||
- 表名和字段名使用下划线命名法(sys_user, create_time)
|
||||
- 必须包含基础字段: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. 文档是否同步更新
|
||||
- 系统级错误(1xxx):1000-1099通用系统错误,1100-1199依赖注入错误,1200-1299数据库错误
|
||||
- 业务级错误(2xxx):2000-2099通用业务错误,2100-2199角色相关,2200-2299 JWT相关等
|
||||
- 错误码命名使用大写字母和下划线,采用"模块_操作_错误"命名方式
|
||||
|
||||
### 缓存使用规范
|
||||
- 缓存注解:
|
||||
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. 持久化操作
|
||||
|
||||
### 数据对象规范
|
||||
- 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
|
||||
- 使用@Cacheable(查询)、@CachePut(更新)、@CacheEvict(删除)注解
|
||||
- 缓存Key格式:模块:业务:标识,如user:info:1
|
||||
- 根据业务场景选择缓存策略: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. 环境配置说明
|
||||
- JWT Token包含Header(算法)、Payload(用户信息)、Signature(签名)
|
||||
- Access Token有效期2小时,Refresh Token有效期7天
|
||||
- 敏感数据加密存储和传输,日志和接口返回需脱敏
|
||||
|
||||
### 测试规范
|
||||
- 单元测试:
|
||||
1. Service层业务测试
|
||||
2. 重要工具类测试
|
||||
3. 边界条件测试
|
||||
- 集成测试:
|
||||
1. Controller层接口测试
|
||||
2. 数据库操作测试
|
||||
3. 缓存操作测试
|
||||
- 测试原则:
|
||||
1. 测试覆盖率要求
|
||||
2. 测试数据隔离
|
||||
3. 测试用例完整性
|
||||
- Service层:使用@SpringBootTest和@MockBean,测试所有业务场景
|
||||
- Controller层:使用@WebMvcTest或MockMvc,测试所有接口路径
|
||||
- Repository层:使用@DataJpaTest,测试所有查询方法
|
||||
|
||||
### 文档规范
|
||||
- 类注释:说明用途、作者、版本
|
||||
- 方法注释:说明参数、返回值、异常
|
||||
- API文档:使用Swagger注解,保持文档同步更新
|
||||
|
||||
### 性能优化规范
|
||||
- 数据库优化:
|
||||
1. 索引设计
|
||||
2. SQL优化
|
||||
3. 分页查询
|
||||
- 代码优化:
|
||||
1. 循环优化
|
||||
2. 集合操作
|
||||
3. 字符串处理
|
||||
- 缓存优化:
|
||||
1. 缓存粒度
|
||||
2. 缓存更新
|
||||
3. 缓存穿透处理
|
||||
- 数据库优化:索引设计、SQL优化、分页查询
|
||||
- 代码优化:循环优化、集合操作、字符串处理
|
||||
- 缓存优化:合理设置缓存粒度、更新策略、防止缓存穿透
|
||||
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.servlet.http.HttpServletResponse;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
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.domain.Entity;
|
||||
import jakarta.persistence.*;
|
||||
@ -26,7 +29,7 @@ public class ExternalSystem extends Entity<Long> {
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SystemType type;
|
||||
private ExternalSystemTypeEnum type;
|
||||
|
||||
/**
|
||||
* 系统访问地址
|
||||
@ -51,11 +54,11 @@ public class ExternalSystem extends Entity<Long> {
|
||||
private Boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 认证方式:BASIC/TOKEN/OAUTH<EFBFBD><EFBFBD>
|
||||
* 认证方式:BASIC/TOKEN/OAUTH
|
||||
*/
|
||||
@Column(name = "auth_type", nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private AuthType authType;
|
||||
private ExternalSystemAuthTypeEnum authType;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
@ -77,7 +80,7 @@ public class ExternalSystem extends Entity<Long> {
|
||||
*/
|
||||
@Column(name = "sync_status")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SyncStatus syncStatus;
|
||||
private ExternalSystemSyncStatusEnum syncStatus;
|
||||
|
||||
/**
|
||||
* 最后同步时间
|
||||
@ -97,30 +100,5 @@ public class ExternalSystem extends Entity<Long> {
|
||||
@Column(columnDefinition = "JSON")
|
||||
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"),
|
||||
|
||||
// 第三方系统相关错误码 (2500-2599)
|
||||
EXTERNAL_SYSTEM_NOT_FOUND(2505, "external.system.not.found"),
|
||||
EXTERNAL_SYSTEM_NAME_EXISTS(2500, "external.system.name.exists"),
|
||||
EXTERNAL_SYSTEM_TYPE_URL_EXISTS(2501, "external.system.type.url.exists"),
|
||||
EXTERNAL_SYSTEM_DISABLED(2502, "external.system.disabled"),
|
||||
|
||||
@ -14,4 +14,5 @@ public class BusinessException extends BaseException {
|
||||
public BusinessException(ResponseCode errorCode, Object[] args) {
|
||||
super(errorCode, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.qqchen.deploy.backend.integration;
|
||||
|
||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||
|
||||
/**
|
||||
* 第三方系统集成接口
|
||||
@ -26,5 +27,5 @@ public interface IExternalSystemIntegration {
|
||||
*
|
||||
* @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;
|
||||
|
||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||
import com.qqchen.deploy.backend.integration.IExternalSystemIntegration;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.*;
|
||||
@ -43,7 +44,7 @@ public class GitIntegration implements IExternalSystemIntegration {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalSystem.SystemType getSystemType() {
|
||||
return ExternalSystem.SystemType.GIT;
|
||||
public ExternalSystemTypeEnum getSystemType() {
|
||||
return ExternalSystemTypeEnum.GIT;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
package com.qqchen.deploy.backend.integration.impl;
|
||||
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.*;
|
||||
@ -9,6 +11,10 @@ import org.springframework.web.client.RestTemplate;
|
||||
|
||||
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
|
||||
@Service
|
||||
public class JenkinsIntegration implements IExternalSystemIntegration {
|
||||
@ -51,7 +57,7 @@ public class JenkinsIntegration implements IExternalSystemIntegration {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalSystem.SystemType getSystemType() {
|
||||
return ExternalSystem.SystemType.JENKINS;
|
||||
public ExternalSystemTypeEnum getSystemType() {
|
||||
return ExternalSystemTypeEnum.JENKINS;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
package com.qqchen.deploy.backend.model;
|
||||
|
||||
import com.qqchen.deploy.backend.entity.ExternalSystem.SystemType;
|
||||
import com.qqchen.deploy.backend.entity.ExternalSystem.AuthType;
|
||||
import com.qqchen.deploy.backend.entity.ExternalSystem.SyncStatus;
|
||||
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.dto.BaseDTO;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
@ -19,7 +19,7 @@ public class ExternalSystemDTO extends BaseDTO {
|
||||
private String name;
|
||||
|
||||
@NotNull(message = "系统类型不能为空")
|
||||
private SystemType type;
|
||||
private ExternalSystemTypeEnum type;
|
||||
|
||||
@NotBlank(message = "系统访问地址不能为空")
|
||||
private String url;
|
||||
@ -31,7 +31,7 @@ public class ExternalSystemDTO extends BaseDTO {
|
||||
private Boolean enabled = true;
|
||||
|
||||
@NotNull(message = "认证方式不能为空")
|
||||
private AuthType authType;
|
||||
private ExternalSystemAuthTypeEnum authType;
|
||||
|
||||
private String username;
|
||||
|
||||
@ -39,7 +39,7 @@ public class ExternalSystemDTO extends BaseDTO {
|
||||
|
||||
private String token;
|
||||
|
||||
private SyncStatus syncStatus;
|
||||
private ExternalSystemSyncStatusEnum syncStatus;
|
||||
|
||||
private LocalDateTime lastSyncTime;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
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.enums.QueryType;
|
||||
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
||||
@ -25,7 +25,7 @@ public class ExternalSystemQuery extends BaseQuery {
|
||||
private String name;
|
||||
|
||||
@QueryField(field = "type")
|
||||
private SystemType type;
|
||||
private ExternalSystemTypeEnum type;
|
||||
|
||||
@QueryField(field = "enabled")
|
||||
private Boolean enabled;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.entity.ExternalSystem;
|
||||
import com.qqchen.deploy.backend.enums.ExternalSystemTypeEnum;
|
||||
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@ -17,7 +18,7 @@ public interface IExternalSystemRepository extends IBaseRepository<ExternalSyste
|
||||
/**
|
||||
* 检查系统类型和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;
|
||||
|
||||
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.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||
@ -47,7 +50,7 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
||||
@Resource
|
||||
private List<IExternalSystemIntegration> systemIntegrations;
|
||||
|
||||
private Map<ExternalSystem.SystemType, IExternalSystemIntegration> integrationMap;
|
||||
private Map<ExternalSystemTypeEnum, IExternalSystemIntegration> integrationMap;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
@ -87,8 +90,8 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
||||
* @param dto 外部系统DTO
|
||||
*/
|
||||
private void validateGitAuth(ExternalSystemDTO dto) {
|
||||
if (dto.getType() == ExternalSystem.SystemType.GIT) {
|
||||
if (dto.getAuthType() != ExternalSystem.AuthType.TOKEN) {
|
||||
if (dto.getType() == ExternalSystemTypeEnum.GIT) {
|
||||
if (dto.getAuthType() != ExternalSystemAuthTypeEnum.TOKEN) {
|
||||
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_GIT_AUTH_TYPE_ERROR);
|
||||
}
|
||||
if (StringUtils.isBlank(dto.getToken())) {
|
||||
@ -127,7 +130,7 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
||||
}
|
||||
|
||||
try {
|
||||
system.setSyncStatus(ExternalSystem.SyncStatus.RUNNING);
|
||||
system.setSyncStatus(ExternalSystemSyncStatusEnum.RUNNING);
|
||||
externalSystemRepository.save(system);
|
||||
|
||||
// TODO: 根据不同的系统类型调用不同的同步方法
|
||||
@ -137,10 +140,10 @@ public class ExternalSystemServiceImpl extends BaseServiceImpl<ExternalSystem, E
|
||||
case ZENTAO -> syncZentaoData(system);
|
||||
}
|
||||
|
||||
system.setSyncStatus(ExternalSystem.SyncStatus.SUCCESS);
|
||||
system.setSyncStatus(ExternalSystemSyncStatusEnum.SUCCESS);
|
||||
system.setLastSyncTime(LocalDateTime.now());
|
||||
} catch (Exception e) {
|
||||
system.setSyncStatus(ExternalSystem.SyncStatus.FAILED);
|
||||
system.setSyncStatus(ExternalSystemSyncStatusEnum.FAILED);
|
||||
log.error("Sync data failed for external system: {}", system.getName(), e);
|
||||
throw new BusinessException(ResponseCode.EXTERNAL_SYSTEM_SYNC_FAILED);
|
||||
} 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
|
||||
(1, NOW(), 'SUPER_ADMIN', '超级管理员', 1, '系统超级管理员,拥有所有权限', 1),
|
||||
(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)
|
||||
@ -145,4 +145,9 @@ INSERT INTO sys_external_system (
|
||||
'GitLab测试环境', 'GIT', 'http://gitlab.test.com', '测试环境GitLab服务器', 2, 1,
|
||||
'TOKEN', NULL, NULL, 'test-token',
|
||||
'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.mock.mockito.MockBean;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -38,7 +37,7 @@ class ExternalSystemServiceImplTest {
|
||||
system = new ExternalSystem();
|
||||
system.setId(1L);
|
||||
system.setName("测试Jenkins");
|
||||
system.setType(ExternalSystem.SystemType.JENKINS);
|
||||
system.setType(ExternalSystem.ExternalSystemSystemType.JENKINS);
|
||||
system.setUrl("http://jenkins.test.com");
|
||||
system.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||
system.setUsername("admin");
|
||||
@ -48,7 +47,7 @@ class ExternalSystemServiceImplTest {
|
||||
|
||||
systemDTO = new ExternalSystemDTO();
|
||||
systemDTO.setName("测试Jenkins");
|
||||
systemDTO.setType(ExternalSystem.SystemType.JENKINS);
|
||||
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.JENKINS);
|
||||
systemDTO.setUrl("http://jenkins.test.com");
|
||||
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||
systemDTO.setUsername("admin");
|
||||
@ -149,7 +148,7 @@ class ExternalSystemServiceImplTest {
|
||||
@Test
|
||||
void validateUniqueConstraints_WhenGitWithoutToken_ShouldThrowException() {
|
||||
// 准备数据
|
||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
||||
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||
systemDTO.setAuthType(ExternalSystem.AuthType.TOKEN);
|
||||
systemDTO.setToken(null);
|
||||
|
||||
@ -167,7 +166,7 @@ class ExternalSystemServiceImplTest {
|
||||
@Test
|
||||
void validateUniqueConstraints_WhenGitWithWrongAuthType_ShouldThrowException() {
|
||||
// 准备数据
|
||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
||||
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||
|
||||
// Mock
|
||||
@ -184,7 +183,7 @@ class ExternalSystemServiceImplTest {
|
||||
@Test
|
||||
void update_WhenGitWithoutToken_ShouldThrowException() {
|
||||
// 准备数据
|
||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
||||
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||
systemDTO.setAuthType(ExternalSystem.AuthType.TOKEN);
|
||||
systemDTO.setToken(null);
|
||||
|
||||
@ -197,7 +196,7 @@ class ExternalSystemServiceImplTest {
|
||||
@Test
|
||||
void update_WhenGitWithWrongAuthType_ShouldThrowException() {
|
||||
// 准备数据
|
||||
systemDTO.setType(ExternalSystem.SystemType.GIT);
|
||||
systemDTO.setType(ExternalSystem.ExternalSystemSystemType.GIT);
|
||||
systemDTO.setAuthType(ExternalSystem.AuthType.BASIC);
|
||||
|
||||
// 验证
|
||||
|
||||
Loading…
Reference in New Issue
Block a user