🚀 后端代码生成标准模板与代码规范约束规则
基于 OpenClaw + Claude Code 的端到端研发自动化系统
版本:v1.0.0 |
发布日期:2026 年 3 月 14 日 |
适用技术栈:Java Spring Boot / Python FastAPI / Node.js NestJS
1. 系统架构概述
🎯 核心目标:构建从需求到部署的全流程自动化研发系统,实现 AI 驱动的智能代码生成、测试和部署,支持人机协同的高效开发模式。
1.1 整体架构图
需求分析
PRD 设计
技术方案设计
前后端
API 协议设计
接口定义
AI Coding
代码生成
Unit Test
单元测试
集成测试
E2E 测试
CI/CD 部署
Docker+K8S
UI 自动化验收
质量验证
1.2 核心组件说明
| 组件名称 |
技术选型 |
职责描述 |
AI 集成度 |
| OpenClaw Agent |
Node.js + LLM |
任务调度、上下文管理、多代理协同 |
100% |
| Claude Code |
Claude Opus 4.6 |
代码理解、智能生成、重构优化 |
100% |
| 代码生成引擎 |
Template Engine + AI |
基于模板和 AI 混合的代码生成 |
80% |
| 测试生成器 |
JUnit/Pytest/Jest + AI |
自动生成单元测试和集成测试 |
90% |
| CI/CD 编排器 |
Jenkins + KubeSphere |
自动化构建、测试、部署流水线 |
70% |
| 质量门禁 |
SonarQube + AI Review |
代码质量检查、安全扫描 |
85% |
1.3 研发角色 Agents 定义
| 角色 Agent |
职责范围 |
输入 |
输出 |
| Product Agent |
需求分析、PRD 撰写、用户故事拆解 |
原始需求文档 |
结构化 PRD、用户故事地图 |
| Backend Architect Agent |
后端技术方案设计、数据库设计、API 规划 |
PRD、业务需求 |
技术架构文档、ER 图、API 清单 |
| Frontend Architect Agent |
前端技术方案设计、组件设计、状态管理 |
PRD、UI 设计稿 |
前端架构文档、组件树、状态流 |
| API Designer Agent |
前后端 API 接口协议设计、Swagger 文档 |
技术方案设计 |
OpenAPI Spec、Mock 数据 |
| Backend Developer Agent |
后端代码实现、业务逻辑开发 |
API 协议、数据库设计 |
Controller/Service/Repository 代码 |
| Frontend Developer Agent |
前端代码实现、页面开发、交互逻辑 |
API 协议、UI 设计稿 |
React/Vue组件、页面代码 |
| QA Engineer Agent |
测试用例设计、自动化测试编写 |
功能需求、API 文档 |
单元测试、集成测试、E2E 测试 |
| DevOps Agent |
CI/CD 配置、容器化部署、监控告警 |
代码仓库、环境配置 |
Jenkinsfile、Dockerfile、K8S YAML |
2. 后端代码生成标准模板体系
📦 模板设计原则:标准化、可复用、可扩展、AI 友好、人机协同
2.1 项目结构模板
Java Spring Boot 项目结构
project-root/
├── src/main/java/com/company/project/
│ ├── Application.java
│ ├── config/
│ │ ├── SecurityConfig.java
│ │ ├── SwaggerConfig.java
│ │ └── RedisConfig.java
│ ├── controller/
│ │ ├── v1/
│ │ │ ├── UserController.java
│ │ │ └── OrderController.java
│ │ └── advice/
│ │ └── GlobalExceptionHandler.java
│ ├── service/
│ │ ├── UserService.java
│ │ ├── UserServiceImpl.java
│ │ └── dto/
│ │ ├── request/
│ │ │ ├── UserCreateRequest.java
│ │ │ └── UserUpdateRequest.java
│ │ └── response/
│ │ ├── UserResponse.java
│ │ └── PageResponse.java
│ ├── repository/
│ │ ├── UserRepository.java
│ │ └── entity/
│ │ ├── User.java
│ │ └── BaseEntity.java
│ ├── common/
│ │ ├── exception/
│ │ │ ├── BusinessException.java
│ │ │ └── ResourceNotFoundException.java
│ │ ├── result/
│ │ │ └── Result.java
│ │ └── constants/
│ │ └── ErrorCode.java
│ └── util/
│ └── BeanUtils.java
├── src/main/resources/
│ ├── application.yml
│ ├── application-dev.yml
│ ├── application-prod.yml
│ └── db/migration/
│ └── V1__init_schema.sql
├── src/test/java/
│ ├── controller/
│ ├── service/
│ └── integration/
├── pom.xml
├── Dockerfile
├── docker-compose.yml
└── README.md
Python FastAPI 项目结构
project-root/
├── app/
│ ├── main.py
│ ├── api/
│ │ ├── v1/
│ │ │ ├── __init__.py
│ │ │ ├── users.py
│ │ │ └── orders.py
│ │ └── deps.py
│ ├── core/
│ │ ├── config.py
│ │ ├── security.py
│ │ └── exceptions.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── order.py
│ ├── schemas/
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── response.py
│ ├── services/
│ │ ├── __init__.py
│ │ ├── user_service.py
│ │ └── order_service.py
│ ├── db/
│ │ ├── session.py
│ │ └── base.py
│ └── utils/
│ └── helpers.py
├── tests/
│ ├── test_api/
│ ├── test_services/
│ └── conftest.py
├── alembic/
│ └── versions/
├── requirements.txt
├── Dockerfile
└── README.md
2.2 Controller 模板
Java Spring Boot Controller 标准模板
package com.company.project.controller.v1;
import com.company.project.common.result.Result;
import com.company.project.service.UserService;
import com.company.project.service.dto.request.UserCreateRequest;
import com.company.project.service.dto.request.UserUpdateRequest;
import com.company.project.service.dto.response.UserResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Tag(name = "用户管理", description = "用户相关 API 接口")
public class UserController {
private final UserService userService;
@GetMapping
@Operation(summary = "分页查询用户列表")
public Result<Page<UserResponse>> listUsers(Pageable pageable) {
return Result.success(userService.listUsers(pageable));
}
@GetMapping("/{id}")
@Operation(summary = "根据 ID 查询用户详情")
public Result<UserResponse> getUserById(@PathVariable Long id) {
return Result.success(userService.getUserById(id));
}
@PostMapping
@Operation(summary = "创建用户")
public Result<UserResponse> createUser(
@Valid @RequestBody UserCreateRequest request) {
return Result.success(userService.createUser(request));
}
@PutMapping("/{id}")
@Operation(summary = "更新用户信息")
public Result<UserResponse> updateUser(
@PathVariable Long id,
@Valid @RequestBody UserUpdateRequest request) {
return Result.success(userService.updateUser(id, request));
}
@DeleteMapping("/{id}")
@Operation(summary = "删除用户")
public Result<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return Result.success();
}
}
2.3 Service 模板
Java Spring Boot Service 标准模板
package com.company.project.service;
import com.company.project.common.exception.BusinessException;
import com.company.project.common.constants.ErrorCode;
import com.company.project.repository.UserRepository;
import com.company.project.repository.entity.User;
import com.company.project.service.dto.request.UserCreateRequest;
import com.company.project.service.dto.request.UserUpdateRequest;
import com.company.project.service.dto.response.UserResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Override
@Transactional(readOnly = true)
public Page<UserResponse> listUsers(Pageable pageable) {
log.info("查询用户列表,page={}, size={}",
pageable.getPageNumber(), pageable.getPageSize());
return userRepository.findAll(pageable)
.map(this::convertToResponse);
}
@Override
@Transactional(readOnly = true)
public UserResponse getUserById(Long id) {
log.info("查询用户详情,id={}", id);
User user = userRepository.findById(id)
.orElseThrow(() -> new BusinessException(
ErrorCode.USER_NOT_FOUND,
"用户不存在,ID: " + id));
return convertToResponse(user);
}
@Override
@Transactional
public UserResponse createUser(UserCreateRequest request) {
log.info("创建用户,username={}", request.getUsername());
if (userRepository.existsByUsername(request.getUsername())) {
throw new BusinessException(
ErrorCode.USER_ALREADY_EXISTS,
"用户名已存在:" + request.getUsername());
}
User user = User.builder()
.username(request.getUsername())
.email(request.getEmail())
.phone(request.getPhone())
.build();
user = userRepository.save(user);
log.info("用户创建成功,id={}", user.getId());
return convertToResponse(user);
}
@Override
@Transactional
public UserResponse updateUser(Long id, UserUpdateRequest request) {
log.info("更新用户信息,id={}", id);
User user = userRepository.findById(id)
.orElseThrow(() -> new BusinessException(
ErrorCode.USER_NOT_FOUND,
"用户不存在,ID: " + id));
user.updateFrom(request);
user = userRepository.save(user);
log.info("用户更新成功,id={}", id);
return convertToResponse(user);
}
@Override
@Transactional
public void deleteUser(Long id) {
log.info("删除用户,id={}", id);
if (!userRepository.existsById(id)) {
throw new BusinessException(
ErrorCode.USER_NOT_FOUND,
"用户不存在,ID: " + id);
}
userRepository.deleteById(id);
log.info("用户删除成功,id={}", id);
}
private UserResponse convertToResponse(User user) {
return UserResponse.builder()
.id(user.getId())
.username(user.getUsername())
.email(user.getEmail())
.phone(user.getPhone())
.createdAt(user.getCreatedAt())
.updatedAt(user.getUpdatedAt())
.build();
}
}
2.4 Repository 模板
Java Spring Data JPA Repository 标准模板
package com.company.project.repository;
import com.company.project.repository.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
boolean existsByUsername(String username);
Optional<User> findByEmail(String email);
@Query("SELECT u FROM User u WHERE " +
"u.username LIKE %:keyword% OR " +
"u.email LIKE %:keyword% OR " +
"u.phone LIKE %:keyword%")
Page<User> searchUsers(@Param("keyword") String keyword, Pageable pageable);
}
2.5 Entity 实体类模板
Java JPA Entity 标准模板
package com.company.project.repository.entity;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
@Entity
@Table(name = "t_user")
@EntityListeners(AuditingEntityListener.class)
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 50)
private String username;
@Column(nullable = false, unique = true, length = 100)
private String email;
@Column(length = 20)
private String phone;
@Column(nullable = false, length = 100)
private String password;
@Column(length = 500)
private String avatar;
@Column(nullable = false)
@Builder.Default
private Boolean enabled = true;
@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
@Column(nullable = false)
private LocalDateTime updatedAt;
public void updateFrom(Object dto) {
}
}
2.6 DTO 数据传输对象模板
请求对象 (Request DTO)
package com.company.project.service.dto.request;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserCreateRequest {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 50, message = "用户名长度必须在 3-50 之间")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@Size(max = 20, message = "手机号长度不能超过 20")
private String phone;
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 100, message = "密码长度必须在 6-100 之间")
private String password;
}
响应对象 (Response DTO)
package com.company.project.service.dto.response;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.*;
import java.time.LocalDateTime;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserResponse {
private Long id;
private String username;
private String email;
private String phone;
private String avatar;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updatedAt;
}
2.7 统一返回结果模板
package com.company.project.common.result;
import com.company.project.common.constants.ErrorCode;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result<T> {
private Integer code;
private String message;
private T data;
private Long timestamp;
public static <T> Result<T> success() {
return Result.<T>builder()
.code(ErrorCode.SUCCESS.getCode())
.message(ErrorCode.SUCCESS.getMessage())
.timestamp(System.currentTimeMillis())
.build();
}
public static <T> Result<T> success(T data) {
return Result.<T>builder()
.code(ErrorCode.SUCCESS.getCode())
.message(ErrorCode.SUCCESS.getMessage())
.data(data)
.timestamp(System.currentTimeMillis())
.build();
}
public static <T> Result<T> error(Integer code, String message) {
return Result.<T>builder()
.code(code)
.message(message)
.timestamp(System.currentTimeMillis())
.build();
}
public static <T> Result<T> error(ErrorCode errorCode) {
return Result.<T>builder()
.code(errorCode.getCode())
.message(errorCode.getMessage())
.timestamp(System.currentTimeMillis())
.build();
}
}
3. 代码规范约束规则
⚠️ 重要提示:所有代码规范必须被 OpenClaw 和 Claude Code 严格遵守,AI 生成的代码必须通过代码规范检查才能进入下一流程。
3.1 命名规范
| 元素类型 |
命名规则 |
示例 |
强制级别 |
| 类名 (Class) |
PascalCase (大驼峰) |
UserController, UserService |
● 强制 |
| 接口名 (Interface) |
PascalCase,可加 I 前缀 |
UserService, IRepository |
● 强制 |
| 方法名 (Method) |
camelCase (小驼峰),动词开头 |
getUserById(), createUser() |
● 强制 |
| 变量名 (Variable) |
camelCase,名词或名词短语 |
userName, orderList |
● 强制 |
| 常量名 (Constant) |
UPPER_SNAKE_CASE |
MAX_RETRY_COUNT |
● 强制 |
| 包名 (Package) |
全小写,单词间用点分隔 |
com.company.project.service |
● 强制 |
| 数据库表名 |
小写,下划线分隔,加模块前缀 |
t_user, t_order_item |
● 强制 |
| 数据库字段名 |
小写,下划线分隔 |
user_name, created_at |
● 强制 |
| REST API 路径 |
小写,复数名词,kebab-case |
/api/v1/users, /api/v1/order-items |
● 强制 |
3.2 注释规范
类注释模板
方法注释模板
行内注释规则
- 何时添加注释:复杂算法、业务规则、特殊处理、性能优化点
- 注释语言:中文注释(国内项目)或英文注释(国际化项目)
- 注释位置:行尾注释需与代码保持至少 2 个空格距离
- 禁止行为:不写废话注释(如
i++ // i 加 1)
3.3 异常处理规范
异常分类体系
| 异常类型 |
基类 |
使用场景 |
HTTP 状态码 |
| 业务异常 |
BusinessException |
业务规则校验失败 |
400 Bad Request |
| 资源未找到 |
ResourceNotFoundException |
请求的资源不存在 |
404 Not Found |
| 权限异常 |
AccessDeniedException |
无权访问资源 |
403 Forbidden |
| 数据验证异常 |
ValidationException |
参数校验失败 |
422 Unprocessable Entity |
| 系统异常 |
SystemException |
系统内部错误 |
500 Internal Server Error |
全局异常处理器模板
package com.company.project.controller.advice;
import com.company.project.common.exception.BusinessException;
import com.company.project.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<Void> handleBusinessException(BusinessException ex) {
log.warn("业务异常:{}", ex.getMessage(), ex);
return Result.error(ex.getErrorCode());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
public Result<Void> handleValidationException(
MethodArgumentNotValidException ex) {
String message = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.findFirst()
.orElse("参数验证失败");
log.warn("参数验证异常:{}", message);
return Result.error(HttpStatus.UNPROCESSABLE_ENTITY.value(), message);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<Void> handleGenericException(Exception ex) {
log.error("系统异常:{}", ex.getMessage(), ex);
return Result.error(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"系统繁忙,请稍后重试");
}
}
3.4 日志规范
日志级别使用规则
| 日志级别 |
使用场景 |
示例 |
| ERROR |
系统错误、异常堆栈、关键业务失败 |
log.error("订单创建失败", ex) |
| WARN |
业务异常、可恢复错误、重要警告 |
log.warn("用户不存在,id={}", id) |
| INFO |
关键业务流程、重要状态变更、审计日志 |
log.info("用户登录成功,userId={}", userId) |
| DEBUG |
调试信息、详细执行过程、开发环境 |
log.debug("SQL 执行时间:{}ms", duration) |
| TRACE |
最详细的跟踪信息、生产环境禁用 |
log.trace("方法入参:{}", params) |
日志内容规范
- 必须包含:关键标识符(用户 ID、订单号等)、操作类型、结果状态
- 禁止记录:敏感信息(密码、银行卡号、身份证号等)
- 格式要求:使用占位符
{},避免字符串拼接
- 异常日志:必须记录完整堆栈信息
3.5 代码质量标准
SonarQube 质量门禁
| 指标 |
阈值 |
强制级别 |
| 代码覆盖率 |
≥ 80% |
● 强制 |
| 重复代码率 |
≤ 3% |
● 强制 |
| Blocker Issues |
0 |
● 强制 |
| Critical Issues |
0 |
● 强制 |
| Major Issues |
≤ 5 |
▲ 建议 |
| 技术债务率 |
≤ 5% |
▲ 建议 |
| 圈复杂度 |
≤ 15 |
▲ 建议 |
4. API 接口开发协议标准
4.1 RESTful API 设计规范
HTTP 方法语义
| 方法 |
语义 |
幂等性 |
示例 |
| GET |
查询资源 |
是 |
GET /api/v1/users/123 |
| POST |
创建资源 |
否 |
POST /api/v1/users |
| PUT |
全量更新资源 |
是 |
PUT /api/v1/users/123 |
| PATCH |
部分更新资源 |
是 |
PATCH /api/v1/users/123 |
| DELETE |
删除资源 |
是 |
DELETE /api/v1/users/123 |
4.2 OpenAPI Specification (Swagger) 模板
openapi: "3.0.3"
info:
title: "用户管理系统 API"
description: "提供用户管理相关的完整 API 接口"
version: "1.0.0"
contact:
name: "API Support Team"
email: "api-support@company.com"
servers:
- url: "https://api.company.com/v1"
description: "生产环境"
- url: "https://dev-api.company.com/v1"
description: "开发环境"
tags:
- name: "users"
description: "用户管理相关接口"
paths:
/users:
get:
tags: [users]
summary: "分页查询用户列表"
operationId: "listUsers"
parameters:
- name: page
in: query
schema:
type: integer
default: 0
- name: size
in: query
schema:
type: integer
default: 20
responses:
"200":
description: "成功"
content:
application/json:
schema:
$ref: "#/components/schemas/UserPageResponse"
post:
tags: [users]
summary: "创建用户"
operationId: "createUser"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UserCreateRequest"
responses:
"201":
description: "创建成功"
content:
application/json:
schema:
$ref: "#/components/schemas/UserResponse"
components:
schemas:
UserCreateRequest:
type: object
required: [username, email, password]
properties:
username:
type: string
minLength: 3
maxLength: 50
email:
type: string
format: email
password:
type: string
minLength: 6
maxLength: 100
UserResponse:
type: object
properties:
id:
type: integer
format: int64
username:
type: string
email:
type: string
createdAt:
type: string
format: date-time
4.3 API 版本管理策略
📌 版本管理规则:
- URL 路径版本:
/api/v1/resource(推荐)
- Header 版本:
X-API-Version: 1
- 查询参数版本:
?version=1(不推荐)
4.4 接口文档自动生成
✅ AI 自动化流程:
- API Designer Agent 根据技术方案生成 OpenAPI Spec
- Swagger UI 自动渲染交互式文档
- Mock Server 自动生成模拟数据
- 前后端并行开发,基于契约测试
5. 单元测试与集成测试规范
5.1 单元测试模板
Java JUnit 5 + Mockito 测试模板
package com.company.project.service;
import com.company.project.common.exception.BusinessException;
import com.company.project.repository.UserRepository;
import com.company.project.repository.entity.User;
import com.company.project.service.dto.request.UserCreateRequest;
import com.company.project.service.dto.response.UserResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.BDDMockito.*;
@ExtendWith(MockitoExtension.class)
@DisplayName("UserService 单元测试")
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserServiceImpl userService;
private UserCreateRequest createRequest;
private User user;
@BeforeEach
void setUp() {
createRequest = UserCreateRequest.builder()
.username("testuser")
.email("test@example.com")
.password("password123")
.build();
user = User.builder()
.id(1L)
.username("testuser")
.email("test@example.com")
.build();
}
@Test
@DisplayName("创建用户_成功场景")
void createUser_Success() {
given(userRepository.existsByUsername("testuser")).willReturn(false);
given(userRepository.save(any(User.class))).willReturn(user);
UserResponse response = userService.createUser(createRequest);
assertThat(response).isNotNull();
assertThat(response.getUsername()).isEqualTo("testuser");
then(userRepository).should().save(any(User.class));
}
@Test
@DisplayName("创建用户_用户名已存在")
void createUser_UsernameAlreadyExists() {
given(userRepository.existsByUsername("testuser")).willReturn(true);
assertThatThrownBy(() -> userService.createUser(createRequest))
.isInstanceOf(BusinessException.class)
.hasMessageContaining("用户名已存在");
}
@Test
@DisplayName("根据 ID 查询用户_成功场景")
void getUserById_Success() {
given(userRepository.findById(1L)).willReturn(Optional.of(user));
UserResponse response = userService.getUserById(1L);
assertThat(response.getId()).isEqualTo(1L);
assertThat(response.getUsername()).isEqualTo("testuser");
}
@Test
@DisplayName("根据 ID 查询用户_用户不存在")
void getUserById_NotFound() {
given(userRepository.findById(999L)).willReturn(Optional.empty());
assertThatThrownBy(() -> userService.getUserById(999L))
.isInstanceOf(BusinessException.class)
.hasMessageContaining("用户不存在");
}
}
5.2 集成测试模板
Spring Boot 集成测试模板
package com.company.project.integration;
import com.company.project.repository.UserRepository;
import com.company.project.repository.entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
@Transactional
@DisplayName("用户 API 集成测试")
class UserApiIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setUp() {
userRepository.deleteAll();
}
@Test
@DisplayName("创建用户_API 测试")
void createUser_ApiTest() throws Exception {
String requestBody = objectMapper.writeValueAsString(Map.of(
"username", "testuser",
"email", "test@example.com",
"password", "password123"
));
mockMvc.perform(post("/api/v1/users")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.username").value("testuser"));
}
@Test
@DisplayName("查询用户列表_API 测试")
void listUsers_ApiTest() throws Exception {
User user = User.builder()
.username("testuser")
.email("test@example.com")
.password("password123")
.build();
userRepository.save(user);
mockMvc.perform(get("/api/v1/users")
.param("page", "0")
.param("size", "10"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.content").isArray())
.andExpect(jsonPath("$.data.totalElements").value(1));
}
}
5.3 测试覆盖率要求
| 代码类型 |
最低覆盖率 |
测试框架 |
| Service 层 |
≥ 90% |
JUnit 5 + Mockito |
| Controller 层 |
≥ 85% |
Spring MVC Test |
| Repository 层 |
≥ 80% |
Spring Data JPA Test |
| 工具类 |
≥ 95% |
JUnit 5 |
| 集成测试 |
核心流程 100% |
TestContainers |
6. CI/CD 流水线配置模板
6.1 Jenkins Pipeline 模板
Jenkinsfile (声明式 Pipeline)
pipeline {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.9-openjdk-17
command:
- cat
tty: true
- name: docker
image: docker:24-dind
securityContext:
privileged: true
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
"""
}
}
environment {
REGISTRY = "registry.company.com"
IMAGE_NAME = "myapp-backend"
KUBE_CONFIG = credentials('kubeconfig')
SONAR_TOKEN = credentials('sonar-token')
}
options {
timestamps()
timeout(time: 60, unit: 'MINUTES')
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '10'))
}
triggers {
pollSCM('*/5 * * * *')
}
stages {
stage('Checkout') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
env.BUILD_VERSION = "${env.BUILD_NUMBER}-${env.GIT_COMMIT_SHORT}"
}
}
}
stage('Code Quality Check') {
steps {
container('maven') {
sh 'mvn -B sonar:sonar \
-Dsonar.projectKey=myapp-backend \
-Dsonar.host.url=http://sonarqube.company.com \
-Dsonar.login=$SONAR_TOKEN'
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
}
stage('Unit Test') {
steps {
container('maven') {
sh 'mvn -B test -DskipITs'
}
}
post {
always {
junit allowEmptyResults: true,
testResults: '**/target/surefire-reports/*.xml'
publishCoverage adapters: [jacocoAdapter('**/target/site/jacoco/jacoco.xml')]
}
}
}
stage('Integration Test') {
steps {
container('maven') {
sh 'mvn -B verify -DskipUnitTests'
}
}
}
stage('Build Docker Image') {
steps {
container('docker') {
sh """
docker build -t ${REGISTRY}/${IMAGE_NAME}:${BUILD_VERSION} .
docker tag ${REGISTRY}/${IMAGE_NAME}:${BUILD_VERSION} ${REGISTRY}/${IMAGE_NAME}:latest
"""
}
}
}
stage('Push to Registry') {
steps {
container('docker') {
withCredentials([usernamePassword(
credentialsId: 'docker-registry',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS'
)]) {
sh """
echo $DOCKER_PASS | docker login ${REGISTRY} -u $DOCKER_USER --password-stdin
docker push ${REGISTRY}/${IMAGE_NAME}:${BUILD_VERSION}
docker push ${REGISTRY}/${IMAGE_NAME}:latest
"""
}
}
}
}
stage('Deploy to K8S') {
when {
branch 'main'
}
steps {
container('maven') {
sh """
export KUBECONFIG=$KUBE_CONFIG
kubectl set image deployment/myapp-backend \
myapp-backend=${REGISTRY}/${IMAGE_NAME}:${BUILD_VERSION} \
-n production
kubectl rollout status deployment/myapp-backend -n production
"""
}
}
}
}
post {
always {
cleanWs()
}
success {
script {
slackSend channel: '#deployments',
color: 'good',
message: "✅ 构建成功:${env.JOB_NAME} #${env.BUILD_NUMBER}\n版本:${env.BUILD_VERSION}\n链接:${env.BUILD_URL}"
}
}
failure {
script {
slackSend channel: '#deployments',
color: 'danger',
message: "❌ 构建失败:${env.JOB_NAME} #${env.BUILD_NUMBER}\n链接:${env.BUILD_URL}"
}
}
}
}
6.2 Dockerfile 模板
Java Spring Boot Dockerfile
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests -B
FROM eclipse-temurin:17-jre-alpine
LABEL maintainer="devops@company.com"
LABEL version="1.0.0"
LABEL description="MyApp Backend Service"
WORKDIR /app
RUN addgroup -g 1001 appgroup && \
adduser -D -u 1001 -G appgroup appuser
COPY --from=builder --chown=appuser:appgroup /app/target/*.jar app.jar
USER appuser
EXPOSE 8080
ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC"
ENV SPRING_PROFILES_ACTIVE=prod
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1
6.3 Kubernetes 部署配置
K8S Deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-backend
namespace: production
labels:
app: myapp-backend
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: myapp-backend
template:
metadata:
labels:
app: myapp-backend
version: v1
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
serviceAccountName: myapp-sa
containers:
- name: myapp-backend
image: registry.company.com/myapp-backend:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
protocol: TCP
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: JAVA_OPTS
value: "-Xms512m -Xmx1024m"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumeMounts:
- name: logs
mountPath: /app/logs
volumes:
- name: logs
emptyDir: {}
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: myapp-backend
topologyKey: kubernetes.io/hostname
---
apiVersion: v1
kind: Service
metadata:
name: myapp-backend-service
namespace: production
spec:
selector:
app: myapp-backend
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-backend-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp-backend
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
6.4 KubeSphere DevOps 配置
🔧 KubeSphere 特性集成:
- 可视化 CI/CD 流水线编辑
- 多分支流水线自动发现
- 内置代码质量检查(SonarQube)
- 容器化构建环境
- 一键部署到多环境
- 灰度发布和蓝绿部署
- 流水线即代码(Jenkinsfile)
7. OpenClaw + Claude Code 集成方案
7.1 OpenClaw 配置模板
OpenClaw 配置文件 (.claw/config.yaml)
version: "2026.3.8"
agents:
product_agent:
model: claude-opus-4.6
system_prompt: "你是资深产品专家,负责需求分析和 PRD 撰写..."
tools: [file_read, file_write, web_search]
backend_architect_agent:
model: claude-opus-4.6
system_prompt: "你是资深后端架构师,负责技术方案设计..."
tools: [file_read, file_write, execute_command]
backend_developer_agent:
model: claude-sonnet-4.5
system_prompt: "你是高级 Java 开发工程师,遵循代码规范..."
tools: [file_read, file_write, execute_command]
qa_engineer_agent:
model: claude-sonnet-4.5
system_prompt: "你是资深测试工程师,负责编写测试用例..."
tools: [file_read, file_write, execute_command]
devops_agent:
model: claude-sonnet-4.5
system_prompt: "你是 DevOps 专家,负责 CI/CD 配置..."
tools: [file_read, file_write, execute_command]
workflow:
name: "端到端研发自动化流程"
stages:
- name: requirement_analysis
agent: product_agent
input: raw_requirements.md
output: prd.md
- name: technical_design
agent: backend_architect_agent
input: prd.md
output: [architecture.md, api_spec.yaml]
- name: code_generation
agent: backend_developer_agent
input: api_spec.yaml
output: source_code/
- name: unit_test
agent: qa_engineer_agent
input: source_code/
output: tests/
- name: ci_cd_setup
agent: devops_agent
input: source_code/
output: [Jenkinsfile, Dockerfile, k8s/]
llm_providers:
anthropic:
api_key: ${ANTHROPIC_API_KEY}
base_url: https://api.anthropic.com
models:
- id: claude-opus-4.6
context_window: 200000
max_tokens: 64000
- id: claude-sonnet-4.5
context_window: 200000
max_tokens: 64000
skills:
- name: code_generator
enabled: true
templates_path: ./templates/
- name: test_generator
enabled: true
coverage_target: 0.85
- name: code_reviewer
enabled: true
ruleset: ./rules/code_quality.yaml
memory:
type: persistent
storage_path: ~/.claw/memory/
max_context_items: 100
security:
sandbox_mode: true
allowed_commands: [mvn, npm, docker, kubectl, git]
blocked_paths: [/etc, /root, /home]
7.2 Claude Code 最佳实践
Claude Code 工作流配置
{
"workspaceRules": [
{
"pattern": "**/*.java",
"instructions": "遵循 Java 代码规范:PascalCase 类名、camelCase 方法名、添加 Javadoc 注释"
},
{
"pattern": "**/controller/**/*.java",
"instructions": "Controller 层必须使用@RestController 注解,返回 Result 包装类"
},
{
"pattern": "**/service/**/*.java",
"instructions": "Service 层必须添加@Transactional 注解,记录业务日志"
}
],
"autoCommands": {
"afterFileCreate": "mvn compile",
"beforeCommit": "mvn test && mvn checkstyle:check"
},
"contextManagement": {
"maxFiles": 50,
"includeGitignore": true,
"respectIgnoreFiles": true
}
}
7.3 AI 代码生成 Prompt 模板
Controller 生成 Prompt
你是一名资深 Java 开发工程师,请根据以下 API 规范生成 Spring Boot Controller 代码:
【技术要求】
1. 使用 Spring Boot 3.x + Java 17
2. 遵循 RESTful API 设计规范
3. 使用 Swagger/OpenAPI 3.0 注解
4. 统一返回 Result<T>包装类
5. 添加完整的异常处理
【API 规范】
- 路径:/api/v1/users
- 方法:
- GET / - 分页查询用户列表
- GET /{id} - 查询用户详情
- POST / - 创建用户
- PUT /{id} - 更新用户
- DELETE /{id} - 删除用户
【代码规范要求】
1. 类名使用 PascalCase
2. 方法名使用 camelCase,动词开头
3. 添加完整的 Javadoc 注释
4. 使用 Lombok 简化代码
5. 参数校验使用@Valid 注解
请生成完整的 UserController 代码。
8. 人机协同工作机制
8.1 人机协同流程
AI 生成代码
Claude Code
人工 Review
代码审查
AI 修复反馈
自动修正
人工确认
最终审核
自动合并
Git Commit
8.2 人工介入节点
| 研发阶段 |
AI 自动化程度 |
人工介入点 |
介入方式 |
| 需求分析 |
70% |
需求确认、优先级排序 |
Review + 批准 |
| 技术方案设计 |
80% |
架构评审、技术选型 |
讨论 + 决策 |
| 代码生成 |
90% |
代码 Review、复杂逻辑 |
Code Review |
| 测试用例 |
85% |
边界场景、异常流程 |
补充 + 验证 |
| 部署上线 |
75% |
上线审批、回滚决策 |
审批 + 监控 |
8.3 代码 Review 检查清单
✅ AI 生成代码人工 Review 要点:
- 业务逻辑正确性:是否满足需求、边界条件处理
- 代码规范符合度:命名、注释、格式是否符合规范
- 异常处理完整性:异常捕获、日志记录、错误提示
- 安全性检查:SQL 注入、XSS、权限校验
- 性能考虑:循环嵌套、数据库查询、缓存使用
- 可测试性:依赖注入、单元测试覆盖
8.4 反馈循环机制
while (feature_not_complete) {
1. AI 生成代码片段
2. 自动运行单元测试
3. IF 测试失败 THEN
3.1 AI 分析失败原因
3.2 AI 自动修复代码
3.3 GOTO 步骤 2
4. ELSE 测试通过 THEN
4.1 人工 Code Review
4.2 IF 发现问题 THEN
4.2.1 人工标注问题
4.2.2 AI 学习并修复
4.2.3 GOTO 步骤 2
4.3 ELSE 无问题 THEN
4.3.1 提交代码
4.3.2 触发 CI/CD 流水线
}