欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java使用Hutool+自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏

 更新時(shí)間:2023年09月07日 09:31:53   作者:Bummon  
我們?cè)谑褂檬謾C(jī)銀行的時(shí)候經(jīng)常能看到APP上會(huì)將銀行卡的卡號(hào)中間部分給隱藏掉使用 ***** 來代替,在某些網(wǎng)站上查看一些業(yè)務(wù)密碼時(shí)(例如簽到密碼等)也會(huì)使用 ***** 來隱藏掉真正的密碼,那么這種方式是如何實(shí)現(xiàn)的呢,本文將給大家介紹使用Hutool+自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏

前言

我們?cè)谑褂檬謾C(jī)銀行的時(shí)候經(jīng)常能看到APP上會(huì)將銀行卡的卡號(hào)中間部分給隱藏掉使用 ***** 來代替,在某些網(wǎng)站上查看一些業(yè)務(wù)密碼時(shí)(例如簽到密碼等)也會(huì)使用 ***** 來隱藏掉真正的密碼,那么這種方式是如何實(shí)現(xiàn)的呢?

Hutool

Hutool是一個(gè)小而全的Java工具類庫,通過靜態(tài)方法封裝,降低相關(guān)API的學(xué)習(xí)成本,提高工作效率,使Java擁有函數(shù)式語言般的優(yōu)雅,讓Java語言也可以“甜甜的”。

Hutool中的工具方法來自每個(gè)用戶的精雕細(xì)琢,它涵蓋了Java開發(fā)底層代碼中的方方面面,它既是大型項(xiàng)目開發(fā)中解決小問題的利器,也是小型項(xiàng)目中的效率擔(dān)當(dāng);

Hutool是項(xiàng)目中 util 包友好的替代,它節(jié)省了開發(fā)人員對(duì)項(xiàng)目中公用類和公用工具方法的封裝時(shí)間,使開發(fā)專注于業(yè)務(wù),同時(shí)可以最大限度的避免封裝不完善帶來的bug。

我們這篇文章的實(shí)現(xiàn)思路就基于Hutool來實(shí)現(xiàn),在Hutool中提供了一個(gè)名為 DesensitizedUtil 的工具類,我們使用這個(gè)工具類來加密。

首先我們先來看一下這個(gè)類里的具體實(shí)現(xiàn),如下:

我們可以看到映入眼簾的除了一個(gè)無參構(gòu)造之外就是一個(gè)名為 desensitized 的方法,這個(gè)方法就是我們加密的主要方法,里面利用了 switch…case 方法來區(qū)分不同的加密方法。我們可以來寫一個(gè)單元測(cè)試來測(cè)試一下通過這個(gè)方法加密后是什么樣的。

以上為加密后的信息,里面我使用了不同的類型來進(jìn)行加密,目前最新版的Hutool支持脫敏加密的類型如下:

  • 用戶ID
  • 中文名
  • 密碼
  • 地址
  • 郵箱
  • 座機(jī)號(hào)
  • 手機(jī)號(hào)
  • 中國大陸的車牌號(hào)
  • 銀行卡號(hào)
  • IPv4地址
  • IPv6地址
  • 自定義脫敏

實(shí)現(xiàn)

通過以上的示例我們就可以開始編寫我們自己的脫敏操作了,首先我們要先根據(jù)以上Hutool中提供的脫敏類型來編寫我們自己的類型**(如嫌麻煩也可省略此步驟,直接使用DesensitizedUtil中的DesensitizedType)**

編寫數(shù)據(jù)脫敏類型

/**
 * @author Bummon
 * @description 數(shù)據(jù)脫敏策略
 * @date 2023-09-01 17:43
 */
public enum DataMaskingType {
    /**
     * 用戶ID
     */
    USER_ID,
    /**
     * 中文名
     */
    CHINESE_NAME,
    /**
     * 身份證號(hào)
     */
    ID_CARD,
    /**
     * 座機(jī)
     */
    FIXED_PHONE,
    /**
     * 手機(jī)號(hào)
     */
    MOBILE_PHONE,
    /**
     * 地址
     */
    ADDRESS,
    /**
     * 郵箱
     */
    EMAIL,
    /**
     * 密碼
     */
    PASSWORD,
    /**
     * 中國大陸車牌號(hào)
     */
    CAR_LICENSE,
    /**
     * 銀行卡號(hào)
     */
    BANK_CARD,
    /**
     * IPv4地址
     */
    IPV4,
    /**
     * IPv6地址
     */
    IPV6,
    /**
     * 自定義類型
     */
    CUSTOM;
}

編寫自定義注解

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @author Bummon
 * @description 數(shù)據(jù)脫敏自定義注解
 * @date 2023-09-01 18:01
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DataMaskingSerialize.class)
public @interface DataMasking {
    /**
     * 數(shù)據(jù)脫敏類型
     */
    DataMaskingType type() default DataMaskingType.CUSTOM;
    /**
     * 脫敏開始位置(包含)
     */
    int start() default 0;
    /**
     * 脫敏結(jié)束位置(不包含)
     */
    int end() default 0;
}

需要注意的是:當(dāng)DataMaskingType為 CUSTOM 時(shí),才需要填寫 start 和 end ,且這兩個(gè)參數(shù)才會(huì)生效,且 start 中是包含當(dāng)前下標(biāo)的字符的,而 end 不包含當(dāng)前下標(biāo)的字符。

編寫自定義序列化類

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.util.Objects;
/**
 * @author Bummon
 * @description
 * @date 2023-09-01 18:14
 */
@AllArgsConstructor
@NoArgsConstructor
public class DataMaskingSerialize extends JsonSerializer implements ContextualSerializer {
    private DataMaskingType type;
    private Integer start;
    private Integer end;
    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        String value = (String) o;
        switch (type) {
            //userId
            case USER_ID:
                jsonGenerator.writeString(String.valueOf(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.USER_ID)));
                break;
            //中文名
            case CHINESE_NAME:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.CHINESE_NAME));
                break;
            //身份證號(hào)
            case ID_CARD:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.ID_CARD));
                break;
            //座機(jī)
            case FIXED_PHONE:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.FIXED_PHONE));
                break;
            //手機(jī)號(hào)
            case MOBILE_PHONE:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.MOBILE_PHONE));
                break;
            //地址
            case ADDRESS:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.ADDRESS));
                break;
            //郵箱
            case EMAIL:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.EMAIL));
                break;
            case BANK_CARD:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.BANK_CARD));
                break;
            //密碼
            case PASSWORD:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.PASSWORD));
                break;
            //中國大陸車牌號(hào)
            case CAR_LICENSE:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.CAR_LICENSE));
                break;
            case IPV4:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.IPV4));
                break;
            case IPV6:
                jsonGenerator.writeString(DesensitizedUtil.desensitized(value, DesensitizedUtil.DesensitizedType.IPV6));
                break;
            //自定義
            case CUSTOM:
                jsonGenerator.writeString(CharSequenceUtil.hide(value, start, end));
                break;
            default:
                break;
        }
    }
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (Objects.nonNull(beanProperty)) {
            //判斷是否為string類型
            if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
                DataMasking anno = beanProperty.getAnnotation(DataMasking.class);
                if (Objects.isNull(anno)) {
                    anno = beanProperty.getContextAnnotation(DataMasking.class);
                }
                if (Objects.nonNull(anno)) {
                    return new DataMaskingSerialize(anno.type(), anno.start(), anno.end());
                }
            }
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(null);
    }
}

我們繼承于 JsonSerializer 并實(shí)現(xiàn)了 ContextualSerializer 中的方法,并對(duì)我們自定義注解聲明的字段進(jìn)行攔截和脫敏加密操作,接下來我們可以來測(cè)試一下效果。

測(cè)試

因?yàn)槭菍?shí)例化的時(shí)候才會(huì)被脫敏,那我們就創(chuàng)建一個(gè)實(shí)體類來存放我們需要加密的信息。

編寫測(cè)試實(shí)體類

import com.bummon.mask.DataMasking;
import com.bummon.mask.DataMaskingType;
import lombok.*;
/**
 * @author Bummon
 * @description
 * @date 2023-09-01 18:29
 */
@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class TestEntity {
    @DataMasking(type = DataMaskingType.USER_ID)
    private Integer userId;
    @DataMasking(type = DataMaskingType.CHINESE_NAME)
    private String userName;
    @DataMasking(type = DataMaskingType.ADDRESS)
    private String address;
    @DataMasking(type = DataMaskingType.ID_CARD)
    private String idCard;
    @DataMasking(type = DataMaskingType.FIXED_PHONE)
    private String fixedPhone;
    @DataMasking(type = DataMaskingType.MOBILE_PHONE)
    private String mobilePhone;
    @DataMasking(type = DataMaskingType.EMAIL)
    private String email;
    @DataMasking(type = DataMaskingType.PASSWORD)
    private String password;
    @DataMasking(type = DataMaskingType.CAR_LICENSE)
    private String carLicense;
    @DataMasking(type = DataMaskingType.BANK_CARD)
    private String bankCard;
    @DataMasking(type = DataMaskingType.IPV4)
    private String ipv4;
    @DataMasking(type = DataMaskingType.IPV6)
    private String ipv6;
    @DataMasking(type = DataMaskingType.CUSTOM,start = 3,end = 9)
    private String custom;
    /**
     * 不進(jìn)行數(shù)據(jù)脫敏的字段
     */
    private String noMask;
}

編寫測(cè)試Controller

import com.bummon.entity.TestEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author Bummon
 * @description
 * @date 2023-09-01 18:39
 */
@RestController
public class TestController {
    @GetMapping("/test")
    public TestEntity test() {
        return TestEntity.builder()
                .userId(1234567890)
                .userName("張三")
                .password("12")
                .address("河南省鄭州市中原區(qū)")
                .email("xxxx@xx.com")
                .fixedPhone("0838-5553792")
                .mobilePhone("13888888888")
                .carLicense("豫P3U253")
                .bankCard("1679374639283740")
                .idCard("412711223344556677")
                .ipv4("192.168.1.236")
                .ipv6("abcd:1234:aCA9:123:4567:089:0:0000")
                .custom("289073458794")
                .noMask("我是不需要數(shù)據(jù)脫敏的字段")
                .build();
    }
}

接下來我們啟動(dòng)項(xiàng)目來看測(cè)試一下得到的是否為我們預(yù)期的數(shù)據(jù):

我們可以看到,我們加了注解的字段都被正確的脫敏了,而沒加注解的字段會(huì)正常顯示。

總結(jié)

我們使用了HutoolDesensitizedUtil中的 desensitized 方法來實(shí)現(xiàn)數(shù)據(jù)脫敏,在 CUSTOM 類型的脫敏字段中,startend 兩個(gè)屬性是必填的,且 start 包含當(dāng)前下標(biāo),而 end 不包含當(dāng)前下標(biāo)。

以上就是Java使用Hutool+自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏的詳細(xì)內(nèi)容,更多關(guān)于Hutool+自定義注解數(shù)據(jù)脫敏的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring?Boot面試必問之啟動(dòng)流程知識(shí)點(diǎn)詳解

    Spring?Boot面試必問之啟動(dòng)流程知識(shí)點(diǎn)詳解

    SpringBoot是Spring開源組織下的子項(xiàng)目,是Spring組件一站式解決方案,主要是簡(jiǎn)化了使用Spring的難度,簡(jiǎn)省了繁重的配置,提供了各種啟動(dòng)器,開發(fā)者能快速上手,這篇文章主要給大家介紹了關(guān)于Spring?Boot面試必問之啟動(dòng)流程知識(shí)點(diǎn)的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • mybatis 如何返回list<String>類型數(shù)據(jù)

    mybatis 如何返回list<String>類型數(shù)據(jù)

    這篇文章主要介紹了mybatis 如何返回list<String>類型數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringSecurity+jwt+redis基于數(shù)據(jù)庫登錄認(rèn)證的實(shí)現(xiàn)

    SpringSecurity+jwt+redis基于數(shù)據(jù)庫登錄認(rèn)證的實(shí)現(xiàn)

    本文主要介紹了SpringSecurity+jwt+redis基于數(shù)據(jù)庫登錄認(rèn)證的實(shí)現(xiàn),其中也涉及到自定義的過濾器和處理器,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Java 實(shí)戰(zhàn)項(xiàng)目錘煉之樸素風(fēng)格個(gè)人博客系統(tǒng)的實(shí)現(xiàn)流程

    Java 實(shí)戰(zhàn)項(xiàng)目錘煉之樸素風(fēng)格個(gè)人博客系統(tǒng)的實(shí)現(xiàn)流程

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java+vue+Springboot+ssm+mysql+maven+redis實(shí)現(xiàn)一個(gè)樸素風(fēng)格的個(gè)人博客系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-11-11
  • 如何使用@AllArgsConstructor和final 代替 @Autowired

    如何使用@AllArgsConstructor和final 代替 @Autowired

    這篇文章主要介紹了使用@AllArgsConstructor和final 代替 @Autowired方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Spring很常用的@Conditional注解的使用場(chǎng)景和源碼解析

    Spring很常用的@Conditional注解的使用場(chǎng)景和源碼解析

    今天要分享的是Spring的注解@Conditional,@Conditional是一個(gè)條件注解,它的作用是判斷Bean是否滿足條件,本文詳細(xì)介紹了@Conditional注解的使用場(chǎng)景和源碼,需要的朋友可以參考一下
    2023-04-04
  • RocketMQ中的消費(fèi)模式和消費(fèi)策略詳解

    RocketMQ中的消費(fèi)模式和消費(fèi)策略詳解

    這篇文章主要介紹了RocketMQ中的消費(fèi)模式和消費(fèi)策略詳解,RocketMQ 是基于發(fā)布訂閱模型的消息中間件,所謂的發(fā)布訂閱就是說,consumer 訂閱了 broker 上的某個(gè) topic,當(dāng) producer 發(fā)布消息到 broker 上的該 topic 時(shí),consumer 就能收到該條消息,需要的朋友可以參考下
    2023-10-10
  • java之向linux文件夾下寫文件無權(quán)限的問題

    java之向linux文件夾下寫文件無權(quán)限的問題

    這篇文章主要介紹了java之向linux文件夾下寫文件無權(quán)限的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java中的常用輸入輸出語句的操作代碼

    Java中的常用輸入輸出語句的操作代碼

    這篇文章主要介紹了Java中的常用輸入輸出語句的操作代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • Java中的分布式事務(wù)Seata詳解

    Java中的分布式事務(wù)Seata詳解

    這篇文章主要介紹了Java中的分布式事務(wù)Seata詳解,Seata 是一款開源的分布式事務(wù)解決方案,致力于提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù),Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案,需要的朋友可以參考下
    2023-08-08

最新評(píng)論