MyBatis-Plus 编程方式配置扫描通用枚举

32 篇文章 1 订阅
6 篇文章 0 订阅

前言

使用Mybatis-Plus的通用枚举功能(https://mp.baomidou.com/guide/enum.html)确实可以很优雅的方式将数据库字段直接映射到我们自定义的枚举类,美中不足的是,官方对于自定义枚举类必须要通过属性配置的方式来扫描枚举类的包路径,在一些非直接发布成Spring Application的场景下,就不够用了。

解决思路

通过查找源代码,mybatis-plus.typeEnumsPackage的这个配置是直接反应到com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties这个类里面的,可以对注入到Spring容器中的MybatisPlusProperties重新进行值的设置:

TypeEnumsPackageConfiguration.java

@Configuraton
public class TypeEnumsPackageConfiguration {
	
	@AutoWried
	public void configTypeEnumsPackage(MybatisPlusProperties mybatisPlusProperties) {
		mybatisPlusProperties.setTypeEnumsPackage(String.join(";", mybatisPlusProperties.getTypeEnumsPackage(), "my.package.type.enums"));
	}
}

解决方法

上面的解决思路试过,确实可以成功,但是不够“优雅”,再看源代码,发现官方提供了com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer 来进行MybatisPlusProperties的自定义设置,其实只要创建一个它的子类,就可以在通过实现customize()方法来自定义配置信息了,那既然要强调“优雅”,并且考虑多模块的复用,可以针对typeEnumsPackage的设定专门做一个抽象类,在子类中只配置扫描路径的方式来完成。

TypeEnumsPackageScanner.java

public abstract class TypeEnumsPackageScanner implements MybatisPlusPropertiesCustomizer {
    @Override
    public void customize(MybatisPlusProperties properties) {
        properties.setTypeEnumsPackage(String.join(";", properties.getTypeEnumsPackage(), this.getTypeEnumsPackage()));
    }

    protected abstract String getTypeEnumsPackage();
}

TypeEnumsPackageScannerConfiguration.java (可在不同模块中分别配置)

@Configuration
public class TypeEnumsPackageScannerConfiguration {

    @Bean
    public TypeEnumsPackageScanner typeEnumsPackageScanner() {
        return new TypeEnumsPackageScanner() {
            @Override
            protected String getTypeEnumsPackage() {
                return "my.package.type.enums";
            }
        };
    }
}

后续

虽然最终满足了需求,其实还是有些许不甘,同样是包扫描,为什么不提供一个类似于@MapperScan的注解来指定呢,而且自定义枚举必须要实现Mybatis自有的一些接口或者注解,这个自定义枚举类提到api接口层的话,强行把Mybatis-plus的依赖也会加到api层,虽说最新的版本以及进行了优化,只需引入mybatis-plus-annotation依赖即可,但是有洁癖的人应该受不了吧。
所以接下来准备自定义一个注解,来指定枚举类扫描,并且要做一个com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler的派生类,主要是要覆盖这段逻辑:

    /**
     * 查找标记标记EnumValue字段
     *
     * @param clazz class
     * @return EnumValue字段
     * @since 3.3.1
     */
    public static Optional<String> findEnumValueFieldName(Class<?> clazz) {
        if (clazz != null && clazz.isEnum()) {
            String className = clazz.getName();
            return Optional.ofNullable(CollectionUtils.computeIfAbsent(TABLE_METHOD_OF_ENUM_TYPES, className, key -> {
                Optional<Field> optional = Arrays.stream(clazz.getDeclaredFields())
                    .filter(field -> field.isAnnotationPresent(EnumValue.class))
                    .findFirst();
                return optional.map(Field::getName).orElse(null);
            }));
        }
        return Optional.empty();
    }

以及参照com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean注册MybatisEnumTypeHandler的逻辑,实现自定义注解与自定义EnumTypeHandler的绑定:

        if (hasLength(this.typeEnumsPackage)) {
            Set<Class<?>> classes;
            if (typeEnumsPackage.contains(StringPool.STAR) && !typeEnumsPackage.contains(StringPool.COMMA)
                && !typeEnumsPackage.contains(StringPool.SEMICOLON)) {
                classes = scanClasses(typeEnumsPackage, null);
                if (classes.isEmpty()) {
                    LOGGER.warn(() -> "Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration.");
                }
            } else {
                classes = new HashSet<>();
                String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage,
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
                Assert.notNull(typeEnumsPackageArray, "not find typeEnumsPackage:" + typeEnumsPackage);
                Stream.of(typeEnumsPackageArray).forEach(typePackage -> {
                    try {
                        Set<Class<?>> scanTypePackage = scanClasses(typePackage, null);
                        if (scanTypePackage.isEmpty()) {
                            LOGGER.warn(() -> "Can't find class in '[" + typePackage + "]' package. Please check your configuration.");
                        } else {
                            classes.addAll(scanTypePackage);
                        }
                    } catch (IOException e) {
                        throw new MybatisPlusException("Cannot scan class in '[" + typePackage + "]' package", e);
                    }
                });
            }
            // 取得类型转换注册器
            TypeHandlerRegistry typeHandlerRegistry = targetConfiguration.getTypeHandlerRegistry();
            classes.stream()
                .filter(Class::isEnum)
                .filter(MybatisEnumTypeHandler::isMpEnums)
                .forEach(cls -> typeHandlerRegistry.register(cls, MybatisEnumTypeHandler.class));
        }

后续进展

https://blog.csdn.net/qq_39609993/article/details/117250091

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值