Cursor AI 编程实战(篇二):Rules、速查与 Adapter/App 全文

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-v2PlatformTransactional 等占位符,便于公开发表;读者落地时请改回各自公司的真实坐标与 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:描述数据流转

  • 分析关键数据的来源、处理和去向
  • 说明数据模型转换和业务含义
  • 关注核心业务实体的状态变化

好的分析的特征

  1. 完整性:覆盖所有核心业务逻辑和分支

  2. 层次性:清晰展示处理流程的层次结构

  3. 业务性:以业务视角描述,而非技术实现细节

  4. 精确性:准确反映代码的实际处理逻辑

  5. 可理解性:业务人员也能理解的表述方式

  6. 实用性:帮助读者快速理解业务流程和规则

    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.mdcapp.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);
            }
        });
    }
}
```

相关推荐
三木檾1 分钟前
从 5 个文件读完一个生产级 AI Chatbot——Vercel AI Chatbot 源码拆解
ai编程·源码阅读·next.js
javahongxi2 分钟前
Spring Cloud Trace 链路实现
java·spring boot·spring cloud
海梨花4 分钟前
腾讯面试高频算法题
java·算法·面试
于先生吖5 分钟前
Java消息队列优化抢单逻辑,同城搬家拉货多场景业务数据库架构设计
java·开发语言·数据库架构
谁似人间西林客5 分钟前
工厂大脑如何让制造从“人驱”迈向“智驱”
大数据·人工智能·制造
小谢小哥6 分钟前
68-持续集成详解
java·后端·架构
财经资讯数据_灵砚智能6 分钟前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年6月3日
大数据·人工智能·python·信息可视化·自然语言处理·灵砚智能
用户925807911487 分钟前
redission原理
java·后端
小旭95277 分钟前
Spring Cloud 集成分布式日志 ELK+Swagger 接口文档实战
java·分布式·后端·elk·spring cloud