背景:
(一)
前台所需的数据结构和后台sql查询的数据结构一般不一致,该情况就涉及到了数据结构的转换,往往很多接口的查询都是固定两种数据结构的转化,这个时候就可以把这种转化关系抽离成一个通用的方法,避免大量的重复代码
(二)
有时我们数据库中有很多原始数据列,每个数据列都是可以衍生出增速字段,增速=(今年数据-上一年数据)/上一年的数据,需求总是在变化的,你无法知道下一刻你需要增加的是那一个数据列的增速字段,然而增加增加增速数据列,会增加大量的冗余字段.
在通常情况下,增速是可以通过数据计算出来的,为此,我在(一)的基础上增加了动态增加增速字段,避免大量的冗余,需求的改变,也只需要通过简单的配置即可以完成,避免重复的开发工作
前台数据结构:
{
year:[2010,2011,2012],
column1:[value,value,value],
column2:[value,value,value],
column3:[value,value,value],
column1_speed:[value,value,value]
}
column1_spped:为动态增加的字段
后台数据结构:
id year column1 column2 column3
1 2010 value value value
2 2011 value value value
3 2012 value value value
4 2013 value value value
实现:
使用List<Map<String,Object>> 接收后台sql查询数据
select year,column1,column2,column3 from test where area_code = 110000 and year>=2010 and year <=2013
year 返回时不可重复
Set<String>去重列名集合作为参数
代码:
/**
* 转化数据结构返回给前端 ,该方法会少传最早的一年数据给前端
* @param results 原始数据结构
* @param addSpeedSet 用于动态增加增速字段的容器
* @return 新的数据结构{a:[],b:[]...}
*/
public Map<String, Object> transfDataStruct(List<Map<String, Object>> results,Set<String> addSpeedSet) {
//key:{static_year:value} 管理引用的容器
Map<String,Map<Integer,Object>> manager = new HashMap<String,Map<Integer,Object>>();
Set<String> keys;
Integer staticYear;
//static_year:value(具体的值)
Map<Integer,Object> yearValue;
Object value;
List<Integer> yearList = new ArrayList<Integer>();
for (Map<String, Object> map : results) {
keys = map.keySet();
staticYear = Integer.parseInt(map.get("static_year").toString());
yearList.add(staticYear);
for (String key : keys) {
if("static_year".equals(key)) {
continue;
}
yearValue = manager.get(key);
if(yearValue==null) {
yearValue = new HashMap<Integer,Object>();
manager.put(key, yearValue);
}
value = map.get(key);
yearValue.put(staticYear, value);
}
}
if(!yearList.isEmpty()) {
//让年份降序排列
Collections.sort(yearList);
//定义结果集
Map<String,Object> result = new HashMap<String,Object>();
result.put("static_year", yearList);
List<Object> resultList;
//定义动态增加的集合
List<Float> speedList;
//计数
int count;
//上一年的数值
BigDecimal lastValue = null;
//现在的数值
BigDecimal nowValue;
//最近的一年
Integer earliestYear = yearList.get(0);
//封装结果集
Set<String> managerKeys = manager.keySet();
for (String key : managerKeys) {
resultList = new ArrayList<Object>();
result.put(key, resultList);
yearValue = manager.get(key);
//动态增加返回字段 值集合
if(addSpeedSet!=null&&addSpeedSet.contains(key)) {
count = 0;
speedList = new ArrayList<Float>();
result.put(key+"_addspeed", speedList);
for (Integer year : yearList) {
count++;
value = yearValue.get(year);
if(count==1) {
//以BigDecimal形式存储上一次的值
if(value==null) {
lastValue = new BigDecimal(0);
}else {
lastValue =new BigDecimal(value.toString());
}
}else {
//以BigDecimal形式存储当前的值
if(value==null) {
nowValue = new BigDecimal(0);
}else {
nowValue =new BigDecimal(value.toString());
}
//无法计算则增速为0
if(lastValue.equals(BigDecimal.ZERO)||nowValue.equals(BigDecimal.ZERO)) {
speedList.add(0f);
//保留下一次的值
lastValue = nowValue;
}else {
//(当前值-上一次的值)/上一次的值 保留4位有效小数
speedList.add(((nowValue.subtract(lastValue)).divide(lastValue,4,BigDecimal.ROUND_HALF_UP)).floatValue());
//保留上一次的值
lastValue = nowValue;
}
}
}
}
for (Integer year : yearList) {
//跳过最早一年
if(year==earliestYear) {
continue;
}
value = yearValue.get(year);
resultList.add(value);
}
}
//清除最近的一年数据
yearList.remove(0);
return result;
}
return null;
}
测试:
public static void main(String[] args) {
MainTest test = new MainTest();
List<Map<String,Object>> results = new ArrayList<Map<String,Object>>();
Map<String,Object> result0 = new HashMap<String,Object>();
results.add(result0);
result0.put("static_year", 2009);
result0.put("column1", 5);
result0.put("column2", 6);
result0.put("column3", 7);
Map<String,Object> result1 = new HashMap<String,Object>();
results.add(result1);
result1.put("static_year", 2010);
result1.put("column1", 15);
result1.put("column2", 16);
result1.put("column3", 17);
Map<String,Object> result2 = new HashMap<String,Object>();
results.add(result2);
result2.put("static_year", 2011);
result2.put("column1", 151);
result2.put("column2", 161);
result2.put("column3", 171);
Map<String,Object> result3 = new HashMap<String,Object>();
results.add(result3);
result3.put("static_year", 2012);
result3.put("column1", 1511);
result3.put("column2", 1611);
result3.put("column3", 1711);
Set<String> addSpeedSet = new HashSet<String>();
addSpeedSet.add("column1");
addSpeedSet.add("column2");
Map<String, Object> transfDataStruct = test.transfDataStruct(results,addSpeedSet);
System.out.println(transfDataStruct);
}
结果:
{column1=[15, 151, 1511], column1_addspeed=[2.0, 9.0667, 9.0066], static_year=[2010, 2011, 2012], column3=[17, 171, 1711], column2=[16, 161, 1611], column2_addspeed=[1.6667, 9.0625, 9.0062]}
后言:
_addspeed为后缀,可以动态的传参数指定,该方法的使用,必须要保证年份是连续的,不连续的情况,需要添加年份保证,连续后值补0或null即可,为了保证计算的顺利,需要往前多查询一年的数据,例如前台需要2010-2016年数据,后台sql查询需要查询2009-2016年数据,通用方法会自动去除2009年的数据,往前一年的数据是为了保证增速计算的必要条件