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

SpringBoot實現(xiàn)返回值數(shù)據(jù)脫敏的步驟詳解

 更新時間:2023年07月14日 10:57:07   作者:月色無痕  
這篇文章主要給大家介紹一下SpringBoot實現(xiàn)返回值數(shù)據(jù)脫敏的步驟,文章通過代碼示例介紹的非常詳細,具有一定的參考價值,需要的朋友可以參考下

介紹

  • SpringBoot實現(xiàn)返回數(shù)據(jù)脫敏

  • 有時,敏感數(shù)據(jù)返回時,需要進行隱藏處理,但是如果一個字段一個字段的進行硬編碼處理的話,不僅增加了工作量,而且后期需求變動的時候,更加是地獄般的工作量變更。

  • 下面,通過身份證,姓名,密碼,手機號等等示例去演示脫敏的流程,當然你也可以在此基礎(chǔ)上添加自己的實現(xiàn)方式

原理

  • 項目使用的是SpringBoot,所以需要在序列化的時候,進行脫敏處理,springboot內(nèi)置的序列化工具為jackson
  • 通過實現(xiàn)com.fasterxml.jackson.databind.JsonSerializer進行自定義序列化
  • 通過重寫com.fasterxml.jackson.databind.ser.ContextualSerializer.createContextual獲取自定義注解的信息

實現(xiàn)

自定義注解類

@Target(ElementType.FIELD) //作用于字段上
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside  // 表示自定義自己的注解Sensitive
@JsonSerialize(using = SensitiveInfoSerialize.class) // 該注解使用序列化的方式
public @interface Sensitive {
    SensitizedType value();
}

創(chuàng)建脫敏字段類型枚舉

public enum SensitizedType {
    /**
     * 用戶id
     */
    USER_ID,
    /**
     * 中文名
     */
    CHINESE_NAME,
    /**
     * 身份證號
     */
    ID_CARD,
    /**
     * 座機號
     */
    FIXED_PHONE,
    /**
     * 手機號
     */
    MOBILE_PHONE,
    /**
     * 地址
     */
    ADDRESS,
    /**
     * 電子郵件
     */
    EMAIL,
    /**
     * 密碼
     */
    PASSWORD,
    /**
     * 中國大陸車牌,包含普通車輛、新能源車輛
     */
    CAR_LICENSE,
    /**
     * 銀行卡
     */
    BANK_CARD,
    /**
     * IPv4地址
     */
    IPV4,
    /**
     * IPv6地址
     */
    IPV6,
    /**
     * 定義了一個first_mask的規(guī)則,只顯示第一個字符。
     */
    FIRST_MASK
}

脫敏工具類

import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
/**
 * @Auther: wu
 * @Date: 2023/7/11
 * @Description: com.wu.demo.common.my_sensitive
 */
public class SensitizedUtil {
    public static String desensitized(CharSequence str, SensitizedType desensitizedType) {
        if (StrUtil.isBlank(str)) {
            return StrUtil.EMPTY;
        }
        String newStr = String.valueOf(str);
        switch (desensitizedType) {
            case USER_ID:
                newStr = String.valueOf(userId());
                break;
            case CHINESE_NAME:
                newStr = chineseName(String.valueOf(str));
                break;
            case ID_CARD:
                newStr = idCardNum(String.valueOf(str), 3, 4);
                break;
            case FIXED_PHONE:
                newStr = fixedPhone(String.valueOf(str));
                break;
            case MOBILE_PHONE:
                newStr = mobilePhone(String.valueOf(str));
                break;
            case ADDRESS:
                newStr = address(String.valueOf(str), 8);
                break;
            case EMAIL:
                newStr = email(String.valueOf(str));
                break;
            case PASSWORD:
                newStr = password(String.valueOf(str));
                break;
            case CAR_LICENSE:
                newStr = carLicense(String.valueOf(str));
                break;
            case BANK_CARD:
                newStr = bankCard(String.valueOf(str));
                break;
            case IPV4:
                newStr = ipv4(String.valueOf(str));
                break;
            case IPV6:
                newStr = ipv6(String.valueOf(str));
                break;
            case FIRST_MASK:
                newStr = firstMask(String.valueOf(str));
                break;
            default:
        }
        return newStr;
    }
    /**
     * 【用戶id】不對外提供userId
     *
     * @return 脫敏后的主鍵
     */
    public static Long userId() {
        return 0L;
    }
    /**
     * 定義了一個first_mask的規(guī)則,只顯示第一個字符。<br>
     * 脫敏前:123456789;脫敏后:1********。
     *
     * @param str 字符串
     * @return 脫敏后的字符串
     */
    public static String firstMask(String str) {
        if (StrUtil.isBlank(str)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(str, 1, str.length());
    }
    /**
     * 【中文姓名】只顯示第一個漢字,其他隱藏為2個星號,比如:李**
     *
     * @param fullName 姓名
     * @return 脫敏后的姓名
     */
    public static String chineseName(String fullName) {
        return firstMask(fullName);
    }
    /**
     * 【身份證號】前1位 和后2位
     *
     * @param idCardNum 身份證
     * @param front     保留:前面的front位數(shù);從1開始
     * @param end       保留:后面的end位數(shù);從1開始
     * @return 脫敏后的身份證
     */
    public static String idCardNum(String idCardNum, int front, int end) {
        //身份證不能為空
        if (StrUtil.isBlank(idCardNum)) {
            return StrUtil.EMPTY;
        }
        //需要截取的長度不能大于身份證號長度
        if ((front + end) > idCardNum.length()) {
            return StrUtil.EMPTY;
        }
        //需要截取的不能小于0
        if (front < 0 || end < 0) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(idCardNum, front, idCardNum.length() - end);
    }
    /**
     * 【固定電話 前四位,后兩位
     *
     * @param num 固定電話
     * @return 脫敏后的固定電話;
     */
    public static String fixedPhone(String num) {
        if (StrUtil.isBlank(num)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(num, 4, num.length() - 2);
    }
    /**
     * 【手機號碼】前三位,后4位,其他隱藏,比如135****2210
     *
     * @param num 移動電話;
     * @return 脫敏后的移動電話;
     */
    public static String mobilePhone(String num) {
        if (StrUtil.isBlank(num)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.hide(num, 3, num.length() - 4);
    }
    /**
     * 【地址】只顯示到地區(qū),不顯示詳細地址,比如:北京市海淀區(qū)****
     *
     * @param address       家庭住址
     * @param sensitiveSize 敏感信息長度
     * @return 脫敏后的家庭地址
     */
    public static String address(String address, int sensitiveSize) {
        if (StrUtil.isBlank(address)) {
            return StrUtil.EMPTY;
        }
        int length = address.length();
        return StrUtil.hide(address, length - sensitiveSize, length);
    }
    /**
     * 【電子郵箱】郵箱前綴僅顯示第一個字母,前綴其他隱藏,用星號代替,@及后面的地址顯示,比如:d**@126.com
     *
     * @param email 郵箱
     * @return 脫敏后的郵箱
     */
    public static String email(String email) {
        if (StrUtil.isBlank(email)) {
            return StrUtil.EMPTY;
        }
        int index = StrUtil.indexOf(email, '@');
        if (index <= 1) {
            return email;
        }
        return StrUtil.hide(email, 1, index);
    }
    /**
     * 【密碼】密碼的全部字符都用*代替,比如:******
     *
     * @param password 密碼
     * @return 脫敏后的密碼
     */
    public static String password(String password) {
        if (StrUtil.isBlank(password)) {
            return StrUtil.EMPTY;
        }
        return StrUtil.repeat('*', password.length());
    }
    /**
     * 【中國車牌】車牌中間用*代替
     * eg1:null       -》 ""
     * eg1:""         -》 ""
     * eg3:蘇D40000   -》 蘇D4***0
     * eg4:陜A12345D  -》 陜A1****D
     * eg5:京A123     -》 京A123     如果是錯誤的車牌,不處理
     *
     * @param carLicense 完整的車牌號
     * @return 脫敏后的車牌
     */
    public static String carLicense(String carLicense) {
        if (StrUtil.isBlank(carLicense)) {
            return StrUtil.EMPTY;
        }
        // 普通車牌
        if (carLicense.length() == 7) {
            carLicense = StrUtil.hide(carLicense, 3, 6);
        } else if (carLicense.length() == 8) {
            // 新能源車牌
            carLicense = StrUtil.hide(carLicense, 3, 7);
        }
        return carLicense;
    }
    /**
     * 銀行卡號脫敏
     * eg: 1101 **** **** **** 3256
     *
     * @param bankCardNo 銀行卡號
     * @return 脫敏之后的銀行卡號
     * @since 5.6.3
     */
    public static String bankCard(String bankCardNo) {
        if (StrUtil.isBlank(bankCardNo)) {
            return bankCardNo;
        }
        bankCardNo = StrUtil.trim(bankCardNo);
        if (bankCardNo.length() < 9) {
            return bankCardNo;
        }
        final int length = bankCardNo.length();
        final int midLength = length - 8;
        final StringBuilder buf = new StringBuilder();
        buf.append(bankCardNo, 0, 4);
        for (int i = 0; i < midLength; ++i) {
            if (i % 4 == 0) {
                buf.append(CharUtil.SPACE);
            }
            buf.append('*');
        }
        buf.append(CharUtil.SPACE).append(bankCardNo, length - 4, length);
        return buf.toString();
    }
    /**
     * IPv4脫敏,如:脫敏前:192.0.2.1;脫敏后:192.*.*.*。
     *
     * @param ipv4 IPv4地址
     * @return 脫敏后的地址
     */
    public static String ipv4(String ipv4) {
        return StrUtil.subBefore(ipv4, '.', false) + ".*.*.*";
    }
    /**
     * IPv4脫敏,如:脫敏前:2001:0db8:86a3:08d3:1319:8a2e:0370:7344;脫敏后:2001:*:*:*:*:*:*:*
     *
     * @param ipv6 IPv4地址
     * @return 脫敏后的地址
     */
    public static String ipv6(String ipv6) {
        return StrUtil.subBefore(ipv6, ':', false) + ":*:*:*:*:*:*:*";
    }
}

上述枚舉類和脫敏工具類,我使用了hutool中的代碼,如果hutool滿足你的需求,可以直接把上述自定義注解類和自定義序列化類使用到的SensitizedType類直接替換為hutool中的cn.hutool.core.util.DesensitizedUtil.DesensitizedType的枚舉類,

添加自定義序列化實現(xiàn)類

public class SensitiveInfoSerialize extends JsonSerializer<String> implements ContextualSerializer {
    private SensitizedType sensitizedType;
    /**
     * 步驟一
     * 方法來源于ContextualSerializer,獲取屬性上的注解屬性,同時返回一個合適的序列化器
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        // 獲取自定義注解
        Sensitive annotation = beanProperty.getAnnotation(Sensitive.class);
        // 注解不為空,且標注的字段為String
        if(Objects.nonNull(annotation) && Objects.equals(String.class, beanProperty.getType().getRawClass())){
            this.sensitizedType = annotation.value();
            //自定義情況,返回本序列化器,將順利進入到該類中的serialize方法中
            return this;
        }
        // 注解為空,字段不為String,尋找合適的序列化器進行處理
        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
    }
    /**
     * 步驟二
     * 方法來源于JsonSerializer<String>:指定返回類型為String類型,serialize()將修改后的數(shù)據(jù)返回
     */
    @Override
    public void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if(Objects.isNull(sensitizedType)){
            // 定義策略為空,返回原字符串
            jsonGenerator.writeString(str);
        }else {
            // 定義策略不為空,返回策略處理過的字符串
            jsonGenerator.writeString(SensitizedUtil.desensitized(str,sensitizedType));
        }
    }
}

測試驗證

在需要的脫敏的實體類字段上加上相應(yīng)的注解

@Data
public class SensitiveBody {
    private String name;
    @Sensitive(SensitizedType.MOBILE_PHONE)
    private String mobile;
    @Sensitive(SensitizedType.ID_CARD)
    private String idCard;
}
    @ApiOperation(value = "脫敏測試處理")
    @GetMapping("sensitiveTest")
    public AjaxResult sensitiveTest(){
        SensitiveBody body = new SensitiveBody();
        body.setMobile("13041064026");
        body.setIdCard("411126189912355689");
        body.setName("Tom");
        return AjaxResult.success(body);
    }

到此這篇關(guān)于SpringBoot實現(xiàn)返回值數(shù)據(jù)脫敏的步驟詳解的文章就介紹到這了,更多相關(guān)SpringBoot返回值數(shù)據(jù)脫敏內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA調(diào)試技巧條件斷點實現(xiàn)步驟詳解

    IDEA調(diào)試技巧條件斷點實現(xiàn)步驟詳解

    這篇文章主要介紹了IDEA調(diào)試技巧條件斷點實現(xiàn)步驟詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • 基于SpringBoot2.0版本與老版本的區(qū)別

    基于SpringBoot2.0版本與老版本的區(qū)別

    這篇文章主要介紹了SpringBoot2.0版本與老版本的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • java讀取txt文件并輸出結(jié)果

    java讀取txt文件并輸出結(jié)果

    這篇文章主要介紹了java讀取txt文件并輸出結(jié)果,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • java 線程之對象的同步和異步(實例講解)

    java 線程之對象的同步和異步(實例講解)

    下面小編就為大家?guī)硪黄猨ava 線程之對象的同步和異步(實例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • Mybatis實現(xiàn)一對多映射處理

    Mybatis實現(xiàn)一對多映射處理

    MyBatis是一種流行的Java持久化框架,這篇文章主要為大家介紹了Mybatis如何實現(xiàn)一對多映射處理,文中的示例代碼講解詳細,需要的可以參考下
    2023-08-08
  • java中File類的三種創(chuàng)建文件夾方法總結(jié)

    java中File類的三種創(chuàng)建文件夾方法總結(jié)

    這篇文章主要給大家介紹了關(guān)于java中File類的三種創(chuàng)建文件夾方法,File類代表文件或目錄路徑名的抽象表達形式,通過File類提供的方法,我們可以很方便地創(chuàng)建文件夾,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-04-04
  • IDEA SSM框架整合配置及步驟詳解

    IDEA SSM框架整合配置及步驟詳解

    這篇文章主要介紹了IDEA SSM框架整合配置以及步驟,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • java如何執(zhí)行l(wèi)inux/cmd命令

    java如何執(zhí)行l(wèi)inux/cmd命令

    本文詳細介紹了在Java中執(zhí)行命令行命令的兩種方法:Runtime.exec()和ProcessBuilder,包括它們的優(yōu)缺點、參數(shù)傳遞、流處理、多線程處理、超時控制、跨平臺兼容性和亂碼問題的解決方案
    2026-01-01
  • SpringBoot啟動后自動執(zhí)行方法的各種方式對比

    SpringBoot啟動后自動執(zhí)行方法的各種方式對比

    這篇文章主要為大家詳細介紹了SpringBoot啟動后自動執(zhí)行方法的各種方式和性能對比,文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下
    2025-04-04
  • Spring中基于xml的AOP實現(xiàn)詳解

    Spring中基于xml的AOP實現(xiàn)詳解

    這篇文章主要介紹了Spring中基于xml的AOP實現(xiàn)詳解,基于xml與基于注解的AOP本質(zhì)上是非常相似的,都是需要封裝橫切關(guān)注點,封裝到切面中,然后把橫切關(guān)注點封裝為一個方法,再把該方法設(shè)置為當前的一個通知,再通過切入點表達式定位到橫切點就可以了,需要的朋友可以參考下
    2023-09-09

最新評論

峨山| 上饶县| 康保县| 建阳市| 枣阳市| 华宁县| 吉首市| 克什克腾旗| 弋阳县| 阿克苏市| 丹棱县| 嘉义市| 永定县| 乌拉特后旗| 白银市| 黄大仙区| 松阳县| 景宁| 康平县| 玉林市| 万盛区| 襄城县| 墨竹工卡县| 肃南| 清河县| 左贡县| 长春市| 定襄县| 岑巩县| 启东市| 石台县| 龙江县| 昭觉县| 青海省| 连城县| 荥阳市| 保靖县| 英德市| 鄂尔多斯市| 内乡县| 万荣县|