245 lines
6.3 KiB
Markdown
245 lines
6.3 KiB
Markdown
# 编码风格规范
|
||
|
||
## 一、命名规范
|
||
|
||
| 类型 | 命名规则 | 示例 |
|
||
|------|---------|------|
|
||
| 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<LotteryTicket> {}
|
||
|
||
// DatabaseService - 简单场景直接用
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class LotteryActivityDatabaseService {
|
||
private final LotteryTicketDAO ticketDAO;
|
||
|
||
public void consumeTicket(Long userId, Long activityId) {
|
||
LambdaQueryWrapper<LotteryTicket> wrapper = new LambdaQueryWrapper<LotteryTicket>()
|
||
.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<String, Object> 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`
|