前言
各位好,这是近半年我在ai编程的使用过程中,不断调整后的project_rules,包含了个人项目的框架设计和编码规范,分享给大家,希望对你有帮助
目录
1. 项目概述
本项目基于微服务架构的企业级云平台系统,采用前后端分离的开发模式。项目包含多个模块,支持多租户、权限管理、部门管理等企业级功能。
1.1 技术栈概览
- 后端: Spring Boot 3.x + Spring Cloud 2023.x + MyBatis Plus
- 前端: React 18 + TypeScript + Vite
- 数据库: MySQL + Redis
- 认证: OAuth2 + JWT
- 消息队列: RocketMQ + Spring Cloud Stream
- 监控: OpenTelemetry + Jaeger
2. 项目架构
2.1 整体架构
- 微服务架构: 基于Spring Cloud微服务生态
- 前后端分离: React + TypeScript前端,Spring Boot后端
- 多模块设计: 按业务领域划分模块
- 多租户支持: 平台级和租户级权限隔离
2.2 模块结构
v3-cloud/
├── v3-pom/ # 依赖管理模块
├── v3-frame/ # 框架核心模块
├── v3-starter/ # 自动配置启动器
├── v3-module/ # 业务模块
├── v3-portal/ # 门户服务
└── v3-web-ui/ # 前端应用
3. 后端开发规范
3.1 代码结构规范
3.1.1 包结构规范
com.wenx.v3system.modular.{domain}/
├── controller/ # 控制器层
├── service/ # 业务服务层
│ └── impl/ # 服务实现
├── domain/ # 领域模型
│ ├── po/ # 持久化对象
│ ├── dto/ # 数据传输对象
│ ├── maps/ # 对象映射转换(MapStruct)
│ └── query/ # 查询条件对象
├── mapper/ # 数据访问层
└── config/ # 配置类
3.1.2 实体类规范
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("table_name")
public class EntityName extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 字段描述
*/
@TableField("column_name")
private String fieldName;
}
要求:
- 继承
BaseEntity
或BaseDeptEntity
- 使用
@Data
和@EqualsAndHashCode(callSuper = true)
- 使用
@TableName
指定表名 - 添加详细的字段注释
- 包含
serialVersionUID
3.1.3 对象映射规范(MapStruct)
项目使用 MapStruct 进行 PO 与 DTO 之间的对象映射转换,统一放置在 maps
包下。
@Mapper(componentModel = "spring")
public interface EntityMap {
EntityMap INSTANCE = Mappers.getMapper(EntityMap.class);
/**
* DTO转PO
*/
Entity toPo(EntityDto dto);
/**
* PO转DTO
*/
EntityDto toDto(Entity po);
/**
* DTO列表转PO列表
*/
List<Entity> toPoList(List<EntityDto> dtoList);
/**
* PO列表转DTO列表
*/
List<EntityDto> toDtoList(List<Entity> poList);
}
要求:
- 使用
@Mapper(componentModel = "spring")
注解,集成Spring容器 - 提供
INSTANCE
静态实例用于非Spring环境调用 - 提供双向转换方法:
toPo()
和toDto()
- 提供批量转换方法:
toPoList()
和toDtoList()
- 映射接口命名规范:
{Entity}Map
3.2 分层职责规范
3.2.1 Controller层职责
控制器层只允许执行以下操作(不超过10行代码):
- 参数接收和验证:接收HTTP请求参数,进行基础验证
- 服务调用:调用对应的Service层方法
- 响应返回:将Service层结果封装为HTTP响应
- 权限验证:使用注解进行权限检查
@RestController
@RequestMapping("/api/v1/resource")
@RequiredArgsConstructor
@Slf4j
@Api(tags = "资源管理")
public class ResourceController {
private final ResourceService resourceService;
@GetMapping("/list")
@ApiOperation("查询资源列表")
@RequiresPermissions(SystemPermission.SYSTEM_READ_CODE)
public R<PageResponse<ResourceDto>> list(ResourceQuery query) {
return R.success(resourceService.page(query));
}
@PostMapping("/add")
@ApiOperation("创建资源")
@RequiresPermissions(SystemPermission.SYSTEM_ALL_CODE)
public R<Long> add(@RequestBody ResourceDto dto) {
return R.success(resourceService.create(dto));
}
}
3.2.2 Service层职责
Service层必须承担以下职责:
- 业务逻辑实现:所有复杂的业务判断、数据处理逻辑
- 数据验证:业务规则验证、数据一致性检查
- 事务管理:使用@Transactional管理事务边界
- 外部服务调用:调用其他微服务或第三方服务
- 数据转换:使用MapStruct进行PO与DTO之间的转换
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class SysRoleRestServiceImpl implements SysRoleRestService {
private final SysRoleMapper roleMapper;
private final SysRoleMenuMapper roleMenuMapper;
@Override
public void assignPermissionsToRoleByData(Long roleId, Object permissionData) {
log.info("开始处理角色权限分配,角色ID: {}", roleId);
// 复杂业务逻辑在Service层实现
if (permissionData instanceof List) {
processPermissionList(roleId, (List<?>) permissionData);
}
log.info("角色权限分配完成,角色ID: {}", roleId);
}
}
3.3 Base层抽象使用规范
3.3.1 BaseRestController 基础控制器
项目提供标准化的基础控制器,自动提供完整的CRUD操作接口。
@RestController
@RequestMapping("/api/v3/sys/users")
public class SysUserRestController extends BaseRestController<SysUserDto, SysUserQuery, SysUserRestService> {
public SysUserRestController(SysUserRestService service) {
super(service);
}
// 自动获得标准CRUD接口:分页查询、详情查询、新增、更新、删除
}
重要技术限制:
警告 泛型类型擦除问题: 使用BaseRestController的超类方法返回视图时,由于Java泛型类型擦除机制,会导致JSON序列化失败。
解决方案: 在Service层明确指定返回类型
// 正确:在Service层明确返回类型
@Service
public class SysUserRestServiceImpl implements SysUserRestService {
@Override
public PageResponse<SysUserDto> page(SysUserQuery query) {
// 明确指定返回类型,避免泛型擦除
Page<SysUser> page = this.page(
new Page<>(query.getPageNum(), query.getPageSize()),
buildQueryWrapper(query)
);
List<SysUserDto> dtoList = SysUserMap.INSTANCE.toDtoList(page.getRecords());
return PageResponse.<SysUserDto>builder()
.records(dtoList)
.total(page.getTotal())
.current(page.getCurrent())
.size(page.getSize())
.build();
}
}
3.4 缓存使用规范
3.4.1 缓存命名规范
项目使用Redis分布式缓存,统一使用@Cacheable
和@CacheEvict
注解进行声明式缓存管理。
缓存命名格式:
- 使用冒号分隔的层级结构:
{domain}:{entity}:{type}
- 缓存Key使用简单动态传递:
key = "#parameter"
或key = "'prefix:' + #parameter"
标准缓存命名示例:
// 用户相关缓存
@Cacheable(value = "sys:user:permissions", key = "#userId")
@Cacheable(value = "sys:user:auth", key = "'account:' + #account")
// 权限相关缓存
@Cacheable(value = "permission:conditions", key = "#permissionId")
@Cacheable(value = "permission:conditions:table", key = "#tableName")
// 角色相关缓存
@Cacheable(value = "sys:role:permissions", key = "#roleId + ':codes'")
3.4.2 缓存使用最佳实践
@Service
@RequiredArgsConstructor
public class SysPermissionConditionCacheServiceImpl implements SysPermissionConditionCacheService {
private final SysPermissionConditionMapper permissionConditionMapper;
// 缓存查询 - 懒加载模式
@Override
@Cacheable(value = "permission:conditions:table", key = "#tableName", unless = "#result.isEmpty()")
public List<SysPermissionCondition> getByTableName(String tableName) {
if (tableName == null) {
return Collections.emptyList();
}
log.debug("从数据库加载表 {} 的权限条件", tableName);
return loadByTableName(tableName);
}
// 缓存清除
@Override
@CacheEvict(value = "permission:conditions:table", key = "#tableName")
public void refreshTableCache(String tableName) {
log.debug("清除表 {} 的权限条件缓存", tableName);
}
}
3.4.3 缓存设计原则
- 懒加载策略:缓存未命中时才读库,不使用预加载
- 细粒度缓存:按业务维度设计缓存Key,便于精确清除
-
条件缓存:使用
unless
条件避免缓存无效数据 - 及时清理:数据更新时必须清除相关缓存
- 统一命名:缓存命名保持与项目其他Service一致
3.5 开发禁止项
3.5.1 架构设计禁止项
- 禁止在Controller层实现业务逻辑,所有业务逻辑必须在Service层实现
- 禁止Controller方法超过10行代码,复杂逻辑必须委托给Service层
- 禁止跨层调用,严格按照Controller -> Service -> Mapper的调用链
-
禁止重复编写CRUD代码,必须使用
BaseRestController
和BaseRestService
-
禁止直接使用
@Autowired
注解,使用@RequiredArgsConstructor
进行依赖注入
3.5.2 技术栈禁止项
- 禁止使用JPA,项目统一使用MyBatis Plus
- 禁止使用Sleuth+Zipkin,项目使用OpenTelemetry+Jaeger
- 禁止引入Spring Boot 2.x或更低版本依赖,项目使用Spring Boot 3.x
-
禁止使用非标准的返回格式,统一使用
R<T>
3.5.3 类型安全禁止项
- 禁止直接使用父类的泛型方法返回视图,必须在Service层明确指定返回类型
- 禁止返回Object或裸对象,必须使用具体的DTO类型
-
禁止在分页查询中忽略泛型指定,必须使用
PageResponse.<DTO>builder()
- 禁止省略MapStruct转换,直接返回Entity对象到前端
3.5.4 缓存使用禁止项
- 禁止使用本地内存缓存,统一使用Redis分布式缓存
-
禁止手动管理缓存,必须使用
@Cacheable
和@CacheEvict
注解 - 禁止缓存命名不规范,必须使用冒号分隔的层级结构
-
禁止缓存更新操作不清除相关缓存,必须使用
@CacheEvict
及时清理
3.5.5 安全禁止项
- 禁止在代码中硬编码敏感信息(密码、密钥、Token等)
-
禁止绕过权限验证,所有接口必须使用
@RequiresPermissions
进行权限控制 - 禁止在日志中输出敏感信息(密码、身份证号、银行卡号等)
- 禁止在代码中拼接SQL语句,使用MyBatis Plus的条件构造器
4. 前端开发规范
4.1 技术栈
- 框架: React 18 + TypeScript
- 构建工具: Vite
- 状态管理: Zustand
- 路由: React Router v6
- UI组件: Ant Design
- HTTP客户端: Axios
- 代码规范: ESLint + Prettier
4.2 项目结构
src/
├── components/ # 通用组件
├── pages/ # 页面组件
├── hooks/ # 自定义Hooks
│ └── business/ # 业务hooks(按功能模块组织)
├── stores/ # 状态管理
├── services/ # API服务
├── utils/ # 工具函数
├── types/ # TypeScript类型定义
├── constants/ # 常量定义
├── assets/ # 静态资源
└── routes/ # 路由配置
4.3 业务逻辑分层规范
4.3.1 Hooks层架构规范
前端组件中的业务逻辑必须迁移到专门的business hooks层实现,组件仅负责UI渲染和事件转发。
一个页面一个hooks原则:
- 每个页面原则上只使用一个主要的business hook
- 将所有相关的业务逻辑整合到一个hooks文件中
- 避免创建过多的小粒度hooks导致组件复杂化
正确示例(统一hooks):
// hooks/business/useRoles.ts - 角色管理统一hooks
export const useRoles = () => {
// 基础数据管理
const [roles, setRoles] = useState([]);
const [loading, setLoading] = useState(false);
// 角色详情管理
const [viewingRole, setViewingRole] = useState(null);
const [detailsVisible, setDetailsVisible] = useState(false);
// 表单管理
const [modalVisible, setModalVisible] = useState(false);
const [editingRole, setEditingRole] = useState(null);
// 权限分配管理
const [permissionModalVisible, setPermissionModalVisible] = useState(false);
const [selectedPermissions, setSelectedPermissions] = useState([]);
// 所有相关的业务方法
const openRoleDetails = useCallback(async (role) => {
// 详情页面逻辑
}, []);
const submitForm = useCallback(async (values) => {
// 表单提交逻辑
}, []);
return {
// 返回所有状态和方法
roles, loading, viewingRole, detailsVisible,
modalVisible, editingRole, permissionModalVisible,
openRoleDetails, submitForm,
// ...其他状态和方法
};
};
// 组件使用
const RolesPage = () => {
const {
roles, loading, viewingRole, detailsVisible,
openRoleDetails, submitForm, // ...其他
} = useRoles(); // 只使用一个hooks
return (
<div>
{/* UI渲染 */}
</div>
);
};
4.3.2 组件职责分离规范
组件层只允许执行以下操作:
- UI渲染:渲染组件的界面元素
- 事件绑定:绑定hooks中的事件处理函数
- 条件渲染:根据hooks状态进行条件渲染
- 样式处理:处理组件的样式和布局
禁止在组件中进行的操作:
- 禁止API调用(使用hooks中的方法)
- 禁止复杂的数据处理逻辑(迁移到hooks)
- 禁止直接管理状态(使用hooks的状态)
- 禁止在组件中定义复杂的事件处理函数
4.4 前端开发禁止项
4.4.1 架构设计禁止项
- 禁止创建过多的小粒度hooks文件(如useRoleDetails、useRoleForm等)
- 禁止在组件中直接定义复杂的事件处理函数
- 禁止在组件中直接进行API调用或复杂数据处理
- 禁止生成重复的类型定义和接口
- 禁止创建不必要的工具类和帮助函数
4.4.2 编码规范禁止项
- 禁止不使用TypeScript严格模式
- 禁止组件名不使用PascalCase
- 禁止文件名不使用kebab-case
- 禁止不使用ESLint和Prettier进行代码质量控制
5. 微服务架构规范
5.1 服务拆分原则
- 业务边界: 按照业务领域进行服务拆分
- 数据独立: 每个服务拥有独立的数据库
- 团队自治: 一个团队负责一个或多个相关服务
- 技术栈统一: 保持技术栈的一致性
5.2 同步通信规范
使用OpenFeign进行服务间调用:
@FeignClient(name = "user-service", path = "/api/v1/users")
public interface UserServiceClient {
@GetMapping("/{userId}")
R<UserDto> getUserById(@PathVariable("userId") Long userId);
@PostMapping("/batch")
R<List<UserDto>> getUsersByIds(@RequestBody List<Long> userIds);
}
5.3 异步通信规范
使用Spring Cloud Stream + RocketMQ:
@Component
public class MessageProcessor {
// 消息处理函数
@Bean
public Consumer<UserCreatedEvent> handleUserCreated() {
return event -> {
log.info("处理用户创建事件: {}", event);
// 处理业务逻辑
};
}
// 消息转换函数
@Bean
public Function<OrderCreatedEvent, NotificationEvent> processOrder() {
return orderEvent -> {
// 转换逻辑
return NotificationEvent.builder()
.userId(orderEvent.getUserId())
.message("订单创建成功")
.build();
};
}
}
// 消息发送
@Component
@RequiredArgsConstructor
public class MessageSender {
private final StreamBridge streamBridge;
public void sendUserCreatedEvent(UserCreatedEvent event) {
streamBridge.send("userCreated-out-0", event);
}
}
6. 数据库设计规范
6.1 命名规范
- 表名使用下划线命名法,如:
sys_user
- 字段名使用下划线命名法,如:
user_name
- 索引名格式:
idx_表名_字段名
- 外键名格式:
fk_表名_字段名
6.2 基础字段
所有业务表必须包含以下基础字段:
CREATE TABLE example_table (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
create_by BIGINT COMMENT '创建人ID',
update_by BIGINT COMMENT '更新人ID',
deleted TINYINT NOT NULL DEFAULT 0 COMMENT '删除标记(0:正常,1:删除)',
-- 业务字段
INDEX idx_create_time (create_time),
INDEX idx_deleted (deleted)
);
6.3 多租户支持
支持多租户的表需要添加租户字段:
tenant_id BIGINT NOT NULL COMMENT '租户ID',
INDEX idx_tenant_id (tenant_id)
7. 安全与测试规范
7.1 安全规范
7.1.1 认证与授权
- 统一使用 OAuth2 + JWT
- 访问接口必须经过权限验证
- 严禁在代码中硬编码密钥或凭证
7.1.2 数据安全
- 所有敏感数据(密码、token、身份证号)必须加密存储
- 日志中禁止打印敏感信息
- 传输层必须使用 HTTPS/TLS
7.1.3 安全编码规范
- 禁止 SQL 拼接,必须使用参数化查询
- 防止 XSS:前端输出必须转义
- 防止 CSRF:后端启用 CSRF Token 校验
- 使用 SonarQube 或 Checkmarx 进行代码安全扫描
7.2 测试规范
7.2.1 单元测试
- 所有业务逻辑必须编写单元测试,覆盖率不低于 80%
- 使用 JUnit5 + Mockito,禁止使用 JUnit4
- 单元测试命名规范:
方法名_场景_预期结果
7.2.2 集成测试
- 使用 Spring Boot Test 进行集成测试
- 引入 Testcontainers 模拟数据库、MQ、Redis 等外部依赖
- 集成测试必须在 CI 中自动运行
7.2.3 前端测试
- 前端使用 Jest + React Testing Library
- 所有 hooks 和组件必须有快照测试或行为测试
- 关键交互逻辑必须有 E2E 测试(Cypress 或 Playwright)
附录
A. 常用工具类
-
R<T>
: 统一返回结果封装 -
BaseEntity
: 基础实体类 -
PageResponse<T>
: 分页响应封装 -
TraceContextManager
: 链路追踪上下文管理工具
B. 权限常量
-
SystemPermission
: 系统权限常量 -
PlatformPermission
: 平台权限常量
C. 架构质量检查清单
后端代码检查:
- Controller方法是否超过10行代码?
- 是否存在业务逻辑在Controller层实现?
- 是否使用了BaseRestController/BaseRestService?
- 是否使用了MapStruct进行对象转换?
- 是否统一使用R返回格式?
- Service层是否明确指定了返回类型,避免泛型擦除?
- 分页查询是否使用
PageResponse.<DTO>builder()
指定泛型? - 是否避免返回Object或裸对象类型?
前端代码检查:
- 是否创建了过多的小粒度hooks文件?
- 组件是否包含复杂的业务逻辑?
- 是否在组件中直接进行API调用?
- hooks是否按功能模块合理组织?
- 是否遵循"一个页面一个主要hooks"原则?