Tablesaw-后端数据可视化工具
1、导入Tablesaw
-
gradle
//tablesaw 库的核心代码,主要是数据的加工处理操作:数据的追加,排序,分组,查询等 implementation "tech.tablesaw:tablesaw-core:0.38.1" //数据可视化的子项目,主要作用加载数据生成可视化图表 implementation "tech.tablesaw:tablesaw-jsplot:0.38.1"
-
maven
<dependency> <groupId>tech.tablesaw</groupId> <artifactId>tablesaw-core</artifactId> <version>LATEST</version> </dependency> <dependency> <groupId>tech.tablesaw</groupId> <artifactId>tablesaw-jsplot</artifactId> <version>LATEST</version> </dependency>
2、创建图表
2.1、方式一
//获取数据并创建记录表格
Table table = Table.create("动环状态记录表").addColumns(
StringColumn.create("时间",times),
//这里注意了要是想数据图中显示的数据为真实的数据,则需要用DoubleColumn等Number型对象
DoubleColumn.create(EnvTypeInfo.getEnvTypeName(envType),values));
2.2、方式二
//直接读csv文件,获取数据
Table table = Table.read().csv(filepath);
3、创建折线图
Plot.show(
TimeSeriesPlot.create(
EnvTypeInfo.getEnvTypeName(envType)+"变化时间序列图",//折线图名称
/**
* table:数据来源
* "时间":x轴,名称必须要和table中的一个字段相对应
* EnvTypeInfo.getEnvTypeName(envType):y轴,名称必须要和table中的一个字段相对应
**/
table, "时间", EnvTypeInfo.getEnvTypeName(envType)));
这里注意了,源码中Plot会执行系统默认浏览器,打开生成的html文件。
但是,由于配置原因这里很容易出现浏览器不支持的问题,这是由于程序默认往往在Headless
模式下工作,此时默认是系统环境缺少了显示设备、键盘或鼠标。解决这种问题有两种方法。
3.1、解决浏览器不支持问题(方式一)
设置jvm options:-Djava.awt.headless=false
生产环境中启动时命令为:java -Djava.awt.headless=false xx.jar
但是这样会有一个弊端:系统实际环境和运行环境可能不符,特别是在项目放在云主机上运行时。
所以不推荐
3.2、解决浏览器不支持问题(方式二)
System.setProperty("java.awt.headless",false)
在创建视图时,设置系统参数java.awt.headless
的参数为false
当创建视图结束后,再在finally中调用,设置回true
即可。
但是,这些都是基于,系统有浏览器的情况,并且,系统只会在服务端
打开视图,并不会出现调用客户端
浏览器的行为。如果你只是自己测试,大可如此,如果放在生产环境中,并没有多大作用。
所以针对这一问题,有如下解决方案
4、客户端打开可视化页面
具体可以将生成的html文件,使用二进制流的方式传输到响应体中,设置ContentType
为text/html
传输给前端,前端调用接口时新打开一个页面来解析html文件即可实现
4.1、重写Plot类
tablesaw的限制太多,可以自行进行重写该类,
public class ShowPlot {
private static final String DEFAULT_DIV_NAME = "target";
private static final String DEFAULT_OUTPUT_FILE = "output.html";
private static final String DEFAULT_OUTPUT_FILE_NAME = "output";
public static final String DEFAULT_OUTPUT_FOLDER = System.getProperty("user.dir") + "/src/main/resources/templates";
//返回html文件对象outputfile
public static File show(Figure figure, String divName, File outputFile) {
Page page = Page.pageBuilder(figure, divName).build();
String output = page.asJavascript();
try (Writer writer =
new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8)) {
writer.write(output);
} catch (IOException e) {
e.printStackTrace();
}
return outputFile;
}
public static void show(Figure figure, String divName) {
show(figure, divName, defaultFile());
}
public static File show(Figure figure) {
return show(figure, randomFile());
}
public static File show(Figure figure, File outputFile) {
return show(figure, DEFAULT_DIV_NAME, outputFile);
}
private static File defaultFile() {
Path path = Paths.get(DEFAULT_OUTPUT_FOLDER, DEFAULT_OUTPUT_FILE);
try {
Files.createDirectories(path.getParent());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return path.toFile();
}
private static File randomFile() {
Path path = Paths.get(DEFAULT_OUTPUT_FOLDER, randomizedFileName());
try {
Files.createDirectories(path.getParent());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return path.toFile();
}
private static String randomizedFileName() {
return DEFAULT_OUTPUT_FILE_NAME + UUID.randomUUID().toString() + ".html";
}
}
4.2、将文件流写入响应体
/**
* 响应体加入文件流
*
* @param response:响应体
* @param htmlFile:tablesaw生成的html文件
*/
public static void responseFileStream(HttpServletResponse response, File htmlFile) {
ServletOutputStream out = null;
FileInputStream in = null;
try {
in = new FileInputStream(htmlFile);
//设置响应体文件格式
response.setContentType("text/html");
out = response.getOutputStream();
// 读取文件流
int len = 0;
byte[] buffer = new byte[1024 * 10];
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.flush();
} catch (FileNotFoundException e) {
log.error("responseFileStream error:FileNotFoundException" + e);
} catch (Exception e) {
log.error("responseFileStream error:" + e);
} finally {
try {
out.close();
in.close();
} catch (NullPointerException e) {
log.error("responseFileStream stream close() error:NullPointerException" + e);
} catch (Exception e) {
log.error("responseFileStream stream close() error:" + e);
}
}
}
4.3、将文件流传输给前端
/**
* 创建动环记录图
* @param devNo
* @param envType
*/
@GetMapping("/{devNo}/{envType}")
public void createTemp(@PathVariable("devNo")String devNo, @PathVariable("envType")String envType,
@RequestParam Map<String,String> param, HttpServletResponse response){
try {
log.info("---->开始创建动环可视化图,{}",devNo);
File file=enviromentRecordService.createPlot(devNo, envType,param);
FileUtils.responseFileStream(response,file);
}catch (Exception e){
log.error("生成数据图异常",e);
}
log.info("创建动环可视化图结束<----");
}
访问URL,得到:
大功告成!
最后设置一个定时任务,清理临时文件就行啦!
4.4、清理临时文件
/**
* 定时删除tablesaw临时文件
*/
@Scheduled(cron = "0 8 * * * *")
public void delTablesawFile() {
log.info("---->开始删除Tablesaw临时文件");
String path = ShowPlot.DEFAULT_OUTPUT_FOLDER;
Boolean result = FileUtils.delete(path);
log.info("删除Tablesaw临时文件结束<----,{}",result);
}