如何優雅實現屬性的動態注入

前言

這是在實際開發項目中遇到的一個問題。從數據庫查詢返回的 List< Map< String, Object>> 的集合。而且返回的列名是中文的,項目也沒有使用mybatis 直接使用的jdbcTemplate. 而且字段還超級多,這樣將數據轉換的時候若是一個一個的注入就會讓代碼臭長臭長的,因此纔有了動態注入。我這裏我整個思路都貼出來。java

實例類Entry

咱們先建一個entry類。用於對象存儲。我這裏 建立一個BaseDateBean 的類linux

@Setter
@Getter
public class BaseDateBean {

    private String  startTime;
    private String  operator;
    private String  code;
    private String  testNumber;
    private String  iphoneCardCode;
    private String  sampleNumber;
    private String  sampleTime;
    private String  callNumber;
    private String  callStatus;
    private String  downInstantaneousSpeedCard;
    private String  upInstantaneousSpeedCard;
    private String  ssid;
    private String  bssid;
    private String  encryptType;
    private String  intranetIp;
    private String  externalIp;
    private String  rssi;
    private String  WIFIFrequency;
    private String  WIFIChannel;
    private String  baiduLongitude;
    private String  baiduLatitude;
    private String  originalLongitude;
    private String  originalLatitude;
    private String  positioningPrecision;
    private String  positioningType;
    private String  businessType;
    private String  networkType;
    private String  speedType;
    private String  tac;
    private String  eci;
    private String  mnc;
    private String  mcc;
    private String  rsrq;
    private String  earfcnDl;
    private String  earfcnUl;
    private String  frequencyDl;
    private String  band;
    private String  sinr;
    private String  cdmaRxlev;
    private String  evdoRxlev;
    private String  earfcn;
    private String  psc;
    private String  uarfcn;
    private String  rscp;
    private String  rsrp;
    private String  imsi;
    private String  imei;
    private String  lac;
    private String  ci;
    private String  signalStrength;
    private String  snr;
    private String  pci;
    private String  nid;
    private String  bid;
    private String  sid;
    private String  cdmaDbm;
    private String  cdmaEcio;
    private String  evdoDbm;
    private String  evdoEcio;
    private String  evdoSnr;
    private String  arfcn;
    private String  frequencyUl;
    private String  bsic;
    private String  rxlev;
    private String  averageSpeed;
    private String  updatedLongitude;
    private String  updatedLatitude;
    private String  averageUpstreamRate;
    private String  averageDownstreamRate;
}複製代碼

能夠看到在實際項目中屬性仍是不少的,我這個還只是第一版的,因此若是一個一個的set注入就很low了。git

建立map映射

在建立好實體類後,還得建立一個靜態的map 集合,將數據庫的列名和咱們實體類的屬性名作一個一一對應。這裏建立的這個map 集合是我我的愚見。沒有想到更好的辦法就先這樣處理的。咱們建立一個BaseDataMap類程序員

public  class BaseDataMap{
    private BaseDataMap(){}
    public static final Map<String,String> cnEnMap=new HashMap<>();
    static{
        cnEnMap.put("測試開始時間","startTime");
        cnEnMap.put("運營商","operator");
        cnEnMap.put("編號","code");
        cnEnMap.put("測試編號","testNumber");
        cnEnMap.put("手機卡編號","iphoneCardCode");
        cnEnMap.put("採樣編號","sampleNumber");
        cnEnMap.put("採樣時間","sampleTime");
        cnEnMap.put("呼叫編號","callNumber");
        cnEnMap.put("呼叫狀態","callStatus");
        cnEnMap.put("下行瞬時速度","downInstantaneousSpeedCard");
        cnEnMap.put("上行瞬時速度","upInstantaneousSpeedCard");
        cnEnMap.put("SSID","ssid");
        cnEnMap.put("BSSID","bssid");
        cnEnMap.put("加密類型","encryptType");
        cnEnMap.put("內網IP","intranetIp");
        cnEnMap.put("外網IP","externalIp");
        cnEnMap.put("RSSI","rssi");
        cnEnMap.put("WIFI頻率","WIFIFrequency");
        cnEnMap.put("WIFI信道","WIFIChannel");
        cnEnMap.put("百度經度","baiduLongitude");
        cnEnMap.put("百度緯度","baiduLatitude");
        cnEnMap.put("原始經度","originalLongitude");
        cnEnMap.put("原始緯度","originalLatitude");
        cnEnMap.put("定位精度","positioningPrecision");
        cnEnMap.put("定位類型","positioningType");
        cnEnMap.put("數據業務類型","businessType");
        cnEnMap.put("網絡類型","networkType");
        cnEnMap.put("速度類型","speedType");
        cnEnMap.put("TAC","tac");
        cnEnMap.put("ECI","eci");
        cnEnMap.put("MNC","mnc");
        cnEnMap.put("MCC","mcc");
        cnEnMap.put("RSRQ","rsrq");
        cnEnMap.put("EARFCN DL","earfcnDl");
        cnEnMap.put("EARFCN UL","earfcnUl");
        cnEnMap.put("FREQUENCY DL","frequencyDl");
        cnEnMap.put("BAND","band");
        cnEnMap.put("SINR","sinr");
        cnEnMap.put("CDMA RXLEV","cdmaRxlev");
        cnEnMap.put("EVDO RXLEV","evdoRxlev");
        cnEnMap.put("EARFCN","earfcn");
        cnEnMap.put("PSC","psc");
        cnEnMap.put("UARFCN","uarfcn");
        cnEnMap.put("RSCP","rscp");
        cnEnMap.put("RSRP","rsrp");
        cnEnMap.put("IMSI","imsi");
        cnEnMap.put("IMEI","imei");
        cnEnMap.put("LAC","lac");
        cnEnMap.put("CI","ci");
        cnEnMap.put("信號強度","signalStrength");
        cnEnMap.put("SNR","snr");
        cnEnMap.put("PCI","pci");
        cnEnMap.put("NID","nid");
        cnEnMap.put("BID","bid");
        cnEnMap.put("SID","sid");
        cnEnMap.put("CDMA DBM","cdmaDbm");
        cnEnMap.put("CDMA ECIO","cdmaEcio");
        cnEnMap.put("EVDO DBM","evdoDbm");
        cnEnMap.put("EVDO ECIO","evdoEcio");
        cnEnMap.put("EVDO SNR","evdoSnr");
        cnEnMap.put("ARFCN","arfcn");
        cnEnMap.put("FREQUENCY UL","frequencyUl");
        cnEnMap.put("BSIC","bsic");
        cnEnMap.put("RXLEV","rxlev");
        cnEnMap.put("速率","averageSpeed");
        cnEnMap.put("更正後經度","updatedLongitude");
        cnEnMap.put("更正後緯度","updatedLatitude");
        cnEnMap.put("上行平均速率","averageUpstreamRate");
        cnEnMap.put("下行平均速率","averageDownstreamRate");
    }
}複製代碼

能夠看到就是一個動態的map。正則表達式

映射類

接下來就是核心代碼啦。咱們建立一個ReflectHelper類數據庫

@Slf4j
public class ReflectHelper {

    private Class cls;
    /**
     * 傳過來的對象
     */
    private Object obj;
    private Hashtable<String, Method> getMethods = null;
    private Hashtable<String, Method> setMethods = null;
    public ReflectHelper(Object o) {
        obj = o;
        initMethods();
    }
    public void initMethods() {
        getMethods = new Hashtable<>();
        setMethods = new Hashtable<>();
        cls = obj.getClass();
        Method[] methods = cls.getMethods();
        // 定義正則表達式,從方法中過濾出getter / setter 函數.
        String gs = "get(\\w+)";
        Pattern getM = Pattern.compile(gs);
        String ss = "set(\\w+)";
        Pattern setM = Pattern.compile(ss);
        // 把方法中的"set" 或者 "get" 去掉,$1匹配第一個
        String rapl = "$1";
        String param;
        for (int i = 0; i < methods.length; ++i) {
            Method m = methods[i];
            String methodName = m.getName();
            if (Pattern.matches(gs, methodName)) {
                param = getM.matcher(methodName).replaceAll(rapl).toLowerCase();
                getMethods.put(param, m);
            } else if (Pattern.matches(ss, methodName)) {
                param = setM.matcher(methodName).replaceAll(rapl).toLowerCase();
                setMethods.put(param, m);
            }
        }
    }
    public boolean setMethodValue(String property,Object object) {
        Method m = setMethods.get(property.toLowerCase());
        if (m != null) {
            try {
                // 調用目標類的setter函數
                m.invoke(obj, object);
                return true;
            } catch (Exception ex) {
                ex.printStackTrace();
                return false;
            }
        }
        return false;
    }
}複製代碼

上面代碼能夠看到其實也就兩個方法setMethodValue 和initMethods 。initMethods 方法是在實例化 ReflectHelper 這個類的時候執行的,主要的工做就是找到咱們須要動態注入實例類的get 和set 方法。而setMethodValue 方法就是給這個屬性賦值的。網絡

實現方法

如今準備工做作好了,怎麼使用呢?mybatis

private List<BaseDateBean> getBaseDateBean(List<Map<String, Object>> mapList){
        List<BaseDateBean> list=new ArrayList<>();
        if(mapList==null||mapList.isEmpty()){
            return list;
        }
        BaseDateBean baseDateBean;
        for(Map<String, Object> map:mapList){
            baseDateBean=new BaseDateBean();
            for(Map.Entry<String, Object> entry : map.entrySet()){
                String mapKey = entry.getKey();
                log.info(mapKey);
                ReflectHelper reflectHelper = new ReflectHelper(baseDateBean);
                log.info(BaseDataMap.cnEnMap.get(mapKey));
                String value=entry.getValue()==null?ConstantPool.SEPARATORNULL:entry.getValue().toString();
                log.info(value);
                if(entry.getValue()!=null){
                    reflectHelper.setMethodValue(BaseDataMap.cnEnMap.get(mapKey),String.valueOf(entry.getValue()));
                }
            }
            list.add(baseDateBean);
        }
        return list;
    }複製代碼

遍歷list 集合中的map,動態的將屬性值注入到實體類中。iphone

番外

我這裏是適合我業務開發設計的思路,給你們借鑑參考。函數

歡迎你們關注我的公衆號 "程序員愛酸奶"

分享各類學習資料,包含java,linux,大數據等。資料包含視頻文檔以及源碼,同時分享本人及投遞的優質技術博文。

若是你們喜歡記得關注和分享喲❤file

相關文章
相關標籤/搜索