最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java利用Jackson序列化實(shí)現(xiàn)數(shù)據(jù)脫敏詳解

 更新時(shí)間:2023年03月31日 09:46:06   作者:京東云開發(fā)者  
在項(xiàng)目中有些敏感信息不能直接展示,比如客戶手機(jī)號(hào)、身份證、車牌號(hào)等信息,展示時(shí)均需要進(jìn)行數(shù)據(jù)脫敏,防止泄露客戶隱私。本文將利用Jackson序列化實(shí)現(xiàn)數(shù)據(jù)脫敏,需要的可以參考一下

1.背景

在項(xiàng)目中有些敏感信息不能直接展示,比如客戶手機(jī)號(hào)、身份證、車牌號(hào)等信息,展示時(shí)均需要進(jìn)行數(shù)據(jù)脫敏,防止泄露客戶隱私。脫敏即是對(duì)數(shù)據(jù)的部分信息用脫敏符號(hào)(*)處理。

2.目標(biāo)

  • 在服務(wù)端返回?cái)?shù)據(jù)時(shí),利用Jackson序列化完成數(shù)據(jù)脫敏,達(dá)到對(duì)敏感信息脫敏展示。
  • 降低重復(fù)開發(fā)量,提升開發(fā)效率
  • 形成統(tǒng)一有效的脫敏規(guī)則
  • 可基于重寫默認(rèn)脫敏實(shí)現(xiàn)的desensitize方法,實(shí)現(xiàn)可擴(kuò)展、可自定義的個(gè)性化業(yè)務(wù)場景的脫敏需求

3.主要實(shí)現(xiàn)

3.1基于Jackson的自定義脫敏序列化實(shí)現(xiàn)

StdSerializer:所有標(biāo)準(zhǔn)序列化程序所使用的基類,這個(gè)是編寫自定義序列化程序所推薦使用的基類。

ContextualSerializer: 是Jackson 提供的另一個(gè)序列化相關(guān)的接口,它的作用是通過字段已知的上下文信息定制JsonSerializer。

package com.jd.ccmp.ctm.constraints.serializer;


import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.jd.ccmp.ctm.constraints.Symbol;
import com.jd.ccmp.ctm.constraints.annotation.Desensitize;
import com.jd.ccmp.ctm.constraints.desensitization.Desensitization;
import com.jd.ccmp.ctm.constraints.desensitization.DesensitizationFactory;
import com.jd.ccmp.ctm.constraints.desensitization.DefaultDesensitization;




import java.io.IOException;




/**
 * 脫敏序列化器
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:10
 */
public class ObjectDesensitizeSerializer extends StdSerializer<Object> implements ContextualSerializer {
    private static final long serialVersionUID = -7868746622368564541L;
    private transient Desensitization<Object> desensitization;
    protected ObjectDesensitizeSerializer() {
        super(Object.class);
    }
    public Desensitization<Object> getDesensitization() {
        return desensitization;
    }
    public void setDesensitization(Desensitization<Object> desensitization) {
        this.desensitization = desensitization;
    }
    @Override
    public JsonSerializer<Object> createContextual(SerializerProvider prov, BeanProperty property) {
//獲取屬性注解
        Desensitize annotation = property.getAnnotation(Desensitize.class);
        return createContextual(annotation.desensitization());
    }
    @SuppressWarnings("unchecked")
    public JsonSerializer<Object> createContextual(Class<? extends Desensitization<?>> clazz) {
        ObjectDesensitizeSerializer serializer = new ObjectDesensitizeSerializer();
        if (clazz != DefaultDesensitization.class) {
            serializer.setDesensitization((Desensitization<Object>) DesensitizationFactory.getDesensitization(clazz));
        }
        return serializer;
    }
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        Desensitization<Object> objectDesensitization = getDesensitization();
        if (objectDesensitization != null) {
            try {
                gen.writeObject(objectDesensitization.desensitize(value));
            } catch (Exception e) {
                gen.writeObject(value);
            }
        } else if (value instanceof String) {
            gen.writeString(Symbol.getSymbol(((String) value).length(), Symbol.STAR));
        } else {
            gen.writeObject(value);
        }

注:createContextual可以獲得字段的類型以及注解。當(dāng)字段擁有自定義注解時(shí),取出注解中的值創(chuàng)建定制的序列化方式,這樣在serialize方法中便可以得到這個(gè)值了。createContextual方法只會(huì)在第一次序列化字段時(shí)調(diào)用(因?yàn)樽侄蔚纳舷挛男畔⒃谶\(yùn)行期不會(huì)改變),所以無需關(guān)心性能問題。

3.2定義脫敏接口、以及工廠實(shí)現(xiàn)

3.2.1脫敏器接口定義

package com.jd.ccmp.ctm.constraints.desensitization;


/**
 * 脫敏器
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 10:56
 */
public interface Desensitization<T> {
    /**
     * 脫敏實(shí)現(xiàn)
     *
     * @param target 脫敏對(duì)象
     * @return 脫敏返回結(jié)果
     */
    T desensitize(T target);
}

3.2.2脫敏器工廠實(shí)現(xiàn)

package com.jd.ccmp.ctm.constraints.desensitization;

import java.util.HashMap;
import java.util.Map;


/**
 * 工廠方法
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 10:58
 */
public class DesensitizationFactory {
    private DesensitizationFactory() {
    }
    private static final Map<Class<?>, Desensitization<?>> map = new HashMap<>();




    @SuppressWarnings("all")
    public static Desensitization<?> getDesensitization(Class<?> clazz) {
        if (clazz.isInterface()) {
            throw new UnsupportedOperationException("desensitization is interface, what is expected is an implementation class !");
        }
        return map.computeIfAbsent(clazz, key -> {
            try {
                return (Desensitization<?>) clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new UnsupportedOperationException(e.getMessage(), e);
            }
        });

3.3常用的脫敏器實(shí)現(xiàn)

3.3.1默認(rèn)脫敏實(shí)現(xiàn)

可基于默認(rèn)實(shí)現(xiàn),擴(kuò)展實(shí)現(xiàn)個(gè)性化場景

package com.jd.ccmp.ctm.constraints.desensitization;


/**
 * 默認(rèn)脫敏實(shí)現(xiàn)
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:01
 */
public interface DefaultDesensitization extends Desensitization<String> {
}

3.3.2手機(jī)號(hào)脫敏器

實(shí)現(xiàn)對(duì)手機(jī)號(hào)中間4位號(hào)碼脫敏

package com.jd.ccmp.ctm.constraints.desensitization;
import com.jd.ccmp.ctm.constraints.Symbol;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 手機(jī)號(hào)脫敏器,保留前3位和后4位
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:02
 */
public class MobileNoDesensitization implements DefaultDesensitization {
    /**
     * 手機(jī)號(hào)正則
     */
    private static final Pattern DEFAULT_PATTERN = Pattern.compile("(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}");




    @Override
    public String desensitize(String target) {
        Matcher matcher = DEFAULT_PATTERN.matcher(target);
        while (matcher.find()) {
            String group = matcher.group();
            target = target.replace(group, group.substring(0, 3) + Symbol.getSymbol(4, Symbol.STAR) + group.substring(7, 11));
        }
        return target;

3.4注解定義

通過@JacksonAnnotationsInside實(shí)現(xiàn)自定義注解,提高易用性

package com.jd.ccmp.ctm.constraints.annotation;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.jd.ccmp.ctm.constraints.desensitization.Desensitization;
import com.jd.ccmp.ctm.constraints.serializer.ObjectDesensitizeSerializer;
import java.lang.annotation.*;


/**
 * 脫敏注解
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:09
 */
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = ObjectDesensitizeSerializer.class)
@Documented
public @interface Desensitize {
    /**
     * 對(duì)象脫敏器實(shí)現(xiàn)
     */
    @SuppressWarnings("all")
    Class<? extends Desensitization<?>> desensitization();

3.4.1默認(rèn)脫敏注解

package com.jd.ccmp.ctm.constraints.annotation;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.jd.ccmp.ctm.constraints.desensitization.DefaultDesensitization;
import java.lang.annotation.*;




/**
 * 默認(rèn)脫敏注解
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:14
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@Desensitize(desensitization = DefaultDesensitization.class)
@Documented
public @interface DefaultDesensitize {

3.4.2手機(jī)號(hào)脫敏注解

package com.jd.ccmp.ctm.constraints.annotation;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.jd.ccmp.ctm.constraints.desensitization.MobileNoDesensitization;
import java.lang.annotation.*;


/**
 * 手機(jī)號(hào)脫敏
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 11:18
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@Desensitize(desensitization = MobileNoDesensitization.class)
@Documented
public @interface MobileNoDesensitize {
}

3.5定義脫敏符號(hào)

支持指定脫敏符號(hào),例如* 或是 ^_^

package com.jd.ccmp.ctm.constraints;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


/**
 * 脫敏符號(hào)
 *
 * @author zhangxiaoxu15
 * @date 2022/2/8 10:53
 */
public class Symbol {
    /**
     * '*'脫敏符
     */
    public static final String STAR = "*";
    private Symbol() {}
    /**
     * 獲取符號(hào)
     *
     * @param number 符號(hào)個(gè)數(shù)
     * @param symbol 符號(hào)
     */
    public static String getSymbol(int number, String symbol) {
        return IntStream.range(0, number).mapToObj(i -> symbol).collect(Collectors.joining());
    }

4.使用樣例&執(zhí)行流程剖析

程序類圖

**執(zhí)行流程剖析**

 1.調(diào)用JsonUtil.toJsonString()開始執(zhí)行序列化

 2.識(shí)別屬性mobile上的注解@MobileNoDesensitize(上文3.4.2)

 3.調(diào)用ObjectDesensitizeSerializer#createContextual(上文3.1 & 3.2),返回JsonSerializer

 4.調(diào)用手機(jī)號(hào)脫敏實(shí)現(xiàn)MobileNoDesensitization#desensitize(上文3.3.2)

 5.輸出脫敏后的序列化結(jié)果,{"mobile":"133****5678"}

不難發(fā)現(xiàn)核心執(zhí)行流程是第3步,但是@MobileNoDesensitize與ObjectDesensitizeSerializer又是如何聯(lián)系起來的呢?

  • 嘗試梳理下引用鏈路:@MobileNoDesensitize -> @Desensitize -> @JsonSerialize -> ObjectDesensitizeSerializer
  • 但是,在ObjectDesensitizeSerializer的實(shí)現(xiàn)中,我們似乎卻沒有發(fā)現(xiàn)上述鏈路的直接調(diào)用關(guān)系
  • 這就不得不說下Jackson元注解的概念
//**Jackson元注解**
//1.提到元注解這個(gè)詞,大家會(huì)想到@Target、@Retention、@Documented、@Inherited
//2.Jackson也以同樣的思路設(shè)計(jì)了@JacksonAnnotationsInside


/**
 * Meta-annotation (annotations used on other annotations)
 * used for indicating that instead of using target annotation
 * (annotation annotated with this annotation),
 * Jackson should use meta-annotations it has.
 * This can be useful in creating "combo-annotations" by having
 * a container annotation, which needs to be annotated with this
 * annotation as well as all annotations it 'contains'.
 * 
 * @since 2.0
 */
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JacksonAnnotationsInside
{
}

正是通過”combo-annotations”(組合注解、捆綁注解)的機(jī)制,實(shí)現(xiàn)了指示Jackson應(yīng)該使用其擁有的元注釋,而不是使用目標(biāo)注釋,從而實(shí)現(xiàn)了自定義脫敏實(shí)現(xiàn)設(shè)計(jì)目標(biāo)。

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

相關(guān)文章

  • SpringBoot整合Canal+RabbitMQ監(jiān)聽數(shù)據(jù)變更詳解

    SpringBoot整合Canal+RabbitMQ監(jiān)聽數(shù)據(jù)變更詳解

    在現(xiàn)代分布式系統(tǒng)中,實(shí)時(shí)獲取數(shù)據(jù)庫的變更信息是一個(gè)常見的需求,本文將介紹SpringBoot如何通過整合Canal和RabbitMQ監(jiān)聽數(shù)據(jù)變更,需要的可以參考下
    2024-12-12
  • Java鍵盤錄入Scanner類的使用方法詳析

    Java鍵盤錄入Scanner類的使用方法詳析

    在Java編程中,引用數(shù)據(jù)類型是用來存儲(chǔ)對(duì)象的引用(地址),而Scanner類是引用數(shù)據(jù)類型的一種,用于讀取輸入數(shù)據(jù),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • Spring Cloud Nacos 和 Eureka區(qū)別解析

    Spring Cloud Nacos 和 Eureka區(qū)別解析

    Spring Cloud Nacos 和 Spring Cloud Eureka 都是 Spring Cloud 微服務(wù)框架中的服務(wù)注冊(cè)和發(fā)現(xiàn)組件,用于幫助開發(fā)者輕松地構(gòu)建和管理微服務(wù)應(yīng)用,這篇文章主要介紹了Spring Cloud Nacos 和 Eureka區(qū)別,需要的朋友可以參考下
    2023-08-08
  • SpringBoot中創(chuàng)建的AOP不生效的原因及解決

    SpringBoot中創(chuàng)建的AOP不生效的原因及解決

    這篇文章主要介紹了SpringBoot中創(chuàng)建的AOP不生效的原因及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java之使用stream對(duì)日期排序方式

    java之使用stream對(duì)日期排序方式

    這篇文章主要介紹了java之使用stream對(duì)日期排序方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java實(shí)現(xiàn)鏈表中元素的獲取、查詢和修改方法詳解

    Java實(shí)現(xiàn)鏈表中元素的獲取、查詢和修改方法詳解

    這篇文章主要介紹了Java實(shí)現(xiàn)鏈表中元素的獲取、查詢和修改方法,結(jié)合實(shí)例形式詳細(xì)分析了Java針對(duì)鏈表中元素的獲取、查詢和修改相關(guān)原理、實(shí)現(xiàn)方法及操作注意事項(xiàng),需要的朋友可以參考下
    2020-03-03
  • Java多線程間的5種通信方式小結(jié)

    Java多線程間的5種通信方式小結(jié)

    有兩個(gè)線程,A 線程向一個(gè)集合里面依次添加元素“abc”字符串,一共添加十次,當(dāng)添加到第五次的時(shí)候,希望 B 線程能夠收到 A 線程的通知,然后 B 線程執(zhí)行相關(guān)的業(yè)務(wù)操作,本文介紹的5種通信方式都是基本這兩種模型來實(shí)現(xiàn)的,需要的朋友可以參考下
    2023-10-10
  • Spring使用@Autowired注解實(shí)現(xiàn)自動(dòng)裝配方式

    Spring使用@Autowired注解實(shí)現(xiàn)自動(dòng)裝配方式

    這篇文章主要介紹了Spring使用@Autowired注解實(shí)現(xiàn)自動(dòng)裝配方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • spring設(shè)置攔截器代碼實(shí)例

    spring設(shè)置攔截器代碼實(shí)例

    這篇文章主要介紹了spring設(shè)置攔截器代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • java搜索無向圖中兩點(diǎn)之間所有路徑的算法

    java搜索無向圖中兩點(diǎn)之間所有路徑的算法

    這篇文章主要介紹了java搜索無向圖中兩點(diǎn)之間所有路徑的算法
    2019-01-01

最新評(píng)論

蛟河市| 镇原县| 南澳县| 华宁县| 横山县| 葫芦岛市| 科技| 高邮市| 舞钢市| 阿坝县| 习水县| 保山市| 凌云县| 柘城县| 明光市| 明光市| 扎兰屯市| 时尚| 麻栗坡县| 项城市| 宁陕县| 兖州市| 芦溪县| 祁门县| 宣威市| 南雄市| 建始县| 澜沧| 建昌县| 龙川县| 潞西市| 江安县| 根河市| 屯门区| 英吉沙县| 新营市| 五台县| 阳城县| 定兴县| 宁乡县| 张家口市|