解决mybatisplus MetaObjectHandler 失效的问题

目录
  • 一、什么是metaObjectHandler
  • 二、失效场景及解决方案

一、什么是metaObjectHandler

MetaObjectHandler接口是mybatisPlus为我们提供的的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值
使用方式如下:

1、在实体类上加入@TableField注解

@Getter
@Setter
public class AbstractBaseDO<T extends Model<T>> extends Model<T> implements Serializable {

    /**
     * 创建时间 新增时填充
     */
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;

    /**
     * 修改时间 新增和更新时填充
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;

    /**
     * 创建人ID 新增时更新
     */
    @TableField(fill = FieldFill.INSERT)
    private Long creatorId;

    /**
     * 修改人ID 新增和更新时填充
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long modifierId;

    /**
     * 逻辑删除字段 新增和更新时填充
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer isDeleted;

    @Override
    public String toString() {
        return new ToStringBuilder(this)
            .append("gmtCreate", gmtCreate)
            .append("gmtModified", gmtModified)
            .append("creatorId", creatorId)
            .append("modifierId", modifierId)
            .append("isDeleted", isDeleted)
            .toString();
    }
}

2、创建配置类实现MetaObjectHandler接口

@Slf4j
@Configuration
public class MetaObjectHandlerConfig implements MetaObjectHandler {
    
    /**
    *插入时自动填充
    */
    @Override
    public void insertFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //获得当前时间
        Date date = Calendar.getInstance().getTime();

        //创建时间
        this.fillStrategy(metaObject, "gmtCreate", date);
        //更新时间
        this.fillStrategy(metaObject, "gmtModified", date);
        //未删除
        this.fillStrategy(metaObject, "isDeleted", CommonConstants.NON_DELETED);
        //创建者
        this.fillStrategy(metaObject, "creatorId", dscUser.getUserId());
        //更新者
        this.fillStrategy(metaObject, "modifierId", dscUser.getUserId());

    }
    
    /**
    *修改时自动填充
    */
    @Override
    public void updateFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //获得当前时间
        Date date = Calendar.getInstance().getTime();
        //强制更新时间
        this.setFieldValByName("gmtModified", date, metaObject);
        //更新者
        this.fillStrategy(metaObject, "modifierId",dscUser.getUserId());

    }
}

二、失效场景及解决方案

1、使用mybatis-plus的boolean update(Wrapper updateWrapper)链式更新方法时失效

1)示例代码

/**
*更新属性
*/
 @Override
    public Boolean expireHistoryTask(Long tenantId, Long produceInfoId) {
        return this.update(new UpdateWrapper<TaskDetailInfoDO>().lambda()
            .eq(TaskDetailInfoDO::getTenantId, tenantId)
            .in(TaskDetailInfoDO::getProduceInfoId, produceInfoId)
            .eq(TaskDetailInfoDO::getIsDeleted, CommonConstants.NON_DELETED)
            .set(TaskDetailInfoDO::getTaskStatus, TaskStatusEnum.EXPIRED.getCode())
            
    }

2)失效原因

这种更新方法失效我们需要去看mbatis-plus的源码

   private static void process(MappedStatement ms, Object parameterObject) {
        if (parameterObject != null) {
            TableInfo tableInfo = null;
            Object entity = parameterObject;
            if (parameterObject instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) parameterObject;
                if (map.containsKey(Constants.ENTITY)) {
                    Object et = map.get(Constants.ENTITY);
                    if (et != null) {
                        entity = et;
                        tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
                    }
                }
            } else {
                tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());
            }
            //tableInfo为空,则不自动填充
            if (tableInfo != null) {
                //到这里就应该转换到实体参数对象了,因为填充和ID处理都是争对实体对象处理的,不用传递原参数对象下去.
                MetaObject metaObject = ms.getConfiguration().newMetaObject(entity);
                if (SqlCommandType.INSERT == ms.getSqlCommandType()) {
                    populateKeys(tableInfo, metaObject, entity);
                    insertFill(metaObject, tableInfo);
                } else {
                    updateFill(metaObject, tableInfo);
                }
            }
        }
    }

从上面的代码可以看出,当tableInfo为空,则不自动填充字段值。而继续看,tableInfo是从parameterObject中获取,而这parameterObject就是要更新的实体对象。
在看我们使用 update(Wrapper updateWrapper)更新的底层逻辑

 /**
     * 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
     *
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    default boolean update(Wrapper<T> updateWrapper) {
        //传入了一个空实体
        return update(null, updateWrapper);
    }

此时是传了一个空对象,这就导致了整个后续的填充都失效了。

3)解决方法

使用update的另一个方法

在更新是传入实体对象

  @Override
    public Boolean expireHistoryTask(Long tenantId, Long produceInfoId) {
        return this.update(new TaskDetailInfoDO(), new UpdateWrapper<TaskDetailInfoDO>().lambda()
            .eq(TaskDetailInfoDO::getTenantId, tenantId)
            .in(TaskDetailInfoDO::getProduceInfoId, produceInfoId)
            .eq(TaskDetailInfoDO::getIsDeleted, CommonConstants.NON_DELETED)
            .set(TaskDetailInfoDO::getTaskStatus, TaskStatusEnum.EXPIRED.getCode())
        );
    }

2、填充时使用 MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) 方法

 @Override
    public void updateFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //更新者
        this.fillStrategy(metaObject, "modifierId", dscUser.getUserId());
    }

fillStartegy的源码时这样的

    /**
     * 填充策略,默认有值不覆盖,如果提供的值为null也不填充
     *
     * @param metaObject metaObject meta object parameter
     * @param fieldName  java bean property name
     * @param fieldVal   java bean property value of Supplier
     * @since 3.3.0
     */
    default MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) {
        if (getFieldValByName(fieldName, metaObject) == null) {
            setFieldValByName(fieldName, fieldVal, metaObject);
        }
        return this;
    }

当需要更新的字段已经有值时,则默认不更新。需要强制更新字段时,使用 MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) 方法更新字段值。

   @Override
    public void updateFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //获得当前时间
        Date date = Calendar.getInstance().getTime();
        //更新时间
        this.setFieldValByName("gmtModified", date, metaObject);
        //更新者
        this.setFieldValByName("modifierId", metaObject, dscUser.getUserId());
    }

到此这篇关于解决mybatisplus MetaObjectHandler 失效的问题的文章就介绍到这了,更多相关mybatisplus MetaObjectHandler 失效内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Mybatis-Plus3.2.0 MetaObjectHandler 无法进行公共字段全局填充

    问题描述 最近在做的这个项目架构组对于配置文件决定,采取的是 .xml 配置文件 一个数据中台项目,因为部署环境比较复杂,可能需要适配阿里.腾讯.开源等环境和机房,所以配置文件和启动类为三类 之前写的 MetaObjectHandler 都是采用的 SpringBoot 配置方式开发,突然换成 .xml 配置文件,还是有不少坑的,其中就有配置的 MetaObjectHandler 死活不起作用 ⬆️

  • 解决mybatisplus MetaObjectHandler 失效的问题

    目录 一.什么是metaObjectHandler 二.失效场景及解决方案 一.什么是metaObjectHandler MetaObjectHandler接口是mybatisPlus为我们提供的的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值使用方式如下: 1.在实体类上加入@TableField注解 @Getter @Setter public class AbstractBaseDO<T extends Model<T>> extends

  • 解决Mybatis-Plus操作分页后数据失效问题

    业务场景 我们知道在使用PageHelper分页插件时,会对执行PageHelper.startPage(pageNum, pageSize);方法后的第一条查询语句进行分页操作.在开发中总会遇到这样的业务情景,在进行分页查询后,需要对获得的列表数据包装成另一种类型,此时需要对新类型的列表进行分页,然而由于PageInfo<T>因为泛型的原因,导致处理后的列表不能加入到该类中. 如,我在数据库分页后查询到的类为PageInfo<User>,此时改类中的list属性为User,在当前

  • SpringBoot整合Mybatis-Plus分页失效的解决

    场景:项目整合mybatis-Plus分页失效,current一直是1,size一直是10,total属性一直是0,数据分页不准 先看官网给的示例: 解决方案是新建mybatis-Plus的配置文件: package com.amc.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; imp

  • 使用微信内嵌H5网页解决JS倒计时失效问题

    项目要求:将H5商城页面嵌套到公司微信公众号里 项目本身的开发跟移动端网页并无太多差异,只是这昨天遇到一个问题,说是棘手,到也简单. 用户下单后,在选择支付方式页面,有个倒计时的逻辑(从下单时开始计算,24小时后未支付,会有ws自动取消这个订单),js代码如下: <script type="text/javascript"><br> var timespan = '20160113'; //后台程序生成24小时时间差值,这里随便写写 var timer; fun

  • 解决laravel session失效的问题

    最新在学习laravel,用到了session,因为laravel没法用$_SESSION 所以只能用框架的session. 贴上代码 <?php namespace App\Http\Controllers; use App\Http\Requests; use Request; use Illuminate\Support\Facades\Session; class CommonController extends Controller { static function login(){

  • idea配置springboot热部署终极解决办法(解决热部署失效问题)

    idea配置springboot热部署终极解决办法,解决热部署失效问题 1. 添加maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <version>2.2.5.RELEASE</version> <optional>true</opt

  • 解决mybatis-plus使用jdk8的LocalDateTime 查询时报错的方法

    mybatis-plus使用jdk8的LocalDateTime 查询时报错: org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'update_time' from result set.  Cause: java.sql.SQLFeatureNotSupportedException ; null; nested exception is java.sql.SQ

  • 完美解决MybatisPlus插件分页查询不起作用总是查询全部数据问题

    问题描述: 在使用mybatisplus插件进行分页查询时分页参数不起作用,总是查出来全部数据. 原因分析: 查看打印的sql日志发现sql后面并没有limit条件,怀疑是缺少配置. 解决方案: 查阅资料通过添加配置类MybatisPlusConfig解决问题: @Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor(){ return new

  • 解决Mybatis-plus找不到对应表及默认表名命名规则的问题

    错误截图 在测试使用Mybatis-plus查询数据库时报错 报错信息大概意思时在数据库中没有user这张表 而实际上确实没有 尝试 我这里application.ymml没有与Mybatis-plus的相关配置 为探究在没有配置的情况下时Mybatis-plus默认时按照什么来定义表名的 猜想有两个地方有可能(因为只有这两个地方是user) 先测试第一个 可以看到和之前的错误一样没有效果 测试第二个点 虽然报错,但是证明了在没有配置表名的情况下mybatis-plus是默认按照实体类名去查询数

  • 解决mybatisplus插入报错argument type mismatch的问题

    今天使用argument type mismatch发现插入的时候报错 java.lang.IllegalArgumentException: argument type mismatch 从错误中看是参数的问题,想到我再实体类里面定义了几个在数据库中没有的字段,就使用了 @TableField(exist = false) 来排除掉这个字段. 再跑发现还是这个错误,后来看了下主键的@TableId默认的type是IdType.NONE,想想我们应该用自增的id就手动增加了一个 @TableId

随机推荐