mybatis+mybatisplus源码学习(十)字段填充器MetaObjectHandler


前言

通过MetaObjectHandler ,可以全局对一些实体类参数进行填充值。


一、自定义MetaObjectHandler

(1)CustomMetaObjectHandler

public class CustomMetaObjectHandler implements MetaObjectHandler {
	//insert操作的字段填充
    @Override
    public void insertFill(MetaObject metaObject) {
        Object createBy = getFieldValByName("createBy", metaObject);
        if (createBy == null) {
            setFieldValByName("createBy", "admin", metaObject);
        }
    }
	//update操作的字段填充
    @Override
    public void updateFill(MetaObject metaObject) {
        Object updateBy = getFieldValByName("updateBy", metaObject);
        if (updateBy == null) {
            setFieldValByName("updateBy", "admin", metaObject);
        }
    }
}

(2)开启填充功能

字段上添加注解

	@TableField(fill = FieldFill.UPDATE)
    private String updateBy;

(3)注册CustomMetaObjectHandler

如果让mybatisplus自动注入该类,就在类上加@Compoment注解;
如果重写了SqlSessionFactory,就手动注入该类

GlobalConfigUtils.getGlobalConfig(configuration).setMetaObjectHandler(new CustomMetaObjectHandler());
 private GlobalConfig globalConfiguration() {
        GlobalConfig conf = GlobalConfigUtils.defaults();
        conf.setMetaObjectHandler(new CustomMetaObjectHandler());
        return conf;
    }

二、实现原理

是通过MybatisParameterHandler来实现的
(1)MybatisParameterHandler

public class MybatisParameterHandler implements ParameterHandler {

public MybatisParameterHandler(MappedStatement mappedStatement, Object parameter, BoundSql boundSql) {
        this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
        this.mappedStatement = mappedStatement;
        this.boundSql = boundSql;
        this.configuration = mappedStatement.getConfiguration();
        this.sqlCommandType = mappedStatement.getSqlCommandType();
        //这里处理参数的入口
        this.parameterObject = processParameter(parameter);
    }
}

(2)processParameter( )

public Object processParameter(Object parameter) {
        /* 只处理插入或更新操作 */
        if (parameter != null
            && (SqlCommandType.INSERT == this.sqlCommandType || SqlCommandType.UPDATE == this.sqlCommandType)) {
            //检查 parameterObject
            if (ReflectionKit.isPrimitiveOrWrapper(parameter.getClass())
                || parameter.getClass() == String.class) {
                return parameter;
            }
            Collection<Object> parameters = getParameters(parameter);
            if (null != parameters) {
                // 感觉这里可以稍微优化一下,理论上都是同一个.
                parameters.forEach(this::process);
            } else {
                process(parameter);
            }
        }
        return parameter;
    }

(3)process( )

private void process(Object parameter) {
        if (parameter != null) {
            TableInfo tableInfo = null;
            Object entity = parameter;
            if (parameter instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) parameter;
                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(parameter.getClass());
            }
            if (tableInfo != null) {
                //到这里就应该转换到实体参数对象了,因为填充和ID处理都是争对实体对象处理的,不用传递原参数对象下去.
                MetaObject metaObject = this.configuration.newMetaObject(entity);
                if (SqlCommandType.INSERT == this.sqlCommandType) {
                	//填充主键
                    populateKeys(tableInfo, metaObject, entity);
                    //插入时填充字段
                    insertFill(metaObject, tableInfo);
                } else {
                	//更新时填充字段
                    updateFill(metaObject, tableInfo);
                }
            }
        }
    }

(4)populateKeys( )

//处理主键
protected static void populateKeys(TableInfo tableInfo, MetaObject metaObject, Object entity) {
        final IdType idType = tableInfo.getIdType();
        final String keyProperty = tableInfo.getKeyProperty();
        if (StringUtils.isNotBlank(keyProperty) && null != idType && idType.getKey() >= 3) {
            final IdentifierGenerator identifierGenerator = GlobalConfigUtils.getGlobalConfig(tableInfo.getConfiguration()).getIdentifierGenerator();
            Object idValue = metaObject.getValue(keyProperty);
            if (StringUtils.checkValNull(idValue)) {
                if (idType.getKey() == IdType.ASSIGN_ID.getKey()) {
                	//雪花算法
                    if (Number.class.isAssignableFrom(tableInfo.getKeyType())) {
                        metaObject.setValue(keyProperty, identifierGenerator.nextId(entity));
                    } else {
                        metaObject.setValue(keyProperty, identifierGenerator.nextId(entity).toString());
                    }
                } else if (idType.getKey() == IdType.ASSIGN_UUID.getKey()) {
                	//UUID
                    metaObject.setValue(keyProperty, identifierGenerator.nextUUID(entity));
                }
            }
        }
    }

(5)insertFill( )

 protected void insertFill(MetaObject metaObject, TableInfo tableInfo) {
        GlobalConfigUtils.getMetaObjectHandler(this.configuration).ifPresent(metaObjectHandler -> {
        	//开启了InsertFill,并且有需要填充的字段
            if (metaObjectHandler.openInsertFill() && tableInfo.isWithInsertFill()) {
                metaObjectHandler.insertFill(metaObject);
            }
        });
    }

   

(6)updateFill( )

 protected void updateFill(MetaObject metaObject, TableInfo tableInfo) {
        GlobalConfigUtils.getMetaObjectHandler(this.configuration).ifPresent(metaObjectHandler -> {
        	//开启了UpdateFill,并且有需要填充的字段
            if (metaObjectHandler.openUpdateFill() && tableInfo.isWithUpdateFill()) {
                metaObjectHandler.updateFill(metaObject);
            }
        });
    }

总结

本文介绍了Mybatisplus字段填充器MetaObjectHandler的使用及原理。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_lrs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值