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

news2025/1/22 18:50:26

文章目录

  • 一、POI设置样式
  • 二、POI导出图片
    • 1.解释XSSFClientAnchor
  • 三、加载指定模板导出
  • 四、👉Workbook、XSSFWorkbook与SXSSFWorkbook
    • 1.大数据量导出
      • 1)根据数据量选择XSSFWorkbook,还是SXSSFWorkbook

书接上篇:工具类——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后半段

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/468717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习笔记之密度聚类——DBSCAN方法(Python代码实现)

机器学习笔记之密度聚类——DBSCAN方法[Python代码实现] 引言基本思想概念介绍算法过程完整算法描述 DBSCAN \text{DBSCAN} DBSCAN的优点和缺陷 2023/4/25 \text{2023/4/25} 2023/4/25补充&#xff1a;基于 Python \text{Python} Python的代码实现 引言 本节将介绍密度聚类——…

【MySQL】索引与事务

索引&#xff1a; 什么是索引&#xff1f;为什么要⽤索引 为了提高查询效率而使用的一种数据结构把数据组织起来&#xff1b; 例如生活中的字典&#xff1a;声母&#xff0c;韵母&#xff0c;声调。 创建索引&#xff1a;自动创建的主键约束&#xff0c;唯一约束&#xf…

qiankun-微前端

项目结构 主应用&#xff1a; vue3 vite 子应用1&#xff1a;vue3 vite 背景介绍 项目采用了vue3vite构建的&#xff0c;又因为qiankun不支持vite&#xff0c;所以需要引用 vite-plugin-qiankun 插件来解决 主应用–改造 安装 qiankun npm install qiankun重新定义一个…

浅浅入门SpringBoot之Thymeleaf模板

Thymeleaf是一个流行的模板引擎,该模板引擎采用Java语言开发模板引擎是一个技术名词,是跨领域跨平台的概念,在Java语言体系下有模板引擎,在C#、PHP语言体系下也有模板引擎,甚至在 Javascript中也会用到模板引擎技术,Java生态下的模板引擎有 Thymeleaf、 Freemaker、Ⅴ elocity、…

【EMQX】EMQX管理控制台即EMQX Dashboard简介

EMQX管理控制台 一、EMQX Dashboard简介二、主要功能2.1 监控和管理 EMQX 集群中的相关信息与数据2.2 访问控制&#xff08;认证与授权&#xff09;管理2.3 数据集成2.4 在线配置热更新2.5 管理系统扩展能力2.6 全面的诊断工具 三、启动3.1 首次登录3.2 忘记密码 四、配置 Dash…

我老板:你根本不懂 React!

前言 我已经使用 React 多年&#xff0c;我确信我非常了解它&#xff0c;但最近我的老板对我说&#xff0c;“你根本不知道 React&#xff0c;你对它一无所知。” 我很生他的气&#xff0c;但他指出了我程序中的三个漏洞。我现在把它记录下来&#xff0c;也分享给还不知道的小…

用好ChatGPT,毕业直接走上人生巅峰

毕业论文交上去了&#xff0c;学分也攒齐了。考研没上岸的准毕业生们接下来要面对的不是惨烈的秋招&#xff0c;就是蹲家准备二战。生活终于要对各位小可爱们动手啦&#xff01; 不想默默承受社会的毒打&#xff1f; 不愿在屡战屡败屡败屡战的压力下秃头&#xff1f; 想必各位…

API 都有这些功能,你真的都知道么?

API&#xff08;应用程序编程接口&#xff09;可以提供以下功能&#xff1a; 数据传输&#xff1a;API可以在应用程序之间传输数据&#xff0c;包括发送和获取数据、更新数据等。 访问功能: API 可以调用另一个系统或应用程序的某些功能&#xff0c;例如获取天气&#xff0c;查…

基于无线传感器网络(WSN) 查找两个节点之间的最短路径并发送数据(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 本代码基于无线传感器网络&#xff0c;在两个节点&#xff08;源节点和目标节点&#xff09;之间找到最短路径&#xff0c;并开…

Java学习过程(韩顺平661-665)

网络通信是指在计算机网络中&#xff0c;通过网络连接的设备之间进行数据交换的过程。网络通信可以分为两种类型&#xff1a;有线网络通信和无线网络通信。 有线网络通信主要通过物理介质&#xff08;如光纤、双绞线等&#xff09;来传输数据&#xff0c;其中最常用的协议是以…

数字孪生新能源智慧充电桩Web3D可视化运维系统

放眼全球&#xff0c;近十年来&#xff0c;新能源汽车赛道堪称“热得发烫”。伴随着进入成年期的新能源汽车行业对相关配套设备支撑水平的提升&#xff0c;作为其“新基建”的充电桩领域表现更为突出的价值势能。过去&#xff0c;在一系列补贴政策和资本刺激下&#xff0c;充电…

七种MOS管栅极驱动电路

01 直接驱动 首先说一下电源IC直接驱动&#xff0c;下图是我们最常用的直接驱动方式&#xff0c;在这类方式中&#xff0c;我们由于驱动电路未做过多处理&#xff0c;因此我们进行PCB LAYOUT时要尽量进行优化。如缩短IC至MOSFET的栅极走线长度&#xff0c;增加走线宽度&#x…

《商用密码应用与安全性评估》第三章商用密码标准与产品应用3.4商用密码标准与产品

一、智能IC卡标准与产品 智能IC卡的分类 存储器卡&#xff1a;内部一般不包含密码安全机制&#xff0c;不具备信息处理能力&#xff0c;外部可对片内信息任意存取&#xff0c;因此存储器卡一般用于存放不需要保密的信息逻辑加密卡&#xff1a;逻辑加密卡内除了具有非易失性存…

redis缓存生产实践(一)---大key压缩

文章目录 前言一、缓存到底是使用String还是hash我该如何选择二、什么是大key及其影响2.1 什么是 Redis 大 key&#xff1f;2.2 大key带来的影响 三、大key压缩3.1 注解标记可能需要压缩的数据3.2 获取注解信息判断内存占用大小3.2 判断对象占用内存3.2 gzip压缩json3.2 判断当…

Reid之损失函数理论学习讲解

基于深度学习的Reid主要流程为输入图像-->CNN(提取特征)-->Global average pooling-->特征向量&#xff0c;将用这些特征来衡量图像的相似情况。并用这些特征进行检索&#xff0c;返回分类情况。 在训练网络的时候需要涉及损失函数&#xff0c;因此就引出了表征学习和…

大数据专业好找工作么

现在&#xff0c;在数字化转型的推动下&#xff0c;越来越多的企业意识到大数据的魅力&#xff0c;并不断在这个领域投入资金&#xff0c;Python大数据开发相关人才也备受青睐&#xff01; 学Python之前&#xff1a;这玩意真有传说中那么好么&#xff1f; 学Python之后&#…

【browser】浏览器跨域处理

好久没有更新博客了&#xff0c;前段时间在疯狂面试&#xff0c;最近工作了才有时间来写博客。 准备来讲讲面试里常问到的跨域处理吧。 说到跨域&#xff0c;我们可能会下意思的说出jsonp&#xff0c;服务端配置cors&#xff0c;node配置代理等&#xff0c;再多了&#xff0c;我…

加密脱胎于去中心化理想,但力求合规 细数各国政府态度之演变

比特币诞生之始&#xff0c;只是极客文化圈内流行的小众货币。如今&#xff0c;加密市场已经发展到无法忽视的程度&#xff0c;虽然全球仍未对加密货币形成共识&#xff0c;但监管已成为各国政府不得不考虑的问题。 美国&#xff1a;监管愈发模糊且不可测 美国始终是加密领域全…

八股文(Mybatis)

文章目录 1. Mybatis缓存机制2. 动态SQL语句3. 分页3. 1 几种分页方式3.2 MyBatis 是如何进行分页的&#xff1f;分页插件的原理是什么&#xff1f;3.3 逻辑分页和物理分页 1. Mybatis缓存机制 作用&#xff1a;避免每次都去查db 一级缓存是SqlSession级别的缓存&#xff0c;也…