本文是上篇java+highchart实现分类下钻柱形图的续集.
本篇重点阐述方式二的实现. 最为上篇中的方式一的补充和优化.
如前篇所述, 方式一, (1)查询数据库次数太多, 而且(2)不利于数据处理成前台要求的格式,毕竟数据库获取到的数据是这种List<Object[]>
形式, 需要手动遍历封装, 非常繁琐. 另外, (3)存在硬编码的问题.
我们知道, 如果给你一个封装好的Javabean要比给你零散的数组或者集合要好很多, 尤其是这种有层次的树形数据结构.
针对上述问题, 笔者考虑加入中间环节: 将数据库获取的数据封装成Javabean, 流程变为: 数据库(或者其他数据源)->封装成Javabean->再其基础上再解析成highchart(或者其他可视化框架)要求的格式->响应..
. 而不是方式一的, 获取数据源->解析->...
.
缘起于此, 想到干脆写一个小插件, 专门用来将数据源封装成一个Javabean.
插件: 封装数据集
实现了前端数据格式和后台数据库的解耦.
- 不论数据源, 只要查询出的数据格式符合本插件要求的样式.
- 前台不论需要什么格式数据, 只需要在本插件封装好的Javabean基础上操作即可. 操作一个Javabean要轻松太多.
插件名称:
pcddatahelper.jar
, 已经上传至GitHub
.
插件下载地址:https://github.com/Nisus-Liu/pcddatahelper
关于插件的使用, README.md
, demo案例以及javadoc
, 已经很详细的说明.
多说一句, 为什么取名: pcddatahelper
.
pcd
: province, city, district.
笔者将所有形如省>市>区
具有层次关系的树形数据集统称为pcd data
(很形象和简洁, 再加有创意 有米有O(∩_∩)O哈哈~).
解析成highchart数据格式
这里没有太大难度, 就是递归的时候要费点脑力. 这样可以实现智能的向下钻取. 不论多少层, 只要服务器扛得住.
Service层代码:
- 主要方法
public Map<String, Object> getData4DrillDownChart3() {
//获取数据源,解析成PCDEntity
List<Object[]> dataframe = areaDao.findByGroupLowestLevel();
//自定义聚合计算器,用来生成百分比
PCDDataHelper helper = new PCDDataHelper(new Aggregator() {
@Override
public void aggregate(PCDEntity[] pcdEntities) {
double sum = pcdEntities[0].getParent().getValue().doubleValue();
for (PCDEntity pcdEntity : pcdEntities) {
//计算份额,并更新statValue字段
pcdEntity.setStatValue(pcdEntity.getValue().doubleValue() / sum * 100);
}
}
});
wtgroup.pojo.PCDEntity root = helper.buildPCDEntity(dataframe, new int[]{0, 1, 2}, new int[]{0, 1, 2}, 3);
root = helper.statPCDEntity(root);
System.out.println(root);
//处理数据,满足highchart格式要求
return parsePCDEntity4Highchart(root);
}
- 辅助方法
(1)针对highchart
要求解析
private Map<String, Object> parsePCDEntity4Highchart(PCDEntity root) {
Series series = new Series();
//定义一个Series类的集合,用来存储drilldown:series
List<Series> drilldownSeries = new ArrayList<Series>();
series.setName("分区分布");
series.setId("subArea");
//递归钻取数据
drilldown(root, series, drilldownSeries);
// 将series和drilldownSeries返回给action
HashMap<String, Object> drilldownData = new HashMap<>();
drilldownData.put("series", series);
drilldownData.put("drilldownSeries", drilldownSeries);
return drilldownData;
}
(2)递归
//向下递归解析数据
private void drilldown(PCDEntity pcdEntity, Series series, List<Series> drilldownSeries) {
if (pcdEntity.isLeaf()) {
return;
}
Series sery = new Series();
sery.setName(pcdEntity.getName());
sery.setId(String.valueOf(pcdEntity.getId()));
List<Series.Point> data = new ArrayList<>();
for (PCDEntity e : pcdEntity.getChildren()) {
Series.Point point = new Series.Point();
point.setName(e.getName());
point.setY(e.getStatValue().doubleValue());
point.setDrilldown(String.valueOf(e.getId()));
data.add(point);
drilldown(e, series, drilldownSeries);
}
sery.setData(data);
//区分根节点和非根节点
//根节点时,sery添加至series,非根节点时添加至drilldownSeries
if (!pcdEntity.isRoot()) {
drilldownSeries.add(sery);
} else {
series.setData(data);
}
return;
}
效果
省级分布
市级分布
区级分布
Thanks for reading~