☰
SpringBoot + MyBatis-Plus 读取数据库数据
2026/10/24 4:13:52 网站建设 项目流程

一、任务要求

  1. SpringBoot + MyBatis-Plus 读取数据库数据返回给前端,需要实现对应的controller、domain、mapper、service四层;
  2. 数据表user结构:id(int 主键)、name(varchar 50)、birthday(date)、sex(varchar 1)、create_time(datetime);
  3. 接口统一根地址/api/user,实现 5 个接口:
    • 3.1 根据用户 id 获取用户信息@GetMapping("/{id}")
    • 3.2 获取所有用户信息@GetMapping("list")
    • 3.3 添加用户信息@PostMapping
    • 3.4 更新某个用户信息(根据 id)@PutMapping
    • 3.5 删除某个用户信息@DeleteMapping("/{id}")
  4. Service、Mapper 增加自定义方法:
    • getAllUserSortByNameDesc:直接写 SQL(注解方式),按姓名降序;
    • selectUserList:与 mapper.xml 配合使用;
    • controller 中编写调用的两个接口。
  5. 代码 + 博客上交,博客记录完整开发过程并附 Postman/ApiFox 测试运行结果。

二、环境准备与建表

2.1 环境版本

组件版本
JDK17
Spring Boot4.1.1
MyBatis-Plus3.5.16(mybatis-plus-spring-boot4-starter)
MySQL8.0
数据库mybatis,表user,预置 50 条测试数据

2.2 建表 SQL

CREATETABLE`user`(`id`INTNOTNULLAUTO_INCREMENTCOMMENT'主键',`name`VARCHAR(50)DEFAULTNULLCOMMENT'姓名',`birthday`DATEDEFAULTNULLCOMMENT'生日',`sex`VARCHAR(1)DEFAULTNULLCOMMENT'性别',`create_time`DATETIMEDEFAULTNULLCOMMENT'创建时间',PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

注意表名user在 MySQL 里是保留字,SQL 里要写成反引号`user`。


三、创建工程与依赖

Spring Initializr 生成骨架后,pom.xml关键依赖:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>4.1.1</version></parent><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webmvc</artifactId></dependency><!-- ✅ Boot 4.x 专用 MyBatis-Plus starter,不能混用 Boot2/3 的 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot4-starter</artifactId><version>3.5.16</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies>

踩坑记录 ①:Spring Boot 4.x 必须用mybatis-plus-spring-boot4-starter,网上教程常见的mybatis-plus-boot-starter(Boot2/3 用)混用会启动报错。

数据源配置application.yml

server:port:8080spring:datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername:rootpassword:1234mybatis-plus:mapper-locations:classpath*:/mapper/**/*.xmlconfiguration:log-impl:org.apache.ibatis.logging.stdout.StdOutImpl# 控制台打印 SQL,方便调试global-config:db-config:id-type:auto# 主键自增

四、四层代码实现

项目结构:

src/main/java/com/example/l06mybatis/ ├── L06MybatisApplication.java ├── config/ │ └── MyMetaObjectHandler.java # 字段自动填充(后期优化加入) ├── controller/ │ └── UserController.java ├── domain/ │ └── User.java ├── mapper/ │ └── UserMapper.java ├── service/ │ ├── UserService.java │ └── impl/UserServiceImpl.java └── tools/ └── Result.java # 统一响应封装 src/main/resources/mapper/ └── UserMapper.xml

4.1 domain 层 —— 实体类

@Data@TableName("`user`")publicclassUserimplementsSerializable{privatestaticfinallongserialVersionUID=1L;@TableId(type=IdType.AUTO)privateIntegerid;privateStringname;privateLocalDatebirthday;privateStringsex;@TableField(fill=FieldFill.INSERT)// 插入时由 MetaObjectHandler 自动填充privateLocalDateTimecreateTime;}

实体字段与表字段一一对应(驼峰 ↔ 下划线由 MyBatis-Plus 自动映射);LocalDate对应date,LocalDateTime对应datetime。

4.2 mapper 层 —— BaseMapper + 注解 SQL

@MapperpublicinterfaceUserMapperextendsBaseMapper<User>{// 自定义方法1:直接写 SQL(注解方式),按姓名降序排序@Select("SELECT id, name, birthday, sex, create_time FROM `user` ORDER BY name DESC")List<User>getAllUserSortByNameDesc();// 自定义方法2:配合 UserMapper.xml 中 <select id="selectUserList">List<User>selectUserList();}

继承BaseMapper<User>后,单表 CRUD(selectById、insert、updateById、deleteById)全部白拿,一行 SQL 不用写。

4.3 mapper.xml —— XML 方式查询

src/main/resources/mapper/UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.l06mybatis.mapper.UserMapper"><!-- 自定义方法2:与 UserMapper.selectUserList() 对应,查询全部用户 --><selectid="selectUserList"resultType="com.example.l06mybatis.domain.User">SELECT id, name, birthday, sex, create_time FROM `user`</select></mapper>

namespace 必须是 Mapper 接口全限定名,id必须与方法名一致。

4.4 service 层

publicinterfaceUserServiceextendsIService<User>{UsergetUserById(Longid);booleancreateUser(Useruser);booleanupdateUserById(Useruser);booleanremoveUserById(Longid);// 自定义方法List<User>getAllUserSortByNameDesc();List<User>selectUserList();}
@ServicepublicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsUserService{@OverridepublicUsergetUserById(Longid){returngetById(id);}@OverridepublicbooleancreateUser(Useruser){returnsave(user);}@OverridepublicbooleanupdateUserById(Useruser){returnupdateById(user);}@OverridepublicbooleanremoveUserById(Longid){returnremoveById(id);}@OverridepublicList<User>getAllUserSortByNameDesc(){returnbaseMapper.getAllUserSortByNameDesc();}@OverridepublicList<User>selectUserList(){returnbaseMapper.selectUserList();}}

继承IService/ServiceImpl,CRUD 直接调用 MyBatis-Plus 提供的getById / save / updateById / removeById。

4.5 tools —— 统一响应封装

@DatapublicclassResult<T>{privateIntegercode;privateStringmessage;privateTdata;publicstatic<T>Result<T>success(Tdata){Result<T>result=newResult<>();result.code=200;result.message="success";result.data=data;returnresult;}publicstatic<T>Result<T>error(Integercode,Stringmessage){Result<T>result=newResult<>();result.code=code;result.message=message;returnresult;}}

4.6 controller 层 —— 5 个作业接口 + 2 个自定义接口

@RestController@RequestMapping("/api/user")publicclassUserController{@AutowiredpublicUserServiceuserService;// 3.1 根据 id 查询单个用户(查不到时返回失败 Result)@GetMapping("/{id}")publicResult<User>getUser(@PathVariableLongid){Useruser=userService.getUserById(id);if(user==null){returnResult.error(404,"用户不存在: id="+id);}returnResult.success(user);}// 3.2 查询全部用户列表@GetMapping("list")publicResult<List<User>>getUserList(){returnResult.success(userService.list());}// 3.3 新增用户@PostMappingpublicResult<Boolean>createUser(@RequestBodyUseruser){returnResult.success(userService.createUser(user));}// 3.4 修改用户@PutMappingpublicResult<Boolean>updateUser(@RequestBodyUseruser){returnResult.success(userService.updateUserById(user));}// 3.5 删除用户@DeleteMapping("/{id}")publicResult<Boolean>deleteUser(@PathVariableLongid){returnResult.success(userService.removeUserById(id));}// 自定义接口1:按姓名降序排序查询(Mapper 注解 SQL)@GetMapping("sortByNameDesc")publicResult<List<User>>getUserSortByNameDesc(){returnResult.success(userService.getAllUserSortByNameDesc());}// 自定义接口2:配合 UserMapper.xml 查询用户列表@GetMapping("selectUserList")publicResult<List<User>>getSelectUserList(){returnResult.success(userService.selectUserList());}}

4.7 字段自动填充(后期优化)

最初版本 POST 之后查询create_time是 null——实体插入时没赋值、表字段也没有默认值。用 MyBatis-Plus 的自动填充解决:

@ComponentpublicclassMyMetaObjectHandlerimplementsMetaObjectHandler{@OverridepublicvoidinsertFill(MetaObjectmetaObject){this.strictInsertFill(metaObject,"createTime",LocalDateTime.class,LocalDateTime.now());}@OverridepublicvoidupdateFill(MetaObjectmetaObject){}}

踩坑记录 ②:strictInsertFill只对实体上标注了@TableField(fill = FieldFill.INSERT)的字段生效,两个要配套。


五、开发过程中排查的两个问题

  1. 新增/修改后createTime返回 null
    原因:实体插入时未给create_time赋值,数据库字段也没设默认值。
    解决:实体加@TableField(fill = FieldFill.INSERT)+ 新增MyMetaObjectHandler,插入时自动写入当前时间。修复后回查"createTime":"2026-10-22T20:25:58"。

  2. 按 id 查询不存在的记录返回data:null,前端无法区分"查询成功但为空"和"用户不存在"
    解决:Result增加error(code, message),Controller 判空后返回{"code":404,"message":"用户不存在: id=999"},语义更明确。


六、Postman 接口测试结果

测试方式:Postman 导入集合,对 5 个作业接口 + 2 个自定义接口逐个发起请求(新增→修改→删除使用临时数据并自清理)。

测试结果总览

#接口方法请求路径HTTP业务 code结果
1查询全部用户列表GET/api/user/list200200✅ 50 条数据
2按 id 查询单个用户GET/api/user/1200200✅
2b按 id 查询(不存在)GET/api/user/999200404✅ 返回"用户不存在"
3新增用户POST/api/user200200✅ 落库成功,createTime 自动填充
4修改用户PUT/api/user200200✅ 复查字段已更新
5删除用户DELETE/api/user/{id}200200✅ 复查已删除
6自定义①按姓名降序GET/api/user/sortByNameDesc200200✅ 注解 SQL 生效
7自定义②mapper.xml 查询GET/api/user/selectUserList200200✅ XML 配置生效

6.1 GET /api/user/list —— 查询全部用户

返回 50 条用户数据,code=200,字段完整(id / name / birthday / sex / createTime)。

6.2 GET /api/user/1 —— 按 id 查询

返回 id=1 的用户"罗秀兰",与列表第 1 条一致。

6.3 POST /api/user —— 新增用户

请求体{"name":"张三","birthday":"1999-01-01","sex":"男"},响应data:true;回查列表确认落库(id 自增)。

6.4 PUT /api/user —— 修改用户

按 id 修改姓名/生日/性别,响应data:true,按 id 复查确认修改生效。

6.5 DELETE /api/user/{id} —— 删除用户

删除新增的临时用户,响应data:true;复查单查返回"用户不存在"、列表回到 50 条,测试数据自清理。

6.6 GET /api/user/sortByNameDesc —— 自定义①(注解 SQL)

Mapper 中直接写 SQLORDER BY name DESC,返回 50 条按姓名降序排列。

6.7 GET /api/user/selectUserList —— 自定义②(mapper.xml)

Mapper 接口方法与UserMapper.xml的<select>配合,查询结果与 list 接口一致,证明 XML 配置生效。


七、总结

  1. MyBatis-Plus 的价值:单表 CRUD 通过BaseMapper+IService零 SQL 完成;需要自定义 SQL 时,注解@Select和 XML 两种方式都能与 Service 层无缝衔接,本实验两种方式各实现了一个。
  2. 四层架构:Controller 只做参数接收与结果包装,Service 承接业务,Mapper 负责数据访问,domain 承载表结构——层次清晰,换 ORM 或改业务互不影响。
  3. 踩坑收获:Boot 4.x 要用对应的mybatis-plus-spring-boot4-starter;user是 MySQL 保留字要加反引号;字段自动填充需要@TableField(fill=...)与MetaObjectHandler配套;接口对"查不到"的场景应返回明确的业务错误码而不是null。
  4. 测试闭环:Postman 全部 7 个接口 200 通过,测试数据自清理,未污染原始数据。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询