Mybatis plus配置MetaObjectHandler无效

项目环境

<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-boot-starter</artifactId>
   <version>3.4.2</version>
</dependency>
<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.3.4.RELEASE</version>
   <relativePath/>
</parent>

自动填充功能

项目引入mybatis-plus后,尝试使用它的自动填充功能,按照官方文档步骤实现,下面列出部分具体代码

注解填充字段

@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
@JSONField(format = "yyyy-MM-dd HH🇲🇲ss")
private LocalDateTime updatedTime;

@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
@JSONField(format = "yyyy-MM-dd HH🇲🇲ss")
private LocalDateTime createdTime;

自定义实现类 TableMetaObjectHandler

@Component
public class TableMetaObjectHandler implements MetaObjectHandler {
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insertFill</span><span class="hljs-params">(MetaObject metaObject)</span> {
    <span class="hljs-built_in">this</span>.strictInsertFill(metaObject, <span class="hljs-string">"createdTime"</span>, LocalDateTime.class, LocalDateTime.now());
    <span class="hljs-built_in">this</span>.strictInsertFill(metaObject, <span class="hljs-string">"updatedTime"</span>, LocalDateTime.class, LocalDateTime.now());
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">updateFill</span><span class="hljs-params">(MetaObject metaObject)</span> {
    <span class="hljs-built_in">this</span>.strictUpdateFill(metaObject, <span class="hljs-string">"updatedTime"</span>, LocalDateTime.class, LocalDateTime.now());
}

}

自动填充字段代码未执行

由于 MetaObjectHandler 实现类中的代码未执行,所以我 debug 寻找 mybatis-plus 源码中执行 insertFill方法的类

com.baomidou.mybatisplus.core.MybatisParameterHandler

从图中可以看出,MetaObjectHandler 没有注入到配置中

解决方案

  1. 检查 MetaObjectHandler 实现类是否使用@Component

    实体类字段使用注解 @TableField(fill = FieldFill.INSERT)

  2. 手动注入 MetaObjectHandler

     	@Bean
        public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
            MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
    		// 获取 mybatis-plus 全局配置
            GlobalConfig globalConfig = GlobalConfigUtils.defaults();
    		//mybatis-plus 全局配置设置元数据对象处理器为自己实现的那个
            globalConfig.setMetaObjectHandler(new TableMetaObjectHandler());
            mybatisSqlSessionFactoryBean.setDataSource(dataSource);
    		//mybatisSqlSessionFactoryBean 关联设置全局配置
            mybatisSqlSessionFactoryBean.setGlobalConfig(globalConfig);
            ...
            return mybatisSqlSessionFactoryBean.getObject();
        }
    
    1. 删除 bean sqlSessionFactory, 这是最终解决我问题的方案

      这是我原来的 Mybatis 配置类,主要配置了 mapper 路径和配置文件路径,后来我删除了此类,将这两项配置写到了 yml 文件里
      出现这个问题的具体原因我没有再跟源码了,猜测是自定义 Bean sqlSessionFactory 影响到了 globalConfig ,导致配置失效。

      @Configuration
      @EnableTransactionManagement
      public class MybatisConfig {
      
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">CONFIG_XML_PATH</span> <span class="hljs-operator">=</span> <span class="hljs-string">"classpath:mybatis-config.xml"</span>;
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">MAPPER_XML_PATH</span> <span class="hljs-operator">=</span> <span class="hljs-string">"classpath:mapping/**/*.xml"</span>;
      
      <span class="hljs-meta">@Bean(name = "sqlSessionFactory")</span>
      <span class="hljs-keyword">public</span> SqlSessionFactory <span class="hljs-title function_">sqlSessionFactoryBean</span><span class="hljs-params">(DataSource dataSource)</span> <span class="hljs-keyword">throws</span> Exception {
          <span class="hljs-type">MybatisSqlSessionFactoryBean</span> <span class="hljs-variable">sqlSessionFactory</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">MybatisSqlSessionFactoryBean</span>();
          <span class="hljs-type">PathMatchingResourcePatternResolver</span> <span class="hljs-variable">pathMatchingResourcePatternResolver</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">PathMatchingResourcePatternResolver</span>();
          sqlSessionFactory.setConfigLocation(pathMatchingResourcePatternResolver.getResource(CONFIG_XML_PATH));
          sqlSessionFactory.setMapperLocations(pathMatchingResourcePatternResolver.getResources(MAPPER_XML_PATH));
          sqlSessionFactory.setDataSource(dataSource);
      
          <span class="hljs-keyword">return</span> sqlSessionFactory.getObject();
      }
      
      <span class="hljs-meta">@Bean</span>
      <span class="hljs-keyword">public</span> DataSourceTransactionManager <span class="hljs-title function_">transactionManager</span><span class="hljs-params">(DataSource dataSource)</span> {
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">DataSourceTransactionManager</span>(dataSource);
      }
      

      }

其他

以上第三种方案还解决另一个问题;使用 MyBatis-Plus 的 通用枚举 特性,进行数据库查询时报错:

No enum constant com.**.workbench.model.enums.SystemStatusEnum.1

这个问题的原因应该和上述自动填充失效一样;由于 global-config.type-enums-package 配置失效,所以枚举类未被扫描。