共160行

自定义注解demo-记录日志

2026-05-08 18:58:31

自定义注解demo-记录日志

📖 @NeedUpdateRecord 注解原理详解

1. 注解定义(第8-12行)

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedUpdateRecord {
    String modal() default "";
}

作用: 标记需要记录操作日志的方法,modal 参数指定业务模块类型(如 "activity")。


2. AOP 切面实现(UpdateRecordAspect.java)

@Aspect
@Component
public class UpdateRecordAspect {

    @Autowired
    private ActivityUpdateRecordService activityUpdateRecordService;

    // 方法执行成功后触发
    @AfterReturning(value = "@annotation(needUpdateRecord)&&args(po,..)")
    public void doUpdateRecord(NeedUpdateRecord needUpdateRecord, ZyActivityPO po) {
        if (ModalEnum.Activity.getCode().equals(needUpdateRecord.modal())) {
            activityUpdateRecordService.saveRecordByActivity(po);
        }
    }
}

关键点:


3. 实际使用场景(ActivityServiceImpl.java:292-304行)

@Transactional(rollbackFor = Exception.class)
@NeedUpdateRecord(modal = "activity")  // ← 标记需要记录日志
public void savePO(ZyActivityPO po, List<Long> activityRuleIdList) {
    this.savePO(po);  // 保存活动
    
    // 删除旧的活动规则关联
    Optional.ofNullable(po.getId())
            .map(zyRelationActivityActivityRuleDAO::findByZyActivityId)
            .ifPresent(zyRelationActivityActivityRuleDAO::deleteInBatch);
    
    // 创建新的活动规则关联
    activityRuleIdList.stream()
            .map(x -> new ZyRelationActivityActivityRulePO(po.getId(), x))
            .forEach(zyRelationActivityActivityRuleDAO::save);
}

4. 记录日志的实现(ActivityUpdateRecordServiceImpl.java:32-42行)

@Override
public void saveRecordByActivity(ZyActivityPO po) {
    // 查询活动的详细信息(包含关联数据)
    ZyActivityPageParams params = new ZyActivityPageParams();
    params.setId(po.getId());
    params.setPageNum(1);
    params.setPageSize(1);
    ZyActivityPageVO contentVO = activityService.page(params).getList().get(0);
    
    // 只有非草稿状态才记录
    if (ZyActivityStatusEnum.DRAFT.getId() != po.getStatus()) {
        zyActivityUpdateRecordDAO.save(
            new ZyActivityUpdateRecordPO(
                po.getId(), 
                contentVO,           // 保存活动的完整快照(JSON格式)
                myRequestUtil.fixGetLoginUid()  // 操作人ID
            )
        );
    }
}

🎯 完整工作流程

用户调用 add() 或 update()
   ↓
通过 Spring 代理调用 savePO()
   ├─ @Transactional 开启事务
   └─ 执行业务逻辑
       ├─ 保存活动数据
       ├─ 更新活动规则关联
       └─ 方法成功返回
           ↓
   @AfterReturning 切面触发
       ├─ 检查 modal 类型("activity")
       └─ 调用 saveRecordByActivity()
           ├─ 查询活动完整信息
           ├─ 生成 JSON 快照
           └─ 保存到 zy_activity_update_record 表

💡 设计优势

1. 解耦业务逻辑和日志记录

2. 统一日志格式

3. 灵活扩展

4. 不影响主流程


⚠️ 注意事项

必须通过代理调用才能生效!

// ❌ 错误:this 调用,AOP 不生效
this.savePO(po, params.getActivityRuleIdList());

// ✅ 正确:通过 Spring 容器获取代理对象
SpringUtil.getBean(ActivityServiceImpl.class).savePO(po, params.getActivityRuleIdList());

这就是为什么你的代码使用了 SpringUtil.getBean() 而不是 this 调用的原因!