用 Claude Code 写 Java 项目,是不是会遇到:

让它写个用户查询接口,它倒是挺勤快,唰唰唰给你生成一段代码。你定睛一看——直接返回 Entity,URL 写成 /user/{id},异常处理就一句 throw new RuntimeException("用户不存在")

你会气着反问它:咱项目不是规定返回 DTO 吗?

那一刻我突然意识到,没配 CLAUDE.md 的 Claude Code,就像一个智商 140 但第一天入职的实习生——聪明是真聪明,但你们项目的规矩、你们团队的忌讳、你们领导在 Code Review 里会骂什么,它一概不知。每次写代码都在盲猜,猜对了算运气,猜错了你擦屁股。

后来我在项目根目录扔了份 CLAUDE.md,情况彻底变了。它突然就知道用构造器注入了,知道 JPA 不许在循环里调数据库,知道错误响应必须用 ProblemDetail。生成的代码拿过来,基本能直接过 Review。

今天把这份模板完整分享出来,顺便讲讲每段背后的门道。

CLAUDE.md 是啥?

说白了,它就是项目根目录下的一个 Markdown 文件,Claude Code 每次启动会自动读。你可以把它理解为给 AI 看的「员工手册」——你们项目用 Java 21 还是 17,分层怎么分,哪些写法是红线,全写在里面。

它的作用层次大概这样:

  • CLAUDE.md:每次必加载,写核心禁令和架构大方向

  • .claude/skills/:按需加载,具体场景的细化规范

  • .claude/agents/:子代理,处理专项任务

图片

你不需要一上来就搞得很复杂。一份好的 CLAUDE.md,足够让 Claude Code 从「野生码农」变成「懂规矩的队友」。

完整模板

下面的内容,复制到项目根目录的 CLAUDE.md 里,改改包名和版本号就能用。我按段落解释为什么这么写。

# CLAUDE.md — Java SpringBoot 项目规范

## 技术栈

- Java: 21(LTS 版本,强制)
- Spring Boot: 3.2.x
- 数据库: MySQL 8.0 或 PostgreSQL 15
- 构建工具: Maven(使用 ./mvnw,不要直接用 mvn)
- 测试框架: JUnit 5 + Testcontainers(集成测试禁止使用 H2)

## 架构规范

### 分层结构

src/main/java/com.company.project/
├── controller/     # REST 端点,只做参数校验和调用 service
├── service/        # 业务逻辑,接口以 I 前缀命名
├── repository/     # 数据访问,继承 JpaRepository
├── model/          # JPA 实体类
├── dto/            # 请求/响应 DTO,不要把 Entity 直接暴露给 API
├── config/         # Spring 配置类
└── exception/      # 自定义异常 + 全局异常处理

### 命名规范

- 包命名:com.company.模块名.层级
- 类命名:大驼峰,Service 接口加 I 前缀(如 IUserService)
- 方法命名:小驼峰,动词开头(如 getUserById、createOrder)
- 常量命名:全大写下划线分隔(如 MAX_RETRY_COUNT)

## 代码规范

### Controller 层

- 使用 @RestController + @RequestMapping
- 统一返回 ResponseEntity<ResponseDTO<T>>
- 参数校验使用 @Valid,不要在 controller 里写 if 判断
- 错误响应使用 ProblemDetail(Spring Boot 3.x 内置,RFC 7807 标准)
- URL 路径使用名词复数:/users 而不是 /getUsers

正确写法:
@PostMapping("/users")
public ResponseEntity<ResponseDTO<UserDTO>> createUser(
    @Valid @RequestBody CreateUserRequest request) {
    return ResponseEntity.ok(ResponseDTO.success(userService.createUser(request)));
}

禁止写法:
@PostMapping("/users")
public UserDTO createUser(@RequestBody CreateUserRequest request) {
    if (request.getName() == null) {
        throw new RuntimeException("name is null");
    }
    return userService.createUser(request);
}

### Service 层

- 使用构造器注入,不要用 @Autowired 字段注入
- 事务注解 @Transactional 只加在 Service 实现类上,不要加在接口上
- 跨服务调用不要嵌套 @Transactional,容易出事务穿透问题

正确写法:
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements IUserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
}

禁止写法:
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserRepository userRepository;
}

### Repository 层(JPA 规范)

- 使用 DTO Projection 替代直接返回 Entity
- 关联查询优先使用 @EntityGraph 或 JPQL JOIN FETCH
- 禁止在循环里调用 repository 方法(N+1 问题)
- 分页查询必须使用 Pageable 参数
- 禁止在 @OneToMany 上使用 FetchType.EAGER

正确写法:
@Query("SELECT new com.company.dto.UserDTO(u.id, u.name, u.email)
        FROM User u WHERE u.id = :id")
Optional<UserDTO> findUserDTOById(@Param("id") Long id);

禁止写法:
Optional<User> findById(Long id); // 然后直接 return 给 API

### 异常处理

- 业务异常继承 BusinessException,包含错误码和错误信息
- 全局异常处理使用 @RestControllerAdvice
- 不允许直接 throw new RuntimeException("xxx"),必须使用自定义异常
- 日志记录使用 SLF4J,不允许使用 System.out.println

正确写法:
throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户不存在: " + userId);

禁止写法:
throw new RuntimeException("用户不存在");

## 工作流规范

### Plan Mode(重要)

任何非简单任务都必须先进入 Plan Mode,写详细方案后再执行。

触发条件:
- 超过 3 个步骤的任务 → Plan Mode
- 涉及架构决策 → Plan Mode
- 修改核心业务逻辑 → Plan Mode
- 数据库 Schema 变更 → Plan Mode

工作流四阶段:探索(理解需求)→ 计划(写方案)→ 实施(写代码)→ 提交(验证)

### 每次修改后必须执行

./mvnw test
./mvnw checkstyle:check

测试通过才能提交,不允许跳过。

## 明确禁止的模式

- 禁止直接将 Entity 暴露在 API 响应里
- 禁止在 @OneToMany 上使用 FetchType.EAGER
- 禁止在循环里调用数据库方法
- 禁止使用 System.out.println 输出日志
- 禁止 catch 所有异常后 log.error("失败") 就完事,必须区分异常类型
- 禁止直接在 Controller 里写业务逻辑
- 禁止跳过测试提交代码
- 禁止修改已有的数据库迁移文件,只能新增

## API 设计规范

- URL 路径使用名词复数:/users 而不是 /getUsers
- HTTP 方法语义正确:GET 查询,POST 创建,PUT 全量更新,PATCH 部分更新,DELETE 删除
- 版本管理:URL 路径前缀 /api/v1/
- 分页接口返回 Page 对象,包含 totalElements 和 totalPages
- 所有时间字段使用 ISO 8601 格式(LocalDateTime + @JsonFormat)

## Git 提交规范

格式:类型(范围): 描述

类型:
- feat: 新功能
- fix: Bug 修复
- refactor: 重构(不涉及功能变化)
- test: 测试相关
- docs: 文档修改
- chore: 构建/配置相关

示例:feat(user): 添加用户手机号绑定功能

技术栈:别让它瞎猜

Java: 21(LTS 版本,强制)Spring Boot: 3.2.x数据库: MySQL 8.0 或 PostgreSQL 15构建工具: Maven(使用 ./mvnw,不要直接用 mvn)测试框架: JUnit 5 + Testcontainers(集成测试禁止使用 H2)

这段看着像废话,但不写的话,AI 真的会乱来。我见过 Claude Code 默认推荐 Java 17 的语法,或者顺手给你用 H2 跑集成测试——如果你的团队明确规定用 Testcontainers 模拟真实数据库,这就踩雷了。

把技术栈钉死,相当于告诉它:「在这个项目里,别跟我玩花的,按这个来。」

架构规范:分层不是摆设

src/main/java/com.company.project/├── controller/     # 只做参数校验和调 service├── service/        # 业务逻辑,接口以 I 前缀命名├── repository/     # 数据访问├── model/          # JPA 实体├── dto/            # 请求/响应 DTO,Entity 不许直接暴露给 API├── config/         # Spring 配置└── exception/      # 自定义异常 + 全局处理

很多团队的分层规范只存在于老员工的脑子里,新人靠猜。现在你把分层写进 CLAUDE.md,AI 生成的代码自然会对号入座——Controller 里不会冒出业务逻辑,Service 接口会按 IUserService 这种风格命名。

代码规范:把 Review 的口水战扼杀在摇篮里

Controller 层

  • 统一返回 ResponseEntity<ResponseDTO<T>>

  • 参数校验用 @Valid,不许在 Controller 里写 if 判断

  • 错误响应用 ProblemDetail(Spring Boot 3.x 内置,RFC 7807 标准)

  • URL 必须用名词复数:/users,不是 /getUsers

Service 层

  • 构造器注入,禁止 @Autowired 字段注入

  • @Transactional 只加在实现类上,不许加在接口上

  • 跨服务调用不许嵌套事务,容易穿透

Repository 层

  • 用 DTO Projection,不许直接返回 Entity 给 API

  • 关联查询优先用 @EntityGraph 或 JOIN FETCH

  • 循环里禁止调 repository(N+1 的罪魁祸首)

  • 分页必须用 Pageable

  • @OneToMany 禁止用 FetchType.EAGER

这些规范不是拍脑袋想的,是无数个项目里踩过坑、被骂过、半夜修过生产事故之后总结出来的。现在把它们写进 CLAUDE.md,相当于让 AI 替你扛住第一波错误。

异常处理:别再用 RuntimeException 糊弄了

throw new BusinessException(ErrorCode.USER_NOT_FOUND, "用户不存在: " + userId);

禁止直接 throw new RuntimeException("xxx"),必须走自定义异常。日志用 SLF4J,禁止 System.out.println

这看起来是小事,但生产环境的日志规范就是从这些「小事」里烂掉的。一个项目里如果到处抛 RuntimeException,你排查问题的时候连错误码都搜不到。

工作流:Plan Mode 是灵魂

任何非简单任务都必须先进入 Plan Mode,写详细方案后再执行。触发条件:- 超过 3 个步骤的任务- 涉及架构决策- 修改核心业务逻辑- 数据库 Schema 变更

这段是整份文件里最有价值的内容之一。

不配这个,你问 Claude Code「帮我设计一个订单服务」,它可能直接开始写 Entity 和 Controller。配了 Plan Mode,它会先给你一份方案——服务边界在哪、API 怎么设计、数据模型怎么关联,等你确认后再动手。

这省下的不是一点时间,是返工的血泪

禁止模式:把团队的「黑名单」写进去

禁止直接将 Entity 暴露在 API 响应里禁止在循环里调用数据库方法禁止 catch 所有异常后 log.error("失败")就完事禁止跳过测试提交代码禁止修改已有的数据库迁移文件,只能新增

有效的规则是具体且可测试的。「禁止在循环里调用数据库方法」比「避免 N+1 问题」管用一百倍。前者 Claude Code 能直接执行,后者它还得自己理解什么叫「避免」。

API 设计 & Git 提交:收尾的体面

API 规范包括 URL 名词复数、HTTP 方法语义正确、版本前缀 /api/v1/、分页返回带 totalElements 和 totalPages、时间字段用 ISO 8601。

Git 提交用常规格式:feat(user): 添加用户手机号绑定功能。类型包括 feat、fix、refactor、test、docs、chore。

装上去,三步搞定

第一步:在项目根目录建文件,把模板贴进去。

第二步:改几处关键信息:

  • 技术栈版本(Java 21 还是 17,Spring Boot 3.2 还是 3.4)

  • 包名(com.company.project 换成你的)

  • Service 接口是否加 I 前缀(有些团队习惯,有些不惯,按你们的来)

  • 你们团队特有的禁止写法(比如「不许用 Map 传参」之类的)

第三步:启动 Claude Code,丢个需求验证一下。

比如你说:「帮我写一个根据 ID 查用户的接口,返回 UserDTO。」

没配 CLAUDE.md 之前,它可能给你这个:

@GetMapping("/user/{id}")
publicUsergetUser(@PathVariableLong id){
return userRepository.findById(id)
.orElseThrow(()->newRuntimeException("用户不存在"));
}

配了之后,它给的是这个:

@GetMapping("/users/{id}")
publicResponseEntity<ResponseDTO<UserDTO>>getUserById(@PathVariableLong id){
UserDTO user = userService.getUserById(id);
returnResponseEntity.ok(ResponseDTO.success(user));
}

差距一眼可见。 URL 规范了,返回格式统一了,分层对了,异常也不乱抛了。

验证完没问题,记得 git add CLAUDE.md,提交,推上去。整个团队共享,所有人的 AI 按同一套规矩干活。

维护它,别让它变成废纸

CLAUDE.md 不是写一次就完事的。三个时机记得更新:

第一,Code Review 里反复出现同一类问题。 比如最近三次 Review 都有人把 Entity 直接返回给前端,那就加一条「禁止将 Entity 暴露在 API 响应里」。

第二,团队引入新技术。 上了 Kafka?把消息消费规范写进去。换了 QueryDSL?把 JPQL 的禁止场景更新一下。

第三,之前的规范被废弃。 如果团队决定不用 I 前缀命名 Service 接口了,赶紧删掉,别让 AI 继续生成过时的代码。

最后一条原则,很重要:

CLAUDE.md 只放 AI 无法自动执行的规则。

能用 Checkstyle 强制的代码风格,别写进去。能用 SpotBugs 检查的问题,别写进去。CLAUDE.md 应该只写架构模式、业务逻辑约束、工作流指令——这些是工具检查不了、只有人和 AI 才能判断的东西。

写多了,文件臃肿,AI 加载起来也迷糊;写少了,该拦的问题拦不住。恰到好处的边界感,是这份文件的艺术。

说到底,用 Claude Code 写企业级 Java 项目,拼的不是谁 prompt 写得花,而是谁的项目规范能被 AI 准确理解并执行。

一份好的 CLAUDE.md,就是你和 AI 之间的「契约」。它让 Claude Code 从一个「聪明的陌生人」,变成「懂你们团队规矩的老搭档」。

今晚就在项目根目录建一个,明天写代码的时候,你会回来谢我的。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐