MP-常用功能
1. MP配置类
1.1 分页功能
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//添加分页
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
具体实现:
@Override
public R<Page> page(int page, int pageSize, String name) {
log.info("page = {} pageSize = {} name = {}",page,pageSize,name);
//构造分页构造器
Page pageInfo=new Page(page,pageSize);
//构造条件构造器
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
//在满足不为空的条件下再去添加
queryWrapper.like(StringUtils.isNotBlank(name), Employee::getUsername, name);
//排序
queryWrapper.orderByDesc(Employee::getUpdateTime);
//Mapper分页查询方法
employeeMapper.selectPage(pageInfo, queryWrapper);
return R.success(pageInfo);
}
分页实现原理
SQL语句中使用limit关键字来实现查询前几条或者中间某几行数据
select * from table_name limit [offset,] rows
参数说明:
offset:指定第一个返回记录行的偏移量(即从哪一行开始返回),注意:初始行的偏移量为0。
rows:返回具体行数。
总结:如果limit后面是一个参数,就是检索前多少行。如果limit后面是2个参数,就是从offset+1行开始,检索rows行记录。
select * from table_name limit 10;//检索前10行记录,从0-9
select * from table_name limit 5 ,10;
//因为是第0行开始,所以如果偏移量是5,起始是从第6条记录开启,检索10行记录,即:检索记录行 6-15
客户端通过传递page(页码),pageSize(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limit m,n,但是该函数的用法和我们的需求不一样,所以就需要我们根据实际情况去改写适合我们自己的分页语句,具体的分析如下:
比如:
查询第1条到第10条的数据的sql是:select * from table limit 0,10; 对应着就是:
select * from table limit (1-1)*10,10;
查询第10条到第20条的数据的sql是:select * from table limit 10,10; 对应着就是:
select * from table limit (2-1)*10,10;
查询第20条到第30条的数据的sql是:select * from table limit 20,10;对应着就是:
select * from table limit (3-1)*10,10;
SQL分页计算:
select * from table limit (page-1)*pageSize,pageSize;
1.2 自动填充功能
在我们实体类中,有一些属性例如:创建时间,创建人,修改时间,修改人。这些属性如果都有自己手动处理的,比较繁琐,这时候可用MP的自动填充功能来完成。
具体实现:
@Data
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
// ………………
//公共字段 可用MP框架的自动填充功能填充
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//代表策略方式,INSERT_UPDATE是在该属性进行插入或更新时自动填充
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
根据MP框架要求,编写元数据对象处理器,在这个类中统一为这些公共字段赋值,需要实现MeatObjectHandler接口
/**
* 自定义元数据对象处理器,交给spring管理
*/
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段自动填充[insert]……");
/**
* name:是指需要填充的属性名
*/
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("createUser", BaseContext.getCurrentId());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段自动填充[update]……");
ThreadLocal<Long> threadLocal = new ThreadLocal<>();
log.info("取出的值{}",BaseContext.getCurrentId());
long id = Thread.currentThread().getId();
log.info("元数据对象处理器--当前线程id{}",id);
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}
}
因为有更新人的需求,并且在实现的这两个方法中,我们用不了HttpServletRequest来获取session中存放的数据,所以我们需要用ThreadLocal这个类帮助我们实现,因为每次Http请求都会在服务端分配一个新的线程来处理。
补充说明:
ThreadLocal并不是一个Thread,而是Thread的局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
ThreadLocal常用方法:
-
public void set(T value)设置当前线程的线程局部变量的值。
-
public T get() 返回当前线程所对应的线程局部变量的值
public void set(T value)设置当前线程的线程局部变量的值。
public T get() 返回当前线程所对应的线程局部变量的值
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗