亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot項(xiàng)目中新增脫敏功能的實(shí)例代碼

 更新時(shí)間:2022年11月30日 16:10:47   作者:來瓶小白干Oo  
項(xiàng)目中,由于使用端有兩個(gè),對于兩個(gè)端的數(shù)據(jù)權(quán)限并不一樣。Web端可以查看所有數(shù)據(jù),小程序端只能查看脫敏后的數(shù)據(jù),這篇文章主要介紹了SpringBoot項(xiàng)目中新增脫敏功能,需要的朋友可以參考下

SpringBoot項(xiàng)目中新增脫敏功能

項(xiàng)目背景

目前正在開發(fā)一個(gè)SpringBoot項(xiàng)目,此項(xiàng)目有Web端和微信小程序端。web端提供給工作人員使用,微信小程序提供給群眾進(jìn)行預(yù)約操作。項(xiàng)目中有部分敏感數(shù)據(jù)需要脫敏傳遞給微信小程序,給與群眾查看。

項(xiàng)目需求描述

項(xiàng)目中,由于使用端有兩個(gè),對于兩個(gè)端的數(shù)據(jù)權(quán)限并不一樣。Web端可以查看所有數(shù)據(jù),小程序端只能查看脫敏后的數(shù)據(jù)。

需要開發(fā)一個(gè)通用脫敏功能

  • 手動進(jìn)行脫敏操作
  • 支持多種對象,
  • 支持不同字段,并脫敏指定字段
  • 字段的脫敏方式多樣
  • 字段的脫敏方式可自定義

項(xiàng)目解決方案

1. 解決方案

使用注解方式,來支持對指定字段,不同字段,多種脫敏操作,并可以脫離對象。
使用工具對象,通過泛型傳參,來支持對不同對象的脫敏操作。

2. 實(shí)現(xiàn)代碼

2.1 注解 Sensitive

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定義數(shù)據(jù)脫敏
 *
 * 例如: 身份證,手機(jī)號等信息進(jìn)行模糊處理
 *
 * @author lzddddd
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sensitive {

    /**
     * 脫敏數(shù)據(jù)類型
     */
    SensitiveType type() default SensitiveType.CUSTOMER;

    /**
     * 前置不需要打碼的長度
     */
    int prefixNoMaskLen() default 0;

    /**
     * 后置不需要打碼的長度
     */
    int suffixNoMaskLen() default 0;

    /**
     * 用什么打碼
     */
    String symbol() default "*";

}

2.1 脫敏類型枚舉 SensitiveType

public enum SensitiveType {

    /**
     * 自定義
     */
    CUSTOMER,
    /**
     * 名稱
     **/
    CHINESE_NAME,
    /**
     * 身份證證件號
     **/
    ID_CARD_NUM,
    /**
     * 手機(jī)號
     **/
    MOBILE_PHONE,
    /**
     * 固定電話
     */
    FIXED_PHONE,
    /**
     * 密碼
     **/
    PASSWORD,
    /**
     * 銀行卡號
     */
    BANKCARD,
    /**
     * 郵箱
     */
    EMAIL,
    /**
     * 地址
     */
    ADDRESS,

}

2.3 脫敏工具 DesensitizedUtils

import com.ruoyi.common.annotation.Sensitive;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.SensitiveType;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.*;

@Slf4j
public class DesensitizedUtils<T> {

    /**
     * 脫敏數(shù)據(jù)列表
     */
    private List<T> list;

    /**
     * 注解列表
     */
    private List<Object[]> fields;

    /**
     * 實(shí)體對象
     */
    public Class<T> clazz;


    public DesensitizedUtils(Class<T> clazz)
    {
        this.clazz = clazz;
    }

    /**
     * 初始化數(shù)據(jù)
     *
     * @param list 需要處理數(shù)據(jù)
     */
    public void init(List<T> list){
        if (list == null)
        {
            list = new ArrayList<T>();
        }
        this.list = list;

        // 得到所有定義字段
        createSensitiveField();
    }

    /**
     * 初始化數(shù)據(jù)
     *
     * @param t 需要處理數(shù)據(jù)
     */
    public void init(T t){

        list = new ArrayList<T>();

        if (t != null)
        {
         list.add(t);
        }

        // 得到所有定義字段
        createSensitiveField();
    }

    /**
     * 得到所有定義字段
     */
    private void createSensitiveField()
    {
        this.fields = new ArrayList<Object[]>();
        List<Field> tempFields = new ArrayList<>();
        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        for (Field field : tempFields)
        {
            // 單注解
            if (field.isAnnotationPresent(Sensitive.class))
            {
                putToField(field, field.getAnnotation(Sensitive.class));
            }

            // 多注解
//            if (field.isAnnotationPresent(Excels.class))
//            {
//                Excels attrs = field.getAnnotation(Excels.class);
//                Excel[] excels = attrs.value();
//                for (Excel excel : excels)
//                {
//                    putToField(field, excel);
//                }
//            }
        }
    }

    /**
     * 對list數(shù)據(jù)源將其里面的數(shù)據(jù)進(jìn)行脫敏處理
     *
     * @param list
     * @return 結(jié)果
     */
    public AjaxResult desensitizedList(List<T> list){

        if (list == null){
            return AjaxResult.error("脫敏數(shù)據(jù)為空");
        }

        // 初始化數(shù)據(jù)
        this.init(list);

        int failTimes = 0;

        for (T t: this.list) {
            if ((Integer)desensitization(t).get("code") != HttpStatus.SUCCESS){
                failTimes++;
            }
        }

        if (failTimes >0){
            return AjaxResult.error("脫敏操作中出現(xiàn)失敗",failTimes);
        }

        return AjaxResult.success();
    }

    /**
     * 放到字段集合中
     */
    private void putToField(Field field, Sensitive attr)
    {
        if (attr != null)
        {
            this.fields.add(new Object[] { field, attr });
        }
    }

    /**
     * 脫敏:JavaBean模式脫敏
     *
     * @param t 需要脫敏的對象
     * @return
     */
    public AjaxResult desensitization(T t) {
        if (t == null){
            return AjaxResult.error("脫敏數(shù)據(jù)為空");
        }

        // 初始化數(shù)據(jù)
        init(t);

        try {
            // 遍歷處理需要進(jìn)行 脫敏的字段
            for (Object[] os : fields)
            {
                Field field = (Field) os[0];
                Sensitive sensitive = (Sensitive) os[1];
                // 設(shè)置實(shí)體類私有屬性可訪問
                field.setAccessible(true);
                desensitizeField(sensitive,t,field);
            }
            return AjaxResult.success(t);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("日志脫敏處理失敗,回滾,詳細(xì)信息:[{}]", e);
            return AjaxResult.error("脫敏處理失敗",e);
        }
    }

    /**
     * 對類的屬性進(jìn)行脫敏
     *
     * @param attr 脫敏參數(shù)
     * @param vo 脫敏對象
     * @param field 脫敏屬性
     * @return
     */
    private void desensitizeField(Sensitive attr, T vo, Field field) throws IllegalAccessException {

        if (attr == null || vo == null || field == null){
            return ;
        }

        // 讀取對象中的屬性
        Object value = field.get(vo);
        SensitiveType sensitiveType = attr.type();
        int prefixNoMaskLen = attr.prefixNoMaskLen();
        int suffixNoMaskLen = attr.suffixNoMaskLen();
        String symbol = attr.symbol();

        //獲取屬性后現(xiàn)在默認(rèn)處理的是String類型,其他類型數(shù)據(jù)可擴(kuò)展
        Object val = convertByType(sensitiveType, value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        field.set(vo, val);
    }

    /**
     * 以類的屬性的get方法方法形式獲取值
     *
     * @param o 對象
     * @param name 屬性名
     * @return value
     * @throws Exception
     */
    private Object getValue(Object o, String name) throws Exception
    {
        if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name))
        {
            Class<?> clazz = o.getClass();
            Field field = clazz.getDeclaredField(name);
            field.setAccessible(true);
            o = field.get(o);
        }
        return o;
    }

    /**
     * 根據(jù)不同注解類型處理不同字段
     */
    private Object convertByType(SensitiveType sensitiveType, Object value, int prefixNoMaskLen, int suffixNoMaskLen, String symbol) {
        switch (sensitiveType) {
            case CUSTOMER:
                value = customer(value, prefixNoMaskLen, suffixNoMaskLen, symbol);
                break;
            case CHINESE_NAME:
                value = chineseName(value, symbol);
                break;
            case ID_CARD_NUM:
                value = idCardNum(value, symbol);
                break;
            case MOBILE_PHONE:
                value = mobilePhone(value, symbol);
                break;
            case FIXED_PHONE:
                value = fixedPhone(value, symbol);
                break;
            case PASSWORD:
                value = password(value, symbol);
                break;
            case BANKCARD:
                value = bankCard(value, symbol);
                break;
            case EMAIL:
                value = email(value, symbol);
                break;
            case ADDRESS:
                value = address(value, symbol);
                break;
        }
        return value;
    }

    /*--------------------------下面的脫敏工具類也可以單獨(dú)對某一個(gè)字段進(jìn)行使用-------------------------*/

    /**
     * 【自定義】 根據(jù)設(shè)置進(jìn)行配置
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return 脫敏后數(shù)據(jù)
     */
    public Object customer(Object value, int prefixNoMaskLen, int suffixNoMaskLen, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }

        return value;
    }

    /**
     * 對字符串進(jìn)行脫敏處理
     *
     * @param s 需處理數(shù)據(jù)
     * @param prefixNoMaskLen 開頭展示字符長度
     * @param suffixNoMaskLen 結(jié)尾展示字符長度
     * @param symbol 填充字符
     * @return
     */
    private String handleString(String s, int prefixNoMaskLen, int suffixNoMaskLen, String symbol){
        // 是否為空
        if (StringUtils.isBlank(s)) {
            return "";
        }

        // 如果設(shè)置為空之類使用 * 代替
        if (StringUtils.isBlank(symbol)){
            symbol = "*";
        }

        // 對長度進(jìn)行判斷
        int length = s.length();
        if (length > prefixNoMaskLen + suffixNoMaskLen){
            String namePrefix = StringUtils.left(s, prefixNoMaskLen);
            String nameSuffix = StringUtils.right(s, suffixNoMaskLen);
            s = StringUtils.rightPad(namePrefix, StringUtils.length(s) - suffixNoMaskLen, symbol).concat(nameSuffix);
        }

        return s;
    }

    /**
     * 【中文姓名】只顯示第一個(gè)漢字,其他隱藏為2個(gè)星號,比如:李**
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return 脫敏后數(shù)據(jù)
     */
    public String chineseName(Object value, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 開頭只展示一個(gè)字符
            int prefixNoMaskLen = 1;
            int suffixNoMaskLen = 0;

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";
    }

    /**
     * 【身份證號】顯示最后四位,其他隱藏。共計(jì)18位或者15位,比如:*************1234
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return 脫敏后數(shù)據(jù)
     */
    public String idCardNum(Object value, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 結(jié)尾只展示四個(gè)字符
            int prefixNoMaskLen = 0;
            int suffixNoMaskLen = 4;

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";
    }

    /**
     * 【固定電話】 顯示后四位,其他隱藏,比如:*******3241
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return 脫敏后數(shù)據(jù)
     */
    public String fixedPhone(Object value, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 結(jié)尾只展示四個(gè)字符
            int prefixNoMaskLen = 0;
            int suffixNoMaskLen = 4;

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";

    }

    /**
     * 【手機(jī)號碼】前三位,后四位,其他隱藏,比如:135****6810
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return 脫敏后數(shù)據(jù)
     */
    public String mobilePhone(Object value, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 開頭只展示三個(gè)字符  結(jié)尾只展示四個(gè)字符
            int prefixNoMaskLen = 3;
            int suffixNoMaskLen = 4;

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";
    }

    /**
     * 【地址】只顯示到地區(qū),不顯示詳細(xì)地址,比如:湖南省長沙市岳麓區(qū)***
     *  只能處理 省市區(qū)的數(shù)據(jù)
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return
     */
    public String address(Object value, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 開頭只展示九個(gè)字符
            int prefixNoMaskLen = 9;
            int suffixNoMaskLen = 0;

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";
    }

    /**
     * 【電子郵箱】 郵箱前綴僅顯示第一個(gè)字母,前綴其他隱藏,用星號代替,@及后面的地址顯示,比如:d**@126.com
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return 脫敏后數(shù)據(jù)
     */
    public String email(Object value, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 開頭只展示一個(gè)字符  結(jié)尾只展示@及后面的地址
            int prefixNoMaskLen = 1;
            int suffixNoMaskLen = 4;

            String s = (String) value;
            if (StringUtils.isBlank(s)) {
                return "";
            }

            // 獲取最后一個(gè)@
            int lastIndex = StringUtils.lastIndexOf(s, "@");
            if (lastIndex <= 1) {
                return s;
            } else {
                suffixNoMaskLen = s.length() - lastIndex;
            }

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";

    }

    /**
     * 【銀行卡號】前六位,后四位,其他用星號隱藏每位1個(gè)星號,比如:6222600**********1234
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return 脫敏后數(shù)據(jù)
     */
    public String bankCard(Object value, String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 開頭只展示六個(gè)字符  結(jié)尾只展示四個(gè)字符
            int prefixNoMaskLen = 6;
            int suffixNoMaskLen = 4;

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";

    }

    /**
     * 【密碼】密碼的全部字符都用*代替,比如:******
     *
     * @param value 需處理數(shù)據(jù)
     * @param symbol 填充字符
     * @return
     */
    public String password(Object value,String symbol) {

        //針對字符串的處理
        if (value instanceof String){
            // 對前后長度進(jìn)行設(shè)置 默認(rèn) 開頭只展示六個(gè)字符  結(jié)尾只展示四個(gè)字符
            int prefixNoMaskLen = 0;
            int suffixNoMaskLen = 0;

            return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol);
        }
        return "";
    }
}

3 使用實(shí)例

3.1 需注解對象

public class User {
    private static final long serialVersionUID = 1L;

    /** 普通用戶ID */
    private Long userId;

    /** 昵稱 */
    @Sensitive(type = SensitiveType.CUSTOMER,prefixNoMaskLen = 2,suffixNoMaskLen = 1)
    private String nickName;

    /** 姓名 */
    @Sensitive(type = SensitiveType.CHINESE_NAME)
    private String userName;

    /** 身份證 */
    @Sensitive(type = SensitiveType.ID_CARD_NUM)
    private String identityCard;

    /** 手機(jī)號碼 */
    @Sensitive(type = SensitiveType.MOBILE_PHONE)
    private String phoneNumber;
}

3.2 脫敏操作

		// 脫敏對象
		User user = new User();
		......
        DesensitizedUtils<User> desensitizedUtils = new DesensitizedUtils<>(User.class);
        desensitizedUtils.desensitization(user);

		//脫敏隊(duì)列
		List<User> users = new ArrayList<>();
		......
        DesensitizedUtils<User> desensitizedUtils = new DesensitizedUtils<>(User.class);
        desensitizedUtils.desensitizedList(users);

到此這篇關(guān)于SpringBoot項(xiàng)目中新增脫敏功能的文章就介紹到這了,更多相關(guān)SpringBoot脫敏內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java零基礎(chǔ)教程之Windows下安裝 JDK的方法圖解

    Java零基礎(chǔ)教程之Windows下安裝 JDK的方法圖解

    這篇文章主要介紹了Java零基礎(chǔ)教程之Windows下安裝 JDK的方法圖解,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-09-09
  • WebSocket簡介與消息推送

    WebSocket簡介與消息推送

    這篇文章介紹了WebSocket簡介與消息推送,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • Java中的跨域和@CrossOrigin注解的作用詳解

    Java中的跨域和@CrossOrigin注解的作用詳解

    這篇文章主要介紹了Java中的跨域和@CrossOrigin注解的作用詳解,跨域,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript施加的安全限制,需要的朋友可以參考下
    2023-12-12
  • Java代理模式的示例詳解

    Java代理模式的示例詳解

    代理模式(Proxy?Parttern)為一個(gè)對象提供一個(gè)替身,來控制這個(gè)對象的訪問,即通過代理對象來訪問目標(biāo)對象。本文將通過示例詳細(xì)講解一下這個(gè)模式,需要的可以參考一下
    2022-08-08
  • 詳談Spring框架之事務(wù)管理

    詳談Spring框架之事務(wù)管理

    下面小編就為大家?guī)硪黄斦凷pring框架之事務(wù)管理。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • Struts1簡介和入門_動力節(jié)點(diǎn)Java學(xué)院整理

    Struts1簡介和入門_動力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了Struts1簡介和入門的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • spring security自定義決策管理器

    spring security自定義決策管理器

    這篇文章主要介紹了spring security自定義決策管理器的實(shí)現(xiàn)代碼,需要的朋友參考下吧
    2017-09-09
  • springboot+maven多環(huán)境動態(tài)配置及編譯失敗的解決方案(步驟詳解)

    springboot+maven多環(huán)境動態(tài)配置及編譯失敗的解決方案(步驟詳解)

    這篇文章主要介紹了springboot+maven多環(huán)境動態(tài)配置及編譯失敗的解決方案,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11
  • Java鏈表中添加元素的原理與實(shí)現(xiàn)方法詳解

    Java鏈表中添加元素的原理與實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Java鏈表中添加元素的原理與實(shí)現(xiàn)方法,結(jié)合實(shí)例形式詳細(xì)分析了Java實(shí)現(xiàn)鏈表中添加元素的相關(guān)原理、操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2020-03-03
  • 聊聊Spring data jpa @query使用原生SQl,需要注意的坑

    聊聊Spring data jpa @query使用原生SQl,需要注意的坑

    這篇文章主要介紹了Spring data jpa@query使用原生SQl,需要注意的坑,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08

最新評論