简介:这是一套借助Trae工具自动生成Spring Boot后端程序的示例工程,面向正在学习前后端分离开发或希望提升脚手架使用效率的Java开发者,也适合需要参考分层代码组织的初中级学习者。压缩包内有20个文件,以xml工程配置、java源码和properties配置为主,另含接口测试说明文档,整体大小只有10KB,属于轻量级工程模板。项目以学生管理场景为例,自动生成的代码覆盖实体类、数据访问接口、服务层、控制器及启动配置,能够直观看出Trae根据数据模型生成可运行的增删改查后端骨架。同时,工程内包含Maven项目结构、开发环境配置文件与接口测试文档,方便导入IDE后对照检查依赖关系和调用链路,也可以作为手工编写与自动生成代码差异对比的参考。目前已有939人学习下载,适合作为自动化代码生成入门及Spring Boot快速上手的参考资料。
1. 动手前先把需求和环境理清楚
1.1 Trae 不是替你思考,是帮你加速
先说结论:Trae 这类 AI 编程工具,真正的价值不在于"一键生成一个完整项目",而在于把那些重复、琐碎、写起来没技术含量但又不得不写的代码,快速变成可运行的产物,让你把精力留在业务设计上。
这次我用 Trae 生成一个前后端分离的 Web 应用程序中的后端程序,技术栈选的是市场上最顺手的组合:Spring Boot + MyBatis-Plus + MySQL。为什么选这套?一是生态成熟,招人好招;二是 Trae 对 Spring Boot 的理解足够深,生成出来的代码质量明显比早期 AI 编程工具高一个档次;三是前后端分离场景下,后端只需要把接口吐出来,前端用 Vue 或者其他框架都无所谓,恰好是 Spring Boot 最擅长的领域。
我建议你试的时候,别一上来就喊"帮我写个后端",那样出来的东西大概率是玩具。先花十分钟想清楚:这个后端要管什么数据、要提供哪些接口、给谁调用。需求越具体,Trae 生成的东西越能用。
1.2 本地环境准备清单
在用 Trae 之前,先把下面这些东西准备好。很多新手在这步翻车,后面全乱套。
| 工具 | 版本建议 | 说明 |
|---|---|---|
| JDK | 1.8 或 17 | 如果用 Spring Boot 2.7.x 就配 JDK 8,用 3.x 就配 JDK 17 |
| Maven | 3.6+ | 构建和依赖管理,装完记得配国内镜像 |
| MySQL | 5.7 或 8.0 | 本地数据库 |
| Trae | 最新版 | 下载安装后,建议登录自己的账号,保证 Builder 模式可用 |
| IDEA 或 VSCode | 任意 | 建议和 Trae 配合用一个编辑器,省得来回切 |
这里有个关键点:Trae 本身是一个编辑器形态的 AI 工具,它带了 Builder 模式,能自动写代码、建文件、甚至跑命令。但生成的 Maven 项目,你最终还是可以用 IDEA 打开去调。我个人的习惯是:让 Trae 负责"生成",IDEA 负责"运行和调试",这样出了问题比较好定位。
1.3 先定义一个小而完整的后端需求
不要一上来就搞大而全的系统,新手做前后端分离实战,最合适的项目是一个"用户管理 + 图书管理"的 CRUD 后端。
为什么选这个?因为它覆盖了后端开发的核心要素:
- 实体类和数据库表的映射
- 增删改查的基础接口
- 分页查询
- 统一返回格式
- 跨域配置(前后端分离必踩的坑)
- 接口文档
把这些跑通了,再做复杂业务就是往上叠加的事。我的需求清单是这样的:
做一个图书管理系统后端,提供用户注册登录、图书的增删改查、分页查询、根据书名模糊搜索这几个功能。数据库用 MySQL,表设计用 user 和 book 两张表。
把这个需求描述给 Trae 之后,剩下的事就是一步步引导它干活。
2. 用 Trae 生成 Spring Boot 项目骨架
2.1 在 Trae 里创建项目与对话约定
打开 Trae,新建一个文件夹作为项目根目录,比如book-system-backend。然后在 Trae 的对话框里,我建议按这个套路提需求:
创建一个 Spring Boot 项目,使用 Maven 构建,JDK 版本 17,Spring Boot 版本 2.7.18。集成 MyBatis-Plus 和 Lombok,包名用 com.example.booksystem。项目路径放在当前目录。
注意几个措辞细节:
- 明确 JDK 版本和 Spring Boot 版本,避免 AI 选一个最新版然后踩兼容性的坑。
- 明确包名,这样生成出来的代码结构统一。
- 明确"放在当前目录"而不是让它新建一个子目录,否则后续路径很乱。
Trae 在 Builder 模式下会自己创建 pom.xml、启动类、application.yml,然后告诉你"项目已生成,接下来要做什么"。这个过程很快,基本在一分钟以内。
2.2 用 Trae 生成 pom.xml 和启动类
Trae 生成的 pom.xml 核心部分是这样的:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>这里我特意选了 2.7.18 而不是 Spring Boot 3.x,主要是为了少踩坑:3.x 里javax变成jakarta,很多老教程代码直接导入会报错。如果你是在学习阶段,用 2.7.x 最省心。
启动类基本不用怎么管,Trae 生成的代码一定是标准写法:
@SpringBootApplication @MapperScan("com.example.booksystem.mapper") public class BookSystemApplication { public static void main(String[] args) { SpringApplication.run(BookSystemApplication.class, args); } }要注意@MapperScan这个注解是 MyBatis-Plus 扫描 Mapper 接口用的,没加这个,后面启动会报"找不到 mapper bean"。
2.3 配置文件与数据源初始化
application.yml 是数据库连接的关键。Trae 生成的默认配置往往是 H2 内存数据库,我们要改成 MySQL。这一步我不会直接让它"改配置",而是给出完整的 yml 内容让它写进去,避免它自己发挥:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/book_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0几个细节值得说:
map-underscore-to-camel-case是让数据库的user_name自动映射到 Java 的userName,少写很多@TableField注解。logic-delete-field: deleted是配置逻辑删除,就是删除记录时改成打标记,而不是物理删掉。这个在管理系统中几乎是标配,Trae 对 MyBatis-Plus 的配置理解没毛病,但如果你不说它不会主动加。- 数据库
book_system要自己手动建好,密码改成你自己的。
3. 核心业务代码的自动生成
3.1 实体类与表结构设计
表结构我沿用经典设计,然后在对话里直接告诉 Trae:
我有 user 和 book 两张表,user 表字段包括 id、username、password、nickname、created_at、deleted;book 表字段包括 id、title、author、price、publish_date、created_at、deleted。帮我生成对应的实体类和建表 SQL。
这一步 Trae 会帮你生成实体类,同时把建表 SQL 也写在注释里。实际上我更建议 SQL 自己先跑一遍,因为 AI 生成的类型映射偶尔会有小问题,比如Decimal映射成Double而不是BigDecimal。价格这种字段,用BigDecimal才是正确的选择,如果你发现 Trae 生成的是Double,直接告诉它"price 字段改成 BigDecimal"就行。
生成的 User 实体大致长这样:
@Data @TableName("user") public class User { @TableId(type = IdType.AUTO) private Long id; private String username; private String password; private String nickname; private LocalDateTime createdAt; @TableLogic private Integer deleted; }3.2 通用返回体与统一异常处理
这是我自己在项目中一直坚持的部分,也是 Trae 生成得比较"看心情"的部分。不是它不会写,而是它默认生成的内容比较朴素,需要你明确提要求。
我给它的话是:
写一个统一返回体 Result ,包含 code、message、data 三个字段,提供 success 和 error 静态方法。同时写一个全局异常处理器 GlobalExceptionHandler,处理参数校验异常和业务异常。
几十秒后,Result 类出来了,核心代码如下:
@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; } public static <T> Result<T> error(Integer code, String message) { Result<T> result = new Result<>(); result.setCode(code); result.setMessage(message); return result; } }全局异常处理器的价值在于:没有它,后端一报错直接把异常堆栈抛给前端,前后端联调就是灾难。有它之后,前端拿到的永远是结构化的 JSON 错误信息,问题定位容易得多。
3.3 用户模块和图书模块的 Controller、Service、Mapper
骨架和基础配置就绪后,业务代码的生成才是这次实操的重头戏。我继续在对话框下发指令:
生成 UserController、UserService、UserMapper,提供注册、登录两个接口。注册时用户名不能重复,密码用 MD5 加密,登录时校验用户名密码是否匹配。返回 Result 类型。
Trae 做的事是帮你把整个链路都建起来,包括 Mapper 接口(继承 BaseMapper)、Service 接口和实现类、Controller 类。不用你一步步去建文件、写 import,这是它比"问一句答一句"的普通 AI 对话模式强的地方。
这里有几个我在实操中验证过的重点经验:
- 密码加密不要用 MD5,至少用 BCrypt。我一开始习惯性让 Trae 写 MD5,后来意识到这是坏习惯。你可以在生成完代码后,手动把加密方式改成
BCryptPasswordEncoder,再把三处调用点改过来。改起来其实很快,但安全等级完全不同。 - Controller 里不要写业务逻辑,只做参数接收和结果返回。Trae 生成的代码偶尔会偷懒把业务逻辑全塞进 Controller 里,你可以检查一遍并让它"抽取到 Service 层"。
- 登录接口返回的密码字段要置空。这是一个非常常见的低级问题:查询出来的 User 对象直接返回给前端,密码也带出去了。让 Trae 在返回前把 password 设为 null 或者写一个
UserVO只返回需要的字段。
图书模块也是类似的套路。分页查询那部分,MyBatis-Plus 自带Page对象,代码很简洁:
public Page<Book> pageBooks(int pageNum, int pageSize, String keyword) { Page<Book> page = new Page<>(pageNum, pageSize); LambdaQueryWrapper<Book> wrapper = new LambdaQueryWrapper<>(); if (StringUtils.hasText(keyword)) { wrapper.like(Book::getTitle, keyword).or().like(Book::getAuthor, keyword); } return bookMapper.selectPage(page, wrapper); }从 Trae 生成到我可以运行,整个过程不到二十分钟。它生成代码的速度是真的快,但你要保持清醒,知道它在干什么。我见过不少朋友让 AI 写完后直接启动,报错了就喊"AI 生成的代码不行"。其实不是不行,是你没告诉它上下文和约束条件。
4. 接口联调与前后端分离的关键配置
4.1 跨域配置必须一次做对
前后端分离项目里,跨域是绕不开的问题。前端跑在http://localhost:5173(Vue 默认端口),后端跑在http://localhost:8080,这种"不同端口即不同源"的情况,浏览器会拦截 AJAX 请求。
Trae 生成的跨域配置有两种路径。第一种是写一个CorsConfig配置类,第二种是在 Controller 上加@CrossOrigin注解。我的建议是用全局配置类,一次性解决所有接口的跨域问题,而不是每个 Controller 都去加注解。
我给 Trae 的指令是:
添加一个 WebMvcConfigurer 的配置类,允许所有来源的跨域请求,允许所有请求头,允许 GET、POST、PUT、DELETE 方法,暴露所有响应头。
生成的代码大致如下:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }需要注意allowCredentials(true)和allowedOriginPatterns("*")的组合。如果你用了allowedOrigins("*"),在开启凭据时会报错,必须改成allowedOriginPatterns。这个坑很隐蔽,Trae 第一次生成的配置大概率就是报错的那种,需要你手动改一下。
4.2 统一接口风格与前端适配
除了跨域,前后端对接还有一个隐蔽问题:接口返回格式不一致。前端写起来最舒服的格式是{ code: 200, message: "操作成功", data: { list: [], total: 0 } },所以后端做分页查询时,Result里的 data 就不能直接放Page对象,而是要放一个包含list和total的 Map 或者PageVO。
我让 Trae 把分页接口的数据结构调整成前端友好的格式:
@GetMapping("/page") public Result<Map<String, Object>> page(@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize, @RequestParam(required = false) String keyword) { Page<Book> result = bookService.pageBooks(pageNum, pageSize, keyword); Map<String, Object> data = new HashMap<>(); data.put("list", result.getRecords()); data.put("total", result.getTotal()); return Result.success(data); }这个改动看起来很小,但直接决定了你联调的时候顺不顺手。如果前端拿到的 total 藏在data.total里还是data.data.total里,就得看后端心情了。先和后端商量好统一格式再动手写前端,是前后端分离实战里最重要的一条潜规则。
4.3 接口自测:用 Apifox 把接口跑通
代码写完不代表工作结束。我在每次让 Trae 生成完接口后,都会用 Apifox(或者 Postman)把接口全部打一遍。我的测试顺序和关注点如下:
- 先测注册接口,看返回是否成功、密码字段是否没暴露。
- 再测登录接口,拿到 token 后再测需要鉴权的接口。
- 测图书的增删改查,每测完一个接口就刷新一次数据库看数据变化是否符合预期。
- 测分页接口,传入
keyword参数,看模糊搜索有没有生效。 - 故意传错误参数(比如把
pageSize传成 0),看全局异常处理器有没有兜住。
如果你想让 Trae 顺便帮你生成接口文档,可以在对话框里加一句"集成 Knife4j,生成接口文档",它会自动加入依赖和配置。启动项目后访问http://localhost:8080/doc.html,就能看到所有接口的在线文档。这对前后端分离项目来说,是给前端同学提供的最大善意。
5. 踩坑记录与排查技巧实录
5.1 Spring Boot 2.7 和 JDK 17 的组合
这个组合本身是兼容的,但有几个细节容易踩。如果你本机装的是 JDK 17,而 pom 里 Spring Boot 是 2.7.x,需要注意 Lombok 插件版本要足够新(1.18.30 以上),否则 IDE 里会报诡异错误。让 Trae 生成 pom 时如果用 2.7.18,Lombok 是默认带好版本的,一般没问题。
如果启动时看到java.lang.reflect.InaccessibleObjectException,别慌,多半是 JDK 模块化导致反射受限。解决方案有两个:一是换 JDK 8,二是给 Maven 加 JVM 参数--add-opens。我的偷懒方案是:直接降级到 JDK 8,对 Spring Boot 2.7 来说完全够用,省心。
5.2 Maven 依赖下载慢或失败
这是国内环境的老大难问题。如果你发现 Trae 生成项目后,Maven 一直在下载依赖且速度感人,建一个~/.m2/settings.xml,把中央仓库换成阿里云镜像:
<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>改完记得重启 IDE 或者重新加载 Maven 工程。这个配置属于一次配好、终身受益的那种。
5.3 Trae 生成代码的"幻觉"环节
再智能的工具也有瞎编的时候。我遇到过比较典型的情况是:让 Trae 写一个"根据用户名查找用户"的方法,它写的 SQL 是SELECT * FROM user WHERE username = ?,没问题;但如果你让它写复杂一点的连表查询,它给出的 SQL 可能跟你的表名、字段名对不上,甚至表名大小写不一致导致报错。
排查这类问题没有捷径,只有一个土办法:SQL 自己跑一遍,接口自己调一遍,把 Trae 生成的东西当成"应该能跑但不保证能跑"的代码来对待。
5.4 常见错误速查表
| 报错信息 | 原因 | 处理方法 |
|---|---|---|
Field 'id' doesn't have a default value | 实体类主键策略不对 | 给@TableId加type = IdType.AUTO |
Cause: java.sql.SQLSyntaxErrorException: Table 'book_system.book' doesn't exist | 表名拼写或库名不对 | 检查数据库名字和表名是否一致 |
NoSuchBeanDefinitionException: UserMapper | 忘了@MapperScan或者 Mapper 接口没加@Mapper | 启动类加@MapperScan("com.example.booksystem.mapper") |
Failed to configure a DataSource: 'url' attribute is not specified | application.yml 里的数据源配置没生效 | 检查配置文件是不是被当成 .txt 了,以及是否放在 resources 下 |
Access denied for user 'root'@'localhost' | MySQL 密码不对 | 检查 yml 里的密码,或者用命令行连一下数据库验证 |
5.5 让 Trae 生成代码更靠谱的三个建议
最后分享三个我自己摸索出来的使用心得,对新手特别管用。
第一,把需求写完整再提交。你给 Trae 的提示越完整,它返回的结果就越贴近你的预期。一次把表结构、接口签名、返回格式说清楚,比让它来回猜十次有效得多。
第二,让 Trae 一步步来。如果你一口气让它"做一个完整的图书管理系统后端",它大概率会生成一堆你没有要求的代码。把任务拆成"先建项目骨架""再生成用户模块""再生成图书模块"这样的小步骤,每一轮都能及时发现问题,也方便你学清楚每一步。
第三,把 Trae 生成的代码当作 DIY 模型的说明书,而不是成品。AI 编程工具提升的是效率下限,而决定质量上限的,永远是你的代码规范和业务理解。我在每次生成后都会做一轮代码审查,该抽的方法抽取,该删的注释删掉,该补充的校验补上。这个习惯保留下来,才不会让项目变成"能跑但没人敢动"的屎山。
我自己实际操作下来,用 Trae 生成一个前后端分离项目的后端,从零到接口全部跑通,大约一个半小时,其中一半时间花在联调和排查上。对于还在学习 Spring Boot 的朋友,我的建议是别把它当"代写作业的工具",而是当"随叫随到的结对编程伙伴",让它解释代码、让它出多种写法、让它帮你重构,这才是使用这类工具最划算的方式。
本文还有配套的精品资源,点击获取