#前言
春节小长假休的比较舒服,第一天上班,继续年前未完成的内容。
本章节完成最后一点:利用thymeleaf模板引擎 和echarts完成数据可视化。
为什么使用thymeleaf和echarts?
1.thymeleaf是基于html的,可以先进行原型设计,即设计静态的html,然后嵌入thymeleaf标签,即使页面渲染不成功,也是标准的html页面,可读性较好,而且独立于java容器,你可以认为它就是一个标准的html页面。
2.echarts作为百度不可多得的开源框架,这里不做详细介绍,类似于highcharts等图表展示工具,非常强大。因为我没用过,所以要尝试一下。
1.html原型设计
1.我这里用的是bootstrap,so 去中文网找个原型吧(能自己写原型固然很牛逼,但不建议,写出来也不一定比人家的好看,不要浪费时间)。
https://v4.bootcss.com/docs/4.0/examples/
我找了个轮播的示例,直接copy html代码到项目中的index.html中,然后自己改了改
此时不要着急实现页面渲染部分的内容,目前只是一个静态的html,然后启动springboot,测试下index.html的样式 css js等是否加载成功,如报错或者跟样例展示效果有出入,请自行修改。
至此,我们的原型设计就完成了。
2.页面动态渲染,实现数据可视化
1.首先要解决的就是前端组装echarts,还是后端组装,我们用后端组装,更灵活。那么问题来了,需要将echarts的所有属性抽象封装成model,我在网上找了个大神写的echarts-java映射类库:https://gitee.com/free/ECharts,把源码下载下来导入项目。
这个类库中用到了lombok减少代码冗余,其实就是不用自己写getter setter方法,只用注解就可以。参考:
http://blog.csdn.net/zhglance/article/details/54931430
2. 此时我试了一下,还遇到一个问题,对象映射成json时,很多null属性也被映射成json了,这样会导致echarts的某些重要属性遭到null覆盖掉,使得echarts加载报错,所以这里就直接上解决方案:过滤掉json中的null和空字段。写一个配置类如下:
package com.cnepay.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.io.IOException;
/**
* Created by wxq on 2018/2/2.
*/
@Configuration
public class JacksonConfig {
@Bean
@Primary
@ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
// Include.Include.ALWAYS 默认
// Include.NON_DEFAULT 属性为默认值不序列化
// Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
// Include.NON_NULL 属性为NULL 不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
// 字段保留,将null值转为""
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
jsonGenerator.writeString("");
}
});
return objectMapper;
}
}
通过以上配置,springboot在将对象转换成json的时候就会过滤掉null和空字段
3.选择一个维度进行数据可视化,简单点,统计电影评价人数
后端代码,拼装Option,对echarts不熟悉的先去官网研究:
/*
* 获取柱状图 json数据
* */
public Option getEchartsOption()
{
List<Movie> list = movieMapper.selectMapList();
//echarts option 对象
Option option = new Option();
option.title("电影评价人数统计").tooltip(Trigger.axis).legend("评价人数");
//x轴为值轴
option.xAxis(new ValueAxis().boundaryGap(0d, 0.01));
//y轴为类目轴
CategoryAxis category = new CategoryAxis();
//柱状数据
Bar bar = new Bar("评价人数");
//循环数据
for (Movie m : list) {
//设置类目
category.data(m.getTitle());
//类目对应的柱状图
bar.data(m.getEvalNum());
}
Grid grid = new Grid();
grid.setLeft(200);
option.setGrid(grid);
option.yAxis(category);
option.series(bar);
return option;
}
前端代码:
参考echarts官方文档:http://echarts.baidu.com/option.html#title:
4.最终效果
5.上映年份维度统计(又做了一个饼状图的统计),附上后台代码:
/*
* 获取饼状图 json数据
* */
public Option getEchartsPieOption()
{
List<Movie> list = movieMapper.selectAllMapList();
Option option = new Option();
//标题
Title title = new Title();
title.setText("豆瓣电影上映年份");
title.setSubtext("来源豆瓣");
title.setX("center");
option.setTitle(title);
//提示框
Tooltip tooltip = new Tooltip();
tooltip.setTrigger(Trigger.item);
tooltip.formatter("{a} <br/>{b} : {c} ({d}%)");
option.setTooltip(tooltip);
//Legend
Legend legend = new Legend();
List<String> legendDataList = Arrays.asList("90年代", "00年代", "10年代","其他");
legend.setOrient(Orient.vertical);
legend.setLeft("left");
legend.setData(legendDataList);
option.setLegend(legend);
//饼状图
Pie pie = new Pie();
//对数据进行简单处理
int y90 =0;
int y00 =0;
int y10 =0;
int yElse =0;
for (Movie movie : list) {
if(movie.getmYear().startsWith("199")){
y90++;
}
else if (movie.getmYear().startsWith("200")){
y00++;
}
else if (movie.getmYear().startsWith("201")){
y10++;
}
else{
yElse++;
}
}
Map<String,String> dataMap90 = new HashMap<>();
dataMap90.put("name","90年代");
dataMap90.put("value",String.valueOf(y90));
Map<String,String> dataMap00 = new HashMap<>();
dataMap00.put("name","00年代");
dataMap00.put("value",String.valueOf(y00));
Map<String,String> dataMap10 = new HashMap<>();
dataMap10.put("name","10年代");
dataMap10.put("value",String.valueOf(y10));
Map<String,String> dataMapElse = new HashMap<>();
dataMapElse.put("name","其他");
dataMapElse.put("value",String.valueOf(yElse));
//封装pie
pie.data(dataMap90, dataMap00, dataMap10, dataMapElse);
pie.setName("上映年代");
pie.setRadius("55%");
String [] centerArray = {"50%","60%"};
pie.setCenter(centerArray);
option.series(pie);
return option;
}
效果:
至此,我们完成了两个维度的数据可视化。
`