Cursor AI 编程实战(篇二):Rules、速查与 Adapter/App 全文
系列 :共三篇。本篇讲 Cursor Rules(全局/项目、
.mdc)、第四节中的分层脱敏片段与 速查 A--E 小代码块,以及「代码分析 / Git」规则全文;并收录 附录 E:Adapter + App 层.mdc完整正文 (可直存.cursor/rules/)。
上一篇 :篇一:Prompt 与案例
下一篇 :篇三:Domain / Infrastructure / 策略
合并完整版 :Cursor-AI编程最佳实践-CSDN发表版.md
系列说明:本文为《Cursor AI 编程实战》连载之一,脱敏整理自团队《最佳实战》。三篇可独立阅读,也可按篇一 → 篇二 → 篇三顺序配合使用。
四、Rules:把「项目语义」交给 AI
LLM 会话相对无状态;Cursor Rules 把团队规范、分层约定、中间件用法固化成可版本化的上下文。
4.1 全局规则(User Rules)
路径:Cursor Settings → Rules → User Rules。作用所有项目。
原则:短、通用、可被项目规则覆盖。示例:
Always respond in 中文(按需)代码简洁,必要注释;回复言简意赅,避免重复解释
4.2 项目规则(推荐)
路径:项目根目录 .cursor/rules/,单文件一条规则,扩展名 .mdc(Markdown + 元数据),可纳入 Git。
| 特性 | 说明 |
|---|---|
| 格式 | .mdc,可读性强 |
| 版本 | 与代码同仓,可评审 |
| 模块化 | 按 Java 规范、Git、中间件等拆分 |
| 作用域 | 可用路径 glob 限定;子目录可有独立 rules |
官方建议:单文件尽量 500 行以内 ;写清楚、少模糊词;可配合 /Generate Cursor Rules 生成初稿再迭代。
4.3 分层与依赖示例(脱敏后的 .mdc 片段)
以下将企业内部 Maven 坐标、Starter 命名、二方搜索组件版本线及事务注解等,统一替换为 com.yourorg.platform.*、platform-*、platform-v2、PlatformTransactional 等占位符,便于公开发表;读者落地时请改回各自公司的真实坐标与 API 名称。
markdown
---
alwaysApply: true
---
# 后端开发通用规范(脱敏示例)
## 项目架构规范
### 父 POM 配置
- 所有业务工程继承统一父 POM(示例):
```xml
<parent>
<groupId>com.yourorg.platform</groupId>
<artifactId>platform-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
Adapter 层
- 职责:适配不同触点(API、Admin、H5、Wechat、PDA 等)
- 包路径 :
*.adapter.* - 文件命名 :以
*Adapter或*Controller结尾 - 特殊规则 :
- 使用 @Action 注解,方法入参必须为单个入参,返回值包装在 Response 下
- Action 名称全局唯一
- 只能调用 App 层代码
- 不同端使用不同包和 path 前缀(/admin、/tenant、/api)
App 层
- 职责:不同场景的业务入口(接口、MQ、定时任务)
- 包路径 :
*.app.* - 文件命名 :以
*AppService、*Consumer、*Job结尾 - 特殊规则:允许在简单场景下跳过 Domain 访问 Infrastructure
Domain 层
- 职责:核心业务逻辑、领域模型抽象
- 包路径 :
*.domain.* - 文件命名 :以
*Service、*DO结尾
Infrastructure 层
- 职责:DB、搜索、文件、外部 RPC;防腐通过 Gateway
- 包路径 :
*.infrastructure.* - 文件命名 :以
*Repository、*Gateway结尾
SPI 层
- 职责:扩展点、字典、消息、基础 PO 等
- 包路径 :
*.spi.*
基础框架依赖(示例命名)
platform-common-api:基础模型、请求应答、通用异常、工具类platform-common-runtime:运行机制、日志切面、上下文、过滤器platform-spring-boot-starter-mybatis:数据访问platform-spring-boot-starter-cache:缓存platform-spring-boot-starter-rocketmq:消息队列
包与类命名
- 根包:
com.yourorg.platform.{应用}.{module} - 各层包路径包含层次标识:adapter、app、domain、infrastructure、spi
依赖注入
- 优先构造器注入:
@AllArgsConstructor或@RequiredArgsConstructor - 避免
@Autowired字段注入
日志规范(完整示例)
java
@Slf4j
public class BusinessService {
public void processOrder(OrderDTO order) {
log.info("开始处理订单,订单号:{}", order.getOrderNo());
try {
log.debug("订单处理详情:{}", JSON.toJSONString(order));
// 业务逻辑
} catch (Exception e) {
log.error("订单处理失败,订单号:{},错误信息:", order.getOrderNo(), e);
throw e;
}
log.info("订单处理完成,订单号:{}", order.getOrderNo());
}
}
异常处理(完整示例)
java
public void validateOrder(OrderDTO order) {
if (order == null) {
throw new BusinessException(OrderMsg.ORDER_NOT_FOUND);
}
if (StringUtils.isEmpty(order.getOrderNo())) {
throw new BusinessException(OrderMsg.ORDER_NO_REQUIRED);
}
}
中间件与数据访问(节选)
- MyBatis-Plus:PO 继承统一
BaseModel;禁止SELECT *;禁止循环打 DB;必须用#{} - 消息:使用团队封装的
PlatformMQProducer(示例名),避免直接使用原生客户端 API - 搜索:若依赖 platform-v2 搜索组件,需在规则中写明「仅在某运行环境下启用」,例如:
xml
<dependency>
<groupId>com.yourorg.platform.v2</groupId>
<artifactId>platform-search-es-api</artifactId>
<version>${platform.v2.version}</version>
</dependency>
事务注解(脱敏)
-
使用团队统一事务注解(示例名
@PlatformTransactional)标记事务方法 -
缩小事务边界;事务内尽量避免远程调用与 MQ;提交后再发消息可用
TransactionSynchronizationManager等模式速查 A:Adapter 层 Controller 与异常处理(完整代码示例,脱敏)
java@Api(tags = "业务模块名称") @RequiredArgsConstructor @RestController @RequestMapping("/admin/module/action") public class ModuleAdminAction { private final ModuleAdminService moduleAdminService; @ApiOperation("业务操作描述") @Action(name = "操作名称", value = "UNIQUE_ACTION_CODE", order = 50) @PostMapping(value = "actionMethod") public Response<ReturnType> actionMethod(@RequestBody RequestType request) { ReturnType result = moduleAdminService.businessMethod(request); return Response.ok(result); } }
java
@Api(tags = "商品管理")
@RequiredArgsConstructor
@RestController
@RequestMapping("/admin/gen/sku/action")
public class GenSkuAdminAction {
private final GenSkuAdminService genSkuAdminService;
@ApiOperation("商品-分页查询")
@Action(name = "商品-分页查询", value = "GEN_SKU_PAGE_QUERY_ACTION", order = 10)
@PostMapping(value = "pageQueryAction")
public Response<Paging<GenSkuMdDTO>> pageQueryAction(@RequestBody GenSkuPageRequest request) {
Paging<GenSkuMdDTO> result = genSkuAdminService.pageQuery(request);
return Response.ok(result);
}
}
java
@PostMapping(value = "businessAction")
public Response<ResultType> businessAction(@RequestBody RequestType request) {
try {
ResultType result = appService.process(request);
return Response.ok(result);
} catch (BusinessException e) {
throw e;
} catch (Exception e) {
log.error("系统异常", e);
throw new SystemException("系统处理异常");
}
}
速查 B:MyBatis-Plus 依赖、配置与 Repository 查询(完整示例,脱敏)
xml
<dependency>
<groupId>com.yourorg.platform.common</groupId>
<artifactId>platform-spring-boot-starter-mybatis</artifactId>
</dependency>
yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:appdb}?autoReconnect=true&tcpKeepAlive=true&useUnicode=true&characterEncoding=UTF8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: ${MYSQL_USERNAME:root}
password: ${MYSQL_PASSWORD:root}
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
type-handlers-package: com.yourorg.platform.app.mybatis.typehandler
type-aliases-package: com.yourorg.platform.app.workbench.*.repository.po
java
default List<EntityPO> listByIds(Collection<Long> ids, String... fields) {
if (CollectionUtils.isEmpty(ids)) {
return Lists.newArrayList();
}
QueryWrapper<EntityPO> queryWrapper = new QueryWrapper<>();
if (fields != null && fields.length > 0) {
queryWrapper.select(fields);
}
queryWrapper.lambda().in(EntityPO::getId, ids);
return selectList(queryWrapper);
}
速查 C:MQ 消费者模板(完整示例,脱敏)
java
@Slf4j
@RequiredArgsConstructor
@MQConsumer(consumerGroup = "${GID_MODULE_GROUP:GID_MODULE_GROUP}")
public class ModuleMqListener {
private final ModuleAppService moduleAppService;
@MQSubscribe(topic = "${platform.mq.topic:}", tag = {MqConstant.MODULE_TAG})
public void processMessage(List<DataType> dataList) {
log.info("[业务消息监听]收到监听消息,消息数量:{}", dataList.size());
if (CollectionUtils.isEmpty(dataList)) {
log.warn("接收到空消息列表");
return;
}
try {
moduleAppService.processData(dataList);
log.info("[业务消息监听]消息处理完成");
} catch (Exception e) {
log.error("[业务消息监听]消息处理异常", e);
throw e;
}
}
}
速查 D:App 层批量写库示例(完整示例)
java
@Service
@AllArgsConstructor
@Slf4j
public class GenLabelAppService {
private final GenLabelLinkMdRepo genLabelLinkMdRepo;
private final IdGenerator idGenerator;
public void genAdaptModelLabelSave(GenLabelLinkMdReq request) {
log.info("开始保存商品标签关联,请求参数:{}", JSON.toJSONString(request));
if (request == null || CollectionUtils.isEmpty(request.getLabelIds())) {
throw new BusinessException(GenMsg.LABEL_IDS_REQUIRED);
}
List<GenLabelLinkMdPO> linkList = request.getLabelIds().stream()
.map(labelId -> {
GenLabelLinkMdPO link = new GenLabelLinkMdPO();
link.setId(idGenerator.nextId());
link.setModelId(request.getModelId());
link.setLabelId(labelId);
return link;
})
.collect(Collectors.toList());
genLabelLinkMdRepo.saveBatch(linkList);
log.info("商品标签关联保存完成,保存数量:{}", linkList.size());
}
}
速查 E:事务提交后发送消息(完整示例,脱敏注解名)
java
@Service
@RequiredArgsConstructor
public class OrderAppService {
@PlatformTransactional
public void processOrderBatch(List<OrderDTO> orders) {
if (CollectionUtils.isEmpty(orders)) {
return;
}
orders.forEach(order -> {
validateOrder(order);
saveOrder(order);
updateInventory(order);
});
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
messageProducer.sendOrderMessage(orders, MqConstant.ORDER_PROCESSED);
}
});
}
}
说明:
@PlatformTransactional为脱敏后的占位注解名,请替换为团队实际提供的事务注解。
五、辅助规则示例:代码分析与 Git
5.1 代码分析规则(完整)
markdown
---
description: 代码分析规则
globs:
alwaysApply: false
---
# 代码分析规则
## 目标
根据代码入口深入分析完整业务流程,生成详细的业务流程文档,便于团队理解和维护代码。
## 关键规则
- **必须生成分析文档保存到项目的 docs 目录下**
- **必须使用 sequential-thinking 辅助分析**
- **必须深入方法内部逻辑,因此你可能需要检索代码**
- **建议使用 sequential-thinking 辅助检索代码**
### 1. 聚焦业务核心逻辑
- 忽略日志打印、参数基础校验等次要逻辑
- 忽略异常处理中的技术细节,只关注业务异常处理逻辑
- 忽略与业务无关的工具方法调用(如字符串处理、集合操作等)
- 聚焦业务状态转换、流程分支、核心计算等关键逻辑
### 2. 深入方法调用链
- 追踪每个关键方法的内部实现,不仅停留在方法调用层面
- 对调用链上的每个重要方法都分析其内部业务逻辑
- 对于外部依赖的服务(如 RPC 调用),说明其功能和业务意义
- 深入分析每个关键业务分支的条件和处理逻辑
### 3. 结合已有文档
- 优先使用已有文档中的描述,避免重复分析
- 如果已有文档对某个方法有详细描述,直接引用该内容
- 基于已有文档进行补充和完善
- 对已有文档与代码实现不一致的地方进行标注
### 4. 文档输出规范
- 分析结果保存到 `/docs` 目录下,使用 Markdown 格式
- 文档命名格式:`业务名称-流程分析.md`(如:`订单创建-流程分析.md`)
- 文档需包含方法调用树,清晰展示调用层级关系
- 使用分步业务流程描述完整处理过程
## 文档结构模板
```markdown
# 业务名称流程分析
## 功能概述
[简要描述该业务功能的目的和作用]
## 入口方法
`com.example.Class.method`
## 方法调用树
入口方法
├─ 一级调用方法1
│ ├─ 二级调用方法1.1
│ ├─ 二级调用方法1.2
├─ 一级调用方法2
├─ 二级调用方法2.1
└─ 二级调用方法2.2
└─ 三级调用方法
## 详细业务流程
1. [步骤1:业务逻辑描述]
2. [步骤2:业务逻辑描述]
- [子步骤2.1:详细逻辑]
- [子步骤2.2:详细逻辑]
3. [步骤3:业务逻辑描述]
## 关键业务规则
- [规则1:描述业务规则及其条件]
- [规则2:描述业务规则及其条件]
## 数据流转
- 输入:[描述方法输入及其业务含义]
- 处理:[描述关键数据处理和转换]
- 输出:[描述方法输出及其业务含义]
## 扩展点/分支逻辑
- [分支1:触发条件及处理逻辑]
- [分支2:触发条件及处理逻辑]
## 外部依赖
- 标注对外部系统的依赖
## 注意事项
- [列出实现中需要特别注意的点]
系统交互图
- 如果业务流程包含多个系统模块,请使用 PlantUML 画出时序图
代码分析技巧
步骤1:明确业务入口
- 确定代码分析的起点(通常是 Controller、Action 层的公开方法)
- 了解该方法的调用场景和业务背景
步骤2:构建方法调用树
- 从入口方法开始,追踪所有重要的方法调用
- 使用缩进表示调用层级,清晰展示调用关系
- 忽略非核心方法调用(如日志、参数校验等)
步骤3:分析业务流程
- 按照代码执行顺序分析业务处理步骤
- 重点关注业务状态转换和分支逻辑
- 提取关键业务规则和数据处理逻辑
步骤4:整理业务规则
- 总结条件判断中隐含的业务规则
- 分析不同场景下的处理差异
- 提炼业务逻辑的核心决策点
步骤5:描述数据流转
- 分析关键数据的来源、处理和去向
- 说明数据模型转换和业务含义
- 关注核心业务实体的状态变化
好的分析的特征
-
完整性:覆盖所有核心业务逻辑和分支
-
层次性:清晰展示处理流程的层次结构
-
业务性:以业务视角描述,而非技术实现细节
-
精确性:准确反映代码的实际处理逻辑
-
可理解性:业务人员也能理解的表述方式
-
实用性:帮助读者快速理解业务流程和规则
5.2 Git 分支与提交(完整)
markdown--- description: Git 分支管理与提交规则 globs: alwaysApply: false --- # Git 分支管理与提交规则 ## 分支命名规范 ### 主要分支 - `develop`: 主开发分支,所有 MR 提交至此分支 - `release/<major>.<minor>`: 生产发版分支,用于回归测试和发布 - `sprint/<major>.<minor>`: 送测分支,基于迭代检出,release 后删除 ### 开发分支 - `feature/<your-feature>`: 功能特性分支,用于新功能开发 - `bugfix/<what-you-want-to-fix>`: 基于 develop 分支的 bug 修复分支 - `hotfix/<what-you-want-to-fix>`: 基于 release 分支的紧急修复分支 ## Git Commit Message 规范 ### 提交格式
():
### CommitType 类型
- `fix`: 修复性提交,针对缺陷或 Issue
- `feat`: 特性提交,新增功能或 API
- `docs`: 文档提交,增加或修改文档
- `perf`: 优化性提交,功能重构或性能优化
- `test`: 单元测试提交,增加或调整测试
- `chore`: 其他杂项,如配置文件、脚本等
- `refactor`: 重构
### Module 模块
- `model`: 模型部分
- `scene`: 场景部分
- `flow`: 流程部分
- `connector`: 连接器部分
- `console`: 控制台部分
- `common`: 公共部分
### 示例
feat(common): Move builtin field type to builtin fields module
fix(model): Fix data validation error in user model
docs(readme): Update installation instructions
## 分支操作规范
### 代码合并原则
1. **从 develop 合并到 feature**: 使用 `git rebase develop`
2. **从 feature 合并到 develop**: 使用 `git merge feature/<branch-name>`
3. **hotfix 分支**: 需要同时提 MR 至 release 分支和 cherry-pick 至 develop 分支
### 推荐工作流程
1. 创建 feature 分支前先拉取最新 develop 分支
2. feature 分支开发过程中定期 rebase develop 内容
3. 提交前确保代码编译通过且单测执行成功
4. 解决冲突时使用 `git add .` 和 `git rebase --continue`,不要使用 `git commit`
## 代码质量要求
- 每次 git push 触发 pipeline,确保代码编译通过
- 单元测试必须执行成功
- 提交信息应简洁明了,必要时附上任务 ID
## 注意事项
- feature/develop 分支仅用于部署联调环境
- 部署联调环境时,将 feature 分支 merge 至 feature/develop
- MVP 阶段后,所有合并必须通过 MR (Merge Request)
- release 分支只允许文档补充和 bugfix,不允许新特性直接合并
附录 E:Adapter / App 层 .mdc 全文(脱敏)
以下为《最佳实战》原文两份入口层规则的正文级复制,可存为 .cursor/rules/adapter.mdc、app.mdc。已做替换:消息 topic 占位符统一为 ${platform.mq.topic:};消息体类型为 PlatformMessage ;事务注解为 @PlatformTransactional(请按贵司实际 API 替换)。路径说明中的笔误「action``」已改为「action`」。
E.1 Adapter 层开发规范(.mdc)
markdown
---
description: Adapter层开发规范
globs:
alwaysApply: false
---
# Adapter层开发规范
## Adapter层职责定义
Adapter层负责适配不同触点场景,包括API、Admin、PC、H5、App等,是系统的入口层。
## 核心约束
### 调用限制
- **只能调用App层代码**,禁止直连Domain/Infrastructure层
- 不同触点使用不同包和path前缀进行隔离
### 包结构要求
```
adapter/
├── tenant/ # 租户端接口
├── admin/ # 运营端接口
└── api/ # 模块间接口
```
## Controller开发规范
### 基础结构模板
```java
@Api(tags = "业务模块名称")
@RequiredArgsConstructor
@RestController
@RequestMapping("/admin/module/action") // 按触点区分path前缀
public class ModuleAdminAction {
private final ModuleAdminService moduleAdminService; // 只能注入App层服务
@ApiOperation("业务操作描述")
@Action(name = "操作名称", value = "UNIQUE_ACTION_CODE", order = 50)
@PostMapping(value = "actionMethod")
public Response<ReturnType> actionMethod(@RequestBody RequestType request) {
ReturnType result = moduleAdminService.businessMethod(request);
return Response.ok(result);
}
}
```
### 路径前缀规范
- **管理端**: `/admin/{module}/action`
- **模块间API**: `/api/{module}/action`
- **H5端**: `/h5/{module}/action`
### @Action注解要求
- **name**: 业务操作的中文描述,全局唯一
- **value**: 操作代码,使用大写字母和下划线,全局唯一
- **order**: 排序字段,用于菜单排序
### 方法参数和返回值规范
- **入参**: 必须为单个入参对象,不允许多个参数
- **返回值**: 必须包装在Response<T>中
- **void方法**: 返回Response.ok()
### 完整示例
```java
@Api(tags = "商品管理")
@RequiredArgsConstructor
@RestController
@RequestMapping("/admin/gen/sku/action")
public class GenSkuAdminAction {
private final GenSkuAdminService genSkuAdminService;
@ApiOperation("商品-分页查询")
@Action(name = "商品-分页查询", value = "GEN_SKU_PAGE_QUERY_ACTION", order = 10)
@PostMapping(value = "pageQueryAction")
public Response<Paging<GenSkuMdDTO>> pageQueryAction(@RequestBody GenSkuPageRequest request) {
Paging<GenSkuMdDTO> result = genSkuAdminService.pageQuery(request);
return Response.ok(result);
}
}
```
## API文档规范
### Swagger注解使用
- **@Api(tags = "模块名称")**: 定义Controller的业务模块
- **@ApiOperation("操作描述")**: 详细描述该接口的功能
- **@ApiParam**: 用于参数说明(如果需要)
### 接口文档要求
- 接口名称要清晰表达业务含义
- 操作描述要包含具体的业务场景
- 参数和返回值要有明确的类型定义
## 错误处理规范
### 统一异常处理
```java
@PostMapping(value = "businessAction")
public Response<ResultType> businessAction(@RequestBody RequestType request) {
try {
ResultType result = appService.process(request);
return Response.ok(result);
} catch (BusinessException e) {
throw e;
} catch (Exception e) {
log.error("系统异常", e);
throw new SystemException("系统处理异常");
}
}
```
### 参数校验
- 使用@Valid注解进行参数校验
- 复杂业务校验在App层处理
- 基础格式校验在请求对象中定义
## 安全规范
### 权限控制
- 使用@Action注解进行权限控制
- 不同端口的接口要有相应的权限策略
- 敏感操作要有额外的权限验证
### 数据安全
- 不要在Controller层直接处理敏感数据
- 日志中避免输出敏感信息
- 返回数据要进行脱敏处理
## 性能考虑
### 接口性能
- 避免在Controller层进行复杂计算
- 大数据量操作要考虑分页和异步处理
- 合理使用缓存减少重复计算
### 监控埋点
- 重要业务接口要有性能监控
- 异常情况要有告警机制
- 关键业务流程要有链路追踪
E.2 App 层开发规范(.mdc)
markdown
---
description: App层开发规范
alwaysApply: false
---
# App层开发规范
## App层职责定义
App层是业务入口层,负责协调各层组件完成业务功能,包括接口调用、MQ消费、定时任务执行等。
## 包结构规范
```
app/
├── service/ # 应用服务
├── consumer/ # MQ消费者
├── producer/ # MQ生产者
└── job/ # 定时任务
```
## AppService开发规范
### 基础结构模板
```java
@Service
@RequiredArgsConstructor
@Slf4j
public class ModuleAppService {
private final ModuleRepo moduleRepo; // 可直接注入Infrastructure层
private final ModuleDomainService moduleDomainService; // 注入Domain层服务
private final IdGenerator idGenerator; // 框架组件
public void businessMethod(RequestDTO request) {
// 简单CRUD可直接在App层实现
// 复杂业务逻辑调用Domain层
}
}
```
### 业务处理原则
- **简单CRUD直接在App层实现**,无需经过Domain层
- **复杂业务逻辑调用Domain层**,保持业务逻辑的复用性
- **可直接跳过Domain层访问Infrastructure层**
### 完整示例
```java
@Service
@AllArgsConstructor
@Slf4j
public class GenLabelAppService {
private final GenLabelLinkMdRepo genLabelLinkMdRepo;
private final IdGenerator idGenerator;
public void genAdaptModelLabelSave(GenLabelLinkMdReq request) {
log.info("开始保存商品标签关联,请求参数:{}", JSON.toJSONString(request));
// 参数校验
if (request == null || CollectionUtils.isEmpty(request.getLabelIds())) {
throw new BusinessException(GenMsg.LABEL_IDS_REQUIRED);
}
// 批量保存
List<GenLabelLinkMdPO> linkList = request.getLabelIds().stream()
.map(labelId -> {
GenLabelLinkMdPO link = new GenLabelLinkMdPO();
link.setId(idGenerator.nextId());
link.setModelId(request.getModelId());
link.setLabelId(labelId);
return link;
})
.collect(Collectors.toList());
genLabelLinkMdRepo.saveBatch(linkList);
log.info("商品标签关联保存完成,保存数量:{}", linkList.size());
}
}
```
## MQ消费者规范
### 消费者结构模板
```java
@Slf4j
@RequiredArgsConstructor
@MQConsumer(consumerGroup = "${GID_MODULE_GROUP:GID_MODULE_GROUP}")
public class ModuleMqListener {
private final ModuleAppService moduleAppService;
@MQSubscribe(topic = "${platform.mq.topic:}", tag = {MqConstant.MODULE_TAG})
public void processMessage(List<DataType> dataList) {
log.info("[业务消息监听]收到监听消息,消息数量:{}", dataList.size());
if (CollectionUtils.isEmpty(dataList)) {
log.warn("接收到空消息列表");
return;
}
try {
moduleAppService.processData(dataList);
log.info("[业务消息监听]消息处理完成");
} catch (Exception e) {
log.error("[业务消息监听]消息处理异常", e);
throw e; // 重新抛出异常,触发重试机制
}
}
}
```
### 消费者开发要点
- 使用@MQConsumer注解定义消费者组
- 使用@MQSubscribe注解订阅特定topic和tag
- 消费方法要有完善的日志记录
- 异常要适当处理,决定是否重试
### 完整示例
```java
@Slf4j
@RequiredArgsConstructor
@MQConsumer(consumerGroup = "${GID_OMS_ORDER_GROUP:GID_OMS_ORDER_GROUP}")
public class OmsOrderPushSoListener {
private final OmsOrderPushSoService omsOrderPushSoService;
@MQSubscribe(topic = "${platform.mq.topic:}", tag = {MqConstant.OMS_ORDER_PUSH_SO})
public void orderPushSo(List<Long> orderIds) {
log.info("[渠道订单下推SO监听]收到监听消息,订单数量:{}", orderIds.size());
if (CollectionUtils.isEmpty(orderIds)) {
log.warn("接收到空订单ID列表");
return;
}
try {
for (Long orderId : orderIds) {
omsOrderPushSoService.pushSingleOrder(orderId);
}
log.info("[渠道订单下推SO监听]所有订单处理完成");
} catch (Exception e) {
log.error("[渠道订单下推SO监听]订单处理异常,订单IDs:{}", orderIds, e);
throw e;
}
}
}
```
## 定时任务规范
### 任务配置文件(job_definition.json)
```json
[
{
"module": "{模块}",
"jobKey": "JOB_KEY",
"jobName": "{任务描述}",
"jobType": "Crontab",
"execType": "Default",
"crontab": "{cron表达式}",
"params": "{}",
"extraInfo": "{}",
"status": "ENABLED"
}
]
```
### 定时任务执行类
```java
@Slf4j
@Component
@RequiredArgsConstructor
public class ModuleScheduledJob {
private final ModuleAppService moduleAppService;
/**
* 定时任务描述
* cron表达式说明
*/
@Job(JobConst.JOB_KEY)
public void executeScheduledTask() {
log.info("开始执行定时任务:{}", JobConst.JOB_KEY);
try {
moduleAppService.processScheduledTask();
log.info("定时任务执行完成:{}", JobConst.JOB_KEY);
} catch (Exception e) {
log.error("定时任务执行异常:{}", JobConst.JOB_KEY, e);
// 根据业务需求决定是否重新抛出异常
}
}
}
```
### 定时任务开发要点
- 使用@Job注解标记定时任务方法
- 任务名称要与配置文件中的jobKey保持一致
- 要有完善的日志记录和异常处理
- 长时间运行的任务要考虑拆分和监控
### 完整示例
```java
@Slf4j
@Component
@RequiredArgsConstructor
public class TenantEnableScheduledJob {
private final GenTenantAppService genTenantAppService;
/**
* 每天0点执行租户启用任务
* cron表达式:0 0 0 * * ? 表示每天0点0分0秒执行
*/
@Job(TenantJobConst.GEN_TENANT_ENABLE_SCHEDULE_JOB)
public void executeTenantEnableJob() {
log.info("开始执行租户启用定时任务");
try {
List<Long> pendingTenantIds = genTenantAppService.getPendingEnableTenants();
log.info("待启用租户数量:{}", pendingTenantIds.size());
if (CollectionUtils.isNotEmpty(pendingTenantIds)) {
genTenantAppService.batchEnableTenants(pendingTenantIds);
log.info("批量启用租户完成,启用数量:{}", pendingTenantIds.size());
}
log.info("租户启用定时任务执行完成");
} catch (Exception e) {
log.error("租户启用定时任务执行异常", e);
// 根据业务需求决定是否需要告警
}
}
}
```
## 消息生产者规范
### 消息发送服务
```java
@Service
@RequiredArgsConstructor
@Slf4j
public class ModuleMessageProducer {
private final EventProducer eventProducer;
@Value("${MQ_TOPIC:MODULE_MQ_TOPIC}")
private String normalTopic;
public void sendBusinessMessage(BusinessDTO businessData, String tag) {
log.info("准备发送业务消息,tag:{}", tag);
PlatformMessage platformMessage = new PlatformMessage();
platformMessage.setBody(businessData);
platformMessage.setTags(tag);
platformMessage.setTopic(normalTopic);
// send方法默认持久化,支持可靠性投递
Long result = eventProducer.send(platformMessage);
if (Objects.isNull(result)) {
log.error("消息发送失败,数据:{}", JSON.toJSONString(businessData));
throw new BusinessException(ModuleMsg.MESSAGE_SEND_FAILED);
}
log.info("业务消息发送成功,消息ID:{}", result);
}
}
```
## 事务处理规范
### 事务使用原则
- 使用@PlatformTransactional注解标记事务方法
- 尽可能缩小事务粒度,避免大事务
- 事务方法内避免远程调用和MQ发送
### 事务处理示例
```java
@Service
@RequiredArgsConstructor
public class OrderAppService {
@PlatformTransactional
public void processOrderBatch(List<OrderDTO> orders) {
if (CollectionUtils.isEmpty(orders)) {
return;
}
// 批量处理,减少事务时间
orders.forEach(order -> {
validateOrder(order);
saveOrder(order);
updateInventory(order);
});
// 事务提交后发送消息
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
messageProducer.sendOrderMessage(orders, MqConstant.ORDER_PROCESSED);
}
});
}
}
```