在这里插入图片描述

写在前面

上周团队接了一个紧急需求:一周内要交付一个包含8张表的商品管理系统。传统开发至少2个人干满5天。我们试了一个新方案——Java后端用AI Agent自动生成代码,人只做审查和微调。在这里插入图片描述

结果:2天交付,Bug率反而比手写低。

这篇文章把这套方案完整拆开给你看。从环境搭建到代码生成到部署验证,每一步都有可复现的代码。环境:Spring Boot 3.3.0 + JDK 21 + Maven 3.9 + MySQL 8.0。

一、先看成品:AI Agent帮你干了什么

开始之前先搞清楚Agent能代替你做什么、不能代替什么。

Agent能做的:

  • 读取已有项目的实体类、Repository接口 → 理解表结构和数据层
  • 根据需求生成完整的Service层代码(含业务逻辑、事务管理、异常处理)
  • 生成RestController(含参数校验、分页、统一响应格式)
  • 自动写单元测试(覆盖CRUD基本场景)
  • 如果需要新依赖,自动建议Maven坐标

Agent做不了的(需要你判断的):

  • 业务规则(比如"订单金额超过5000需要审批"这种规则Agent不知道)
  • 架构决策(该不该拆微服务、该用哪种缓存策略)
  • 权限策略(角色继承、数据行权限)

记住这个边界,后面不会掉坑里。

二、环境搭建:15分钟搞定脚手架

2.1 创建Spring Boot项目

在IDEA里 New Project → Spring Initializr,选:

  • JDK 21
  • Spring Boot 3.3.0
  • 依赖勾选:Spring Web、Spring Data JPA、MySQL Driver、Lombok、Spring Boot DevTools、Spring Validation

项目名:ai-agent-crud-demo

2.2 配置application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/ai_agent_demo?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4
    username: root
    password: yourpassword
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: false
    properties:
      hibernate:
        format_sql: true
        dialect: org.hibernate.dialect.MySQLDialect

server:
  port: 8080

启动项目,确认控制台输出 “Started AiAgentCrudDemoApplication”,环境就绪。

2.3 准备一张测试表

CREATE TABLE product (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(200) NOT NULL COMMENT '商品名称',
    description TEXT COMMENT '商品描述',
    price DECIMAL(10,2) NOT NULL COMMENT '价格',
    stock INT NOT NULL DEFAULT 0 COMMENT '库存',
    category VARCHAR(100) COMMENT '分类',
    status TINYINT DEFAULT 1 COMMENT '状态:1-上架 0-下架',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_category (category),
    INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';

三、定义AI Agent的交互协议

这部分是核心。我们不绑任何特定AI产品,定义一套通用的请求/响应格式,方便你替换任意AI服务。

3.1 请求结构

package com.example.aiagent.dto;

import lombok.Data;
import java.util.List;

@Data
public class AgentRequest {
    // 需求描述
    private String requirement;
    // 目标生成类型:SERVICE / CONTROLLER / REPOSITORY / TEST
    private String targetType;
    // 关联的实体类源代码(让AI知道表结构)
    private String entityCode;
    // 已有的Repository代码(让AI知道数据层接口)
    private String repositoryCode;
    // 已存在的依赖列表
    private List<String> existingDependencies;
}

3.2 响应结构

package com.example.aiagent.dto;

import lombok.Data;
import java.util.List;

@Data
public class AgentResponse {
    // 生成的完整代码
    private String generatedCode;
    // 建议的文件路径(如 service/ProductService.java)
    private String suggestedFilePath;
    // 需要新增的Maven依赖
    private List<String> newDependencies;
    // AI对代码逻辑的简要说明
    private String explanation;
}

3.3 Prompt构建器

package com.example.aiagent.service;

import com.example.aiagent.dto.AgentRequest;
import org.springframework.stereotype.Component;

@Component
public class PromptBuilder {
    
    public String build(AgentRequest request) {
        StringBuilder prompt = new StringBuilder();
        
        prompt.append("你是一个Spring Boot 3.x开发专家。请根据以下信息生成Java代码。\n\n");
        
        prompt.append("## 项目环境\n");
        prompt.append("- Spring Boot 3.3.0\n");
        prompt.append("- JDK 21\n");
        prompt.append("- 使用Spring Data JPA\n");
        prompt.append("- 包路径:com.example.aiagent\n");
        prompt.append("- 已有依赖:" + String.join(", ", request.getExistingDependencies()) + "\n\n");
        
        prompt.append("## 实体类代码\n```java\n");
        prompt.append(request.getEntityCode());
        prompt.append("\n```\n\n");
        
        if (request.getRepositoryCode() != null) {
            prompt.append("## Repository层代码\n```java\n");
            prompt.append(request.getRepositoryCode());
            prompt.append("\n```\n\n");
        }
        
        prompt.append("## 生成要求\n");
        prompt.append("请生成" + request.getTargetType() + "层代码。\n");
        prompt.append("需求:" + request.getRequirement() + "\n\n");
        
        prompt.append("## 规范要求\n");
        prompt.append("1. 代码必须完整可运行,包含所有import语句\n");
        prompt.append("2. 使用@Transactional注解管理事务\n");
        prompt.append("3. Service层需包含完整的参数校验和异常处理\n");
        prompt.append("4. Controller层使用统一的ResponseEntity包装返回\n");
        prompt.append("5. 分页接口使用Spring Data的Pageable\n");
        prompt.append("6. 所有数据库操作优先使用已有的Repository方法\n");
        prompt.append("7. 如果需要新的Maven依赖,在代码最后以注释形式列出\n");
        prompt.append("8. 只返回代码,不要解释\n");
        
        return prompt.toString();
    }
}

四、调用AI服务生成代码

以下是AI服务调用层的核心实现。callAiApi方法的实现取决于你使用的AI服务,这里用通用的HTTP调用方式示意。

package com.example.aiagent.service;

import com.example.aiagent.dto.AgentRequest;
import com.example.aiagent.dto.AgentResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;

@Service
public class AgentService {
    
    @Value("${ai.api.endpoint}")
    private String apiEndpoint;
    
    @Value("${ai.api.key}")
    private String apiKey;
    
    private final PromptBuilder promptBuilder;
    private final CodeWriterService codeWriter;
    private final ObjectMapper objectMapper;
    
    public AgentService(PromptBuilder promptBuilder, CodeWriterService codeWriter) {
        this.promptBuilder = promptBuilder;
        this.codeWriter = codeWriter;
        this.objectMapper = new ObjectMapper();
    }
    
    public AgentResponse generateAndWrite(AgentRequest request) throws Exception {
        // 1. 构建prompt
        String prompt = promptBuilder.build(request);
        
        // 2. 调用AI API
        String rawCode = callAiApi(prompt);
        
        // 3. 解析依赖建议
        List<String> dependencies = extractDependencies(rawCode);
        
        // 4. 构建响应
        AgentResponse response = new AgentResponse();
        response.setGeneratedCode(cleanCode(rawCode));
        response.setSuggestedFilePath(buildPath(request.getTargetType(), "Product"));
        response.setNewDependencies(dependencies);
        response.setExplanation("代码已生成,请检查业务逻辑和异常处理");
        
        // 5. 写入文件
        codeWriter.writeToFile(response);
        
        return response;
    }
    
    private String callAiApi(String prompt) throws Exception {
        // OpenAI兼容的调用方式
        String requestBody = String.format("""
            {
                "model": "gpt-4o",
                "messages": [
                    {"role": "system", "content": "你是一个Spring Boot开发助手。只返回代码,不要解释。"},
                    {"role": "user", "content": "%s"}
                ],
                "temperature": 0.2
            }
            """, prompt.replace("\"", "\\\"").replace("\n", "\\n"));
        
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(apiEndpoint))
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + apiKey)
            .POST(HttpRequest.BodyPublishers.ofString(requestBody))
            .build();
        
        HttpResponse<String> response = client.send(request, 
            HttpResponse.BodyHandlers.ofString());
        
        JsonNode root = objectMapper.readTree(response.body());
        return root.path("choices").get(0).path("message").path("content").asText();
    }
    
    private String cleanCode(String raw) {
        return raw.replaceAll("```java\\n?", "")
                  .replaceAll("```\\n?", "")
                  .trim();
    }
    
    private List<String> extractDependencies(String raw) {
        List<String> deps = new ArrayList<>();
        for (String line : raw.split("\n")) {
            if (line.contains("建议添加依赖") || line.contains("Maven依赖")) {
                deps.add(line.replaceAll("//.*依赖[::]", "").trim());
            }
        }
        return deps;
    }
    
    private String buildPath(String targetType, String entityName) {
        return switch (targetType) {
            case "SERVICE" -> "service/" + entityName + "Service.java";
            case "CONTROLLER" -> "controller/" + entityName + "Controller.java";
            case "REPOSITORY" -> "repository/" + entityName + "Repository.java";
            case "TEST" -> "service/" + entityName + "ServiceTest.java";
            default -> throw new IllegalArgumentException("不支持的类型:" + targetType);
        };
    }
}

五、代码写入服务

package com.example.aiagent.service;

import com.example.aiagent.dto.AgentResponse;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class CodeWriterService {
    
    private static final String BASE_PATH = "src/main/java/com/example/aiagent/";
    
    public void writeToFile(AgentResponse response) throws IOException {
        Path filePath = Paths.get(BASE_PATH + response.getSuggestedFilePath());
        
        Files.createDirectories(filePath.getParent());
        Files.writeString(filePath, response.getGeneratedCode());
        
        System.out.println("✓ 代码已写入:" + filePath.toAbsolutePath());
        
        if (response.getNewDependencies() != null && !response.getNewDependencies().isEmpty()) {
            System.out.println("⚠ 需要手动添加以下Maven依赖:");
            response.getNewDependencies().forEach(dep -> System.out.println("  - " + dep));
        }
    }
}

六、实战演示:生成完整的商品管理模块

配置好AI服务的API地址和Key后(通过application.yml或环境变量),编写一个启动入口测试:

package com.example.aiagent;

import com.example.aiagent.dto.AgentRequest;
import com.example.aiagent.service.AgentService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.List;

@SpringBootApplication
public class AiAgentCrudDemoApplication implements CommandLineRunner {
    
    private final AgentService agentService;
    
    public AiAgentCrudDemoApplication(AgentService agentService) {
        this.agentService = agentService;
    }
    
    public static void main(String[] args) {
        SpringApplication.run(AiAgentCrudDemoApplication.class, args);
    }
    
    @Override
    public void run(String... args) throws Exception {
        // 第一步:生成Service层
        AgentRequest serviceRequest = new AgentRequest();
        serviceRequest.setTargetType("SERVICE");
        serviceRequest.setRequirement("""
            生成ProductService,包含:
            1. 商品创建(校验名称和价格不为空,价格必须>0)
            2. 商品列表查询(支持按分类筛选、按名称模糊搜索、分页)
            3. 商品更新(只更新非null字段,库存不能为负数)
            4. 商品删除(逻辑删除,将status改为0)
            5. 库存预警查询(查询库存<10的商品)
            """);
        serviceRequest.setEntityCode("""
            @Entity @Table(name = "product") @Data
            public class Product {
                @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
                private Long id;
                private String name;
                private String description;
                private BigDecimal price;
                private Integer stock;
                private String category;
                private Integer status;
                private LocalDateTime createTime;
                private LocalDateTime updateTime;
            }
            """);
        serviceRequest.setExistingDependencies(List.of(
            "spring-boot-starter-data-jpa", "spring-boot-starter-web", "lombok"
        ));
        
        agentService.generateAndWrite(serviceRequest);
        System.out.println("✓ Service层生成完成");
        
        // 第二步:生成Controller层
        AgentRequest controllerRequest = new AgentRequest();
        controllerRequest.setTargetType("CONTROLLER");
        controllerRequest.setRequirement("""
            生成ProductController,路径:/api/products
            接口:
            - POST / 创建商品
            - GET / 查询商品列表(keyword/category/page/size参数)
            - GET /{id} 查询商品详情
            - PUT /{id} 更新商品
            - DELETE /{id} 逻辑删除商品
            - GET /low-stock 库存预警查询
            要求:使用@Valid校验、统一用ResponseEntity封装
            """);
        controllerRequest.setEntityCode("同上(实际使用时读取Product.java文件内容)");
        controllerRequest.setExistingDependencies(List.of(
            "spring-boot-starter-data-jpa", "spring-boot-starter-web", "lombok",
            "spring-boot-starter-validation"
        ));
        
        agentService.generateAndWrite(controllerRequest);
        System.out.println("✓ Controller层生成完成");
    }
}

跑一遍,AI Agent会自动生成ProductService.java和ProductController.java写入项目的对应目录。

七、踩坑记录:3个你可能也遇到的

使用AI Agent生成代码时,有几个一定要手动补的坑。

坑1:@Transactional经常漏。 AI生成的Service方法经常忘记加事务注解。解决方案:在所有涉及写操作的Service方法上,手动加上@Transactional(rollbackFor = Exception.class)。如果涉及多表级联操作,这个不能忘。

坑2:JPA查询方法名可能跑不通。 AI生成的Repository方法名有时不符合Spring Data的命名规范。比如它可能给你生成findByProductName而不是findByName。解决:生成后立即编译一次,有报错就修正方法名,或直接加上@Query注解明确写SQL。

坑3:Controller参数校验不完整。 AI不会自动给Request类加@NotNull@Min(0)等校验注解。用户传一个负数价格进来直接就存数据库了。解决:在生成的Request类上手动加上Spring Validation的注解,Controller方法参数前加@Valid

八、总结

用这套方案,我把一个8张表的CRUD系统从5天压缩到2天。核心收益不是"少写代码",而是把精力从重复劳动转移到架构设计和代码审查上。

如果你正在用Spring Boot做CRUD密集的项目,建议花一个下午把这套Agent框架搭好。一次投入,长期复用。

有问题评论区交流。如果这篇对你有帮助,点赞收藏支持一下,我下一篇写《AI生成SQL的9个安全漏洞》。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐