在 IntelliJ IDEA 中创建第一个 Spring Boot 项目 增删改查 MyBatis + PageHelper 全面整合(适配 JsonResult + 分页)
📚 最终完整教程:Spring Boot + MyBatis + PageHelper 全面整合(适配 JsonResult + 分页)
这是一份可直接运行的生产级教程,基于你项目的
JsonResult风格和PageHelper分页,从零开始完整实现基于 YAML 配置的 CRUD + 分页功能。
📁 一、项目完整结构
demo-user-management
├── src
│ └── main
│ ├── java
│ │ └── com/example/demo
│ │ ├── DemoApplication.java # 启动类
│ │ ├── common
│ │ │ └── JsonResult.java # 统一返回结果
│ │ ├── config
│ │ │ └── PageHelperConfig.java # PageHelper 配置类
│ │ ├── controller
│ │ │ └── UserController.java # 控制器
│ │ ├── entity
│ │ │ └── User.java # 实体类
│ │ ├── mapper
│ │ │ └── UserMapper.java # Mapper 接口
│ │ └── service
│ │ ├── UserService.java # 服务接口
│ │ └── impl
│ │ └── UserServiceImpl.java # 服务实现
│ └── resources
│ ├── application.yml # YAML 配置文件
│ └── mapper
│ └── UserMapper.xml # MyBatis XML 映射
└── pom.xml # Maven 依赖
🗄️ 二、数据库准备
在 MySQL 中执行以下 SQL:
-- 创建数据库
CREATE DATABASE IF NOT EXISTS demo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE demo_db;
-- 创建用户表
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
name VARCHAR(50) NOT NULL COMMENT '姓名',
email VARCHAR(100) UNIQUE NOT NULL COMMENT '邮箱',
age INT COMMENT '年龄',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 插入测试数据(20条,方便测试分页)
INSERT INTO users (name, email, age) VALUES
('张伟', 'zhangwei@example.com', 25),
('李娜', 'lina@example.com', 30),
('王芳', 'wangfang@example.com', 28),
('刘洋', 'liuyang@example.com', 35),
('陈静', 'chenjing@example.com', 22),
('赵敏', 'zhaomin@example.com', 27),
('孙强', 'sunqiang@example.com', 33),
('周洁', 'zhoujie@example.com', 29),
('吴浩', 'wuhao@example.com', 31),
('郑爽', 'zhengshuang@example.com', 24),
('钱华', 'qianhua@example.com', 26),
('冯丽', 'fengli@example.com', 32),
('蒋明', 'jiangming@example.com', 28),
('沈月', 'shenyue@example.com', 23),
('韩雪', 'hanxue@example.com', 27),
('杨光', 'yangguang@example.com', 34),
('朱婷', 'zhuting@example.com', 26),
('秦岚', 'qinlan@example.com', 29),
('尤娜', 'youna@example.com', 31),
('许静', 'xujing@example.com', 24);
📦 三、Maven 依赖配置(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo-user-management</artifactId>
<version>1.0.0</version>
<name>demo-user-management</name>
<description>用户管理完整示例</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis Spring Boot Starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- PageHelper 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.3</version>
</dependency>
<!-- PageHelper 依赖的 SQL 解析器 -->
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.7</version>
</dependency>
<!-- 热部署(开发工具) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!-- 确保 XML 文件被正确打包 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.yml</include>
<include>**/*.properties</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
⚙️ 四、YAML 配置文件(application.yml)
在 src/main/resources/application.yml 中完整配置:
# ==================== Spring Boot 核心配置 ====================
spring:
# 数据源配置
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: root
password: 123456 # ⚠️ 请替换为你的实际密码
driver-class-name: com.mysql.cj.jdbc.Driver
# 连接池配置(HikariCP)
hikari:
maximum-pool-size: 20
minimum-idle: 5
idle-timeout: 30000
connection-timeout: 30000
max-lifetime: 1800000
# 应用名称
application:
name: demo-user-management
# ==================== MyBatis 配置 ====================
mybatis:
# 实体类别名包(XML 中 resultType 可省略包名)
type-aliases-package: com.example.demo.entity
# Mapper XML 文件位置
mapper-locations: classpath:mapper/*.xml
# MyBatis 全局配置
configuration:
# 开启驼峰命名自动映射(user_name -> userName)
map-underscore-to-camel-case: true
# 控制台打印 SQL 日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 开启懒加载
lazy-loading-enabled: true
# 开启二级缓存
cache-enabled: true
# 设置超时时间(秒)
default-statement-timeout: 30
# ==================== PageHelper 分页插件配置 ====================
# 注意:Spring Boot 2.4+ 可能不自动加载此配置,需要配合 Java 配置类
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count=countSql
# ==================== 日志配置 ====================
logging:
level:
# 显示 Mapper 接口执行的 SQL
com.example.demo.mapper: DEBUG
# 显示 SQL 参数绑定
org.mybatis: DEBUG
# 显示 PageHelper 分页信息
com.github.pagehelper: DEBUG
pattern:
console: '%d{yyyy-MM-dd HH:mm:ss} - %msg%n'
# ==================== 服务器配置 ====================
server:
port: 8080
servlet:
context-path: /
# 优雅关闭
shutdown: graceful
📄 五、统一返回结果类(JsonResult)
完全沿用你项目的设计风格,基于 HashMap 实现灵活的数据存储,支持链式调用:
package com.example.demo.common;
import java.io.Serializable;
import java.util.HashMap;
/**
* 统一返回结果类
*
* <p>用法示例:
* <pre>
* // 成功返回数据
* return JsonResult.success(pageInfo);
*
* // 成功返回自定义消息
* return JsonResult.success(pageInfo, "查询成功");
*
* // 链式追加额外字段
* return JsonResult.success(pageInfo).put("extra", "extraValue");
*
* // 失败返回
* return JsonResult.fail("用户不存在");
* </pre>
*
* @author System
* @version 1.0
*/
public class JsonResult extends HashMap<String, Object> implements Serializable {
private static final long serialVersionUID = 1L;
/** 成功状态码 */
public static final int CODE_SUCCESS = 200;
/** 失败状态码 */
public static final int CODE_FAIL = 0;
public JsonResult() {
// 默认构造
}
/**
* 构建成功返回结果
*
* @param data 数据体(可以是 PageInfo、List、Object 等)
* @return JsonResult
*/
public static JsonResult success(Object data) {
JsonResult result = new JsonResult();
result.put("code", CODE_SUCCESS);
result.put("msg", "操作成功");
result.put("data", data);
return result;
}
/**
* 构建成功返回结果(自定义消息)
*
* @param data 数据体
* @param msg 自定义成功消息
* @return JsonResult
*/
public static JsonResult success(Object data, String msg) {
JsonResult result = new JsonResult();
result.put("code", CODE_SUCCESS);
result.put("msg", msg);
result.put("data", data);
return result;
}
/**
* 构建失败返回结果
*
* @param msg 错误信息
* @return JsonResult
*/
public static JsonResult fail(String msg) {
JsonResult result = new JsonResult();
result.put("code", CODE_FAIL);
result.put("msg", msg);
result.put("data", null);
return result;
}
/**
* 构建失败返回结果(自定义错误码)
*
* @param code 错误码
* @param msg 错误信息
* @return JsonResult
*/
public static JsonResult fail(int code, String msg) {
JsonResult result = new JsonResult();
result.put("code", code);
result.put("msg", msg);
result.put("data", null);
return result;
}
/**
* 链式追加自定义字段(覆盖 HashMap 的 put 方法)
*
* @param key 键
* @param value 值
* @return JsonResult(支持链式调用)
*/
@Override
public JsonResult put(String key, Object value) {
super.put(key, value);
return this;
}
/**
* 判断是否成功
*
* @return true 表示成功
*/
public boolean isSuccess() {
Object code = this.get("code");
if (code == null) {
return false;
}
return CODE_SUCCESS == (int) code;
}
/**
* 快速获取 data 字段
*/
public Object getData() {
return this.get("data");
}
}
🧩 六、实体类(User.java)
package com.example.demo.entity;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 用户实体类(对应数据库 users 表)
*
* @author System
*/
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private String email;
private Integer age;
private LocalDateTime createTime;
// ===== 构造方法 =====
public User() {}
public User(String name, String email, Integer age) {
this.name = name;
this.email = email;
this.age = age;
}
// ===== Getter & Setter =====
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
// ===== toString =====
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
", createTime=" + createTime +
'}';
}
}
🔧 七、PageHelper 配置类(解决 YAML 不生效问题)
package com.example.demo.config;
import com.github.pagehelper.PageInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* PageHelper 分页插件配置类
*
* <p>由于 Spring Boot 2.4+ 可能无法自动读取 application.yml 中的 pagehelper 配置,
* 通过 Java 配置类手动创建 PageInterceptor Bean,确保分页插件生效。
*
* @author System
*/
@Configuration
public class PageHelperConfig {
/**
* 创建 PageHelper 拦截器
*/
@Bean
public Interceptor pageHelperInterceptor() {
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
// 设置数据库方言为 MySQL
properties.setProperty("helperDialect", "mysql");
// 分页参数合理化:pageNum <= 0 时查第一页,pageNum > 总页数时查最后一页
properties.setProperty("reasonable", "true");
// 支持通过 Mapper 接口参数传递分页参数
properties.setProperty("supportMethodsArguments", "true");
// 分页参数映射
properties.setProperty("params", "count=countSql");
// 自动分页 COUNT 查询优化
properties.setProperty("autoRuntimeDialect", "false");
pageInterceptor.setProperties(properties);
return pageInterceptor;
}
}
🗺️ 八、Mapper 接口(UserMapper.java)
package com.example.demo.mapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 用户 Mapper 接口
*
* @author System
*/
@Mapper
public interface UserMapper {
// =============================================
// 查询操作
// =============================================
/**
* 查询所有用户
*
* @return 用户列表
*/
List<User> findAll();
/**
* 根据 ID 查询用户
*
* @param id 用户 ID
* @return 用户对象
*/
User findById(@Param("id") Integer id);
/**
* 按姓名模糊查询(用于分页)
*
* @param name 姓名(模糊匹配)
* @return 用户列表
*/
List<User> findByNameLike(@Param("name") String name);
/**
* 条件查询(支持多条件,用于复杂分页)
*
* @param name 姓名(模糊匹配)
* @param minAge 最小年龄
* @param maxAge 最大年龄
* @return 用户列表
*/
List<User> findByCondition(@Param("name") String name,
@Param("minAge") Integer minAge,
@Param("maxAge") Integer maxAge);
// =============================================
// 新增操作
// =============================================
/**
* 新增用户(返回自增主键)
*
* @param user 用户对象
* @return 影响行数
*/
int insert(User user);
// =============================================
// 修改操作
// =============================================
/**
* 更新用户信息
*
* @param user 用户对象
* @return 影响行数
*/
int update(User user);
// =============================================
// 删除操作
// =============================================
/**
* 根据 ID 删除用户
*
* @param id 用户 ID
* @return 影响行数
*/
int deleteById(@Param("id") Integer id);
/**
* 批量删除用户
*
* @param ids ID 列表
* @return 影响行数
*/
int deleteBatch(@Param("ids") List<Integer> ids);
}
📝 九、MyBatis XML 映射文件(UserMapper.xml)
在 src/main/resources/mapper/UserMapper.xml 中编写 SQL:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<!-- ============================================= -->
<!-- 结果映射 -->
<!-- ============================================= -->
<resultMap id="userResultMap" type="com.example.demo.entity.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="email" column="email"/>
<result property="age" column="age"/>
<result property="createTime" column="create_time"/>
</resultMap>
<!-- 通用查询列(提高可维护性) -->
<sql id="baseColumns">
id, name, email, age, create_time
</sql>
<!-- ============================================= -->
<!-- 1. 查询所有用户 -->
<!-- ============================================= -->
<select id="findAll" resultMap="userResultMap">
SELECT <include refid="baseColumns"/>
FROM users
ORDER BY id
</select>
<!-- ============================================= -->
<!-- 2. 根据 ID 查询用户 -->
<!-- ============================================= -->
<select id="findById" resultMap="userResultMap">
SELECT <include refid="baseColumns"/>
FROM users
WHERE id = #{id}
</select>
<!-- ============================================= -->
<!-- 3. 按姓名模糊查询(分页用) -->
<!-- ============================================= -->
<select id="findByNameLike" resultMap="userResultMap">
SELECT <include refid="baseColumns"/>
FROM users
<where>
<if test="name != null and name != ''">
name LIKE CONCAT('%', #{name}, '%')
</if>
</where>
ORDER BY id
</select>
<!-- ============================================= -->
<!-- 4. 条件查询(多条件分页) -->
<!-- ============================================= -->
<select id="findByCondition" resultMap="userResultMap">
SELECT <include refid="baseColumns"/>
FROM users
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="minAge != null">
AND age >= #{minAge}
</if>
<if test="maxAge != null">
AND age <= #{maxAge}
</if>
</where>
ORDER BY id
</select>
<!-- ============================================= -->
<!-- 5. 新增用户(返回自增主键) -->
<!-- ============================================= -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO users (name, email, age)
VALUES (#{name}, #{email}, #{age})
</insert>
<!-- ============================================= -->
<!-- 6. 更新用户(动态更新) -->
<!-- ============================================= -->
<update id="update">
UPDATE users
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="email != null and email != ''">
email = #{email},
</if>
<if test="age != null">
age = #{age},
</if>
</set>
WHERE id = #{id}
</update>
<!-- ============================================= -->
<!-- 7. 根据 ID 删除用户 -->
<!-- ============================================= -->
<delete id="deleteById">
DELETE FROM users
WHERE id = #{id}
</delete>
<!-- ============================================= -->
<!-- 8. 批量删除用户 -->
<!-- ============================================= -->
<delete id="deleteBatch">
DELETE FROM users
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>
💼 十、Service 层实现
UserService.java(接口)
package com.example.demo.service;
import com.example.demo.entity.User;
import com.github.pagehelper.PageInfo;
import java.util.List;
/**
* 用户服务接口
*
* @author System
*/
public interface UserService {
// =============================================
// 基础 CRUD
// =============================================
/**
* 查询所有用户
*/
List<User> findAll();
/**
* 根据 ID 查询用户
*/
User findById(Integer id);
/**
* 新增用户
*/
int insert(User user);
/**
* 更新用户
*/
int update(User user);
/**
* 删除用户
*/
int deleteById(Integer id);
/**
* 批量删除用户
*/
int deleteBatch(List<Integer> ids);
// =============================================
// 分页查询(返回 PageInfo)
// =============================================
/**
* 分页查询所有用户
*
* @param pageNo 当前页码(从 1 开始)
* @param pageSize 每页条数
* @return PageInfo 分页对象
*/
PageInfo<User> queryPageList(int pageNo, int pageSize);
/**
* 按姓名分页查询
*
* @param name 姓名(模糊查询)
* @param pageNo 当前页码
* @param pageSize 每页条数
* @return PageInfo 分页对象
*/
PageInfo<User> queryPageListByName(String name, int pageNo, int pageSize);
/**
* 多条件分页查询
*
* @param name 姓名(模糊查询)
* @param minAge 最小年龄
* @param maxAge 最大年龄
* @param pageNo 当前页码
* @param pageSize 每页条数
* @return PageInfo 分页对象
*/
PageInfo<User> queryPageListByCondition(String name, Integer minAge, Integer maxAge,
int pageNo, int pageSize);
}
UserServiceImpl.java(实现类)
package com.example.demo.service.impl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 用户服务实现类
*
* @author System
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
// =============================================
// 基础 CRUD 实现
// =============================================
@Override
public List<User> findAll() {
return userMapper.findAll();
}
@Override
public User findById(Integer id) {
return userMapper.findById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int insert(User user) {
return userMapper.insert(user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int update(User user) {
return userMapper.update(user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int deleteById(Integer id) {
return userMapper.deleteById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int deleteBatch(List<Integer> ids) {
if (ids == null || ids.isEmpty()) {
return 0;
}
return userMapper.deleteBatch(ids);
}
// =============================================
// 分页查询实现(核心)
// =============================================
@Override
public PageInfo<User> queryPageList(int pageNo, int pageSize) {
// 1. 开启分页(必须在查询前调用)
PageHelper.startPage(pageNo, pageSize);
// 2. 执行查询
List<User> userList = userMapper.findAll();
// 3. 返回 PageInfo
return new PageInfo<>(userList);
}
@Override
public PageInfo<User> queryPageListByName(String name, int pageNo, int pageSize) {
PageHelper.startPage(pageNo, pageSize);
List<User> userList = userMapper.findByNameLike(name);
return new PageInfo<>(userList);
}
@Override
public PageInfo<User> queryPageListByCondition(String name, Integer minAge, Integer maxAge,
int pageNo, int pageSize) {
PageHelper.startPage(pageNo, pageSize);
List<User> userList = userMapper.findByCondition(name, minAge, maxAge);
return new PageInfo<>(userList);
}
}
🌐 十一、Controller 层(完全适配你的项目风格)
package com.example.demo.controller;
import com.example.demo.common.JsonResult;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 用户管理控制器
*
* <p>完全适配项目现有风格:
* <ul>
* <li>统一使用 POST 请求接收 Map 参数</li>
* <li>统一返回 JsonResult</li>
* <li>分页使用 PageHelper + PageInfo</li>
* </ul>
*
* @author System
*/
@RestController
@RequestMapping("/api/users")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
// =============================================
// 1. 分页查询(核心接口)
// =============================================
/**
* 分页查询用户列表
*
* <p>请求示例:
* <pre>
* POST /api/users/page
* {
* "pageNo": 1,
* "pageSize": 5,
* "name": "张"
* }
* </pre>
*
* @param params 请求参数
* @return JsonResult 包含 PageInfo 的分页数据
*/
@PostMapping("/page")
public JsonResult page(@RequestBody Map<String, Object> params) {
try {
// 1. 提取参数(与你项目写法完全一致)
String name = params.get("name") != null ? params.get("name").toString() : null;
int pageNo = Integer.parseInt(params.get("pageNo").toString());
int pageSize = Integer.parseInt(params.get("pageSize").toString());
logger.info("分页查询用户:pageNo={}, pageSize={}, name={}", pageNo, pageSize, name);
// 2. 调用 Service
PageInfo<User> pageInfo = userService.queryPageListByName(name, pageNo, pageSize);
// 3. 返回成功结果(直接将 PageInfo 放入 data)
return JsonResult.success(pageInfo);
} catch (NumberFormatException e) {
logger.error("分页参数格式错误", e);
return JsonResult.fail("分页参数格式错误:pageNo 和 pageSize 必须为数字");
} catch (Exception e) {
logger.error("查询用户列表失败", e);
return JsonResult.fail("查询用户列表失败:" + e.getMessage());
}
}
/**
* 多条件分页查询
*/
@PostMapping("/page/condition")
public JsonResult pageByCondition(@RequestBody Map<String, Object> params) {
try {
String name = params.get("name") != null ? params.get("name").toString() : null;
Integer minAge = params.get("minAge") != null ? Integer.parseInt(params.get("minAge").toString()) : null;
Integer maxAge = params.get("maxAge") != null ? Integer.parseInt(params.get("maxAge").toString()) : null;
int pageNo = Integer.parseInt(params.get("pageNo").toString());
int pageSize = Integer.parseInt(params.get("pageSize").toString());
PageInfo<User> pageInfo = userService.queryPageListByCondition(name, minAge, maxAge, pageNo, pageSize);
return JsonResult.success(pageInfo);
} catch (Exception e) {
logger.error("多条件查询失败", e);
return JsonResult.fail("查询失败:" + e.getMessage());
}
}
// =============================================
// 2. 新增用户
// =============================================
@PostMapping("/add")
public JsonResult add(@RequestBody Map<String, Object> params) {
try {
// 参数校验
String name = params.get("name") != null ? params.get("name").toString() : null;
String email = params.get("email") != null ? params.get("email").toString() : null;
String ageStr = params.get("age") != null ? params.get("age").toString() : null;
if (name == null || name.trim().isEmpty()) {
return JsonResult.fail("姓名不能为空");
}
if (email == null || email.trim().isEmpty()) {
return JsonResult.fail("邮箱不能为空");
}
User user = new User();
user.setName(name.trim());
user.setEmail(email.trim());
user.setAge(ageStr != null ? Integer.parseInt(ageStr) : null);
int result = userService.insert(user);
if (result > 0) {
return JsonResult.success(user, "新增成功");
} else {
return JsonResult.fail("新增失败");
}
} catch (NumberFormatException e) {
return JsonResult.fail("年龄格式错误");
} catch (Exception e) {
logger.error("新增用户失败", e);
return JsonResult.fail("新增用户失败:" + e.getMessage());
}
}
// =============================================
// 3. 修改用户
// =============================================
@PostMapping("/update")
public JsonResult update(@RequestBody Map<String, Object> params) {
try {
Integer id = params.get("id") != null ? Integer.parseInt(params.get("id").toString()) : null;
if (id == null) {
return JsonResult.fail("用户 ID 不能为空");
}
User user = new User();
user.setId(id);
if (params.get("name") != null) {
user.setName(params.get("name").toString());
}
if (params.get("email") != null) {
user.setEmail(params.get("email").toString());
}
if (params.get("age") != null) {
user.setAge(Integer.parseInt(params.get("age").toString()));
}
int result = userService.update(user);
if (result > 0) {
return JsonResult.success(null, "修改成功");
} else {
return JsonResult.fail("修改失败,用户不存在");
}
} catch (NumberFormatException e) {
return JsonResult.fail("参数格式错误");
} catch (Exception e) {
logger.error("修改用户失败", e);
return JsonResult.fail("修改用户失败:" + e.getMessage());
}
}
// =============================================
// 4. 删除用户
// =============================================
@PostMapping("/delete")
public JsonResult delete(@RequestBody Map<String, Object> params) {
try {
Integer id = params.get("id") != null ? Integer.parseInt(params.get("id").toString()) : null;
if (id == null) {
return JsonResult.fail("用户 ID 不能为空");
}
int result = userService.deleteById(id);
if (result > 0) {
return JsonResult.success(null, "删除成功");
} else {
return JsonResult.fail("删除失败,用户不存在");
}
} catch (NumberFormatException e) {
return JsonResult.fail("ID 格式错误");
} catch (Exception e) {
logger.error("删除用户失败", e);
return JsonResult.fail("删除用户失败:" + e.getMessage());
}
}
/**
* 批量删除用户
*/
@PostMapping("/delete/batch")
public JsonResult deleteBatch(@RequestBody Map<String, Object> params) {
try {
@SuppressWarnings("unchecked")
List<Integer> ids = (List<Integer>) params.get("ids");
if (ids == null || ids.isEmpty()) {
return JsonResult.fail("请选择要删除的用户");
}
int result = userService.deleteBatch(ids);
return JsonResult.success(result, "成功删除 " + result + " 条记录");
} catch (Exception e) {
logger.error("批量删除失败", e);
return JsonResult.fail("批量删除失败:" + e.getMessage());
}
}
// =============================================
// 5. 查询用户详情
// =============================================
@PostMapping("/info")
public JsonResult info(@RequestBody Map<String, Object> params) {
try {
Integer id = params.get("id") != null ? Integer.parseInt(params.get("id").toString()) : null;
if (id == null) {
return JsonResult.fail("用户 ID 不能为空");
}
User user = userService.findById(id);
if (user != null) {
return JsonResult.success(user, "查询成功");
} else {
return JsonResult.fail("用户不存在");
}
} catch (NumberFormatException e) {
return JsonResult.fail("ID 格式错误");
} catch (Exception e) {
logger.error("查询用户详情失败", e);
return JsonResult.fail("查询失败:" + e.getMessage());
}
}
// =============================================
// 6. 查询所有用户(不分页)
// =============================================
@PostMapping("/all")
public JsonResult all() {
try {
List<User> userList = userService.findAll();
return JsonResult.success(userList);
} catch (Exception e) {
logger.error("查询所有用户失败", e);
return JsonResult.fail("查询失败:" + e.getMessage());
}
}
}
🚀 十二、启动类(DemoApplication.java)
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Spring Boot 启动类
*
* @author System
*/
@SpringBootApplication
@EnableTransactionManagement // 开启事务管理
@MapperScan("com.example.demo.mapper") // 扫描 Mapper 接口
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
System.out.println("========================================");
System.out.println(" 🚀 用户管理服务启动成功!");
System.out.println(" 📍 访问地址:http://localhost:8080");
System.out.println("========================================");
}
}
🧪 十三、接口测试指南
1. 分页查询用户
请求地址:POST http://localhost:8080/api/users/page
请求 Body(JSON):
{
"pageNo": 1,
"pageSize": 5,
"name": "张"
}
返回结果:
{
"code": 200,
"msg": "操作成功",
"data": {
"total": 2,
"list": [
{"id": 1, "name": "张伟", "email": "zhangwei@example.com", "age": 25, "createTime": "2026-07-17T10:00:00"},
{"id": 19, "name": "张伟", "email": "zhangwei_dup@example.com", "age": 26, "createTime": "2026-07-17T10:00:00"}
],
"pageNum": 1,
"pageSize": 5,
"pages": 1,
"isFirstPage": true,
"isLastPage": true
// ... PageInfo 其他属性
}
}
2. 多条件分页查询
请求地址:POST http://localhost:8080/api/users/page/condition
{
"pageNo": 1,
"pageSize": 10,
"name": "张",
"minAge": 20,
"maxAge": 30
}
3. 新增用户
请求地址:POST http://localhost:8080/api/users/add
{
"name": "赵六",
"email": "zhaoliu@example.com",
"age": 26
}
4. 修改用户
请求地址:POST http://localhost:8080/api/users/update
{
"id": 1,
"name": "张伟更新",
"age": 26
}
5. 删除用户
请求地址:POST http://localhost:8080/api/users/delete
{
"id": 6
}
6. 批量删除用户
请求地址:POST http://localhost:8080/api/users/delete/batch
{
"ids": [7, 8, 9]
}
7. 查询用户详情
请求地址:POST http://localhost:8080/api/users/info
{
"id": 1
}
8. 查询所有用户
请求地址:POST http://localhost:8080/api/users/all
🔧 十四、常见问题解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| PageHelper 分页不生效 | YAML 配置未被 Spring Boot 自动加载 | ✅ 按照教程第7步,添加 PageHelperConfig 配置类 |
| 找不到 Mapper 接口 | 未扫描到 Mapper 包 | ✅ 在启动类添加 @MapperScan("com.example.demo.mapper") |
| XML 文件无法加载 | 路径配置错误或 XML 文件未被打包 | ✅ 确保 mapper-locations: classpath:mapper/*.xml,并检查 Maven 资源配置 |
| 数据库连接失败 | 密码错误/URL 不正确/MySQL 未启动 | ✅ 检查 application.yml 中的 password 和 url |
| 日期类型映射异常 | create_time 字段映射失败 |
✅ MySQL 驱动版本 >= 8.0,或改用 java.util.Date |
| SQL 日志不显示 | 未配置 MyBatis 日志 | ✅ 配置 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl |
| 参数解析异常 | Controller 接收参数为空 | ✅ 确保请求 Content-Type 为 application/json |
| 事务不回滚 | 未开启事务管理或异常被捕获 | ✅ 添加 @EnableTransactionManagement,使用 @Transactional(rollbackFor = Exception.class) |
| 分页总记录数不对 | PageHelper 版本或配置问题 | ✅ 在配置类中添加 params=count=countSql 参数 |
📊 十五、返回数据格式说明
成功返回格式
{
"code": 200,
"msg": "操作成功",
"data": "任意数据(PageInfo/List/Object/String)"
}
失败返回格式
{
"code": 0,
"msg": "具体错误信息",
"data": null
}
分页返回 data 结构(PageInfo 包含的字段)
| 字段 | 类型 | 说明 |
|---|---|---|
total |
long | 总记录数 |
list |
List | 当前页数据列表 |
pageNum |
int | 当前页码 |
pageSize |
int | 每页条数 |
pages |
int | 总页数 |
isFirstPage |
boolean | 是否第一页 |
isLastPage |
boolean | 是否最后一页 |
prePage |
int | 上一页页码 |
nextPage |
int | 下一页页码 |
✅ 十六、教程总结
本教程完整覆盖了以下核心内容:
| 序号 | 核心内容 | 实现方式 |
|---|---|---|
| 1 | 数据库设计 | MySQL 8.0 + users 表 |
| 2 | 项目依赖 | Maven + Spring Boot 2.7 + MyBatis + PageHelper |
| 3 | YAML 配置 | 数据源 + MyBatis + 日志 |
| 4 | PageHelper 配置 | Java 配置类(解决 YAML 不生效问题) |
| 5 | 统一返回结果 | JsonResult(基于 HashMap,支持链式调用) |
| 6 | 实体类 | User 与数据库表映射 |
| 7 | Mapper 接口 | @Mapper 注解 + XML 映射 |
| 8 | XML 映射 | resultMap + 动态 SQL + 批量操作 |
| 9 | Service 层 | 接口 + 实现 + 事务管理 |
| 10 | Controller 层 | POST 请求接收 Map 参数 + 返回 JsonResult |
| 11 | 分页实现 | PageHelper.startPage + PageInfo |
| 12 | 完整 CRUD | 增、删、改、查 + 批量操作 |
核心代码片段汇总
分页核心实现(Service 层):
PageHelper.startPage(pageNo, pageSize);
List<User> list = userMapper.findByNameLike(name);
return new PageInfo<>(list);
统一返回(Controller 层):
PageInfo<User> pageInfo = userService.queryPageListByName(name, pageNo, pageSize);
return JsonResult.success(pageInfo);
链式追加额外字段:
return JsonResult.success(pageInfo)
.put("extra1", "value1")
.put("extra2", "value2");
🎉 恭喜!你现在已经掌握了在 Spring Boot 中使用 YAML + MyBatis + PageHelper + JsonResult 实现完整增删改查和分页查询的全部技能! 你可以将这套代码直接复制到你的项目中使用,也可以根据实际业务需求进行扩展。
更多推荐




所有评论(0)