소스 정보
- 저장소
- zhangloveyan/backend-skill
- 최근 소스 활동
- 2026년 1월 20일 03:40
- 감지된 SKILL.md 언어
- 중국어
- 스타
- 97
- 포크
- 28
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
SOC 직업 분류 기준
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/zhangloveyan/backend-skill --skill proj-common명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
| name | proj-common |
| description | 查看公共类规范和使用方式。包括R响应类、ErrorCode错误码、异常处理、事务、缓存、并发控制、日志等。 |
| 类 | 包路径 | 用途 |
|---|---|---|
| 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 | 登录用户上下文 |
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();
| 场景 | 是否需要事务 |
|---|---|
| 单表写操作 | 否(MyBatis-Plus 自动处理) |
| 多表写操作 | 是 |
| 先查后改 | 是(需保证一致性时) |
| 纯查询 | 否 |
// 写操作
@Transactional(rollbackFor = Exception.class)
public void bindUserRole(Long userId, List<Long> roleIds) {
// 多表操作
}
// 只读事务(查询多表需一致性快照)
@Transactional(readOnly = true)
public UserDetailResponse getDetail(Long id) {
// 多表查询
}
@Transactional{项目}:{模块}:{业务}:{标识}
示例:toy:user:info:123、toy: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());
}
| 问题 | 解决方案 |
|---|---|
| 缓存穿透 | 空值缓存(短过期)或布隆过滤器 |
| 缓存击穿 | 分布式锁或永不过期+异步更新 |
| 缓存雪崩 | 过期时间加随机值 |
// 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);
}
| 异常类型 | 处理方式 |
|---|---|
| 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);
log.info("[类名.方法名] 操作描述, 参数={}", value);
| 级别 | 场景 |
|---|---|
| ERROR | 系统错误、影响业务的异常 |
| WARN | 潜在问题、可恢复异常 |
| INFO | 关键业务流程、重要操作 |
| DEBUG | 调试信息 |
System.out.println@Async("taskExecutor")
public void sendNotification(Long userId, String message) {
// 异步执行
}