proj-common

Installation
SKILL.md

公共类与通用规范

任务文档同步

  • 如引用本规范中的限制或约束,将关键约束记录到任务文档“上下文快照”

1. 公共类清单

包路径 用途
R common.core 统一响应类
ErrorCode common.core 错误码枚举
PageResult common.core 分页结果
BusinessException common.exception 业务异常
GlobalExceptionHandler common.exception 全局异常处理
Constants common.constant 全局常量
RedisKeys common.constant Redis Key 常量
RedisUtils common.utils Redis 工具类
AssertUtils common.utils 断言工具类
LoginUserHolder common.security 登录用户上下文

2. 快速使用

返回响应

return R.success();                    // 成功,无数据
return R.success(data);                // 成功,有数据
return R.fail(ErrorCode.NOT_FOUND);    // 失败

抛出异常

throw new BusinessException(ErrorCode.NOT_FOUND);
throw new BusinessException(ErrorCode.PARAM_ERROR, "用户名不能为空");

断言校验

AssertUtils.notNull(user, ErrorCode.NOT_FOUND);
AssertUtils.isTrue(condition, ErrorCode.PARAM_ERROR, "条件不满足");

获取登录用户

Long userId = LoginUserHolder.getUserId();
LoginUser loginUser = LoginUserHolder.get();

3. 事务规范

使用场景

场景 是否需要事务
单表写操作 否(MyBatis-Plus 自动处理)
多表写操作
先查后改 是(需保证一致性时)
纯查询

标准用法

// 写操作
@Transactional(rollbackFor = Exception.class)
public void bindUserRole(Long userId, List<Long> roleIds) {
    // 多表操作
}

// 只读事务(查询多表需一致性快照)
@Transactional(readOnly = true)
public UserDetailResponse getDetail(Long id) {
    // 多表查询
}

禁止事项

  • 禁止在 Controller 层使用 @Transactional
  • 禁止事务方法内调用同类的另一个事务方法(事务失效)
  • 禁止事务内进行 RPC/HTTP 调用
  • 禁止大事务(事务方法超过 20 行需拆分)

4. 缓存规范

Key 命名

{项目}:{模块}:{业务}:{标识}

示例:toy:user:info:123toy:order:detail:456

过期时间

数据类型 过期时间 常量
热点数据 1小时 Constants.CACHE_1_HOUR
普通数据 24小时 Constants.CACHE_1_DAY
配置数据 7天 Constants.CACHE_7_DAY
验证码 5分钟 Constants.CACHE_5_MIN

缓存策略

// 查询:先缓存后数据库
public User getById(Long id) {
    String key = RedisKeys.USER_INFO + id;
    User user = redisUtils.get(key, User.class);
    if (user == null) {
        user = userMapper.selectById(id);
        if (user != null) {
            redisUtils.set(key, user, Constants.CACHE_1_HOUR);
        }
    }
    return user;
}

// 更新:先数据库后删缓存
public void update(User user) {
    userMapper.updateById(user);
    redisUtils.delete(RedisKeys.USER_INFO + user.getId());
}

防护措施

问题 解决方案
缓存穿透 空值缓存(短过期)或布隆过滤器
缓存击穿 分布式锁或永不过期+异步更新
缓存雪崩 过期时间加随机值

5. 并发控制

乐观锁(推荐)

// Entity 添加版本字段
@Version
private Integer version;

// 更新时自动检查版本
userMapper.updateById(user);  // WHERE version = ?

适用:冲突概率低、读多写少

悲观锁

@Select("SELECT * FROM user WHERE id = #{id} FOR UPDATE")
User selectForUpdate(Long id);

适用:冲突概率高、必须成功

分布式锁

String lockKey = RedisKeys.LOCK_ORDER + orderId;
boolean locked = redisUtils.tryLock(lockKey, 10, TimeUnit.SECONDS);
if (!locked) {
    throw new BusinessException(ErrorCode.SYSTEM_BUSY);
}
try {
    // 业务逻辑
} finally {
    redisUtils.unlock(lockKey);
}

6. 异常处理

异常分类

异常类型 处理方式
BusinessException 返回错误码和消息
MethodArgumentNotValidException 返回参数校验错误
其他异常 返回系统错误,记录日志

使用规范

// 业务校验失败
if (user == null) {
    throw new BusinessException(ErrorCode.USER_NOT_FOUND);
}

// 带自定义消息
throw new BusinessException(ErrorCode.PARAM_ERROR, "手机号格式不正确");

// 使用断言(推荐)
AssertUtils.notNull(user, ErrorCode.USER_NOT_FOUND);

7. 日志规范

格式

log.info("[类名.方法名] 操作描述, 参数={}", value);

级别

级别 场景
ERROR 系统错误、影响业务的异常
WARN 潜在问题、可恢复异常
INFO 关键业务流程、重要操作
DEBUG 调试信息

禁止事项

  • 禁止在循环中打印日志
  • 禁止打印敏感信息(密码、手机号、身份证)
  • 禁止使用 System.out.println

8. 异步处理

使用场景

  • 发送通知(短信、邮件、推送)
  • 日志记录
  • 数据同步
  • 非核心业务

使用方式

@Async("taskExecutor")
public void sendNotification(Long userId, String message) {
    // 异步执行
}

禁止事项

  • 禁止异步方法内操作主流程数据(数据可能未提交)
  • 禁止异步方法抛出异常不处理
  • 禁止在同类内调用异步方法(失效)
Related skills
Installs
8
GitHub Stars
65
First Seen
Jan 25, 2026