JXLS模板开发图表报表「终于解决」

JXLS模板开发图表报表「终于解决」背景:因业务需求,需要开发带有统计图表的excel报表。做了一番调研,发现市面上做excel报表的开源库还是比较多的,其中比较优秀的有JXLS、

欢迎大家来到IT世界,在知识的湖畔探索吧!

背景:因业务需求,需要开发带有统计图表的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的官网 http://jxls.sourceforge.net,上面有模板相关标签的使用方法及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>

欢迎大家来到IT世界,在知识的湖畔探索吧!

  1. 一个简单的例子

以下模板使用jx:each输出一个列表。

JXLS模板开发图表报表「终于解决」

JXLS模板开发图表报表「终于解决」

  1. 支持的命令

除了jx:each,jxls还支持很多命令,以下是一些常用的。

  1. jx:each: 遍历集合,生成多行数据。
  2. jx:if: 根据条件判断是否生成数据。
  3. jx:area: 定义单元格范围。
  4. jx:grid: 将数据导出到指定的单元格范围内
  5. jx:eachCommand: 在循环中执行自定义命令。
  6. jx:formula: 计算公式并将结果输出到单元格中。
  7. jx:image: 在单元格中插入图片。
  8. jx:mergeCells: 合并单元格。
  9. jx:dateCell: 输出日期并指定格式。

用法详见官网示例: https://jxls.sourceforge.net/samples/object_collection.html

二、在excel中加入图表

如何在excel报表中加入图表呢?先看以下两种方式的生成效果。

方式一:使用Excel自带的图表工具

此方式的好处是如果数据发生改变,图表也会随之改变。

  1. 创建一个包含图表的 Excel 模板文件。模板中分别插入了一个柱状图、一个折线图。
JXLS模板开发图表报表「终于解决」

  1. 生成效果。
JXLS模板开发图表报表「终于解决」

方式二:使用Image作为图表

此方式使用图片生成图表,所以当数据发生变化时,图表无法联动。而且由于图片的比较大,会使生成的报表比使用excel自带的图表工具要大很多。

  1. 创建一个 Excel 模板文件。模板中通过jx:chart批注插入了一个柱状图、一个折线图(src、imageType属性)。
JXLS模板开发图表报表「终于解决」

  1. 生成效果。
JXLS模板开发图表报表「终于解决」

Image方式产生的图表使用的是d3.js库所产生的svg转换成图片而来。

JXLS扩展

从上面例子可以看到,无论方式一还是方式二,模板中都有一个jx:chart的批注,此命令并非JXLS自带的command,是为了展示图表而扩展的一个command。因为模板中插入的图表在生成最终报表时,图表的位置及大小不能随数据的部局变化而自行移动到合适的位置,并且图表xy轴也不能随动态填充的数据而改变选择数据的范围,所以扩展一个jx:chart command来实现这个功能。

jx:chart命令的作用是确定图表在生成的excel中报表中放置的位置、宽度高度及选择数据的单元格区域,它具有以下属性:

(注:粗体为必填项,方式一时必填seriesAxis,方式二时必填imageBytes)

欢迎大家来到IT世界,在知识的湖畔探索吧!chartName;//图片名称,需与模板里插入的图表名称匹配。 String
startCol;//起始列位置(index从1算起)。 int
startRow;//起始行位置(index从1算起)。 int
cols;//长度占多少列单元格。 int
rows;//高度占多少行单元格。 int
seriesAxis;//选择数据,当使用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图表,选择数据…

JXLS模板开发图表报表「终于解决」

三、示例代码

欢迎大家来到IT世界,在知识的湖畔探索吧!package com.test.report.generation.generator.chart;

@Slf4j
public 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图表的报表步骤:

  1. 创建模板。
  2. 模板中插入图表(修改图表名称)。
  3. 为图表选择数据区域。
  4. 添加jx:chart命令批注(对应好图表名称)。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/22812.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信