MybatisPlus快速入门
- 快速入门
- 入门案例
- 常见注解
- 常见配置
- 核心功能
- 条件构造器
- 自定义SQL
- Service接口
- 扩展功能
- 代码生成
- 静态工具
- 逻辑删除
- 枚举处理器
- JSON处理器
- 插件功能
- 分页插件
- 通用分页实体
参考文档
mybatis-plus参考文档
全部资料链接
讲义
快速入门
入门案例
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 记得指定泛型为你操作的实体类的类型
}
常见注解
常见配置
核心功能
条件构造器
@Test
void testQueryWrapper(){
// 1.构建查询条件
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
// 2.查询
List<User> users = userMapper.selectList(wrapper);
//3. 遍历打印
users.forEach(System.out::println);
}
@Test
void testUpdateByQueryWrapper(){
// 1. 要更新的数据
User user = new User();
user.setBalance(2000);
// 2. 更新的操作
QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("username","jack");
// 3. 执行更新
userMapper.update(user,wrapper);
}
@Test
void testUpdateWrapper(){
List<Long> ids = Arrays.asList(1L, 2L, 3L);
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
.setSql("balance = balance - 200")
.in("id",ids);
userMapper.update(null,wrapper);
}
@Test
void testLambdaQueryWrapper(){
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.select(User::getId,User::getUsername,User::getInfo,User::getBalance)
.like(User::getUsername,"o")
.ge(User::getBalance,1000);
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
自定义SQL
Service接口
我们的自定义接口UserService需要去继承IService接口,我们的实现类UserServiceImpl也要继承他的实现类ServiceImpl
package com.itheima.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;
public interface IUserService extends IService<User> {
}
package com.itheima.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.mapper.UserMapper;
import com.itheima.mp.service.IUserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
// 泛型中要指定mapper的类型和实体类的类型
}
package com.itheima.mp.service;
import com.itheima.mp.domain.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class IUserServiceTest {
@Autowired
private IUserService userService;
@Test
void testSaveUser(){
User user = new User();
// user.setId(5L);
user.setUsername("Lilei");
user.setPassword("123");
user.setPhone("18688990011");
user.setBalance(200);
user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userService.save(user);
}
@Test
void testQuery(){
List<User> users = userService.listByIds(Arrays.asList(1L, 2L, 3L));
users.forEach(System.out::println);
}
}
package com.itheima.mp.controller;
import cn.hutool.core.bean.BeanUtil;
import com.itheima.mp.domain.dto.UserFormDTO;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.query.UserQuery;
import com.itheima.mp.domain.vo.UserVO;
import com.itheima.mp.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Api(tags = "用户管理接口")
@RequestMapping("/users")
@RestController
@RequiredArgsConstructor
public class UserController {
// final搭配lombok的RequiredArgsConstructor注解
// 实现根据需要自动注入,不需要注入的不加lombok注解就行了
private final IUserService userService;
@ApiOperation("新增用户接口")
@PostMapping
public void saveUser(@RequestBody UserFormDTO userDto){
// 1. 把DTO拷贝到PO
User user = BeanUtil.copyProperties(userDto, User.class);
// 2. 新增
userService.save(user);
}
@ApiOperation("删除用户接口")
@DeleteMapping("{id}")
public void deleteUserById(@ApiParam("用户id") @PathVariable("id") Long id){
userService.removeById(id);
}
@ApiOperation("根据id查询用户")
@GetMapping("{id}")
public UserVO getUserById(@ApiParam("用户id") @PathVariable("id") Long id){
User user = userService.getById(id);
return BeanUtil.copyProperties(user,UserVO.class);
}
@ApiOperation("根据id批量查询用户")
@GetMapping
public List<UserVO> getUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids){
List<User> users = userService.listByIds(ids);
return BeanUtil.copyToList(users,UserVO.class);
}
@ApiOperation("扣减用户余额接口")
@DeleteMapping("{id}/deduction/{money}")
public void deductMoneyById(@ApiParam("用户id") @PathVariable("id") Long id,
@ApiParam("扣减的金额") @PathVariable("money") Integer money){
userService.deductBalance(id, money);
}
}
controller层
@ApiOperation("根据复杂条件查询用户")
@GetMapping("/list")
public List<UserVO> queryUsers(UserQuery query){
// 1. 查询用户PO
List<User> users = userService.queryUsers(query.getName(),query.getStatus(),query.getMinBalance(),query.getMaxBalance());
// 2. 把PO拷贝到VO
return BeanUtil.copyToList(users, UserVO.class);
}
service层
@Override
public List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {
return lambdaQuery().like(name != null, User::getUsername, name)
.eq(status != null, User::getStatus, status)
.ge(minBalance != null, User::getBalance, minBalance)
.le(maxBalance != null, User::getBalance, maxBalance)
.list();
}
@Override
@Transactional
public void deductBalance(Long id, Integer money) {
// 1. 查询用户
User user = getById(id); // 我们继承了ServiceImpl,爸爸的就是我的,已经有UserService了,不用注入,this一下看看哦
// 2. 校验用户状态
if(user==null || user.getStatus() == 2 ){
throw new RuntimeException("用户状态异常");
}
// 3. 校验余额是否充足
if(user.getBalance() < money){
throw new RuntimeException("用户余额不足!");
}
// 4. 扣减余额 update user set balance = balance - ?
// baseMapper.deductBalance(id,money);
int remainBalance = user.getBalance() - money;
lambdaUpdate()
.set(User::getBalance,remainBalance)
.set(remainBalance == 0,User::getStatus,0)
.eq(User::getId,id)
.eq(User::getBalance,user.getBalance()) // 乐观锁
.update(); // 一定记得加上update,上面只是在构建sql语句
}
扩展功能
代码生成
静态工具
根据id查询用户的接口
@ApiOperation("根据id查询用户")
@GetMapping("{id}")
public UserVO getUserById(@ApiParam("用户id") @PathVariable("id") Long id){
// User user = userService.getById(id);
// return BeanUtil.copyProperties(user,UserVO.class);
return userService.queryUserAndAddressById(id);
}
实现方法
@Override
public UserVO queryUserAndAddressById(Long id) {
// 1. 查询用户
User user = getById(id);
if(user == null || user.getStatus() == 2){
throw new RuntimeException("用户状态异常!");
}
// 2. 查询地址——使用静态工具
List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();
// 3.封装VO
// 3.1转User额PO为Vo
UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
//3.2 转地址VO
if(CollUtil.isNotEmpty(addresses)){
userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));
}
return userVO;
}
根绝id批量查询用户的接口
controller层
@ApiOperation("根据id批量查询用户")
@GetMapping
public List<UserVO> getUserByIds(@ApiParam("用户id集合") @RequestParam("ids") List<Long> ids){
// List<User> users = userService.listByIds(ids);
// return BeanUtil.copyToList(users,UserVO.class);
return userService.queryUserAndAddressByIds(ids);
}
实现
@Override
public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
// 1. 查询用户
List<User> users = listByIds(ids);
if(CollUtil.isEmpty(users)){
return Collections.emptyList();
}
// 2.查询地址
// 2.1 获取用户id集合
List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
// 2.2 根据用户id查询地址
List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();
// 2.3 转换地址VO
List<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);
// 2.4 用户地址集合分组处理,相同的用户放入一个集合(组)中
Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);
if(CollUtil.isNotEmpty(addressVOList)){
addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
}
// 3. 转换VO返回
ArrayList<UserVO> list = new ArrayList<>(users.size());
for (User user : users) {
// 3.1. 转换User的PO为VO
UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
// 3.2 转换地址VO
vo.setAddresses(addressMap.get(user.getId()));
list.add(vo);
}
return list;
}
逻辑删除
枚举处理器
就是Java中的枚举类型和数据库中的int类型的转换的问题
package com.itheima.mp.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;
@Getter
public enum UserStatus {
NORML(1,"正常"),
FROZEN(2,"冻结"),
;
@EnumValue
private final int value;
@JsonValue // 前端默认返回枚举项的名字,不友好,设置返回desc(由spring控制)
private final String desc;
UserStatus(int value, String desc){
this.value = value;
this.desc = desc;
}
}
JSON处理器
实现Java中的对象和数据库中的json格式数据的映射
package com.itheima.mp.domain.po;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor(staticName = "of")
public class UserInfo {
private Integer age;
private String intro;
private String gender;
}
package com.itheima.mp.domain.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.itheima.mp.enums.UserStatus;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName(value = "user", autoResultMap = true)
public class User {
/**
* 用户id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 注册手机号
*/
private String phone;
/**
* 详细信息
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;
/**
* 使用状态(1正常 2冻结)
*/
private UserStatus status;
/**
* 账户余额
*/
private Integer balance;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}
package com.itheima.mp.domain.vo;
import com.itheima.mp.domain.po.UserInfo;
import com.itheima.mp.enums.UserStatus;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(description = "用户VO实体")
public class UserVO {
@ApiModelProperty("用户id")
private Long id;
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("详细信息")
private UserInfo info;
@ApiModelProperty("使用状态(1正常 2冻结)")
private UserStatus status;
@ApiModelProperty("账户余额")
private Integer balance;
@ApiModelProperty("用户的收货地址")
private List<AddressVO> addresses;
}
插件功能
分页插件
package com.itheima.mp.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//创建分页插件
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setMaxLimit(1000L);
// 添加分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
@Test
void testPageQuery(){
int pageNo = 1, pageSize = 2;
// 准备分页条件
// 1.1 分页条件
Page page = Page.of(pageNo, pageSize);
// 1.2 排序条件
page.addOrder(new OrderItem("balance", true));
page.addOrder(new OrderItem("id",true));
// 2. 分页查询
Page<User> p = userService.page(page);
// 3. 解析
// 2.总条数
System.out.println("total = " + p.getTotal());
// 3.总页数
System.out.println("pages = " + p.getPages());
// 4.数据
List<User> records = p.getRecords();
records.forEach(System.out::println);
}
通用分页实体
package com.itheima.mp.domain.query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {
@ApiModelProperty("页码")
private Long pageNo;
@ApiModelProperty("页码")
private Long pageSize;
@ApiModelProperty("排序字段")
private String sortBy;
@ApiModelProperty("是否升序")
private Boolean isAsc;
}
package com.itheima.mp.domain.query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "用户查询条件实体")
public class UserQuery extends PageQuery{
@ApiModelProperty("用户名关键字")
private String name;
@ApiModelProperty("用户状态:1-正常,2-冻结")
private Integer status;
@ApiModelProperty("余额最小值")
private Integer minBalance;
@ApiModelProperty("余额最大值")
private Integer maxBalance;
}
controller层
@ApiOperation("根据分页查询用户接口")
@GetMapping("/page")
public PageDto<UserVO> queryUsersPage(UserQuery query){
return userService.queryUsersPage(query);
}
service层
@Override
public PageDto<UserVO> queryUsersPage(UserQuery query) {
String name = query.getName();
Integer status = query.getStatus();
// 构建分页条件
// 1.1分页条件
Page<User> page = Page.of(query.getPageNo(), query.getPageSize());
// 1.2 排序条件
if(StrUtil.isNotBlank(query.getSortBy())){
// 不为空
page.addOrder(new OrderItem(query.getSortBy(),query.getIsAsc()));
}else{
// 为空,默认按照更新时间排序
page.addOrder(new OrderItem("update_time",false));
}
// 2. 分页查询
Page<User> p = lambdaQuery()
.like(name != null, User::getUsername, name)
.eq(status != null, User::getStatus,status)
.page(page);
// 封装VO结果
PageDto<UserVO> dto = new PageDto<>();
// 3.1 总条数
dto.setTotal(p.getTotal());
// 3.2 总页数
dto.setPages(p.getPages());
// 3.3 当前页数据
List<User> records = p.getRecords();
if(CollUtil.isEmpty(records)){
dto.setList(Collections.emptyList());
return dto;
}
// 3.4 拷贝user的VO
List<UserVO> vos = BeanUtil.copyToList(records, UserVO.class);
dto.setList(vos);
// 4返回
return dto;
}
package com.itheima.mp.domain.query;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description = "分页查询实体")
public class PageQuery {
@ApiModelProperty("页码")
private Integer pageNo = 1;
@ApiModelProperty("页码")
private Integer pageSize = 5;
@ApiModelProperty("排序字段")
private String sortBy;
@ApiModelProperty("是否升序")
private Boolean isAsc = true;
public <T> Page<T> toMpPage(OrderItem ... items){
// 1.1分页条件
Page<T> page = Page.of(pageNo, pageSize);
// 1.2 排序条件
if(StrUtil.isNotBlank(sortBy)){
// 不为空
page.addOrder(new OrderItem(sortBy,isAsc));
}else if(items != null){
// 为空,默认排序
page.addOrder(items);
}
return page;
}
public <T> Page<T> toMpPage(String defaultSortBy, Boolean defaultAsc){
return toMpPage(new OrderItem(defaultSortBy,defaultAsc));
}
public <T> Page<T> toMpPageDefaultSortByCreateTime(){
return toMpPage(new OrderItem("create_time",false));
}
public <T> Page<T> toMpPageDefaultSortByUpdateTime(){
return toMpPage(new OrderItem("update_time",false));
}
}
package com.itheima.mp.domain.dto;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@Data
@ApiModel(description = "分页结果")
public class PageDTO<T> {
@ApiModelProperty("总条数")
private Long total;
@ApiModelProperty("总页数")
private Long pages;
@ApiModelProperty("集合")
private List<T> list;
public static <PO,VO> PageDTO<VO> of(Page<PO> p, Function<PO,VO> convertor){
PageDTO<VO> dto = new PageDTO<>();
// 3.1 总条数
dto.setTotal(p.getTotal());
// 3.2 总页数
dto.setPages(p.getPages());
// 3.3 当前页数据
List<PO> records = p.getRecords();
if(CollUtil.isEmpty(records)){
dto.setList(Collections.emptyList());
return dto;
}
// 3.4 拷贝user的VO
dto.setList(records.stream().map(convertor).collect(Collectors.toList()));
// 4返回
return dto;
}
}
封装完成后,分页查询的实现就更简洁了
@Override
public PageDTO<UserVO> queryUsersPage(UserQuery query) {
String name = query.getName();
Integer status = query.getStatus();
// 构建分页条件
Page<User> page = query.toMpPageDefaultSortByUpdateTime();
// 2. 分页查询
Page<User> p = lambdaQuery()
.like(name != null, User::getUsername, name)
.eq(status != null, User::getStatus,status)
.page(page);
// 3.封装VO结果
PageDTO<UserVO> dto = new PageDTO<>();
return PageDTO.of(p,user->{
// 1. 拷贝基础属性
UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
// 2. 处理特殊逻辑
vo.setUsername(vo.getUsername().substring(0, vo.getUsername().length() - 2) + "**");
return vo;
});
}