下面是一个完整的 Spring Boot + MyBatis Plus CRUD 示例,以用户管理为例:
1. 项目结构和依赖
pom.xml 关键依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
application.yml 配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
logging:
level:
com.example.mapper: debug
2. 实体类 (Entity)
package com.rongx.reggie.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String email;
private String phone;
private Integer status;
private Integer age;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
private Integer deleted;
// 版本号,用于乐观锁
@Version
private Integer version;
}
3. Mapper 接口
package com.rongx.reggie.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.rongx.reggie.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 可以在这里添加自定义的 SQL 方法
// 例如:根据用户名查询用户
// User selectByUsername(@Param("username") String username);
}
4. Service 接口和实现
Service 接口
package com.rongx.reggie.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.rongx.reggie.entity.User;
public interface UserService extends IService<User> {
/**
* 自定义业务方法:根据用户名查询用户
*/
User getByUsername(String username);
/**
* 自定义业务方法:用户注册
*/
boolean register(User user);
/**
* 自定义业务方法:更新用户状态
*/
boolean updateStatus(Long id, Integer status);
}
Service 实现类
package com.rongx.reggie.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongx.reggie.entity.User;
import com.rongx.reggie.mapper.UserMapper;
import com.rongx.reggie.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public User getByUsername(String username) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, username);
return this.getOne(wrapper);
}
@Override
public boolean register(User user) {
// 检查用户名是否已存在
User existingUser = this.getByUsername(user.getUsername());
if (existingUser != null) {
throw new RuntimeException("用户名已存在");
}
// 密码加密(简单示例)
String encryptedPassword = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(encryptedPassword);
// 设置默认状态
user.setStatus(1);
return this.save(user);
}
@Override
public boolean updateStatus(Long id, Integer status) {
User user = new User();
user.setId(id);
user.setStatus(status);
return this.updateById(user);
}
}
5. Controller 层
package com.rongx.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.rongx.reggie.common.R;
import com.rongx.reggie.entity.User;
import com.rongx.reggie.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
// ==================== 新增操作 ====================
/**
* 新增用户
*/
@PostMapping
public R<String> save(@RequestBody User user) {
log.info("新增用户: {}", user);
try {
boolean success = userService.register(user);
return success ? R.success("新增用户成功") : R.error("新增用户失败");
} catch (Exception e) {
log.error("新增用户异常", e);
return R.error(e.getMessage());
}
}
/**
* 批量新增用户
*/
@PostMapping("/batch")
public R<String> saveBatch(@RequestBody List<User> users) {
log.info("批量新增用户,数量: {}", users.size());
boolean success = userService.saveBatch(users);
return success ? R.success("批量新增成功") : R.error("批量新增失败");
}
// ==================== 查询操作 ====================
/**
* 根据ID查询用户
*/
@GetMapping("/{id}")
public R<User> getById(@PathVariable Long id) {
log.info("根据ID查询用户: id={}", id);
User user = userService.getById(id);
return user != null ? R.success(user) : R.error("用户不存在");
}
/**
* 查询所有用户
*/
@GetMapping("/list")
public R<List<User>> list() {
List<User> users = userService.list();
return R.success(users);
}
/**
* 分页查询用户
*/
@GetMapping("/page")
public R<IPage<User>> page(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) String username,
@RequestParam(required = false) String email) {
log.info("分页查询用户: page={}, size={}, username={}, email={}",
pageNum, pageSize, username, email);
// 创建分页对象
Page<User> page = new Page<>(pageNum, pageSize);
// 创建查询条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(username != null, User::getUsername, username)
.like(email != null, User::getEmail, email)
.orderByDesc(User::getCreateTime);
// 执行分页查询
IPage<User> userPage = userService.page(page, wrapper);
return R.success(userPage);
}
/**
* 条件查询用户列表
*/
@GetMapping("/listByCondition")
public R<List<User>> listByCondition(User user) {
log.info("条件查询用户: {}", user);
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 动态添加查询条件
if (user.getUsername() != null) {
wrapper.like("username", user.getUsername());
}
if (user.getEmail() != null) {
wrapper.like("email", user.getEmail());
}
if (user.getStatus() != null) {
wrapper.eq("status", user.getStatus());
}
wrapper.orderByDesc("create_time");
List<User> users = userService.list(wrapper);
return R.success(users);
}
/**
* 根据用户名查询用户
*/
@GetMapping("/username/{username}")
public R<User> getByUsername(@PathVariable String username) {
log.info("根据用户名查询用户: username={}", username);
User user = userService.getByUsername(username);
return user != null ? R.success(user) : R.error("用户不存在");
}
// ==================== 更新操作 ====================
/**
* 更新用户信息
*/
@PutMapping
public R<String> update(@RequestBody User user) {
log.info("更新用户: {}", user);
boolean success = userService.updateById(user);
return success ? R.success("更新成功") : R.error("更新失败");
}
/**
* 批量更新用户
*/
@PutMapping("/batch")
public R<String> updateBatch(@RequestBody List<User> users) {
log.info("批量更新用户,数量: {}", users.size());
boolean success = userService.updateBatchById(users);
return success ? R.success("批量更新成功") : R.error("批量更新失败");
}
/**
* 更新用户状态
*/
@PutMapping("/status/{id}")
public R<String> updateStatus(@PathVariable Long id, @RequestParam Integer status) {
log.info("更新用户状态: id={}, status={}", id, status);
boolean success = userService.updateStatus(id, status);
return success ? R.success("状态更新成功") : R.error("状态更新失败");
}
// ==================== 删除操作 ====================
/**
* 根据ID删除用户(逻辑删除)
*/
@DeleteMapping("/{id}")
public R<String> delete(@PathVariable Long id) {
log.info("删除用户: id={}", id);
boolean success = userService.removeById(id);
return success ? R.success("删除成功") : R.error("删除失败");
}
/**
* 批量删除用户
*/
@DeleteMapping("/batch")
public R<String> deleteBatch(@RequestBody List<Long> ids) {
log.info("批量删除用户: ids={}", ids);
boolean success = userService.removeByIds(ids);
return success ? R.success("批量删除成功") : R.error("批量删除失败");
}
/**
* 根据条件删除用户
*/
@DeleteMapping("/byCondition")
public R<String> deleteByCondition(@RequestBody User user) {
log.info("根据条件删除用户: {}", user);
QueryWrapper<User> wrapper = new QueryWrapper<>();
if (user.getUsername() != null) {
wrapper.eq("username", user.getUsername());
}
if (user.getStatus() != null) {
wrapper.eq("status", user.getStatus());
}
boolean success = userService.remove(wrapper);
return success ? R.success("删除成功") : R.error("删除失败");
}
// ==================== 统计操作 ====================
/**
* 统计用户数量
*/
@GetMapping("/count")
public R<Long> count() {
long count = userService.count();
return R.success(count);
}
/**
* 根据条件统计用户数量
*/
@GetMapping("/countByCondition")
public R<Long> countByCondition(User user) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
if (user.getStatus() != null) {
wrapper.eq("status", user.getStatus());
}
if (user.getUsername() != null) {
wrapper.like("username", user.getUsername());
}
long count = userService.count(wrapper);
return R.success(count);
}
}
6. 配置类
MyBatis Plus 配置
package com.rongx.reggie.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
@Slf4j
@Configuration
public class MybatisPlusConfig {
/**
* MyBatis Plus 插件配置
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInterceptor.setMaxLimit(1000L); // 单页分页条数限制
paginationInterceptor.setOverflow(true); // 页码超出后是否处理
interceptor.addInnerInterceptor(paginationInterceptor);
return interceptor;
}
/**
* 自动填充处理器
*/
@Bean
public MetaObjectHandler metaObjectHandler() {
return new MetaObjectHandler() {
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始插入填充...");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始更新填充...");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
};
}
}
7. 统一返回结果封装
package com.rongx.reggie.common;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class R<T> {
private Integer code;
private String msg;
private T data;
private Map<String, Object> map = new HashMap<>();
public static <T> R<T> success(T object) {
R<T> r = new R<>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R<T> r = new R<>();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}
}
8. 数据库表结构
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`status` int(1) DEFAULT '1' COMMENT '状态 0:禁用 1:正常',
`age` int(3) DEFAULT NULL COMMENT '年龄',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` int(1) DEFAULT '0' COMMENT '逻辑删除 0:未删除 1:已删除',
`version` int(11) DEFAULT '0' COMMENT '版本号',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
KEY `idx_status` (`status`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
9. 测试用例
package com.rongx.reggie;
import com.rongx.reggie.entity.User;
import com.rongx.reggie.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.List;
@Slf4j
@SpringBootTest
class UserCRUDTests {
@Autowired
private UserService userService;
@Test
void testCRUD() {
// 1. 新增
User user = new User();
user.setUsername("testuser");
user.setPassword("123456");
user.setEmail("test@example.com");
user.setPhone("13800138000");
userService.save(user);
log.info("新增用户: {}", user);
// 2. 查询
User foundUser = userService.getById(user.getId());
log.info("查询用户: {}", foundUser);
// 3. 更新
foundUser.setEmail("updated@example.com");
userService.updateById(foundUser);
log.info("更新用户: {}", foundUser);
// 4. 删除(逻辑删除)
userService.removeById(user.getId());
log.info("删除用户完成");
// 5. 批量操作
List<User> users = Arrays.asList(
createUser("user1", "user1@example.com"),
createUser("user2", "user2@example.com"),
createUser("user3", "user3@example.com")
);
userService.saveBatch(users);
log.info("批量新增完成");
}
private User createUser(String username, String email) {
User user = new User();
user.setUsername(username);
user.setPassword("123456");
user.setEmail(email);
return user;
}
}
10. API 使用示例
10.1 新增用户
POST /user
Content-Type: application/json
{
"username": "zhangsan",
"password": "123456",
"email": "zhangsan@example.com",
"phone": "13800138000",
"age": 25
}
10.2 分页查询
GET /user/page?pageNum=1&pageSize=10&username=zhang
10.3 条件查询
GET /user/listByCondition?username=zhang&status=1
10.4 更新用户
PUT /user
Content-Type: application/json
{
"id": 1,
"username": "zhangsan",
"email": "newemail@example.com",
"age": 26
}
10.5 删除用户
DELETE /user/1
11. 高级查询示例
复杂条件查询
// 在 Service 中实现复杂查询
public List<User> complexQuery(String keyword, Integer minAge, Integer maxAge, Integer status) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// 多个条件组合
wrapper.and(qw -> qw
.like(User::getUsername, keyword)
.or()
.like(User::getEmail, keyword)
.or()
.like(User::getPhone, keyword)
)
.ge(minAge != null, User::getAge, minAge)
.le(maxAge != null, User::getAge, maxAge)
.eq(status != null, User::getStatus, status)
.orderByDesc(User::getCreateTime);
return this.list(wrapper);
}
这个完整的 CRUD 示例涵盖了 Spring Boot + MyBatis Plus 的常见操作,包括:
- ✅ 基础 CRUD 操作
- ✅ 分页查询
- ✅ 条件查询
- ✅ 批量操作
- ✅ 逻辑删除
- ✅ 自动填充
- ✅ 统一返回格式
- ✅ 异常处理
您可以根据实际业务需求进行调整和扩展。
1398





