工具类——Java导出EXCEL2(设置样式、加载并填充图片、加载指定模板、大数据量设置窗口大小与刷新频率)

书接上篇:工具类——Java 浏览器导入、导出Excel(Java import、export)demo
在这里插入图片描述
POI的导出方式:创建/加载Workbook,设置样式,填充数据,然后生成本地临时文件,最终以浏览器的形式打开,完成整个导出动作。

一、POI设置样式

demo如下,

private void setCellStyleDemo(T wb, T sheet) {
	def row1 = sheet.createRow(1)
	// 创建style并设置样式
    CellStyle style1 = wb.createCellStyle()
    style1.setWrapText(true)// 文本自动换行
    style1.setAlignment(HorizontalAlignment.CENTER)// 水平居中
    style1.setVerticalAlignment(VerticalAlignment.CENTER)// 垂直居中
    style1.setBorderLeft(BorderStyle.THIN)// 设置左边框
    style1.setBorderTop(BorderStyle.THIN)// 设置上边框
    style1.setBorderRight(BorderStyle.THIN)// 设置右边框
    style1.setBorderBottom(BorderStyle.THIN)// 设置下边框
    // 设置字体
	Font font1 = wb.createFont()
    font1.setFontHeight(11)// 大小
    font1.setBold(true)// 加粗与否
    style1.setFont(font1)
    // 填充单元格value为“序号”,并未它设置以上样式
    row1.createCell(0).setCellValue("序号")
    row1.getCell(0).setCellStyle(style1)
    
    // 设置列宽、行高
    sheet.setColumnWidth(0, 5 * 256)// 设置第一列宽度为5个字符宽度
    for (int i = 1; i <= len; i++) {
        sheet.setColumnWidth(i, 20 * 256)// 设置第二至…宽度为20个字符宽度
    }
    row0.setHeightInPoints(50)// 设置第1行高度为50px
}

二、POI导出图片

demo如下,

 /**
     * 加载头像,并填充
     * @param wb (xlsx)
     * @param sheet 页签
     * @param imgUrl 图片路径
     * @return 是否填充图片:否,填充(2寸照片)的字眼
     */
    boolean setPngToSheet(XSSFWorkbook wb, XSSFSheet sheet, String imgUrl) {
        if (imgUrl.indexOf(".") == -1) {
            return false
        }
        String imgType = imgUrl.substring(imgUrl.indexOf(".") + 1)// jpg、png…
        FileInputStream fs
        ByteArrayOutputStream baos
        try {
            File imgFile = new File(imgUrl)
            fs = new FileInputStream(imgFile)
            baos = new ByteArrayOutputStream()
            BufferedImage bi = ImageIO.read(fs)
            // 图片入流
            ImageIO.write(bi, imgType, baos)
            // 写入excel
            XSSFDrawing patriarch = sheet.createDrawingPatriarch()
            // 图片导入指定单元格
            XSSFClientAnchor anchor = new XSSFClientAnchor(350, 100, 150, 0, (short) 8, 2, (short) 9, 6)

            int type
            switch (imgType) {
                case "png":
                    type = XSSFWorkbook.PICTURE_TYPE_PNG
                    break
                case "jpg":
                    type = XSSFWorkbook.PICTURE_TYPE_JPEG
                    break
                default:
                    type = 6// PNG
            }
            // 插入图片
            patriarch.createPicture(anchor, wb.addPicture(baos.toByteArray(), type))
        } catch (Exception ex) {
            logger.error("个人图片插入失败", ex)
            return false
        } finally {
            if (fs != null) {
                fs.close()
            }
            if (baos != null) {
                baos.close()
            }
        }

        return true
    }

1.解释XSSFClientAnchor

XSSFClientAnchor anchor = new XSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2)

👉源码,

/**
     * Creates a new client anchor and sets the top-left and bottom-right
     * coordinates of the anchor by cell references and offsets.
     * Sets the type to {@link AnchorType#MOVE_AND_RESIZE}.
     *
     * @param dx1  the x coordinate within the first cell.
     * @param dy1  the y coordinate within the first cell.
     * @param dx2  the x coordinate within the second cell.
     * @param dy2  the y coordinate within the second cell.
     * @param col1 the column (0 based) of the first cell.
     * @param row1 the row (0 based) of the first cell.
     * @param col2 the column (0 based) of the second cell.
     * @param row2 the row (0 based) of the second cell.
     */
    public XSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) {
        anchorType = AnchorType.MOVE_AND_RESIZE;
        cell1 = CTMarker.Factory.newInstance();
        cell1.setCol(col1);
        cell1.setColOff(dx1);
        cell1.setRow(row1);
        cell1.setRowOff(dy1);
        cell2 = CTMarker.Factory.newInstance();
        cell2.setCol(col2);
        cell2.setColOff(dx2);
        cell2.setRow(row2);
        cell2.setRowOff(dy2);
    }

👉解释,

  • dx1:表示图片左上角相对于单元格左边界的X轴偏移量,单位为英寸/EMU;
  • dy1:表示图片左上角相对于单元格顶部边界的Y轴偏移量,单位为英寸/EMU;
  • dx2:表示图片右下角相对于单元格左下角的X轴偏移量,单位为英寸/EMU;
  • dy2:表示图片右下角相对于单元格左下角的Y轴偏移量,单位为英寸/EMU;
  • col1:表示该锚点对应的起始单元格列号,从0开始计数;
  • row1:表示该锚点对应的起始单元格行号,从0开始计数;
  • col2:表示该锚点对应的结束单元格列号,从0开始计数;
  • row2:表示该锚点对应的结束单元格行号,从0开始计数。

👉例如,
XSSFClientAnchor anchor = new XSSFClientAnchor(350, 100, 150, 0, (short) 8, 2, (short) 9, 6)

1)后四位,设置图片位置:

  • 左上角位于:第9列,第3行
  • 右下角位于:第10列,第7行

2)前四位,设置图片收缩距离:

  • 与左侧间隔350英寸/EMU
  • 与上侧间隔100英寸/EMU
  • 与右侧间隔150英寸/EMU
  • 与下侧间隔0英寸/EMU
    在这里插入图片描述

三、加载指定模板导出

demo如下,

/**
    * 加载指定模板
    * @param path 文件路径
    * @return 返回Workbook,可指定XSSFWorkbook或者SXSSFWorkbook
    */
   private Workbook readTemplateFile(String path) {
       FileInputStream fs
       Workbook wb = null
       try {
           File temFile = new File(path)
           fs = new FileInputStream(temFile)
           // 读取模板文件
           wb = new Workbook(fs)
       } catch (Exception ex) {
           logger.error("加载EXCEL模板失败", ex)
       } finally {
           if (fs != null) {
               fs.close()
           }
       }
       return wb
   }

四、👉Workbook、XSSFWorkbook与SXSSFWorkbook

Workbook是XSSFWorkbook与SXSSFWorkbook的父类,可以用父类指向子类来调用不确定的子类方法。

XSSFWorkbook和SXSSFWorkbook都是Java中Apache POI库提供的用于操作Excel文档的对象,其中XSSFWorkbook是基于内存模型(in-memory model)实现的,而SXSSFWorkbook则是基于流的方式(streaming way)实现的。

区别主要体现在以下两个方面:

1、内存占用:XSSFWorkbook会将整个Excel文档加载到内存中,因此在处理大量数据时,需要消耗大量的内存。而SXSSFWorkbook采用基于流的方式,将一个sheet中的数据分段写入磁盘以避免内存溢出,因此能够更好地处理海量数据,并且占用的内存较少。

2、性能表现:由于SXSSFWorkbook采用了基于流的方式进行Excel文件的操作,使得其性能表现优于XSSFWorkbook,尤其是对于导出海量数据的情况下,SXSSFWorkbook的速度可能会显著快于XSSFWorkbook。

因此,建议在处理大规模Excel数据时,选择采用SXSSFWorkbook对象,而在需求较小的情况下,XSSFWorkbook也可以满足相关操作需求。

1.大数据量导出

注意点一:
SXSSFWorkbook wb = new SXSSFWorkbook()
初始化时,未指定窗口大小,默认使用100.

1、在写入数据时,只有在当前窗口内的数据才会被缓存到内存中,之外的数据将直接写入到硬盘上,并且该窗口会随着当前位置的移动而进行滚动更新
2、缓存窗口的大小一般需要根据具体应用场景和系统资源情况来确定,并没有一个固定的标准。缓存窗口可以理解为内存中的缓存区,它用于暂时存储待处理的数据或文件,并能够提高程序的读写速度和响应时间。
3、 在实际应用中,选择合适的缓存窗口大小需要考虑多个因素,包括数据大小、读写频率、系统内存大小、CPU处理能力等,以及操作系统、数据库、网络传输等其他相关因素。通常情况下,我们可以通过建立模拟测试环境来评估不同缓存窗口大小对系统性能的影响,并根据测试结果进行调整和优化。

注意点二:
其中数据量大时,使用SXSSFWorkbook需要:

if (sheet instanceof SXSSFWorkbook) {
    // 一些情况下,可能会在循环遍历过程中频繁地创建行(Row)对象,此时执行完一定数量的行(Row)对象后,调用flushRows方法可以显式地告知系统将缓存数据写入磁盘,降低内存占用(避免OOM)。
    ((SXSSFSheet) sheet).flushRows()
}

1、一般来说,flushRows方法的调用频率取决于内存使用情况和可用内存的大小。如果数据量很大,内存持续占用,就需要更加频繁地调用flushRows方法,以便及时释放内存。
2、 具体来说,可以根据系统的可用内存、JVM的堆内存设置以及数据集合所需内存的大小等变化情况,适当调整flushRows方法的使用策略。常见的建议是每3000~5000行调用一次flushRows方法,这样可以有效地平衡内存占用和程序性能。
3、特别是在处理大数据集时,推荐使用SXSSF工作簿,并结合设置缓存窗口大小的方式来优化性能:通过SXSSFWorkbook类的setRowAccessWindowSize(int rowAccessWindowSize)方法,来设置缓存窗口大小,在写入数据时,只有在当前窗口内的数据才会被缓存到内存中,之外的数据将直接写入到硬盘上,并且该窗口会随着当前位置的移动而进行滚动更新,从而实现最大程度的内存优化。

1)根据数据量选择XSSFWorkbook,还是SXSSFWorkbook

已有一套XSSFWorkbook导出,但是当数据量较大时(假如3000条以上),我想使用SXSSFWorkbook流式导出

demo如下,
在我保留XSSFWorkbook的前提下,数据量大使用SXSSFWorkbook,数据量小依旧使用XSSFWorkbook,


    def exportPersonPool(@Nullable Object... args) {      
        try {
            // 查询数据量
            Long count = 2000// 查询数据库,统计待导出数据总数
            
            def wb
            if (count > PERSON_MAX_SIZE) {
                wb = exportPersonPoolLarge(args, count)
            } else {
                wb = exportPersonPoolSmall(args)
            }
            // 生成导出路径,略
            return MyExcelUtil.getMyExportExcel(wb, String.format("测试导出表%s%s",System.currentTimeMillis(), ExcelUtil.XLSX))
        } catch (Exception ex) {
            logger.error("导出失败", ex)
        }
    }

    /**
     * 大数据量
     */
    SXSSFWorkbook exportPersonPoolLarge(@Nullable Object... args, Long count) {
    	// 使用默认窗口大小100
        SXSSFWorkbook wb = new SXSSFWorkbook()
        // 获取sheet,并填充数据
        SXSSFSheet sheet = wb.createSheet("mySheet")
        // 设置导出头,略
        buildPoolSheetHeader(wb, sheet, args)
        // 设置当前页1\2,
        int countPageIndex = (int) Math.ceil(count / PERSON_MAX_SIZE)
        for (int i = 1; i <= countPageIndex; i++) {
            List<Map<String, Object>> dataList = getPersonPool(args, i)// 分页查询数据库
            // 填充sheet,略
            fillPoolSheet(wb, sheet, fillList, dataList, i)
        }
        return wb
    }

    /**
     * 小数据量
     */
    XSSFWorkbook exportPersonPoolSmall(@Nullable Object... args) {
        XSSFWorkbook wb = new XSSFWorkbook()
        // 获取sheet,并填充数据
        XSSFSheet sheet = wb.createSheet("mySheet")
        // 设置导出头,略
        buildPoolSheetHeader(wb, sheet, args)
        List<Map<String, Object>> dataList = getPersonPool(args,1)// 查询数据库(第一页)
        // 填充sheet,略
        fillPoolSheet(wb, sheet, fillList, dataList, 1)

        return wb
    }

	 /**
	  * 填充sheet
	  */
	private void fillPoolSheet(@Nullable Object... args) {
		// 略
	
	
		if (sheet instanceof SXSSFWorkbook) {
	        ((SXSSFSheet) sheet).flushRows()
	    }
	}


上文路径:工具类——Java 浏览器导入、导出Excel(Java import、export)
如何生成临时文件,参考:导出/service后半段
如何浏览器下载,参考:导出/controller后半段

为脱敏手改代码,可能存在错误,还请与我交流,谢谢!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: NPOI是一个.NET平台下的excel读写操作类库。通过NPOI,我们可以轻松地读取、写入excel文件,同时支持导入和导出excel文件。 使用NPOI进行导出操作时,首先需要初始化一个Workbook对象,该对象代表着Excel文件的整个文档,可以通过其创建Sheet对象,代表着Excel文件中的一个工作表。然后我们对Sheet进行行列操作,使用CellStyle对单元格进行样式设置,最后使用FileStream将Workbook对象写入内存中或者硬盘上即可以实现导出Excel的操作。 需要注意的是,为了确保程序的性能和效率,我们可以在导出Excel文件时采用分段写入的方式,这样可以避免一次性将所有数据写入Excel文件,导致内存溢出或程序崩溃的情况发生。同时,我们可以对导出代码进行优化,将公共代码提取出来进行复用,提高程序的重用性和可维护性。 总之,使用NPOI进行Excel导出操作可以方便、快捷地实现数据表格的导出,同时可以根据业务需求对导出Excel文件进行定制化设置,为业务开发提供强有力的支持。 ### 回答2: NPOI是一个适用于.NET应用程序的开源类库,它能够帮助我们实现许多与Excel文件相关的操作,包括读取、写入、修改、导入和导出等。其中,NPOI的Excel导出操作类尤为重要,因为它可以帮助我们以程序化的方式生成并导出Excel文件,并控制文件格式和样式。 NPOI的Excel导出操作类通常需要使用Workbook类和Sheet类来完成。Workbook是Excel文档的主要类,它可以包含多个Sheet。Sheet则是Excel文档中的工作表,我们可以在Sheet中添加行和单元格,并指定它们的数据和格式。 Excel导出操作的一般步骤如下:首先,我们需要实例化一个Workbook对象,并在其中添加一个或多个Sheet。然后,在Sheet中逐行逐列地添加数据和样式。最后,我们可以将Workbook对象保存为Excel文件,或者将其输出到一个流中。 NPOI的Excel导出操作类通常提供了一些简便的方法来帮助我们导出Excel文件,比如将DataTable或List转换成Excel中的一张表格。此外,NPOI还提供了许多功能强大的类库和工具,可以帮助我们自动生成和处理Excel文档,从而提高我们的开发效率和业务质。 ### 回答3: NPOI 是实现了 Microsoft Office Open XML 标准的 .NET 应用程序开发库,可以与 Excel、Word 和 PowerPoint 文件进行交互。通过 NPOI,我们可以方便地将数据导出Excel。 在使用 NPOI 实现导出Excel 的操作时,我们需要先引用 NPOI 库,然后通过代码创建 Excel 工作簿(Workbook)、工作表(Sheet)和单元格(Cell)。我们可以通过设置单元格的样式(Style)及合并单元格等方式来控制 Excel 的排版和样式。在数据绑定方面,我们可以使用 NPOI 提供的 DataTable、DataSet 等数据源对象,也可以自行在代码中构建数据表格,通过遍历数据表格将数据填充至工作表中。 在导出数据至 Excel 的操作完成后,我们还需要将工作簿保存为 Excel 文件。NPOI 提供了多种保存格式,包括 Excel 97-2003(.xls)、Excel 2007 及以上版本(.xlsx)等,并且可以通过设置文件名和存储位置来保存文件。 总体来说,使用 NPOI 导出Excel 操作类具有灵活性高、可扩展性强的优势,可以满足不同场景下的数据导出需求。同时,在导出数据时,也可以通过分批次处理数据、分页等方式来提高导出效率和降低内存占用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈年_H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值