欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-18 20:44:04
前言 这是在实际开发项目中遇到的一个问题。从数据库查询返回的 List\ 的集合。并且返回的列名是中文的,项目也没有使用mybatis 直接使用的jdbcTemplate. 并且字段还超级多,这样将数据转换的时候如果一个一个的注入就会让代码臭长臭长的,所以才有了动态注入。 我这里我整个思路都贴出来。 ......

前言

这是在实际开发项目中遇到的一个问题。从数据库查询返回的 list< map< string, object>> 的集合。并且返回的列名是中文的,项目也没有使用mybatis 直接使用的jdbctemplate. 并且字段还超级多,这样将数据转换的时候如果一个一个的注入就会让代码臭长臭长的,所以才有了动态注入。
我这里我整个思路都贴出来。

实例类entry

我们先建一个entry类。用于对象存储。
我这里 创建一个basedatebean 的类

@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了。

创建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 方法就是给这个属性赋值的。
# 实现方法
现在准备工作做好了,怎么使用呢?
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,动态的将属性值注入到实体类中。

# 番外
我这里是适合我业务开发设计的思路,给大家借鉴参考。

欢迎大家关注个人公众号 "程序员爱酸奶"

分享各种学习资料,包含java,linux,大数据等。资料包含视频文档以及源码,同时分享本人及投递的优质技术博文。

如果大家喜欢记得关注和分享哟❤
如何优雅实现属性的动态注入