利用Jackson實現(xiàn)數(shù)據(jù)脫敏的示例詳解
在我們的企業(yè)項目中,為了保護用戶隱私,數(shù)據(jù)脫敏成了必不可少的操作,那么我們怎么優(yōu)雅的去實現(xiàn)它呢?
一、簡介
什么是序列化?
序列化就是把對象轉(zhuǎn)化為可傳輸?shù)淖止?jié)序列過程,該字節(jié)序列包括對象的數(shù)據(jù)、對象的類型、數(shù)據(jù)的類型
在使用Jackson序列化進行數(shù)據(jù)脫敏時,就是在序列化過程中拿到對象的數(shù)據(jù)類型和對象的數(shù)據(jù)完成的操作。
二、實現(xiàn)
上邊介紹完什么是序列化,那我們接下來就來做一個數(shù)據(jù)脫敏的小Demo吧。
1. 脫敏枚舉
/** * @author hob * @date 2022/10/23 18:05 * @description: <h1>脫敏枚舉</h1> */ public enum DesensitizationEnum { /** * 真實姓名 */ 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), "*"), "***"))), /** * 手機號 */ 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,該接口的作用就是接受一個輸入?yún)?shù),返回一個結(jié)果,例如Function<String, Integer>,就是將 “10” 轉(zhuǎn)換為 10 的過程,也就是將字符串轉(zhuǎn)為整數(shù)。使用Function接口的目的就是將原字符串,轉(zhuǎn)換為脫敏后的新字符串,上邊的操作可以理解為val值給了第一個Sting, lambada轉(zhuǎn)換完成給了第二個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: 這個注解用來標(biāo)記Jackson復(fù)合注解,當(dāng)你使用多個Jackson注解組合成一個自定義注解時會用到它。
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)); } /** * 在序列化時獲取字段注解屬性 * * @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方法,該方法的作用就是序列化,還實現(xiàn)了ContextualSerializer接口,重寫了createContextual方法,該方法的作用就是在序列化時獲取字段注解屬性。先執(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; /** * 真實姓名 */ @Desensitization(type = DesensitizationEnum.REAL_NAME) private String realName; /** * 性別 */ private String gender; /** * 地址 */ @Desensitization(type = DesensitizationEnum.ADDRESS) private String address; /** * 手機號 */ @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實現(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問題的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12在IntelliJ IDEA中多線程并發(fā)代碼的調(diào)試方法詳解
這篇文章主要介紹了在IntelliJ IDEA中多線程并發(fā)代碼的調(diào)試方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08使用springboot整合mybatis-plus實現(xiàn)數(shù)據(jù)庫的增刪查改示例
這篇文章主要介紹了使用springboot整合mybatis-plus實現(xiàn)數(shù)據(jù)庫的增刪查改示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Java之HashMap.values()轉(zhuǎn)List時的錯誤和正確演示
這篇文章主要介紹了Java之HashMap.values()轉(zhuǎn)List時的錯誤和正確演示,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03Java SimpleDateFormat中英文時間格式化轉(zhuǎn)換詳解
這篇文章主要為大家詳細(xì)介紹了Java SimpleDateFormat中英文時間格式化轉(zhuǎn)換,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12