SpringBoot实现导出Excel功能

news2024/11/18 0:14:31

在这里插入图片描述

1 问题背景

需求要做一个导出excel的功能

2 前言

本篇着重阐述后端怎么实现,前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的,不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。

3 实现思路

  1. 后端查询要导出的数据,此处简称data
  2. 使用阿里的EasyExcel组件将data写道HttpServletResponse里面,返回指定的响应头、响应内容的类型、字符编码。响应出去的数据是二进制数据,此处简称bytes数据
  3. 前端使用前端框架提供的方法,将 bytes数据转成blob,然后生成下载地址,然后进行下载

4 后端实现

要引入阿里的EasyExcel依赖,此处不赘述

<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>easyexcel</artifactId>
			<version>2.1.7</version>
		</dependency>

下面是excel文件要保存的信息,需要指定列头

@Data
public class UserInfoVO {
  @ExcelProperty(value = "用户ID",index = 0)
  private Long id;
  @ExcelProperty(value = "用户姓名",index = 1)
  private String username;
  @ExcelProperty(value = "性别",index = 2)
  private String sex;
}

导出的伪代码如下:

  @PostMapping("/xx/xxx/xxx")
  public void export(HttpServletResponse reponse) {
        // 设置响应头等
        response.setHeader("Content-Disposition", "attachment;filename=" + "文件名(随便定义).xlsx");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("UTF-8");

        // 查数据,假如要导出UserInfo的列表信息
        List<UserInfoVO> data = selectData();
       // 导出数据 
       EasyExcel.write(response.getOutputStream()).head(UserInfoVO.class).sheet().doWrite(data);
  }

5 设置Excel自适应列宽

思路:实现easyexcel提供的类并重写方法,写数据到HttpServletReponse的时候注册一个自适应列宽的bean

实现AbstractColumnWidthStyleStrategy类,如下所示:

public class CustomCellWriteWeightConfig extends AbstractColumnWidthStyleStrategy {

    private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());
            if (maxColumnWidthMap == null) {
                maxColumnWidthMap = new HashMap<>();
                CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
            }

            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
            if (columnWidth >= 0) {
                if (columnWidth > 254) {
                    columnWidth = 254;
                }

                Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                    Sheet sheet = writeSheetHolder.getSheet();
                    sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
                }

            }
        }
    }

    /**
     * 计算长度
     * @param cellDataList
     * @param cell
     * @param isHead
     * @return
     */
    private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        // 换行符(数据需要提前解析好)
                        int index = cellData.getStringValue().indexOf("\n");
                        return index != -1 ?
                                cellData.getStringValue().substring(0, index).getBytes().length + 1 : cellData.getStringValue().getBytes().length + 1;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
}

注册自适应列宽的组件:

EasyExcel.write(response.getOutputStream())
                    .head(SubscriptionOrderExportResp.class)
                    //  注册自适应列宽组件
                    .registerWriteHandler(new CustomCellWriteWeightConfig())
                    .sheet()
                    .doWrite(data);

6 方案优缺点

优点:

实现简单,轻量级。能快速迭代上线 。

缺点:

使用了同步方式返回数据,如果excel文件很多,那么将耗费很多时间,甚至http连接已经断开了还未响应出去。

改进:

本文解决方案是采用了同步方式导出,实时返回excel文件。可以做一个异步方式,后端创建一个任务异步生成excel文件,然后文件上传到对象存储服务器。前端轮询任务是否完成,后端返回文件地址给前端下载。

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

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

相关文章

103. 二叉树的锯齿形层序遍历【191】

难度等级&#xff1a;中等 上一篇算法&#xff1a; 104. 二叉树的最大深度【75】 力扣此题地址&#xff1a; 103. 二叉树的锯齿形层序遍历 - 力扣&#xff08;Leetcode&#xff09; 1.题目&#xff1a;103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root &#xff0c;返回其…

p65 内网安全-域环境工作组局域网探针方案

数据来源 基本概念 DMZ区域&#xff1a;称为“隔离区”&#xff0c;也称‘’非军事化区/停火区” 工作组&#xff08;Work Group&#xff09;是局域网中的一个概念。它是最常见最简单最普通的资源管理模式&#xff0c;就是将不同的电脑按功能分别列入不同的组中&#xff0c;以…

完美解决丨except NameError:

示例如下&#xff1a; try: print(xx) except: print(xx is not defined) print(continue) 解决办法 第一种解决办法&#xff1a; try: print(xx) except NameError: print(xx is not defined) print(continue) 第二种解决办法&#xff1a; print(xx) if xx in locals() e…

camunda工作流user task如何使用

在Camunda中使用User Task通常需要以下步骤&#xff1a; 1、创建User Task&#xff1a;使用BPMN 2.0图形化设计器&#xff08;如Camunda Modeler&#xff09;&#xff0c;将User Task元素拖到流程图中&#xff0c;并为任务命名&#xff0c;指定参与者&#xff08;用户或用户组…

第二章 Maven 核心程序解压和配置

第一节 Maven核心程序解压与配置 1、Maven 官网地址 首页&#xff1a; Maven – Welcome to Apache Maven(opens new window) 下载页面&#xff1a; Maven – Download Apache Maven(opens new window) 下载链接&#xff1a; 具体下载地址&#xff1a;https://dlcdn.apac…

算法:(力扣)(牛客)打印螺旋矩阵题

手撕螺旋矩阵 题目思路解题 题目 描述&#xff1a;给定一个m x n大小的矩阵&#xff08;m行&#xff0c;n列&#xff09;&#xff0c;按螺旋的顺序返回矩阵中的所有元素。数据范围&#xff1a;0 \le n,m \le 100≤n,m≤10&#xff0c;矩阵中任意元素都满足 |val| \le 100∣val…

makefile 规则的覆盖

makefile 中经常会使用规则的覆盖&#xff0c;同样一个target 可能有多个prerequisites&#xff0c;这种依赖关系可以放到一起&#xff0c;也可以分开指定。 例1&#xff1a; test1:echo "test111"test2:echo "test222"test3:echo "test333"he…

vsync-app 不稳定导致抖动

问题描述&#xff1a;跟对比机器对比uc 浏览器新闻页滑动场景&#xff0c;出现抖动 1、trace 看是没有丢帧&#xff0c;对比看送帧buffer 给到 SF 步调不够一致&#xff0c;从间隔较大的两个 送帧buffer看&#xff0c;发现vsync-app 时间比正常的要长3ms 左右&#xff0c;vsync…

网络交换机端口管理工具

如今&#xff0c;企业或组织级网络使用数百个交换机端口作为其 IT 基础架构的一部分来实现网络连接。这使得交换机端口管理成为日常网络管理任务的一部分。传统上&#xff0c;网络管理员必须依靠手动网络交换机端口管理技术来跟踪交换机及其端口连接状态。这种手动任务弊大于利…

基于斯坦福大学开源,从零搭建chatGPT

下载地址&#xff1a; https://huggingface.co/datasets/togethercomputer/RedPajama-Data-1T 预处理仓库&#xff1a;https://github.com/togethercomputer/RedPajama-Data 复刻ChatGPT&#xff01;斯坦福等开启红睡衣计划&#xff0c;开源1.2万亿token训练集 【新智元导读…

JAVA队列(Queue)用法附实例讲解

队列是什么 队列用于模拟队列这种数据结构&#xff0c;队列通常是指“先进先出”的容器。新元素插入&#xff08;offer&#xff09;到队列的尾部&#xff0c;访问元素&#xff08;poll&#xff09;操作会返回队列头部的元素。通常&#xff0c;队列不允许随机访问队列中的元素 …

【JavaWeb】Servlet(崔老师版)

文章目录 1.概述1.1 JavaWeb三大组件1.2 Servlet作用 2.ServletConfig接口3.Servlet接口3.1 实现Servlet的方式3.2 Servlet生命周期 4.HttpServlet抽象类6.ServletContext5.1 概述5.2 获取ServletContext5.3 JavaWeb四大域对象5.4 获取应用初始化参数5.5 ServletContext获取资源…

【UML建模】时序图(Sequence Diagram)

文章目录 1.概述2.时序图的组成元素2.1.角色&#xff08;Actor&#xff09;2.2.实体和对象2.3.生命周期线&#xff08;Lifeline&#xff09;2.3.1.激活&#xff08;Activation&#xff09;2.3.2.消息&#xff08;Messages&#xff09;2.3.3.组合片段&#xff08;Fragments&…

learn C++ NO.1——命名空间域、输入输出、函数重载

前言 什么是C C&#xff08;c plus plus&#xff09;是一种计算机高级程序设计语言&#xff0c;由C语言扩展升级而产生&#xff0c;最早于1979年由本贾尼斯特劳斯特卢普在AT&T贝尔工作室研发。C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的…

Cache存储系统详解(全相联映射、直接映射、组相联映射、替换策略和性能计算)

1. 存储系统的层次结构 为了解决容量、速度和价格之间的矛盾&#xff0c;把各种不同存储容量&#xff0c;不同存取速度&#xff0c;不同价格的存储器&#xff0c;按照一定的体系结构组织起来&#xff0c;使所存放的程序和数据按层次分布在各存储器中&#xff0c;形成---多层次的…

读书笔记//《数据科学工程实践》

出版时间&#xff1a;2021年11月 副标题&#xff1a;用户行为分析、A/B实验、SQLFlow 作者们是一线互联网企业的数据科学家、数据分析师和算法工程师&#xff0c;主要就职于滴滴、部分就职于腾讯、快手等。 点评&#xff1a;神仙下凡布道。感谢大佬们的分享。本书让我领略了大厂…

小白也能看懂,解读数据中台

不同的企业对数据有不同的需求。企业数据应用不断更新迭代&#xff0c;企业的中台系统也需要不断变化。从数据处理与数据治理两个维度出发&#xff0c;可以设计一个解耦的数据中台体系架构。该数据中台体系架构具有一定的柔性&#xff0c;可按照企业应用需求进行组合&#xff0…

多语言(CurlPHPPHPsdkJAVAC#Python)调用阿里巴巴商品API接口

2月2日消息&#xff0c;《晚点LatePost》独家报道&#xff0c;阿里集团国内批发业务1688近期完成了一系列组织和业务调整。其中&#xff0c;原1688商贸发展中心和产地发展中心合并为1688商家发展中心&#xff0c;由原商贸发展中心总经理王强负责&#xff1b;1688新成立分销供应…

苹果天气应用专利获批,苹果Find My技术改变防丢技术走向

根据美国商标和专利局&#xff08;USPTO&#xff09;公示的清单&#xff0c;苹果近日获得了名为“用于管理天气信息的用户界面”专利&#xff0c;编号为 US 11630559 B2。 苹果在专利描述中表示&#xff0c;部分管理天气信息的技术复杂且效率低下&#xff0c;用户需要多次点击…

spring redis Sentinel 哨兵 原理

客户端选择 redis 常用的连接客户端 有三个 Jedis&#xff1a;是老牌的Redis的Java实现客户端&#xff0c;提供了比较全面的Redis命令的支持&#xff0c;Redisson&#xff1a;实现了分布式和可扩展的Java数据结构。Lettuce&#xff1a;高级Redis客户端&#xff0c;用于线程安…