前言:
现在同学们对“java大数据报表”大约比较注意,我们都想要剖析一些“java大数据报表”的相关文章。那么小编在网摘上汇集了一些有关“java大数据报表””的相关资讯,希望大家能喜欢,小伙伴们快快来学习一下吧!背景:因业务需求,需要开发带有统计图表的excel报表。做了一番调研,发现市面上做excel报表的开源库还是比较多的,其中比较优秀的有JXLS、EasyExcel。EasyExcel属于阿里系,据说生成速度比较快,也省内存,但模板填充功能比较简单,比较复杂的一些excel报表难以用模板实现,要书写较多的额外代码,无法满足日后要利用模板开发大量报表需求的目的。而JXLS模板填充功能在所有开源库中算是比较全面的,也支持使用SXSSF(Streaming Usermodel API,这是一种专门用于处理大型Excel文件的API,可以在内存中处理大量数据并生成Excel文件,避免OutOfMemoryError),本文主要讲述利用JXLS开发带图表的excel报表。
一、JXLS
先说一下什么是JXLS。JXLS是一个流行的Excel报表模板库,可以将数据填充到Excel模板中,生成丰富的Excel报表。JXLS支持多种数据源,包括Java集合、JavaBeans、SQL查询等。它还提供了多种模板标记,可以方便地控制报表的样式和布局。
JXLS的官网 ,上面有模板相关标签的使用方法及sample。相对还算丰富,包含循环(纵向、横向)、条件判断、动态表格、自定义函数、公式等,基本满足我们现在excel报表的实现需求。JXLS有1跟2版本,有较大区别,2版本改用批注方式写命令标签,功能也更丰富,我们采用jxls2最新版。
使用jxls需引入依赖:
<dependency> <groupId>org.jxls</groupId> <artifactId>jxls</artifactId> <version>2.11.0</version></dependency><dependency> <groupId>org.jxls</groupId> <artifactId>jxls-poi</artifactId> <version>2.11.0</version></dependency>一个简单的例子
以下模板使用jx:each输出一个列表。
支持的命令
除了jx:each,jxls还支持很多命令,以下是一些常用的。
jx:each: 遍历集合,生成多行数据。jx:if: 根据条件判断是否生成数据。jx:area: 定义单元格范围。jx:grid: 将数据导出到指定的单元格范围内jx:eachCommand: 在循环中执行自定义命令。jx:formula: 计算公式并将结果输出到单元格中。jx:image: 在单元格中插入图片。jx:mergeCells: 合并单元格。jx:dateCell: 输出日期并指定格式。
用法详见官网示例:
二、在excel中加入图表
如何在excel报表中加入图表呢?先看以下两种方式的生成效果。
方式一:使用Excel自带的图表工具
此方式的好处是如果数据发生改变,图表也会随之改变。
创建一个包含图表的 Excel 模板文件。模板中分别插入了一个柱状图、一个折线图。生成效果。方式二:使用Image作为图表
此方式使用图片生成图表,所以当数据发生变化时,图表无法联动。而且由于图片的比较大,会使生成的报表比使用excel自带的图表工具要大很多。
创建一个 Excel 模板文件。模板中通过jx:chart批注插入了一个柱状图、一个折线图(src、imageType属性)。生成效果。
Image方式产生的图表使用的是d3.js库所产生的svg转换成图片而来。
JXLS扩展
从上面例子可以看到,无论方式一还是方式二,模板中都有一个jx:chart的批注,此命令并非JXLS自带的command,是为了展示图表而扩展的一个command。因为模板中插入的图表在生成最终报表时,图表的位置及大小不能随数据的部局变化而自行移动到合适的位置,并且图表xy轴也不能随动态填充的数据而改变选择数据的范围,所以扩展一个jx:chart command来实现这个功能。
jx:chart命令的作用是确定图表在生成的excel中报表中放置的位置、宽度高度及选择数据的单元格区域,它具有以下属性:
(注:粗体为必填项,方式一时必填seriesAxis,方式二时必填imageBytes)
chartName;//图片名称,需与模板里插入的图表名称匹配。 StringstartCol;//起始列位置(index从1算起)。 intstartRow;//起始行位置(index从1算起)。 intcols;//长度占多少列单元格。 introws;//高度占多少行单元格。 intseriesAxis;//选择数据,当使用excel的图表工具插入图表时,需选择依赖的单元格数据。String //此属性是一个数组串,一个数组元素代表一个数据选择(x、y轴依赖的数据域), //一个数组元素中包含的属性有: // catAx=图表右键选择数据里的水平(分类)轴坐标 // catStartCol=x轴数据区域起始列位置(index从1算起) // catStartRow=x轴数据区域起始行位置(index从1算起) // catCols=x轴数据区域长度占多少列单元格 // catRows=x轴数据区域长度占多少行单元格 // // valAx=图表右键选择数据里的Y值 // valStartCol=y轴数据区域起始列位置(index从1算起) // valStartRow=y轴数据区域起始行位置(index从1算起) // valCols=y轴数据区域长度占多少列单元格 // valRows=y轴数据区域长度占多少行单元格imageBytes;//图片数据,当使用图片方式生成图表时需填写的属性。 byte[]imageType;//图片格式,JPEG、PNG。 String
还是以上面方式一的例子,以柱图为例,它的批注如下:
jx:chart(chartName="chart1" cols="4" rows="14" lastCell="C7" seriesAxis="[{catAx=Template!$A$5, catStartCol=1, catStartRow=5, catCols=1, catRows=items1.size(), valAx=Template!$B$5, valStartCol=2, valStartRow=5, valCols=1, valRows=items1.size()}, {catAx=Template!$A$5, catStartCol=1, catStartRow=5, catCols=1, catRows=items1.size(), valAx=Template!$C$5, valStartCol=3, valStartRow=5, valCols=1, valRows=items1.size()}]")//注释://1. chartName="chart1" 与柱图的名称对应(图中蓝色部分)//2. cols="4" 图表的宽度为4//3. rows="14" 图表的高度为14//4. seriesAxis中有两个元素:// (1) catAx=Template!$A$5 x轴数据区域// catStartCol=1 x轴数据区域起始列// catStartRow=5 x轴数据区域起始行// catCols=1 x轴数据区域宽度为1// catRows=items1.size() x轴数据区域高度// valAx=Template!$B$5 y轴数据区域// catStartCol=2 y轴数据区域起始列// catStartRow=5 y轴数据区域起始行// valCols=1 y轴数据区域宽度为1// valRows=items1.size() y轴数据区域高度// (2) ...
右键data1图表,选择数据...
三、示例代码
package com.test.report.generation.generator.chart;@Slf4jpublic class JxlsChartSample { public Map<String, Object> getData() throws Exception { Map<String, Object> data = new HashMap<>(); List<Item> items1 = new ArrayList<>(); Item item1 = new Item(); item1.setName("股票 (香港)"); item1.setY1(new BigDecimal("9001558.50")); item1.setY2(new BigDecimal("3501558.50")); item1.setValue(item1.getY1()); items1.add(item1); Item item2 = new Item(); item2.setName("股票 (美國)"); item2.setY1(new BigDecimal("6501558.50")); item2.setY2(new BigDecimal("4234266.50")); item2.setValue(item2.getY1()); items1.add(item2); Item item3 = new Item(); item3.setName("股票 (其他)"); item3.setY1(new BigDecimal("20015580.43")); item3.setY2(new BigDecimal("7015580.50")); item3.setValue(item3.getY1()); items1.add(item3); Item item4 = new Item(); item4.setName("期貨"); item4.setY1(new BigDecimal("1941558.50")); item4.setY2(new BigDecimal("3501558.50")); item4.setValue(item4.getY1()); items1.add(item4); Item item5 = new Item(); item5.setName("轉倉"); item5.setY1(new BigDecimal("-2015580.50")); item5.setY2(new BigDecimal("-40015580.50")); item5.setValue(item5.getY1()); items1.add(item5); Item item6 = new Item(); item6.setName("利息 (香港)"); item6.setY1(new BigDecimal("-30401558.50")); item6.setY2(new BigDecimal("-40201558.50")); item6.setValue(item6.getY1()); items1.add(item6); Item item7 = new Item(); item7.setName("利息 (美國)"); item7.setY1(new BigDecimal("-50155890.50")); item7.setY2(new BigDecimal("-3015580.50")); item7.setValue(item7.getY1()); items1.add(item7); List<Item> items2 = new ArrayList<>(); for (Item item : items1) { Item itemClone = item.clone(); itemClone.setName("华盛-" + item.getName()); BigDecimal multiplier = new BigDecimal("3000"); itemClone.setY1(item.getY1().multiply(multiplier)); itemClone.setY2(item.getY2().multiply(multiplier)); itemClone.setValue(itemClone.getY1()); items2.add(itemClone); } //todo 方式一:ExcelSelf 使用Excel自带的图表工具生成图表(1..在Excel模板中插入图表,选择数据;2.在Excel模板中增加jx:chart批注,确定图表的位置及大小。) data.put("items1", items1); data.put("items2", items2); //todo 方式二:Image 使用图片格式的图表(1.ScriptEngineInvoke.generateChartImage会根据传入的数据及图表类型,调用js生成SVG串,再将SVG串转成PNG图片。2.再在Excel模板中增加jx:chart批注,确定图表的位置及大小,src为PNG的byte值。) //data.put("lineChartPngByte", ScriptEngineInvoke.generateChartImage(items1, ChartTypeEnum.Line.options())); //data.put("barChartPngByte", ScriptEngineInvoke.generateChartImage(items2, ChartTypeEnum.Bar.options())); return data; } @Data public static class Item implements Cloneable{ private String name; private BigDecimal y1; private BigDecimal y2; private BigDecimal value; @Override public Item clone() { Item detail = null; try { detail = (Item) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } return detail; } } private static String template = "/templates/charts_ExcelSelf.xlsx"; private static String output = "report/src/main/resources/1_charts_ExcelSelf.xlsx"; public static void main(String[] args) throws Exception { JxlsChartSample jxlsChartSample = new JxlsChartSample(); Map<String, Object> data = jxlsChartSample.getData(new HashMap<>()); log.info("Opening input stream"); try (InputStream is = JxlsChartSample.class.getResourceAsStream(template)) { log.info("InputStream={}", is); try (OutputStream os = new FileOutputStream(output)) { Context context = PoiTransformer.createInitialContext(); context.putVar("items1", data.get("items1")); context.putVar("items2", data.get("items2")); context.putVar("lineChartPngByte", data.get("lineChartPngByte")); context.putVar("barChartPngByte", data.get("barChartPngByte")); // with multi sheets it is better to use StandardFormulaProcessor by disabling the FastFormulaProcessor //JxlsHelper.getInstance().setUseFastFormulaProcessor(false).processTemplate(is, os, context); JxlsExcelGenerator jxlsExcelGenerator = new JxlsExcelGenerator(); jxlsExcelGenerator.processTemplate(is, os, context); } } }}总结一下,开发一个Excel图表的报表步骤:创建模板。模板中插入图表(修改图表名称)。为图表选择数据区域。添加jx:chart命令批注(对应好图表名称)。
标签: #java大数据报表