Appearance
对象内省
1.对象内省
当你未指定填充使用的数据源容器时,crane4j 将会直接将待处理对象本身作为数据源,换而言之,这是当容器为空时的一种特殊处理。
例如:
java
public class Foo {
@Assemble(props = @Mapping(ref = "alias"))
private String name;
private String alias;
}
在上述示例中,通过对象内省的方式,将对象的 name
字段映射到 alias
字段上。
这个功能通常用于同步冗余的别名字段,可以通过对象内省自动将一个字段的值设置到另一个字段上,从而实现字段值的同步更新。
2.键值映射
在 2.6.0 及以上版本,crane4j 提供了选项式配置风格的键值映射功能,它实际上是基于键值的内省。
它可以用于在某些场景下仅针对键值进行转换,比如字段脱敏,或者字段加解密。
2.1.配置
在使用前,你需要向 AssembleKeyAnnotationHandler
注册指定的值映射策略,这里我们以手机号脱敏为例:
java
// 创建一个操作门面,在 Spring 环境中你也可以直接从 Spring 容器获取
Crane4jTemplate crane4jTemplate = Crane4jTemplate.withDefaultConfiguration();
Crane4jTemplate crane4jTemplate = Crane4jTemplate.withDefaultConfiguration();
crane4jTemplate.opsForComponent().configureOperationAnnotationHandler(
// 获取注解处理器
AssembleKeyAnnotationHandler.class, (t, handler) -> {
// 注册一个键值映射策略
handler.registerValueMapperProvider("phone_number_desensitization", element ->
key -> { // 将手机号中间四位替换为 *
String phone = (String)key;
return phone.substring(0, 3) + "****" + phone.substring(7);
}
);
}
);
在 Spring 环境中,你也可以直接实现 AssembleKeyAnnotationHandler.ValueMapperProvider
接口,并将其交给 Spring 容器管理,crane4j 在启动后将会自动注册。
2.2.使用
接着,在你要转换的字段——这里是手机号字段——上添加 @AssembleKey
注解即可:
java
private static class Foo {
@AssembleKey(mapper = "phone_number_desensitization", sort = 1)
private String phone;
}
2.3.获取注解元素
我们会注意到,registerValueMapperProvider
方法的入参是一个函数式接口:
java
@FunctionalInterface
public interface ValueMapperProvider {
@NonNull
UnaryOperator<Object> get(AnnotatedElement element);
}
这里的 element
实际上就是你声明的 @AssembleKey
注解所在的元素,它可以是类、方法或属性,通过获取它,你可以基于注解完成一些自定义的逻辑。
比如,手机号可能前面会带有国家代码,因此对于 "0086-xxxxxxxx" 格式的手机号,你需要跳过前五位 “0086-”,那么你可以这么做:
java
private static class Foo {
@Skip(5) // 跳过前四位国家编码
@AssembleKey(mapper = "phone_number_desensitization", sort = 1)
private String phone;
}
AssembleKeyAnnotationHandler handler = SpringUtil.getBean(AssembleKeyAnnotationHandler.class);
handler.registerValueMapperProvider("phone_number_desensitization", element -> {
Skip skip = element.getAnnotation(Skip.class); // 通过获取注解得到额外的信息
return key -> {
String phone = (String)key;
// 如果是 0086-10012341234 格式,那么根据注解的配置跳过 ‘0086-’前五个字符
if (Objects.nonNull(skip)) {
phone = phone.substring(skip.value());
}
return phone.substring(0, 3) + "****" + phone.substring(7); // 将手机号中间四位替换为 *
}
});