Mybatis全局变量模式配置EnumValue

本文介绍了一种使用Mybatis全局变量简化Enum配置的方法,通过查找所有BaseEnumValue实现类并获取Enum实例,避免了在Mapper文件中使用<bind>和TypeHandler处理器的繁琐步骤。该方案虽简便,但不支持同名ClassName,需注意。

前言:

    之前一篇《Mybatis自定义Enum解析器》,里面有写到使用自定义EnumTypeHandler的处理,在使用EnumValue作为查询参数时需要配置<bind>和TypeHandler处理器,使用起来比较繁琐,于是有了此篇的内容。

正文:

    利用Mybatis的全局变量来简化配置和使用。

    1、查找所有BaseEnumValue的实现类并获取到所有Enum的实例

// Enum类型定义

/**
 * Auther: Charles.Chen <br>
 * Description: 类型标识接口
 * Date: Create in 10:32 2018/5/25
 **/
public interface BaseEnumValue {

	String getEnumValue();
}

 

// 异常定义

/**
 * Auther: Charles.Chen <br>
 * Description: className冲突异常
 * Date: Create in 11:12 2018/6/13
 **/
public class ClassNameConflictException extends RuntimeException {

	private String className;
	private String classPath1;
	private String classPath2;

	public ClassNameConflictException(String className, String classPath1, String classPath2) {
		this.className = className;
		this.classPath1 = classPath1;
		this.classPath2 = classPath2;
	}

	/**
	 * Returns the detail message string of this throwable.
	 *
	 * @return the detail message string of this {@code Throwable} instance
	 * (which may be {@code null}).
	 */
	@Override
	public String getMessage() {
		return "[ Mybatis EnumTypeHandler 扩展不支持同名ClassName,信息如下:" +
				"ClassName = " + this.className + ",ClassPath-1 = " + classPath1 + ",ClassPath-2 = " + classPath2 + " ]";
	}
}

 

// 获取EnumValue数据

/**
 * Auther: Charles.Chen <br>
 * Description: 获取所有实现了BaseEnumValue的类
 * Date: Create in 9:42 2018/6/13
 **/
public class BaseEnumValueBeanFactory {

	private final static Logger logger = LoggerFactory.getLogger(BaseEnumValueBeanFactory.class);

	public static Map<String, Object> loadAllEnumValue(String packagePath) throws Exception {
		ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
		provider.addIncludeFilter(new AssignableTypeFilter(BaseEnumValue.class));

		Map<String, String> allEnumValueClassPath = new HashMap<>();
		Map<String, Object> enumValueMap = new HashMap<>();

		Set<BeanDefinition> components = provider.findCandidateComponents(packagePath);
		for (BeanDefinition component : components)
		{
			String classPath = component.getBeanClassName();
			String className = classPath.substring(classPath.lastIndexOf(".") + 1);

			logger.debug("className = {}, classPath = {}", className, classPath);

			if(allEnumValueClassPath.containsKey(className)) {
				logger.error("类名冲突,className = {}, classPath = {}, classPath = {}", className, classPath, allEnumValueClassPath.get(className));
				throw new ClassNameConflictException(className, classPath, allEnumValueClassPath.get(className));
			}
			allEnumValueClassPath.put(className, classPath);

			Class enumValueClass = Class.forName(classPath);
			enumValueMap.putAll(loadEnum(enumValueClass));
		}

		logger.info("BaseEnumValue.size = {}", enumValueMap.size());

		if(logger.isDebugEnabled()) {
			logger.debug("BaseEnumValue.data = {}", Arrays.toString(enumValueMap.keySet().toArray()));
		}
		return enumValueMap;
	}

	/**
	 * 获取所有枚举实例
	 * @param enumValueClass
	 * @return
	 * @throws Exception
	 */
	private static Map<String, String> loadEnum(Class enumValueClass) throws Exception{
		Map<String, String> enumValueMap = new HashMap<>();

		Method method = enumValueClass.getMethod("values");
		BaseEnumValue enumValues[] = (BaseEnumValue[]) method.invoke(null, null);
		String className = enumValueClass.getSimpleName();

		for (BaseEnumValue enumValue : enumValues) {
			enumValueMap.put(className + "." + enumValue, enumValue.getEnumValue());
		}
		return enumValueMap;
	}

}

    2、配置到Mybaits中

// 配置全局变量

@Bean
public SqlSessionFactory sqlSessionFactory(DataSource bssDataSource,@Qualifier("enumValueMapping")Properties enumValueMapping) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(bssDataSource);

    if(enumValueMapping != null || enumValueMapping.size() >= 0) {
        bean.setConfigurationProperties(enumValueMapping);
    }
    return bean.getObject();
}

@Bean
@Qualifier("enumValueMapping")
public Properties getProperties() throws Exception {
    Properties properties = new Properties();
    // 此处必须为Map<String, String>类型,若Value类型不为String,在mapper.xml中无法获取到值,就算配置成功了,也获取不到,原因待核实
    Map<String, String> enumValues = BaseEnumValueBeanFactory.loadAllEnumValue("com.clyy");
    properties.putAll(enumValues);
    return properties;
}

    3、使用

// 使用全局变量

<select id="selectUser" resultType="java.util.Map">
  select * from user where `status` = '${User.delete}'
</select>

// 注意上面的 ${User.delete}, 在Mybatis中只能使用${}方式来注入全局变量数据,且此数据需要使用者注意类型,需要符合SQL规范,否则会出现SQL异常。 ${User.delete} 中的User为类名,delete是枚举中的实例名

使用此种方案可以不用在使用<bind>进行数据绑定和配置TypeHandler解析器,但此方案也有缺陷。比如上面的实现是不允许同名ClassName的,就算是不同Package也不允许。若使用Package.ClassName来做变量名,在使用时就需要注意不能变更Package的路径了,这两种方式相比,使用ClassName更加简单。

转载于:https://my.oschina.net/clyy/blog/1829771

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值