龙空技术网

JXLS模板开发图表报表

IvanLan 179

前言:

现在同学们对“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大数据报表