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 510;
//因为是第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() 返回当前线程所对应的线程局部变量的值

我们可以在LoginCheckFilter的doFilter方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值(用户id),然后在MyMetaObjectHandler的updateFill方法中调用ThreadLocal的get方法来获得当前线程所对应的线程局部变量的值(用户id)。

例如:

      在用户列表页面中,点击用户禁用功能,发起一次update请求,先经过过滤器,controller,再经过MyMetaObjectHandler中的updateFill方法,这是一次完整的请求,通过打印日志发现,这是同一个线程。

也可以看见元对象处理器自动填充的数据就是存储的我们登录用户的id。

posted @   别停  阅读(119)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示