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