設計模式-責任鏈模式在實際項目中的使用

来源:https://www.cnblogs.com/clovejava/archive/2018/07/14/9311142.html
-Advertisement-
Play Games

最近一次迭代,參與了公司數據應用平臺的開發,其中負責的一塊功能早早的就完成了代碼的編寫工作,即將進入測試階段,因為有時間思考和總結代碼編寫中遇到的難題,便想著將代碼做一次重構:其中優化的一個功能就是關於數據平臺敏感欄位的收集 功能描述:數據平臺敏感欄位的收集: 開始的版本: 可以看出邏輯都散落在fo ...


  最近一次迭代,參與了公司數據應用平臺的開發,其中負責的一塊功能早早的就完成了代碼的編寫工作,即將進入測試階段,因為有時間思考和總結代碼編寫中遇到的難題,便想著將代碼做一次重構:其中優化的一個功能就是關於數據平臺敏感欄位的收集

功能描述:數據平臺敏感欄位的收集:

提供 service 方法,查詢是否需要掃描表做觸髮式收集,指定具體實例與庫的表,隨機取 N 行(1~max(id) 之間);
a.對每一行的每一個欄位的值(取非 null 非空的值)做正則匹配
b. 對每一行的每一個欄位的值看是否包含了敏感欄位的 key
c. 對每一行的每一個欄位名做匹配;如果匹配,再判斷該欄位為敏感欄位還是疑似敏感欄位,添加到 secret_column 中

開始的版本:

/**
     * 敏感欄位的收集
     *
     * @param instance
     * @param schema
     */
    public void collectSecretColumn(String instance, String schema, String table) {
        //查詢該表是否掃描過
        CollectedTable collectedTable = collectedTableService.getCollectedTable(instance, schema, table);
        if (collectedTable != null) {
            return;
        }

        //隨機獲取n行記錄
        JdbcResult query = getPartQueryResult(instance, schema, table);
        if (query == null || (query != null && StringUtils.isNotBlank(query.getQueryErrorMsg()))) {
            throw new CjjServerException(500, "系統繁忙,請稍後再試");
        }
        //key為column value為值的集合
        Map<String, List<String>> groupMap = convertListToMap(query.getResult());
        Set<Map.Entry<String, List<String>>> entries = groupMap.entrySet();
        List<SecretContainedKey> secretContainedKeys = secretContainedKeyMapper.listSecretContainedKeys();
        List<SecretValueRegex> secretValueRegexs = secretValueRegexService.getSecretValueRegexes();

        for (Map.Entry<String, List<String>> entry : entries) {
            //獲取column
            String column = entry.getKey();
            List<String> values = entry.getValue();
            //判斷該欄位是否已經存在在敏感欄位表中
            boolean secretColumnExist = isSecretColumnExist(instance, schema, table, column);
            if (secretColumnExist) {
                continue;
            }

            //c:對欄位名做匹配
            boolean isValueContaninsKey = secretContainedKeyService.columnKeyIsContainsKey(instance, schema, table, secretContainedKeys, column);
            if (isValueContaninsKey) {
                continue;
            }

            //b:欄位的值是否包含敏感欄位的key
            boolean isContainsKey = secretContainedKeyService.columnValueIsContainsKey(instance, schema, table, secretContainedKeys, column, values);
            if (isContainsKey) {
                continue;
            }

            //a:通過正則匹配欄位值
            secretValueRegexService.regexMatch(instance, schema, table, column, values, secretValueRegexs);

        }
        CollectedTable collected = CollectedTable
                .builder()
                .instanceName(instance)
                .schemaName(schema)
                .tableName(table)
                .build();
        collectedTableMapper.save(collected);

    }

  

可以看出邏輯都散落在for迴圈中

通過責任鏈模式:後代碼:

 /**
     * 敏感欄位的收集
     *
     * @param instance
     * @param schema
     */
    public void collectSecretColumn(String instance, String schema, String table) {
        //查詢該表是否掃描過
        CollectedTable collectedTable = collectedTableService.getCollectedTable(instance, schema, table);
        if (collectedTable != null) {
            return;
        }

        //隨機獲取n行記錄
        JdbcResult query = getPartQueryResult(instance, schema, table);
        if (query == null || (query != null && StringUtils.isNotBlank(query.getQueryErrorMsg()))) {
            throw new CjjServerException(500, "系統繁忙,請稍後再試");
        }
        //key為column value為值的集合
        Map<String, List<String>> groupMap = convertListToMap(query.getResult());
        Set<Map.Entry<String, List<String>>> entries = groupMap.entrySet();
        secretValueRegexHandler.setSuccessor(secretValueContainedKeyHandler);
        secretValueContainedKeyHandler.setSuccessor(secretColumnContainedKeyHandler);
        for (Map.Entry<String, List<String>> entry : entries) {
            //獲取column
            String column = entry.getKey();
            List<String> values = entry.getValue();
            //判斷該欄位是否已經存在在敏感欄位表中
            boolean secretColumnExist = isSecretColumnExist(instance, schema, table, column);
            if (secretColumnExist) {
                continue;
            }
            secretValueRegexHandler.handleCollect(instance, schema, table, column, values);
        }
        CollectedTable collected = CollectedTable
                .builder()
                .instanceName(instance)
                .schemaName(schema)
                .tableName(table)
                .build();
        collectedTableMapper.save(collected);

    }

  可以看出這邊的代碼量減少了,看起來結構更清晰了

為了方便理解:我會列出部分代碼供大家參考

package cn.caijiajia.firekylin.service.secret;

import java.util.List;

/**
 * 責任鏈設計模式
 *
 * @author chenlang
 * date 2018/7/13
 */
public abstract class CollectSecretColumnHandler {

    protected CollectSecretColumnHandler successor;

    public abstract void handleCollect(String instance, String schema, String table, String column, List<String> values);

    /**
     * 獲取責任對象
     */
    public CollectSecretColumnHandler getSuccessor() {
        return successor;
    }

    /**
     * 設置後繼的責任對象
     */
    public void setSuccessor(CollectSecretColumnHandler successor) {
        this.successor = successor;
    }

}

  

package cn.caijiajia.firekylin.service.secret;

import cn.caijiajia.firekylin.domain.SecretContainedKey;
import cn.caijiajia.firekylin.mapper.SecretContainedKeyMapper;
import cn.caijiajia.firekylin.service.SecretColumnService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author chenlang
 * date 2018/7/13
 */
@Component
public class SecretColumnContainedKeyHandler extends CollectSecretColumnHandler {
    @Autowired
    private SecretColumnService secretColumnService;
    @Autowired
    private SecretContainedKeyMapper secretContainedKeyMapper;

    @Override
    public void handleCollect(String instance, String schema, String table, String column, List<String> values) {
        List<SecretContainedKey> secretContainedKeys = secretContainedKeyMapper.listSecretContainedKeys();
        boolean columnKeyIsContainsKey = columnKeyIsContainsKey(instance, schema, table, secretContainedKeys, column);
        if (!columnKeyIsContainsKey) {

        }

    }

    public boolean columnKeyIsContainsKey(String instance, String schema, String table, List<SecretContainedKey> secretContainedKeys, String column) {
        SecretContainedKey secretContainedKeyByColumn = getSecretContainedKeyByColumn(column, secretContainedKeys);
        if (secretContainedKeyByColumn != null) {
            secretColumnService.saveSecretColumn(instance, schema, table, column, secretContainedKeyByColumn.getSecretType(), secretContainedKeyByColumn.getColumnType());
            return true;
        }
        return false;
    }

    /**
     * 欄位名是否包含敏感的key
     *
     * @param column
     * @param secretContainedKeys
     * @return
     */
    public SecretContainedKey getSecretContainedKeyByColumn(String column, List<SecretContainedKey> secretContainedKeys) {
        Map<String, SecretContainedKey> keysMap = secretContainedKeys.stream().collect(Collectors.toMap(SecretContainedKey::getContainedKey, a -> a));
        Set<Map.Entry<String, SecretContainedKey>> entries = keysMap.entrySet();
        for (Map.Entry<String, SecretContainedKey> entry : entries) {
            String key = entry.getKey();
            boolean contains = column.toLowerCase().contains(key);
            if (contains) {
                return keysMap.get(key);
            }
        }
        return null;
    }
}

  

package cn.caijiajia.firekylin.service.secret;

import cn.caijiajia.firekylin.domain.SecretContainedKey;
import cn.caijiajia.firekylin.mapper.SecretContainedKeyMapper;
import cn.caijiajia.firekylin.service.SecretColumnService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author chenlang
 * date 2018/7/13
 */
@Component
public class SecretValueContainedKeyHandler extends CollectSecretColumnHandler {
    @Autowired
    private SecretColumnService secretColumnService;
    @Autowired
    private SecretContainedKeyMapper secretContainedKeyMapper;

    @Override
    public void handleCollect(String instance, String schema, String table, String column, List<String> values) {
        List<SecretContainedKey> secretContainedKeys = secretContainedKeyMapper.listSecretContainedKeys();

        boolean columnValueIsContainsKey = columnValueIsContainsKey(instance, schema, table, secretContainedKeys, column, values);
        if (!columnValueIsContainsKey) {
            getSuccessor().handleCollect(instance, schema, table, column, values);
        }


    }

    public boolean columnValueIsContainsKey(String instance, String schema, String table, List<SecretContainedKey> secretContainedKeys, String column, List<String> values) {
        for (SecretContainedKey secretContainedKey : secretContainedKeys) {
            boolean isSecretColumnContainsKey = isSecretColumnContainsKey(values, secretContainedKey);
            if (isSecretColumnContainsKey) {
                secretColumnService.saveSecretColumn(instance, schema, table, column, secretContainedKey.getSecretType(), secretContainedKey.getColumnType());
                return true;
            }
        }
        return false;
    }

    /**
     * 欄位值是否包含敏感欄位的key
     *
     * @param columnValues
     * @param secretContainedKey
     * @return
     */
    public boolean isSecretColumnContainsKey(List<String> columnValues, SecretContainedKey secretContainedKey) {
        for (String columnValue : columnValues) {
            if (columnValue.toLowerCase().contains(secretContainedKey.getContainedKey())) {
                return true;
            }
        }
        return false;
    }
}

  

package cn.caijiajia.firekylin.service.secret;

import cn.caijiajia.firekylin.constant.SecretType;
import cn.caijiajia.firekylin.domain.SecretValueRegex;
import cn.caijiajia.firekylin.service.SecretColumnService;
import cn.caijiajia.firekylin.service.SecretValueRegexService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.regex.Pattern;

/**
 * 正則匹配收集敏感欄位
 *
 * @author chenlang
 * date 2018/7/13
 */
@Component
public class SecretValueRegexHandler extends CollectSecretColumnHandler {
    @Autowired
    private SecretColumnService secretColumnService;
    @Autowired
    private SecretValueRegexService secretValueRegexService;


    @Override
    public void handleCollect(String instance, String schema, String table, String column, List<String> values) {
        List<SecretValueRegex> secretValueRegexs = secretValueRegexService.getSecretValueRegexes();
        boolean regexMatch = regexMatch(instance, schema, table, column, values, secretValueRegexs);
        if (!regexMatch) {
            if (getSuccessor() != null) {
                getSuccessor().handleCollect(instance, schema, table, column, values);
            }
        }


    }


    public boolean regexMatch(String instance, String schema, String table, String column, List<String> values, List<SecretValueRegex> secretValueRegexs) {
        for (SecretValueRegex secretValueRegex : secretValueRegexs) {
            boolean secretByRegex = isSecretByRegex(values, secretValueRegex.getPattern());
            if (secretByRegex) {
                secretColumnService.saveSecretColumn(instance, schema, table, column, SecretType.SECRECT, secretValueRegex.getCode());
                return true;
            }
        }
        return false;
    }

    /**
     * 欄位值是否匹配正則表達式
     *
     * @param columnValues
     * @return
     */
    public boolean isSecretByRegex(List<String> columnValues, Pattern compile) {
        if (CollectionUtils.isEmpty(columnValues)) {
            return false;
        }
        for (String columnValue : columnValues) {
            boolean isSecret = compile.matcher(columnValue).matches();
            if (!isSecret) {
                return false;
            }
        }
        return true;
    }
}

  

現在每種情況對應一種handler,同時繼承自

CollectSecretColumnHandler

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 剛開始接觸這個概念的時候真的是完全不夠理解什麼叫做面向對象,即使到了現在人就是不能夠完全可以說明白。 程式員之路的設計理念分為:面向過程和麵向對象; 面向過程:要想得到一個結果需要一步一步的去設計出來,一步一步的敲代碼去實現這是一個過程。 比如說要比較兩個數的大小有以下程式: int a=3; in ...
  • 一,五大核心組件 1.DispatcherServlet 請求入口 2.HandlerMapping 請求派發,負責請求和控制器建立一一對應的關係 3.Controller 處理器 4.ModelAndView 封裝模型信息和視圖信息 5.ViewResolver 視圖處理器,定位頁面 二,Spri ...
  • JavaDay04總結 1、實現介面VS繼承類 : 1. 實現介面是繼承的補充 2. 實現介面可以在不打破繼承關係的前提下,對某個功能擴展 2、綁定 : 1. 前期綁定:在程式運行前進行綁定,由編譯器和連接程式實現,又叫靜態綁定 2. 後期綁定:在運行時根據對象的類型進行綁定,由方法調用機制實現,又 ...
  • 跟昨天那個自己寫的,沒有按照模板來的一看風格就不相類似,今天模擬賽的時候就是用的我的那個自己YY的代碼,才拿了10分。個人認為關鍵的問題應該在於對於數據的處理太過繁瑣了,所以回來之後,就拿了大佬的程式對照著改。在這裡不得不吐槽一下c++的讀入,cin40分,scanf滿分。還是模板的線段樹比較清晰, ...
  • 在Spring中通過註解@EnableScheduling 來開啟對計劃任務的支持,然後再執行集合任務的方法上註解@Scheduled,聲明這是一個計劃任務。 ...
  • 轉載請註明出處:https://www.cnblogs.com/funnyzpc/p/9190233.html 先來一段詩 ``` 就這樣吧 忍受折磨 然後,躺進醫院 然後,死去 化作一抔土 從此,這世界沒有煩惱 沒有病痛 沒有我 也沒有這個世界 ``` 以上是在半睡半醒中想到的,寫的不好,讀者可直 ...
  • 主要使用後端驗證,調用awt API ,會簡單調用即可,繪圖代碼已封裝到LoginVerifyUtils中。 界面展示: LoginVerifyUtils全部代碼 1 import java.awt.Color; 2 import java.awt.Font; 3 import java.awt.G ...
  • 本周大部分的時間都用在了使用JAVA語言進行編程之前的準備工作上,主要包括:JDK的安裝以及環境變數的配置,MyEclipse軟體的安裝以及熟悉界面。 下麵將詳細的介紹本周的收穫。 首先解決了第一個問題使用JAVA語言為什麼需要安裝JDK:JDK是 Java 語言的軟體開發工具包,主要用於移動設備、 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...