如何优雅实现属性的动态注入
前言
这是在实际开发项目中遇到的一个问题。从数据库查询返回的 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,大数据等。资料包含视频文档以及源码,同时分享本人及投递的优质技术博文。
如果大家喜欢记得关注和分享哟❤