上会我们已经将整体的插件模板创建完成了,那么今天我们继续来完成最后的策略实现,以及一些简单的优化

策略类实现

首先我们知道,我们定义了一个策略接口DesensitizeStrategy,同时再我们的模板代码,以及注解定义中,我们都看到了策略接口的身影:

1
2
DesensitizeStrategy desensitizeStrategy = (DesensitizeStrategy) strategy.newInstance();
setMethod.invoke(data, desensitizeStrategy.doDesensitize(value));
1
2
3
4
5
6
7
8
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Desensitized {

Class<? extends DesensitizeStrategy> strategy() default DefaultDesensitizeStrategy.class;
}

根据注解的定义,只要实现了DesensitizeStrategy的注解接口,那么就能在我们的插件中实例化出来,所以我们现在就来实现一个手机号脱敏策略:

1
2
3
4
5
6
7
8
public class PhoneDesensitizeStrategy implements DesensitizeStrategy<String, String> {

@Override
public String doDesensitize(String data) {


}
}

我们假定所有的手机号都是通过字符串存储的,那么接下来我们使用常用的手机号脱敏方式就是我们常看到了的136****9958这样的一个格式,那么我们这里用一下正则表达式来实现:

1
2
3
4
@Override
public String doDesensitize(String data) {
return data.replaceAll("(\\d{3})\\d{4}(\\d+)", "$1****$2");
}

现在我们给我们的UseruserPhone字段打上对应的策略类:

1
2
3
4
5
6
7
@Data
public class User {
private Long id;
private String userName;
@Desensitized(strategy = PhoneDesensitizeStrategy.class)
private String userPhone;
}

允许之后我们得到以下以下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@e1ce44] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@31007053 wrapping conn0: url=jdbc:h2:mem:testdb user=SA] will not be managed by Spring
==> Preparing: select * from user
==> Parameters:
<== Columns: ID, USER_NAME, USER_PHONE
<== Row: 1, user1, 110112113114
<== Row: 2, user2, 110112113114
<== Row: 3, user3, 110112113114
<== Row: 4, user4, 110112113114
<== Row: 5, user5, 110112113114
<== Row: 6, user6, 110112113114
<== Total: 6
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@e1ce44]
User(id=1, userName=user1, userPhone=110****13114)
User(id=2, userName=user2, userPhone=110****13114)
User(id=3, userName=user3, userPhone=110****13114)
User(id=4, userName=user4, userPhone=110****13114)
User(id=5, userName=user5, userPhone=110****13114)
User(id=6, userName=user6, userPhone=110****13114)

可以看到,虽然我们从数据库里面查到的是明文,但是我们最终得到的数据是通过了我们脱敏的数据

优化

目前我们的插件很轻易的就能发现由很多可以优化的点

1. 策略类不需要每次都创建,我们可以使用全局单例类来处理

1
2
3
4
5
6
7
DesensitizeStrategy desensitizeStrategy = STRATEGY_MAP.computeIfAbsent(annotation.strategy(), (key) -> {
try {
return (DesensitizeStrategy) key.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
return new DefaultDesensitizeStrategy();
}
});

我们可以使用一个STRATEGY_MAP来装载策略类,避免每次都需要重新创建

2.对于类的反射操作也是一样,不需要每次都使用反射的方式去获取

处理方式同上方一样,这里就不再赘述了。

总结

通过以上方式,我们就创建了一个可让用户自己实现脱敏策略的 Mybatis 插件,当然还有很多不足和值得优化的地方,后续有时间,我们再继续进行调整

相关代码地址:
100daysCode