开发目的

新项目中类似状态值都是使用数据库的KEY:VALUE替代的.发现同事都是每次都是自己去数据库查出来,然后循环对比值…

开发目的

新项目中类似状态值都是使用数据库的KEY:VALUE替代的.发现同事都是每次都是自己去数据库查出来,然后循环对比值.
或者是给前端提供枚举查询接口,然后前端遍历.非常麻烦.
所以使用Mybatis插件替代这个重复性工作.
开发完毕后,发现Mybatis有类型转换器,但是和项目现在的现象出入挺大.以下介绍以下插件的开发.之后还发现和PageHepler冲突,修复了一番.

插件配置到spring容器中

此处有点坑,起初按照容器初始化加入到容器的方式.但是与Springboot的Mybatis的PagerHepler的starter顺序不好控制.导致插件的加载顺序不一致.由于分页插件的拦截顺序严格控制.如果拦截相同的地方就会导致分页插件总计失效.所以采用以下方式,采用容器启动后,加入到Mybatis拦截中的最后一个位置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 配置枚举翻译插件
*
* @author: 李涛
* @version: 2019年04月28日 15:23
*/
@Component
public class MybatisPluginConfig implements ApplicationRunner {

@Autowired
private List<SqlSessionFactory> sqlSessionFactoryList;

@Override
public void run(ApplicationArguments args) throws Exception {
Iterator var3 = this.sqlSessionFactoryList.iterator();
while (var3.hasNext()) {
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) var3.next();
sqlSessionFactory.getConfiguration().addInterceptor(new MyBatisEnumHandlePlugin());
}
}
}

插件开发代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
* 处理枚举字段
*
* @author: 李涛
* @version: 2019年04月28日 14:57
*/
@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class)
})
public class MyBatisEnumHandlePlugin implements Interceptor {

@Override
public Object intercept(Invocation invocation) throws Throwable {
DefaultResultSetHandler statementHandler = (DefaultResultSetHandler) invocation.getTarget();
Object proceed = invocation.proceed();
if (proceed instanceof List) {
List data = (List) proceed;
if (data == null || data.isEmpty()) {
return proceed;
}
// 对第一个对象进行分析
List<Map<String, Object>> translationInformation = getTranslationInformation(data.get(0).getClass());
// 如果没有字典标识,直接返回
if (translationInformation.isEmpty()) {
return proceed;
}

// 遍历结果进行设置翻译值
for (Object datum : data) {
for (Map<String, Object> info : translationInformation) {
Field readField = (Field) info.get("read");
Field writeField = (Field) info.get("write");
Map dictValues = (Map) info.get("value");
FieldUtils.writeField(writeField, datum, dictValues.get(readField.get(datum)), true);
}
}
return data;
}
return proceed;
}

@Override
public Object plugin(Object o) {
return Plugin.wrap(o, this);
}

@Override
public void setProperties(Properties properties) {

}

/**
* 通过类,获取需要翻译的字段信息
*
* @param cls
* @return
*/
private List<Map<String, Object>> getTranslationInformation(Class<?> cls) {
// 查询字典值service
ISysDictSV sysDictSV = SpringUtil.getObject(ISysDictSV.class);
List<Map<String, Object>> list = new ArrayList<>();
List<DictField> dicts = new ArrayList<>();
getAllDictAnnotation(cls, dicts);
if (dicts.isEmpty()) {
return list;
}
// 开始填充Field
for (DictField dictField : dicts) {
if (dictField.enumClass().equals(DictEnum.class)) {
// 如果是父类枚举直接返回
continue;
}
// 字典读写翻译信息存储
Map<String, Object> fieldInfo = new HashMap<>();
String toField = dictField.to();
if ("".equals(toField)) {
//如果没有设置,默认为From()+Name
toField = dictField.from() + "Name";
}
Field readField = FieldUtils.getField(cls, dictField.from(), true);
Field writeField = FieldUtils.getField(cls, toField, true);
Map dictValues = sysDictSV.getDictValues(dictField.enumClass(), dictField.codeType());
if (readField == null || writeField == null || dictValues == null) {
continue;
}
fieldInfo.put("read", readField);
fieldInfo.put("write", writeField);
fieldInfo.put("value", dictValues);
list.add(fieldInfo);
}
return list;
}


/**
* 获取所有的字典注解
*
* @param cls 类信息
* @param fields 存放值
*/
private void getAllDictAnnotation(Class<?> cls, List<DictField> fields) {
DictEntity annotation = cls.getAnnotation(DictEntity.class);
// 加入注解
if (annotation != null) {
DictField[] value = annotation.value();
fields.addAll(Arrays.asList(value));
}
// 继续往上找
if (cls.getSuperclass() != null && cls.getSuperclass() != BaseSearchModel.class && cls.getSuperclass() != Object.class) {
getAllDictAnnotation(cls.getSuperclass(), fields);
}
}
}

枚举翻译注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 标识是一个含有数据字典的实体
*
* @author: 李涛
* @version: 2019年04月28日 12:30
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DictEntity {
DictField[] value();
}

/**
* 标识是一个含有数据字典的实体
*
* @author: 李涛
* @version: 2019年04月28日 12:30
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(value = DictEntity.class)
public @interface DictField {

/**
* 要翻译的字段名称
*/
String from();

/**
* 翻译到哪个字段.默认为from()+Name,可以自定义
*/
String to() default "";

/**
* 枚举类
*/
Class<? extends DictEnum> enumClass();

/**
* code类型
*/
Class codeType() default String.class;

}