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

被折叠的 条评论
为什么被折叠?



