利用Jackson實(shí)現(xiàn)數(shù)據(jù)脫敏的示例詳解
在我們的企業(yè)項(xiàng)目中,為了保護(hù)用戶隱私,數(shù)據(jù)脫敏成了必不可少的操作,那么我們怎么優(yōu)雅的去實(shí)現(xiàn)它呢?
一、簡介
什么是序列化?
序列化就是把對象轉(zhuǎn)化為可傳輸?shù)淖止?jié)序列過程,該字節(jié)序列包括對象的數(shù)據(jù)、對象的類型、數(shù)據(jù)的類型
在使用Jackson序列化進(jìn)行數(shù)據(jù)脫敏時(shí),就是在序列化過程中拿到對象的數(shù)據(jù)類型和對象的數(shù)據(jù)完成的操作。
二、實(shí)現(xiàn)
上邊介紹完什么是序列化,那我們接下來就來做一個(gè)數(shù)據(jù)脫敏的小Demo吧。
1. 脫敏枚舉
/**
* @author hob
* @date 2022/10/23 18:05
* @description: <h1>脫敏枚舉</h1>
*/
public enum DesensitizationEnum {
/**
* 真實(shí)姓名
*/
REAL_NAME(val -> val.replaceAll("(.).*", "$1**")),
/**
* 身份證號碼
*/
ID_CARD(val -> val.replaceAll("(\d{4})\d{10}(\w{4})", "$1****$2")),
/**
* 住址
*/
ADDRESS(val -> StringUtils.left(val, 3).concat(StringUtils.removeStart(StringUtils
.leftPad(StringUtils.right(val, val.length()-11), StringUtils.length(val), "*"), "***"))),
/**
* 手機(jī)號
*/
PHONE(val -> val.replaceAll("(\d{3})\d{4}(\d{4})", "$1****$2"));
private final Function<String, String> function;
DesensitizationEnum(Function<String, String> function) {
this.function = function;
}
public Function<String, String> getFunction() {
return function;
}
}在上邊的脫敏枚舉中,使用了Java 8 的函數(shù)式接口Function,該接口的作用就是接受一個(gè)輸入?yún)?shù),返回一個(gè)結(jié)果,例如Function<String, Integer>,就是將 “10” 轉(zhuǎn)換為 10 的過程,也就是將字符串轉(zhuǎn)為整數(shù)。使用Function接口的目的就是將原字符串,轉(zhuǎn)換為脫敏后的新字符串,上邊的操作可以理解為val值給了第一個(gè)Sting, lambada轉(zhuǎn)換完成給了第二個(gè)String。是不是很方便呢.
2. 脫敏注解
/**
* @author hob
* @date 2022/10/23 18:09
* @description: <h1>脫敏注解</h1>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerialize.class)
public @interface Desensitization {
/**
* 脫敏類型 枚舉
* @return
*/
DesensitizationEnum type();
}@JacksonAnnotationsInside: 這個(gè)注解用來標(biāo)記Jackson復(fù)合注解,當(dāng)你使用多個(gè)Jackson注解組合成一個(gè)自定義注解時(shí)會(huì)用到它。
3. 脫敏
/**
* @author hob
* @date 2022/10/23 18:12
* @description: <h1>脫敏序列化</h1>
*/
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {
private DesensitizationEnum type;
/**
* 序列化
*
* @param s
* @param jsonGenerator
* @param serializerProvider
* @throws IOException
*/
@Override
public void serialize(String s, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(type.getFunction().apply(s));
}
/**
* 在序列化時(shí)獲取字段注解屬性
*
* @param serializerProvider
* @param beanProperty
* @return
* @throws JsonMappingException
*/
@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider,
BeanProperty beanProperty) throws JsonMappingException {
// 主要判斷字符串,不是字符串的話就跳過
if (Objects.nonNull(beanProperty) && Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);
if (!ObjectUtils.isEmpty(desensitization)) {
// 如果屬性上有Desensitization注解,就獲取枚舉類型
this.type = desensitization.type();
return this;
}
return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
return serializerProvider.findNullValueSerializer(beanProperty);
}
}在DesensitizationSerialize類中繼承了JsonSerializer類重寫了serialize方法,該方法的作用就是序列化,還實(shí)現(xiàn)了ContextualSerializer接口,重寫了createContextual方法,該方法的作用就是在序列化時(shí)獲取字段注解屬性。先執(zhí)行createContextual方法后執(zhí)行serialize方法。
4.將要脫敏的字段標(biāo)注注解
/**
* 用戶表信息
* @TableName user
*/
@Data
@TableName(value ="user")
public class User implements Serializable {
/**
* 主鍵
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 用戶名
*/
private String username;
/**
* 密碼
*/
private String password;
/**
* 身份證號
*/
@Desensitization(type = DesensitizationEnum.ID_CARD)
private String idCard;
/**
* 真實(shí)姓名
*/
@Desensitization(type = DesensitizationEnum.REAL_NAME)
private String realName;
/**
* 性別
*/
private String gender;
/**
* 地址
*/
@Desensitization(type = DesensitizationEnum.ADDRESS)
private String address;
/**
* 手機(jī)號
*/
@Desensitization(type = DesensitizationEnum.PHONE)
private String phone;
/**
* 年齡
*/
private String age;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}5. controller測試類
/**
* @author hob
* @date 2022/10/23 18:03
* @description: <h1>測試脫敏</h1>
*/
@RestController
public class UserController {
@Autowired
private UserService userService;
/**
* 獲取用戶列表
*
* @param userParams 查詢參數(shù)
* @return
*/
@GetMapping("/list")
public List<User> getUserList(UserParams userParams) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(userParams.getAddress())) {
queryWrapper.lambda().eq(User::getAddress, userParams.getAddress());
}
return userService.list(queryWrapper);
}
}結(jié)果如下
先看一下數(shù)據(jù)庫中的數(shù)據(jù)

脫敏之前返回的數(shù)據(jù)

脫敏之后返回的數(shù)據(jù)

怎么樣,這樣的數(shù)據(jù)脫敏是不是很優(yōu)雅呢?
依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hob99</groupId>
<artifactId>springboot-jackson-desensitization</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-jackson-desensitization</name>
<description>springboot-jackson-desensitization</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.13</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- commons-lang3工具類 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!--編譯跳過測試文件檢查的生命周期-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>用到的依賴版本及插件
依賴:
- springboot 2.7.5
- mysql5.7
- mybatis-plus3.5.2
- commons-lang3工具包3.12.0
插件:
- RestfulTool: 測試接口
- lombok: 生成getter, setter
- mybatisX: 快速生成代碼
JDK版本: 17
以上就是利用Jackson實(shí)現(xiàn)數(shù)據(jù)脫敏的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Jackson數(shù)據(jù)脫敏的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot設(shè)置了server.port但是沒有用,還是8080問題
這篇文章主要介紹了springboot設(shè)置了server.port但是沒有用,還是8080問題的解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
在IntelliJ IDEA中多線程并發(fā)代碼的調(diào)試方法詳解
這篇文章主要介紹了在IntelliJ IDEA中多線程并發(fā)代碼的調(diào)試方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
使用springboot整合mybatis-plus實(shí)現(xiàn)數(shù)據(jù)庫的增刪查改示例
這篇文章主要介紹了使用springboot整合mybatis-plus實(shí)現(xiàn)數(shù)據(jù)庫的增刪查改示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Java之HashMap.values()轉(zhuǎn)List時(shí)的錯(cuò)誤和正確演示
這篇文章主要介紹了Java之HashMap.values()轉(zhuǎn)List時(shí)的錯(cuò)誤和正確演示,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
利用Java發(fā)送郵件的實(shí)現(xiàn)代碼
這篇文章給大家分享了如何利用Java發(fā)送郵件,文章通過實(shí)例代碼介紹的很詳細(xì),有需要的可以參考借鑒。2016-08-08
Java SimpleDateFormat中英文時(shí)間格式化轉(zhuǎn)換詳解
這篇文章主要為大家詳細(xì)介紹了Java SimpleDateFormat中英文時(shí)間格式化轉(zhuǎn)換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12

