如何优雅实现属性的动态注入

前言

这是在实际开发项目中遇到的一个问题。从数据库查询返回的 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

相关文章
相关标签/搜索