学习文档地址
https://b11et3un53m.feishu.cn/wiki/FJAnwOhpIihMkLkOKQocdWZ7nUc
1 MybatisPlus
https://baomidou.com/reference/annotation/
1.1 使用的基本步骤
1.2 常用注解
1.3 常用配置
1.4 核心功能
1.4.1 条件构造器
用法及建议
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
1.4.2 自定义sql
xml
<update id="updateBalanceByIds">
update user set balance = balance - #{amount}
${ew.customSqlSegment}
</update>
mapper
void updateBalanceByIds(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper,@Param("amount") int amount);
逻辑
List<Long> ids = List.of(1L, 3L, 4L);
int amount = 200;
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.in("id", ids);
// 调用自定义
userMapper.updateBalanceByIds(wrapper, amount);
基于wrapper的多表关联查询
1.4.3 Service接口
图示
举例:
1、创建IUserService接口并且继承IService接口
2、定义UserServiceImpl实现类,实现IUserService接口,并继承ServiceImpl实现类
3、在UserServiceImpl就可以直接调用MP(MybatisPlus)相关的方法,如getById;
UserServiceImpl中对应的mapper就是baseMapper,这个就等于是注入的userMapper=>这个是ServiceImpl已经有的,可以直接拿来用
关于Autowired注入的调整
1.4.3.1 IService中的Lambda查询
@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();
}
1.4.3.2 IService中的Lambda更新
lambdaUpdate()
.set(User::getBalance, user.getBalance() - money)
.set(user.getBalance() - money == 0,User::getStatus, 2)
.eq(User::getId, id)
.eq(User::getBalance, user.getBalance()) // 乐观锁:先比较再更新
.update();
1.4.3.3 批量新增
&rewriteBatchedStatements=true
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
1.5 扩展功能
1.5.1 MyBatisPlus插件使用
jdbc:mysql://127.0.0.1:3306/mp?useSSL=false&serverTimezone=Asia/Shanghai
1.5.2 DB静态工具–高版本的mp才有
stream流的map提取后收集
users.stream().map(User::getId).collect(Collectors.toList());
stream流的根据某个返回值分组收集
addressVOS.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
@Override
public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
// 查用户
List<User> users = listByIds(ids);
if (CollUtil.isEmpty(users)) {
return Collections.emptyList();
}
// 获取用户id集合
List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
// 根据id集合查所有地址
List<Address> addressList = Db.lambdaQuery(Address.class)
.in(Address::getUserId, userIds).list();
// 将地址转vo
List<AddressVO> addressVOS = BeanUtil.copyToList(addressList, AddressVO.class);
// 所有vo地址根据id分类
Map<Long, List<AddressVO>> AddressVOMap = new HashMap<>(0);
if(CollUtil.isNotEmpty(addressList)) {
AddressVOMap = addressVOS.stream()
.collect(Collectors.groupingBy(AddressVO::getUserId));
}
// 转vo返回
List<UserVO> list = new ArrayList<>(users.size());
for (User user : users) {
// 转vo
UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
userVO.setAddresses(AddressVOMap.get(user.getId()));
list.add(userVO);
}
return list;
}
1.5.3 逻辑删除
1.5.3 枚举处理器
1.5.4 JSON处理器
(1)@TableName(autoResultMap = true)
(2)
@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;
1.6 分页功能
1.6.1 配置(先配置,底层是拦截器拦截)
1.6.2 通用分页实体
(1)先定义一个通用实体
(2)需要查询的实体继承(1)
@Override
public PageDTO<UserVO> queryUsersPage(UserQuery query) {
String name = query.getName();
Integer status = query.getStatus();
Page<User> page = Page.of(query.getPageNo(), query.getPageSize());
if (StrUtil.isNotBlank(query.getSortBy())){
page.addOrder(new OrderItem().setColumn(query.getSortBy()).setAsc(query.getIsAsc()));// query.getSortBy(),query.getIsAsc()
}else{
page.addOrder(new OrderItem().setColumn("update_time").setAsc(false));
}
Page<User> p = lambdaQuery()
.like(name != null, User::getUsername, name)
.eq(status != null, User::getStatus, status)
.page(page);
PageDTO<UserVO> pageDTO = new PageDTO<>();
pageDTO.setTotal(p.getTotal()); // 条数
pageDTO.setPages(p.getPages()); // 页面
List<User> records = p.getRecords();
if(CollUtil.isEmpty(records)){
pageDTO.setList(Collections.emptyList());
}else{
pageDTO.setList(BeanUtil.copyToList(records, UserVO.class));
}
return pageDTO;
}
1.6.3 基于分页和封装条件编写通用MP分页实体
PageQuery – 泛型
package com.itheima.mp.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 lombok.Data;
@Data
@ApiModel(value = "分页查询实体")
public class PageQuery {
private Integer pageNo = 1;
private Integer pageSize = 5;
private String sortBy;
private Boolean isAsc = true;
public <T>Page<T> toMpPage(OrderItem...items){
Page<T> page = Page.of(pageNo, pageSize);
if (StrUtil.isNotBlank(sortBy)){
page.addOrder(new OrderItem().setColumn(sortBy).setAsc(isAsc));// query.getSortBy(),query.getIsAsc()
}else if(items != null){
page.addOrder(items);
}
return page;
}
public <T>Page<T> toMpPage(String column, boolean isAsc){
return toMpPage(new OrderItem().setColumn(column).setAsc(isAsc));
}
public <T>Page<T> toMpPageDefaultSortByCreateTime(){
return toMpPage(new OrderItem().setColumn("create_time").setAsc(isAsc));
}
public <T>Page<T> toMpPageDefaultSortByUpdateTime(){
return toMpPage(new OrderItem().setColumn("update_time").setAsc(isAsc));
}
}
PageDTO – 泛型加函数式接口
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 com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "分页查询结果")
public class PageDTO<T> {
private Long total;
private Long pages;
private List<T> list;
// 其他对象转PageDTO对象,使用static变为静态方法,让别人创建时就可以调用
// <PO, VO>不可以放在static之前,是因为类的泛型参数是在类实例化时确定的,而静态方法在实例化之前就可以被调用,因此无法直接引用类的泛型参数
public static <PO, VO> PageDTO<VO> of(Page<PO> p, Class<VO> voClass){
PageDTO<VO> pageDTO = new PageDTO<>();
pageDTO.setTotal(p.getTotal()); // 条数
pageDTO.setPages(p.getPages()); // 页面
List<PO> records = p.getRecords();
if(CollUtil.isEmpty(records)){
pageDTO.setList(Collections.emptyList());
}else{
// 变量名一样的PO到VO的转换
pageDTO.setList(BeanUtil.copyToList(records, voClass)); // VO是没有.class的,所以要传参进来
}
return pageDTO;
}
// 变量名不一样的PO到VO的转换
// 那就要传行为,也就是一个行为即函数,那就要传一个函数式接口了 Function
public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor){
PageDTO<VO> pageDTO = new PageDTO<>();
pageDTO.setTotal(p.getTotal()); // 条数
pageDTO.setPages(p.getPages()); // 页面
List<PO> records = p.getRecords();
if(CollUtil.isEmpty(records)<