# 编码风格规范 ## 一、命名规范 | 类型 | 命名规则 | 示例 | |------|---------|------| | Controller | `{功能}RestController` | `LotteryActivityRestController` | | Service 接口 | `{功能}Service` | `LotteryActivityRestService` | | Service 实现 | `{功能}ServiceImpl` | `LotteryActivityRestServiceImpl` | | 写操作执行器 | `{功能}CmdExe` 或 `{功能}Exe` | `LotteryDrawExe` | | 查询执行器 | `{功能}QryExe` | `LotteryRecordQryExe` | | 写命令 | `{功能}Cmd` | `LotteryDrawCmd` | | 查询命令 | `{功能}QryCmd` | `LotteryRecordQryCmd` | | 返回对象 | `{功能}CO` | `LotteryDrawResultCO` | | DAO | `{实体名}DAO` | `LotteryTicketDAO` | | Entity | `{实体名}` | `LotteryTicket` | | 数据库服务 | `{功能}DatabaseService` | `LotteryActivityDatabaseService` | | Gateway | `{功能}Gateway` + `{功能}GatewayImpl` | `LotteryActivityGateway` | --- ## 二、Controller 规范 ```java /** * 功能说明. * * @author xxx * @eo.api-type http * @eo.groupName 模块名.子模块名 * @eo.path /模块/资源 */ @RestController @RequestMapping(value = "/user/user-profile", produces = MediaType.APPLICATION_JSON_VALUE) @RequiredArgsConstructor public class UserProfileRestController extends BaseController { private final UserProfileService userProfileService; /** * 接口说明. * * @eo.name 接口名称 * @eo.url /具体路径(GET 无路径时留空) * @eo.method get/post/put/delete * @eo.request-type formdata(GET)/ json(POST/PUT) */ @GetMapping public UserProfileDTO getProfile(UserProfileQryCmd cmd) { return userProfileService.getUserProfile(cmd); } @PostMapping("/draw") public LotteryDrawResultCO draw(@RequestBody @Validated LotteryDrawCmd cmd) { return lotteryService.draw(cmd); } } ``` **关键点**: - 继承 `BaseController` - `@RequiredArgsConstructor`(构造器注入) - API 文档用 `@eo.` 注解,不用 Swagger - GET 请求参数直接用 Cmd 对象接收(无 `@RequestBody`) - POST/PUT 用 `@RequestBody @Validated` --- ## 三、Cmd / CO 规范 ```java // 写命令 - 继承 AppExtCommand(包含 reqUserId 等公共字段) @Data public class LotteryDrawCmd extends AppExtCommand { @NotNull private Long activityId; @Min(1) @Max(10) private Integer drawCount; } // 查询命令 - 分页继承 PageQueryCmd @Data public class LotteryRecordQryCmd extends PageQueryCmd { private Long activityId; } // 返回对象 @Data public class LotteryDrawResultCO { private Long prizeId; private String prizeName; } ``` **规则**: - 校验注解用 `jakarta.validation.constraints.*`(不用 javax) - Cmd 需要用户身份时继承 `AppExtCommand`,通过 `cmd.getReqUserId()` 获取当前用户 --- ## 四、Service / CmdExe 规范 ```java // ServiceImpl - 门面,调用 CmdExe @Service @RequiredArgsConstructor @Slf4j public class LotteryActivityRestServiceImpl implements LotteryActivityRestService { private final LotteryDrawExe lotteryDrawExe; private final LotteryRecordQryExe recordQryExe; @Override public LotteryDrawResultCO draw(LotteryDrawCmd cmd) { return lotteryDrawExe.execute(cmd); } } // CmdExe - 核心业务逻辑 @Component @RequiredArgsConstructor @Slf4j public class LotteryDrawExe { private final LotteryActivityDatabaseService lotteryDbService; @Transactional public LotteryDrawResultCO execute(LotteryDrawCmd cmd) { // 1. 参数校验 // 2. 业务逻辑 // 3. 记录日志 log.info("用户抽奖: userId={}, activityId={}", cmd.getReqUserId(), cmd.getActivityId()); // 4. 返回结果 } } ``` --- ## 五、Infrastructure 规范 ```java // DAO - 继承 BaseDAO public interface LotteryTicketDAO extends BaseDAO {} // DatabaseService - 简单场景直接用 @Service @RequiredArgsConstructor public class LotteryActivityDatabaseService { private final LotteryTicketDAO ticketDAO; public void consumeTicket(Long userId, Long activityId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .eq(Objects.nonNull(userId), LotteryTicket::getUserId, userId) .eq(Objects.nonNull(activityId), LotteryTicket::getActivityId, activityId); // ... } } // Gateway - 复杂场景:锁 + 缓存 + 多数据源 @Component @RequiredArgsConstructor public class LotteryActivityGatewayImpl implements LotteryActivityGateway { private final LotteryTicketDAO ticketDAO; private final RedisTemplate redisTemplate; @Override public void consumeTicketWithLock(Long userId, Long activityId) { String lockKey = "lottery:lock:" + userId; // 分布式锁 + DB 操作 + 缓存更新 } } ``` --- ## 六、通用代码规范 ### 条件判断 ```java // ✅ if (StringUtils.isNotBlank(name)) { ... } if (Objects.nonNull(userId)) { ... } // ❌ if (name != null && !name.isEmpty()) { ... } if (userId != null) { ... } ``` ### 金额 ```java // ✅ BigDecimal amount = new BigDecimal("100.00"); BigDecimal total = a.add(b); // ❌ 禁止 double amount = 100.00; ``` ### 返回分页 ```java return PageResult.of(records, total, cmd.getPageNum(), cmd.getPageSize()); ``` ### 异常 ```java // ✅ throw new BusinessException("抽奖券不足"); // ❌ throw new RuntimeException("抽奖券不足"); ``` ### Redis Key 规范 ``` 缓存: {module}:{entity}:{id} user:info:10001 排行榜: ranking:{type}:{period}:{date} ranking:send_gift:day:20240101 分布式锁: {module}:lock:{bizId} coin:lock:10001 ``` --- ## 七、新功能开发顺序(黄金路径) 1. 定义 Cmd / CO(other-client) 2. 定义 Service 接口(other-client) 3. 实现 CmdExe(other-application) 4. 实现 ServiceImpl(other-application) 5. 创建 Controller(other-adapter) 6. 按需创建 DatabaseService 或 Gateway(other-infrastructure) 7. 如需跨服务调用,添加 Inner API --- ## 八、质量检查清单 - [ ] 命名清晰,无 a/b/temp 类命名 - [ ] 参数校验(`@Validated`、`@NotNull`) - [ ] 写操作有 `@Transactional` - [ ] 金额操作有幂等性保障(bizNo) - [ ] 并发场景有分布式锁 - [ ] 关键操作有 `log.info` / `log.error` - [ ] 业务异常用 `BusinessException` - [ ] 无魔法值(常量或枚举) - [ ] 分页查询用 `PageResult`