[片段] Mybatis ResultSetHandler实践

这次拦截的方法是handleResultSets(Statement stmt),用来批量解密用@Encrypted注解的String字段,可能还有一些坑。

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
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

final List<Object> multipleResults = new ArrayList<Object>();

int resultSetCount = 0;
ResultSetWrapper rsw = getFirstResultSet(stmt);

List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}

String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}

return collapseSingleResultList(multipleResults);
}
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
114
115
116
117
118
119
120
121
122
123
package app.pooi.common.encrypt;


import app.pooi.common.encrypt.anno.CipherSpi;
import app.pooi.common.encrypt.anno.Encrypted;
import lombok.Getter;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.*;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;

@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}),
})
public class EncryptInterceptor implements Interceptor {

private static final Logger logger = Logger.getLogger(EncryptInterceptor.class.getName());

private CipherSpi cipherSpi;

public EncryptInterceptor(CipherSpi cipherSpi) {
this.cipherSpi = cipherSpi;
}

@Override
public Object intercept(Invocation invocation) throws Throwable {

final Object proceed = invocation.proceed();

if (proceed == null) {
return proceed;
}

List<?> results = (List<?>) proceed;

if (results.isEmpty()) {
return proceed;
}

final Object first = results.iterator().next();

final Class<?> modelClazz = first.getClass();

final List<String> fieldsNeedDecrypt = Arrays.stream(modelClazz.getDeclaredFields())
.filter(f -> f.getAnnotation(Encrypted.class) != null)
.filter(f -> {
boolean isString = f.getType() == String.class;
if (!isString) {
logger.warning(f.getName() + "is not String, actual type is " + f.getType().getSimpleName() + " ignored");
}
return isString;
})
.map(Field::getName)
.collect(Collectors.toList());

final List<List<String>> partition = partition(fieldsNeedDecrypt, 20);

for (Object r : results) {
final MetaObject metaObject = SystemMetaObject.forObject(r);

for (List<String> fields : partition) {
final Map<String, String> fieldValueMap = fields.stream().collect(Collectors.toMap(Function.identity(), f -> (String) metaObject.getValue(f)));
final ArrayList<String> values = new ArrayList<>(fieldValueMap.values());
Map<String, String> decryptValues = cipherSpi.decrypt(values);

fieldValueMap.entrySet()
.stream()
.map(e -> Tuple2.of(e.getKey(), decryptValues.getOrDefault(e.getValue(), "")))
.forEach(e -> metaObject.setValue(e.getT1(), e.getT2()));
}
}

return results;
}

private <T> List<List<T>> partition(List<T> list, int batchCount) {
if (!(batchCount > 0)) {
throw new IllegalArgumentException("batch count must greater than zero");
}

List<List<T>> partitionList = new ArrayList<>(list.size() / (batchCount + 1));

for (int i = 0; i < list.size(); i += batchCount) {
partitionList.add(list.stream().skip(i).limit(batchCount).collect(Collectors.toList()));

}
return partitionList;
}

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

@Override
public void setProperties(Properties properties) {

}
}

@Getter
class Tuple2<T1, T2> {

private final T1 t1;

private final T2 t2;

Tuple2(T1 t1, T2 t2) {
this.t1 = t1;
this.t2 = t2;
}

static <T1, T2> Tuple2<T1, T2> of(T1 t1, T2 t2) {
return new Tuple2<>(t1, t2);
}
}

代码外的生存之道-读书笔记-职业篇

职业发展的驱动力应该来自自身,工作属于公司,职业生涯属于自己。

第一要务 拥有正确的心态

大多数人形成的错误的心态: 认为在为公司打工,没有把自己的职业生涯当作生意来看待。铭记在心,开始积极主动的管理自己的职业生涯吧。

像企业一样思考

自己能提供什么:自己的能力就是创造软件
自己需要做什么:

  • 持续不断地改进和完善自己的产品

  • 传达自己的价值,和千万同行的独特之处

一头扎进工作不可能非同凡响,你应该:

  • 专注于你正在提供怎样的服务, 以及如何营销这项服务;
  • 想方设 提升你的服务;
  • 思考你可以专注为哪一 特定类型的客户或行业提供特定的服务;
  • 集中精力成为一位专家,专门为某一特定类型的客户提供专业的整体服务( 记住, 作为一个软件开发 人员, 你 只有真正专注 于一类客户,才能找到非常好的工作)。
  • 更好的宣传自己的产品,更好的找到你的客户

第二要务 设定自己的目标

无论因为何种原因你没有为自己的职业生涯设定目标, 现在都是时候设定目标了。 不是明天, 也不是下周, 就是现在。 没有明确的方向, 你走的每一步都是徒劳的。

如何设定目标?

先在心中树立一个大目标,然后分解成多个小目标

追踪你的目标

定期核对自己的目标,必要时还要调整。

人际交往能力

[感悟] 2018我的所见所闻所感

1. 我就喜欢写代码行不行?

如果刚刚投入工作,工作还无法完全胜任,那我的建议是多写写代码,打怪升级完成自己的年度绩效。

如果已经能够胜任当前工作,下一步应该集中在提效上。这一步和之前自己积累的经验和知识密不可分,只有真正了解代码懂代码,才能从同龄人中的“熟练工”脱颖而出,两者的提效虽然结果一样,但是本质却完全不一样。

如果已经摆脱了熟练工的称号,实际上已经完成了自我提效,提前完成自己的本职任务,下一步可以计划推动团队的效率。

如果太过专注技术,专心自己的一亩三分田,相当于给自己设限成毕业两三年的水平。这种人应该被打上不胜任的标签,在寒冬中很容易被优化掉。专注技术还有一个误区,就是容易把“实施细节”和“技术”两者混淆,特别在软件行业“实施细节”很容易随时代改变,基本三年就会大变样,而“技术”类似于“知识”不会过时。看到这里大家可以自己思考下,自己学到的到底是“实施细节”还是真正的“技术”。

2.如何推动团队进步

恭喜你跨过了第一道坎,推动团队进步不是一个人的事,一般推动团队分为两部分:个人影响团队,团队自我驱动。

个人影响团队比较简单,就是把自我提效所积累的经验和知识共享给整个团队,完成的手段可以是博客分享,会议分享,文档分享。

团队自我驱动,实际上我把整个团队拟作了一个人,一个人找出别人的缺点很容易,但是找出一个团队的问题却没那么容易,同时也会受到公司和领导的局限,比如一些项目管理的领导就是二传手,只催你进度的那种,这时候就需要你主动找他讨论。

如何找到团队的缺点?可以通过下面两个大类的套路:管理手段和技术手段。

管理手段可以从知识管理、代码规范、需求分析三处着手:

知识管理: 建立知识库,避免重复的培训,重复的解答问题

代码规范:借助代码缺陷检查工具,具体到负责人提升代码规范

需求分析:避免低效,无效会议,避免各种妥协下产生的需求

技术手段比较简单:

重构升级:弃用老的架构,拥抱新技术,带领团队提升技术

内部造轮子:内部定制工具,帮助团队高效完成任务

找到了团队的缺点接下来可以制定度量,衡量团队的推进程度,可以从两个角度进行度量:

跟自己比较:比如这次做需求提测bug数减少,需求delay少了,满足需求不需要上线只要配置上线,等等

和别的团队比较:这个比较凶残,我也不知道用什么度量比,但是有的大公司就是这样做的。

3.总结与晋升

从发现缺点到最后得到成果完成团队推进目标,是时候写个ppt在领导面前吹一波了,这个就不用我教了。

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×