Springboot + EasyExcel + Vue 实现excel下载功能

一、添加EasyExcel依赖

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

二、后端代码示例

controller:

    @GetMapping("/download")
    public void download(HttpServletResponse response) throws IOException {
        String dataFormat = new SimpleDateFormat("yyyyMMdd").format(new Date());
        //xlsx格式:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet  xls格式:application/vnd.ms-excelExport
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("满意度调查信息导出表" + dataFormat, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel
                .write(response.getOutputStream(), ScorePsnExcelDTO.class)
                .registerWriteHandler(EasyExcelUtils.getStyle())//引用样式
                .registerWriteHandler(new CustomCellWriteWidthConfig())//自适应列宽
                .registerWriteHandler(new CustomCellWriteHeightConfig())//自适应行高
                .sheet("调查表")
                .doWrite(data());//业务数据
    }

DTO(模板数据):

package cn.hsa.pss.pw.web.thirdinterface.excelExport.dto;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 * 医疗机构评价 -评价人DTO
 *
 * @Author:
 * @Date:2024-01-23 16:46
 * @Description:
 */
@Data
public class ScorePsnExcelDTO {

    @ExcelProperty(value = "序号", index = 0)
    private Integer no;

    //定点统筹区(参保人统筹区
    @ExcelProperty(value = "定点统筹区", index = 1)
    private String areaCode;

    //医药机构编码
    @ExcelProperty(value = "医药机构编码", index = 2)
    private String medInsCode;

    //医药机构名称
    @ExcelProperty(value = "医药机构名称", index = 3)
    private String medInsName;

    //医药机构类型
    @ExcelProperty(value = "医药机构类型", index = 4)
    private String medInsType;

    //医疗类别
    @ExcelProperty(value = "医疗类别", index = 5)
    private String medType;

    //就医人次
    @ExcelProperty(value = "就医人次", index = 6)
    private Integer medNum;

    //参与调查人次
    @ExcelProperty(value = "参与调查人次", index = 7)
    private Integer scoreNum;

    //很不满意
    @ExcelProperty(value = {"评价分布", "很不满意"}, index = 8)
    private Integer scoreOne;

    //不满意
    @ExcelProperty(value = {"评价分布", "不满意"}, index = 9)
    private Integer scoreTwo;

    //一般
    @ExcelProperty(value = {"评价分布", "一般"}, index = 10)
    private Integer scoreThree;

    //比较满意
    @ExcelProperty(value = {"评价分布", "比较满意"}, index = 11)
    private Integer scoreFour;

    //很满意
    @ExcelProperty(value = {"评价分布", "很满意"}, index = 12)
    private Integer scoreFive;

    //参与调查率
    @ExcelProperty(value = "参与调查率", index = 13)
    private Double scoreRate;

    //满意度
    @ExcelProperty(value = "满意度", index = 14)
    private String goodRate;
}

关键点1:响应头设置

//如果前端接收xlsx格式,则
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

//如果前端接收xls格式,则
        response.setContentType("application/vnd.ms-excelExport");

关键点2:ScorePsnExcelDTO 

1、 @ExcelProperty(value = "序号", index = 0) 

value对应的导出excel的列名,index代表顺序

2、如果涉及到单元格合并,可以这么写:

@ExcelProperty(value = {"评价分布", "很不满意"}, index = 8)

 @ExcelProperty(value = {"评价分布", "一般"}, index = 10)

效果如下:

关键点3:

要使用get方法

自适应行高:

package cn.hsa.pss.pw.web.thirdinterface.excelExport.config;

import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;

import java.util.Iterator;

/**
 * 自适应行高
 *
 * @Author:
 * @Date:2024-02-01 14:00
 * @Description:
 */
public class CustomCellWriteHeightConfig extends AbstractRowHeightStyleStrategy {

    /**
     * 默认高度
     */
    private static final Integer DEFAULT_HEIGHT = 300;

    @Override
    protected void setHeadColumnHeight(Row row, int relativeRowIndex) {

    }

    @Override
    protected void setContentColumnHeight(Row row, int relativeRowIndex) {
        Iterator<Cell> cellIterator = row.cellIterator();
        if (!cellIterator.hasNext()) {
            return;
        }
        // 默认为 1行高度
        int maxHeight = 1;
        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();
            if (cell.getCellTypeEnum() == CellType.STRING) {
                String value = cell.getStringCellValue();
                int len = value.length();
                int num = 0;
                if (len > 50) {
                    num = len % 50 > 0 ? len / 50 : len / 2 - 1;
                }
                if (num > 0) {
                    for (int i = 0; i < num; i++) {
                        value = value.substring(0, (i + 1) * 50 + i) + "\n" + value.substring((i + 1) * 50 + i, len + i);
                    }
                }
                if (value.contains("\n")) {
                    int length = value.split("\n").length;
                    maxHeight = Math.max(maxHeight, length) + 1;
                }
            }
        }
        row.setHeight((short) ((maxHeight) * DEFAULT_HEIGHT));
    }


}

自适应列宽:

package cn.hsa.pss.pw.web.thirdinterface.excelExport.config;

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 自适应列宽
 *
 * @Author:
 * @Date:2024-02-01 13:38
 * @Description:
 */
public class CustomCellWriteWidthConfig extends AbstractColumnWidthStyleStrategy {

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

    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            Map<Integer, Integer> maxColumnWidthMap = CACHE.computeIfAbsent(writeSheetHolder.getSheetNo(), k -> new HashMap<>());

            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
            // 单元格文本长度大于60换行
            if (columnWidth >= 0) {
                if (columnWidth > 60) {
                    columnWidth = 60;
                }
                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<WriteCellData<?>> 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;
                }
            }
        }
    }


}

字体样式工具类:

package cn.hsa.pss.pw.web.thirdinterface.excelExport.utils;

import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;

import java.util.ArrayList;

/**
 * 设置excel工具类
 *
 * @Author:wangguangxing
 * @Date:2024-02-01 14:18
 * @Description:
 */
public class EasyExcelUtils {

    public static HorizontalCellStyleStrategy getStyle() {
//自定义表头样式  浅橙色 居中
        WriteCellStyle headCellStyle = new WriteCellStyle();
        headCellStyle.setFillForegroundColor(IndexedColors.TAN.getIndex());  //表头颜色
        headCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);    //文本居中
        //字体
        WriteFont writeFont = new WriteFont();
        writeFont.setFontName("微软雅黑");                                   //字体
        writeFont.setFontHeightInPoints((short) 10);                         //字体大小
        headCellStyle.setWriteFont(writeFont);
        // 自动换行
        headCellStyle.setWrapped(true);

        //内容样式
        WriteCellStyle contentCellStyle = new WriteCellStyle();
        contentCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); //文本居中
        contentCellStyle.setWriteFont(writeFont);
        //设置边框
        contentCellStyle.setBorderLeft(BorderStyle.THIN);                    //左边框线
        contentCellStyle.setBorderTop(BorderStyle.THIN);                     //顶部框线
        contentCellStyle.setBorderRight(BorderStyle.THIN);                   //右边框线
        contentCellStyle.setBorderBottom(BorderStyle.THIN);                  //底部框线
        ArrayList<WriteCellStyle> contentCells = new ArrayList<>();
        contentCells.add(contentCellStyle);
        //样式策略
        HorizontalCellStyleStrategy handler = new HorizontalCellStyleStrategy();
        handler.setHeadWriteCellStyle(headCellStyle);                        //表头样式
        handler.setContentWriteCellStyleList(contentCells);                  //内容样式
        return new HorizontalCellStyleStrategy(headCellStyle, contentCells);
    }
}

三、前端代码示例

1、
     exportFile() {
          
                this.downLoading = true
                exportScoreList().then((res) => {
                    this.downLoading = false
                    const str = res.headers["content-disposition"]
                    const fileName = decodeURI(str.substr(str.indexOf("%")))
                    this.downloadFile(res.data, fileName)
                }).catch((err) => {
                    this.downLoading = false
                })
            }


2、
 downloadFile(res, fileName) {
               
                let blob = new Blob([res], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
                if (!fileName) {
                    fileName = res.headers['content-disposition'].split('filename=').pop();
                }
                if ('msSaveOrOpenBlob' in navigator) {
                    window.navigator.msSaveOrOpenBlob(blob, fileName);
                } else {
                    const elink = document.createElement('a');
                    elink.download = fileName;
                    elink.style.display = 'none';
                    elink.href = window.URL.createObjectURL(blob);
                    document.body.appendChild(elink);
                    elink.setAttribute('href', elink.href)
                    elink.click();
                    document.body.removeChild(elink);
                    window.URL.revokeObjectURL(elink.href);

                }
            }

3、
export function exportScoreList() {
    return axios({
        url: `${path}/excel/download`,
        method: "get",
        responseType: "blob"
    });
}

关键点1:

responseType: "blob"    method: "get",

关键点2:

 let blob = new Blob([res], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}) 

要与后台响应头类型对应上。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SwiftUI 动画入门之一:路径动画(Path Animations)

概览 在 SwiftUI 的开发中,我们往往需要使用千姿百态的动画把我们的界面元素妆点的更加鲜活灵动。 如上图所示,我们使用路径动画使折线图更加生动了!这是怎么做到的呢? 在本篇博文中,您将学到以下内容: 概览1. 路径与形状(Path and Shape)2. 路径动画的原理3. 让路径…

Springboot 批量增加redis中的数据,并批量设置过期时间

1. 背景 一个功能需要一次性解析大量数据放到 Redis 中缓存&#xff0c;并且每个 key 都需要设置过期时间&#xff0c;但是 Redis 本身命令不支持批量设置过期时间&#xff0c;RedisTemplate 中也没有相关的方法。 2. 实现方式 1. RedisTemplate 使用 redisTemplate.opsForV…

工业物联网接入网关在制造企业的实际应用-天拓四方

随着工业4.0和智能制造的兴起&#xff0c;工业物联网&#xff08;IIoT&#xff09;已成为工厂自动化的关键驱动力。在这个转变中&#xff0c;工业物联网网关扮演着至关重要的角色。它们充当了设备与企业系统之间的桥梁&#xff0c;实现了数据采集、分析和设备控制等功能。 案例…

linux安装mysql客户端--极速成功版

翻了无数个帖子都没有安装好&#xff0c;遇到了各种各样奇奇怪怪的问题。结果看了菜鸟教程的步骤&#xff0c;一路顺利&#xff0c;5分钟装完。 1、安装前&#xff0c;检测系统是否自带安装 MySQL rpm -qa | grep mysql2、安装mysql 下载 wget http://repo.mysql.com/mysql-…

Modbus协议学习第六篇之基于libmodbus库的示例程序(可以联合Modbus模拟仿真软件进行调试)

前置工作 学了这么多Modbus的知识&#xff0c;如果不进行实际的操作&#xff0c;总感觉懂的不透彻。基于此&#xff0c; 本篇博文就带各位读者来了解下如何通过编写程序来模拟与Modbus Slave仿真软件的通讯。当然了&#xff0c;这里有两个前提&#xff0c;如下&#xff1a; 1.请…

【AutoCAD2023】删除验证组件+桌面应用程序+登陆组件方法

Autodesk删除验证组件桌面应用程序登陆组件方法&#xff1a; :: 建议在安装前找到官方安装包释放后的安装文件所在位置 例如&#xff1a;AutoCAD_2023_Simplified_Chinese_Win_64bit_dlm 删除验证组件Autodesk Genuine Service -> x64\AGS (必删) 删除桌面程序Autodesk Desk…

2023安防行业十件大事,一定有你关心的

2023年对我国安防行业来说&#xff0c;可以说是既充满希望又充满不确定性的一年。经历三年的市场低迷&#xff0c;2023年安防市场开始逐渐回暖&#xff0c;行业景气度缓慢上升。 那么&#xff0c;2023年我国安防行业都发生了哪些值得铭记的大事&#xff1f;哪些事件对安防产业…

浏览器内存泄漏排查指南

1、setTimeout执行原理 使用setInterval/setTimeOut遇到的坑 - 掘金 2、Chrome自带的Performance工具 当我们怀疑页面发生了内存泄漏的时候&#xff0c;可以先用Performance录制一段时间内页面的内存变化。 点击开始录制执行可能引起内存泄漏的操作点击停止录制 如果录制结束…

实现vue3响应式系统核心-shallowReactive

简介 今天来实现一下 shallowReactive 这个 API。 reactive函数是一个深响应&#xff0c;当你取出的值为对象类型&#xff0c;需要再次调用 reactive进行响应式处理。很明显我们目前的代码是一个浅响应&#xff0c;即 只代理了对象的第一层&#xff0c;也就是 shallowReactiv…

wespeaker项目grpc-java客户端开发

非常重要的原始参考资料&#xff1a; 链接: triton-inference-server/client github/grpc java ps&#xff1a; 使用grpc协议的其它项目python/go可以参考git hub目录client/tree/main/src/grpc_generated下的其它项目 其它链接&#xff1a; 想要系统了解triton-inference-ser…

#《AI中文版》V3 第 3 章 知情搜索

参考链接&#xff1a; [1] 开源内容&#xff1a;https://github.com/siyuxin/AI-3rd-edition-notes [2] Kimi Chat官网链接 正文笔记 P90 针对 大型问题。 知情搜索&#xff08;informed search&#xff0c;也称有信息搜索&#xff09;&#xff1a;利用启发式方法&#xff0c…

新版多功能去水印工具微信小程序源码下载+带流量主功能

新版多功能去水印工具微信小程序源码下载&#xff0c;带流量主功能。自带去水印接口的多功能小程序&#xff0c;支持各大平台短视频去水印。 支持保存封面、图集、标题等等&#xff1b;支持本地图片去水印&#xff1b;支持图片拼接&#xff1b;支持九宫格切图&#xff1b;支持…

如何实现任意设备远程SSH访问Deepin操作系统【内网穿透】

文章目录 推荐前言1. 开启SSH服务2. Deppin安装Cpolar3. 配置ssh公网地址4. 公网远程SSH连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击跳…

三、软硬件工作流程分析

现在的计算机主要是由两部分组成&#xff1a;软件系统和硬件系统。这里先捋清楚硬件和软件的关系&#xff0c;以及电脑 各个组成部分是如何配合工作的。 软件系统主要被分类为两大类&#xff1a; 系统软件&#xff1a;这包括操作系统&#xff0c;如Windows、Linux等。操作系统是…

果冻跳跃

欢迎来到程序小院 果冻跳跃 玩法&#xff1a;点击果冻跳跃&#xff0c;果冻会消失掉&#xff0c;果冻只能跳一个果冻的距离高度&#xff0c;共36关卡&#xff0c; 不同关卡有不同的跳板&#xff0c;快去闯关吧^^。开始游戏https://www.ormcc.com/play/gameStart/265 html <…

【全csdn最前沿LVGL9】按钮的使用(lv_button)、标签的使用(lv_label)

文章目录 前言一、按钮概述二、按钮的使用2.1 创建一个按钮2.2 按钮的样式 三、标签概述四、标签的使用4.1 创建一个标签4.2 样式4.3 设置文本4.4 长文本模式4.5 文本选择4.6 文本对齐4.7 非常长的文本4.8 字体设置字体支持的Unicode字符字体列表特殊的字体 总结 前言 欢迎来到…

CXO清单:低代码平台必备的16个基本功能:从需求到实现的全面指南

对于 CIO、CTO 和 CDO&#xff08;在此统称为 CXO&#xff09;来说&#xff0c;认识到快速变化的技术和竞争格局以及他们在组织中的角色变化至关重要。处理持续不断的软件开发请求、考虑不断变化的业务流程、提高客户和法规的透明度、提高企业数据安全性以及在短时间内扩展基础…

2024斋月大促跨境卖家准备指南

市场覆盖西欧、中东、东南亚、北非地区的跨境电商卖家注意了&#xff0c;2024年的斋月即将开启&#xff0c;较往年日期&#xff0c;今年提前了10天左右&#xff0c;斋月的第一天预测在3月11日星期一到来。 根据Google搜索数据可知&#xff0c;目前已经进入高频“斋月”搜索期&…

与数组相关经典面试题

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

嵌入式学习第十六天

制作俄罗斯方块小游戏&#xff08;一&#xff09; 分析&#xff1a; printf函数高级用法 \033[&#xff1a;表示转义序列的开始 m&#xff1a;表示转义序列的结束 0&#xff1a;重置所有属性 1&#xff1a;设置粗体或高亮 30-37&#xff1a;设置字体色 30: 黑 31: 红 32:…