Java 程序员的 AI 进化论 | 用 AI 生成 Spring Boot 脚手架,省下两小时重复劳动

Java 程序员的 AI 进化论 | 用 AI 生成 Spring Boot 脚手架,省下两小时重复劳动

上周新项目启动, Tech Lead 说「先把脚手架搭起来,下周一能跑就行」。以前这种活我至少得花半天------建包结构、写配置类、搞异常处理、加 Swagger 文档、配日志格式,一套下来脑子都木了。这次我换了个思路,直接让 AI 帮我生成。

结果从输入需求到项目能跑起来,总共花了不到 20 分钟。不是那种「生成一堆模板代码然后手动修半天」的 20 分钟,是真正能启动、能访问接口、能打日志的 20 分钟。

一、为什么脚手架值得用 AI 生成

老实讲,脚手架代码是最不该人手写的东西。它没有业务逻辑难度,但量大、碎、容易漏。我之前每次搭项目都要对着上个项目的目录抄一遍,改包名、改配置、删掉不用的依赖,光是确认这些零碎东西就要 40 分钟。

传统方式有几种选择,但各有各的问题:

方式 耗时 问题
手动建包抄代码 40-60 分钟 容易漏文件,包名改错
Spring Initializr 15 分钟 只生成空壳,业务骨架全得手写
拷贝旧项目改 30 分钟 残留旧代码,依赖冲突
AI 生成完整骨架 15-20 分钟 需要好的 Prompt,但结构最完整

Spring Initializr 生成的东西大家都用过,一个 Application 启动类加上 application.yml,然后呢?统一异常处理要自己写吧,响应包装要自己写吧,Swagger 配置要自己写吧。这些东西 AI 能一次性全给你生成出来,而且风格统一。

关键是你要会「点菜」------把需求说清楚,AI 才知道给你生成什么。

二、Prompt 模板设计

我踩过的最大的坑就是:Prompt 写得太笼统,AI 生成的代码跟你想要的对不上。一开始我就写了句「帮我生成一个 Spring Boot 项目脚手架」,结果给我返回了一堆 main 方法里打印 Hello World 的东西,完全没法用。

后来我总结了一个 Prompt 模板,分五个要素,生成的质量直接上了一个台阶:

text 复制代码
角色:你是资深 Java 架构师,精通 Spring Boot 3.x
任务:生成一个完整的 Spring Boot 项目脚手架
技术栈:Java 17、Spring Boot 3.2、MyBatis-Plus、PostgreSQL
项目结构要求:
  - com.example.demo (根包)
  - controller / service / mapper / entity / config / common
功能要求:
  1. 统一响应体 Result<T>,含 code、message、data
  2. 全局异常处理 GlobalExceptionHandler,捕获 BusinessException 和系统异常
  3. Swagger 文档配置(springdoc-openapi)
  4. 一个示例 CRUD 接口(User 实体的增删改查)
  5. application.yml 含数据源、日志、Swagger 配置
约束:包名 com.example.demo,端口 8080

这个模板的核心思路是「五要素法」:角色定位、任务描述、技术栈、结构要求、功能清单。缺任何一个,生成质量都会打折扣。

三、生成的项目结构

用上面那个 Prompt,AI 生成的项目结构长这样:

text 复制代码
demo/
├── src/main/java/com/example/demo/
│   ├── DemoApplication.java
│   ├── common/
│   │   ├── Result.java
│   │   └── ResultCode.java
│   ├── config/
│   │   ├── SwaggerConfig.java
│   │   └── MyBatisPlusConfig.java
│   ├── controller/
│   │   └── UserController.java
│   ├── entity/
│   │   └── User.java
│   ├── exception/
│   │   ├── BusinessException.java
│   │   └── GlobalExceptionHandler.java
│   ├── mapper/
│   │   └── UserMapper.java
│   └── service/
│       ├── UserService.java
│       └── impl/UserServiceImpl.java
├── src/main/resources/
│   ├── application.yml
│   └── mapper/UserMapper.xml
└── pom.xml

这个结构是我觉得比较舒服的分层方式。common 放公共类,config 放配置类,exception 单独拎出来放异常相关的东西。有些人喜欢把异常塞到 common 里,我习惯分开,因为异常类多了以后混在一起不好找。

生成的核心代码质量也不错,我挑几个关键类看看。

3.1 统一响应体

java 复制代码
package com.example.demo.common;

import lombok.Data;

@Data
public class Result<T> {
    private Integer code;
    private String message;
    private T data;

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("操作成功");
        result.setData(data);
        return result;
    }

    // 失败响应,code 从 ResultCode 枚举取,别硬编码数字
    public static <T> Result<T> fail(Integer code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
}

这段代码我基本没改。有个小细节:失败方法我让它接受 codemessage 两个参数,而不是直接传 ResultCode 枚举。因为有些场景错误码是动态的(比如第三方接口返回的 HTTP 状态码),枚举覆盖不全。

3.2 全局异常处理

java 复制代码
package com.example.demo.exception;

import com.example.demo.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 业务异常单独捕获,返回 200 + 业务错误码,前端判断 code 字段
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        log.warn("业务异常: {}", e.getMessage());
        return Result.fail(e.getCode(), e.getMessage());
    }

    // 参数校验异常,把字段错误信息拼出来方便排查
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleValidException(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(err -> err.getField() + ": " + err.getDefaultMessage())
                .reduce((a, b) -> a + "; " + b)
                .orElse("参数校验失败");
        log.warn("参数校验异常: {}", msg);
        return Result.fail(400, msg);
    }

    // 兜底:其他异常统一返回 500,别把堆栈抛给前端
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return Result.fail(500, "系统内部错误");
    }
}

这里有个踩坑经验要分享。第一次生成的版本里,BusinessException 的 handler 没有 log.warn,导致业务异常被 Exception 的兜底 handler 的 log.error 打了完整堆栈。日志里全是 WARN 级别的业务异常堆栈,每天几百条,排查真正的问题时特别烦。后来我手动加了日志级别区分------业务异常用 warn,系统异常用 error,日志清爽多了。

3.3 依赖配置

依赖这块我改了一些,AI 默认给的版本有时候不是最新的。以下是我实际使用的依赖清单:

依赖 groupId artifactId 版本 作用
Spring Boot Web org.springframework.boot spring-boot-starter-web 3.2.5 Web 框架
MyBatis-Plus com.baomidou mybatis-plus-spring-boot3-starter 3.5.5 ORM 增强
PostgreSQL 驱动 org.postgresql postgresql 42.7.3 数据库驱动
springdoc-openapi org.springdoc springdoc-openapi-starter-webmvc-ui 2.3.0 Swagger 文档
Lombok org.projectlombok lombok 1.18.32 简化代码
validation org.springframework.boot spring-boot-starter-validation 3.2.5 参数校验

四、踩坑经验

4.1 包名不一致导致扫描失败

AI 生成代码的时候,有时候同一个类在不同的消息轮次里,包名会变。比如第一轮生成的 UserController 包名是 com.example.demo.controller,第二轮生成的 UserService 包名变成了 com.example.demo.service.impl 但 import 路径写的是 com.example.demo.service.UserService

这个问题如果项目小还好排查,项目一大就坑死你。我的建议是 Prompt 里把包名写死,而且生成完之后先跑一遍编译,有 import 错误立刻能发现。

常见包名问题 现象 解决方案
包名漂移 编译报错找不到符号 Prompt 中明确写死根包名
import 路径错 IDE 标红但能自动修复 统一用 IDE 的 organize imports
同名类冲突 两个包下有同名类 生成时指定类名前缀或后缀

4.2 Swagger 版本不匹配

第二个坑是 Swagger 的版本。Spring Boot 3.x 之后,老的 Springfox 不支持了,必须用 springdoc-openapi。AI 如果没有在 Prompt 里明确技术栈版本,有概率给你生成 Springfox 的配置类,编译直接报错。

java 复制代码
// 错误写法:Spring Boot 3 下不兼容,编译报错
// @EnableSwagger2  ← 这个注解在 Spring Boot 3 里找不到
// SwaggerConfig 继承 Docket ← Docket 类已废弃

// 正确写法:springdoc-openapi,零配置即可
package com.example.demo.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("Demo API")
                        .description("AI 生成的 Spring Boot 脚手架接口文档")
                        .version("1.0.0"));
    }
}

springdoc-openapi 比老 Springfox 简单太多了,基本上只要引入依赖就能用,配置类只是加个文档描述信息。别让 AI 用旧版本糊弄你 ,Prompt 里一定要写清楚 springdoc-openapi 而不是 SwaggerSpringfox

五、效率对比

我把这次用 AI 生成脚手架跟之前手动搭的经历做了个对比,数据比较真实:

环节 手动搭建 AI 生成 节省时间
项目结构创建 15 分钟 1 分钟 14 分钟
配置类编写 20 分钟 2 分钟 18 分钟
异常处理框架 15 分钟 3 分钟 12 分钟
示例 CRUD 接口 25 分钟 5 分钟 20 分钟
Swagger 文档配置 10 分钟 2 分钟 8 分钟
调试与修复 10 分钟 7 分钟 3 分钟
合计 95 分钟 20 分钟 75 分钟

省了 75 分钟,差不多一个半小时。注意「调试与修复」那行------AI 生成不是零成本,你得花时间检查包名、版本、依赖冲突这些问题。但跟纯手写比,调试时间还是短了很多。

六、Prompt 调优建议

用了一个月下来,我发现 Prompt 质量直接决定生成质量。有几个调优技巧值得分享:

技巧一:给约束比给自由更重要。 Prompt 里写「端口 8080」「包名 com.example.demo」这种硬约束,比写「请合理设计端口」效果好得多。AI 不擅长猜你的偏好,你不说它就自己编。

技巧二:分轮生成比一次性生成好。 如果一次性让 AI 生成全部 10 个类,后面的类质量会下降(上下文太长,注意力分散)。我的做法是分三轮:第一轮生成基础结构(Result、Exception、Config),第二轮生成业务代码(Controller、Service、Mapper),第三轮生成配置文件和依赖。每轮只关注一件事,质量高很多。

技巧三:生成后必须编译验证。 AI 生成的代码可能有 90% 是对的,但那 10% 的错误(包名漂移、版本不匹配、import 缺失)会要你的命。跑一遍 mvn compile,有错立刻修,别攒着。

技巧四:用示例锚定风格。 AI 生成代码风格的稳定性不是太好,尤其是多轮对话之后容易跑偏。我会在 Prompt 里加一段示例代码,AI 会照着这个风格生成后续内容。比如:

java 复制代码
// 示例代码风格
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @GetMapping("/{id}")
    public Result<User> getById(@PathVariable Long id) {
        return Result.success(userService.getById(id));
    }
}

把这段示例贴进 Prompt,AI 后续生成的代码风格就跟它对齐了------命名规范、注解位置、构造器注入还是字段注入,全部统一。这种「以例锚定」的方式比口头描述「请用 Lombok 和构造器注入」效果好十倍。

技巧五:避免一次生成太多类。 我设定的上限是单轮生成 8 个类。超过 8 个类,AI 的注意力会分散,后面生成的代码质量明显下降。有时候项目需要 12 个类,我会分两轮:基础类一轮,业务类一轮。

Prompt 要素 不写会怎样 写了的好处
角色定位 生成新手级代码 代码风格成熟,命名规范
技术栈版本 用旧版依赖 版本统一,兼容性好
包名约束 包名随机 结构清晰,扫描不出错
功能清单 只生成空壳 一次性生成完整骨架
约束条件 想到哪写到哪 生成结果可控

七、总结

用 AI 生成 Spring Boot 脚手架这件事,关键不在于 AI 能不能生成代码,而在于你能不能把需求说清楚。Prompt 写得好,20 分钟出活;写得差,改代码的时间比自己写还长。

检查项 建议
Prompt 五要素 角色、任务、技术栈、结构、功能缺一不可
包名写死 在 Prompt 里明确根包名,防止包名漂移
分轮生成 基础类→业务类→配置,每轮聚焦一个主题
版本指定 Spring Boot 3.x 用 springdoc 不用 Springfox
编译验证 生成后立刻 mvn compile,有错马上修
日志分级 业务异常 warn,系统异常 error,别混
响应体设计 失败方法接受动态 code,别只用枚举
依赖表格 用 Markdown 表格替代 XML,公众号不兼容 XML

这套流程我跑了一个月,搭了 4 个新项目的脚手架,每个都 20 分钟以内搞定。当然脚手架只是起点,真正的业务代码还是得自己写。但把重复劳动甩给 AI,省下来的时间用来想业务逻辑,这笔买卖不亏。

相关推荐
名字还没想好☜1 小时前
Java 用 MethodHandle 替代反射:调用性能实测、invokeExact 的坑与缓存
java·开发语言·缓存·反射·methodhandle
SMF19191 小时前
【Linux】完美解决缩略图工具gm调用java.io.FileNotFoundException: gm问题
java·开发语言·python
sugar__salt1 小时前
MyBatis-Plus 从入门到实战:高效简化数据库开发的完整指南
数据库·spring boot·mybatis·数据库开发
小当家.1051 小时前
LLM服务缓存与连接池管理:三层缓存架构与ChatClient池化
java·后端·spring·缓存·llm·agent
万岳科技系统开发2 小时前
医疗诊所小程序如何实现患者管理和会员运营?
java·小程序·apache
小当家.1052 小时前
Token成本控制实战:语义缓存、上下文压缩与工具缓存
java·spring·缓存·token·上下文
乐观勇敢坚强的老彭2 小时前
C++ STL 常用容器的速查表
java·c++·算法
wwwzhouzy2 小时前
SpringBoot 响应式编程
java·spring boot·后端·响应式编程
冰夏之夜影2 小时前
【解决方案】SpringBoot项目添加ssl证书后不生效问题
spring boot·后端·ssl