Java与Vue前端导出Excel表格文件并解决乱码和下载完后文件打不开情况

JAVA后端

<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>5.0.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>5.0.0</version>
</dependency>

后端实现 :

import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 江湖人称小程
 */
@RestController
@RequestMapping("export")
public class ExportExcelController {

    @GetMapping("data")
    public void exportData(HttpServletResponse response) {

        // 1. 创建工作空间
        Workbook workbook = new XSSFWorkbook(); // .xlsx 用 XSSFWorkbook
//        Workbook workbook = new HSSFWorkbook(); // .xls 用 HSSFWorkbook

        // 2. 创建工作表
        Sheet sheet = workbook.createSheet("学生信息");
        // 2.1 创建标题行(第一行)
        Row headerRow = sheet.createRow(0);


        /* 3. 定义一个字体(建议将定义字体这段代码,提取出来进行封装,后续可以定义各式各样的的字体) */
        // 3.1 创建字体
        Font headerFont = workbook.createFont();
        // 3.2 14号大小
        headerFont.setFontHeightInPoints((short) 14);
        // 3.3 黑色字体
        headerFont.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
        // 3.4 宋体
        headerFont.setFontName("宋体");

        /* 4. 声明样式 CellStyle,并设置 */
        // 4.1 创建 style
        CellStyle style = workbook.createCellStyle();
        // 4.2 将字体设置进 style 对象中
        style.setFont(headerFont);
        // 4.3 水平和垂直居中
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);

        /* 设置列宽和表头样式 */
        String[] headers= {"姓名", "性别", "年龄", "班级" , "联系方式" , "家庭住址"};
        for (int i = 0; i < headers.length; i++) {
            // 设置每一列的宽度
            sheet.setColumnWidth(i, 230*30);
            // 设置每一列的 style 和 标题
            Cell headerCell = headerRow.createCell(i);
            headerCell.setCellStyle(style);
            headerCell.setCellValue(headers[i]);
        }

        /* 模拟数据 */
        List<Student> students = new ArrayList<>();
        students.add(new Student("小明", "男", 17, "三年二班", "1524215241", "牛牛村"));
        students.add(new Student("小红", "女", 16, "三年二班", "1524215241", "牛牛村"));
        students.add(new Student("小张", "女", 17, "三年二班", "1524215241", "牛牛村"));
        students.add(new Student("小李", "男", 18, "三年二班", "1524215241", "牛牛村"));
        students.add(new Student("小王", "nv", 16, "三年二班", "1524215241", "牛牛村"));

        /* 遍历 */
        for (int j = 0; j < students.size(); j++) {
            Row row = sheet.createRow(j + 1);
            for(int i = 0;i < headers.length ;i++){
                Cell cell = row.createCell(i);
                // 每一列的数据与表头对应上
                if(i == 0){
                    cell.setCellValue(students.get(j).getName());
                }else if(i == 1){
                    cell.setCellValue(students.get(j).getSex());
                }else if(i == 2){
                    cell.setCellValue(students.get(j).getAge());
                }else if(i == 3){
                    cell.setCellValue(students.get(j).getClassName());
                }else if(i == 4){
                    cell.setCellValue(students.get(j).getPhone());
                }else {
                    cell.setCellValue(students.get(j).getAddress());
                }

                // 这里将每一数据行的样式设置成和表头样式一样的,建议将 style 样式进行封装,根据不同的需求获取不同的样式
                cell.setCellStyle(style);
            }
        }

        try (OutputStream osOut = response.getOutputStream()){
            // 设置响应类型与编码
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("学生表.xlsx","UTF-8"));
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");  // .xlsx 用这个
//            response.setContentType("application/vnd.ms-excel;charset=utf-8"); // .xls 用这个
            response.setCharacterEncoding("utf-8");

            // 将指定的字节写入此输出流
            workbook.write(osOut);
            // 刷新此输出流并强制将所有缓冲的输出字节被写出
            osOut.flush();
            // 关闭流
            osOut.close();
            workbook.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此时,后端的代码已全部实现,由于是 Get 请求,所以我们可以直接在浏览器访问URL进行下载:

前端实现:

type类型 // 这里一定要和后端对应,不然可能出现乱码或者打不开文件

// 导出设备数据
function exportItem() {
    exportDeviceApi(searchParams).then(resolve => {
        const blob = new Blob([resolve], 
{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })  //你需要的类型 转化为blob对象
        const url = window.URL.createObjectURL(blob)         //将对象转化为链接
        let a = document.createElement('a')
        // 下载链接
        a.href = url
        a.download = '导出设备数据.xlsx'
        document.body.appendChild(a)
        // 点击a标签,进行下载 
        a.click()
        // 移除元素
        document.body.removeChild(a)
    })
}

exportDeviceApi的封装:

// 导出设备数据 /device/export
export function exportDeviceApi(param) {
    return request({
        url: "/device/export",
        method: "post",
        data: param,
        responseType: 'blob',  // 设置响应数据类型为 blob。这句话很重要!!!
    })
}

问题

对于文件下载后打开乱码,很有可能是以下两个问题:
文件格式与响应类型对不上,前端后端都得对上
没有设置编码 UTF-8
对于文件损坏,提示无法打开,很有可能是:
文件格式与响应类型对不上,前端后端都得对上

 

 


总结
                

Java端
在创建Workbook的时候,要确认是用 .xlsx 格式还是用 .xls,并使用对应的XSSFWorkbook 和
HSSFWorkbook 来创建正确的工作空间
字体的创建和列样式CellStyle都建议单独封装。
设置响应头的时候,如果中文文件名乱码,可以使用URLEncoder进行UTF-8 编码。
响应类型ContentType 一定要根据不同的文件格式,设置正确的响应类型
最后记得 flush 一下,并关闭流。
前端
创建 Blob 的时候,type 最好和Java的响应类型保持一致
一定要设置响应数据类型为 blob:responseType: 'blob'

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

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

相关文章

K8S(十一)—Service详解

目录 Service发布服务&#xff08;服务类型&#xff09;type: ClusterIP选择自己的 IP 地址例子 type: NodePort选择你自己的端口为 type: NodePort 服务自定义 IP 地址配置例子 type: LoadBalancer混合协议类型的负载均衡器禁用负载均衡器节点端口分配设置负载均衡器实现的类别…

0基础学习VR全景平台篇第129篇:认识单反相机和鱼眼镜头

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 一、相机 单反和微单 这里说的相机是指可更换镜头的单反/微单数码相机。那两者有何差异呢&#xff1f; 1&#xff09;取景结构差异 两者最直观的区别在于&#xff0c;微单相机…

ffmpeg入门之Windows开发之二(视频转码)

添加ffmpeg windows编译安装及入门指南-CSDN博客 的头文件和依赖库如下&#xff1a; main 函数如下&#xff1a; extern "C" { #ifdef __cplusplus #define __STDC_CONSTANT_MACROS #endif } extern "C" { #include <libavutil/timestamp.h> #in…

nodejs+vue+微信小程序+python+PHP国漫推荐系统-计算机毕业设计推荐

使得本系统的设计实现具有可使用的价。做出一个实用性好的国漫推荐系统&#xff0c;使其能满足用户的需求&#xff0c;并可以让用户更方便快捷地国漫推荐。这个系统的设计主要包括系统页面的设计和方便用户互动的后端数据库&#xff0c;在开发后需要良好的数据处理能力、友好的…

Redis发布与订阅

什么是发布与订阅 答: redis发布订阅是一种消息通信通信模式&#xff0c;由发送者(pub)发送消息,订阅者(sub)接收消息。 如下图client2、4、5就是订阅着&#xff0c;订阅了channel1的消息。 当channel1要发送消息时&#xff0c;这几个订阅者都会实时收到消息。 发布订阅的方式…

Koa.js 入门手册:洋葱模型插件机制详解以及常用中间件

前言 Nodejs 提供了 http 能力&#xff0c;我们通过如下代码可以快速创建一个http server服务 const http require(http);http.createServer((req, res) > {res.write(hello\n);res.end();}).listen(3000);使用nodejs提供的原生能力启动一个http server并不麻烦&#xff…

gun-fight枪战对决游戏(自创)

前言 好久都没有更新过啦&#xff01; 游戏介绍 这是一款枪战游戏&#xff0c;你将和人机对战&#xff0c;在火线中对决&#xff01;具体是怎么样的快下载试试吧&#xff01; 下载链接 文件 密码是1111 后言 点个赞吧&#xff01;

阿里云主导《Serverless 计算安全指南》国际标准正式立项!

日前&#xff0c;在韩国召开的国际电信联盟电信标准分局 ITU-T SG17 全会上&#xff0c;由阿里云主导的《Serverless 计算安全指南》国际标准正式立项成功。 图 1 项目信息 在现今数字化时代&#xff0c;Serverless 计算正逐渐成为云计算的一个新的发展方向&#xff0c;其灵活…

智能优化算法应用:基于世界杯算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于世界杯算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于世界杯算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.世界杯算法4.实验参数设定5.算法结果6.参考文…

Python 爬虫之简单的爬虫(三)

爬取动态网页&#xff08;上&#xff09; 文章目录 爬取动态网页&#xff08;上&#xff09;前言一、大致内容二、基本思路三、代码编写1.引入库2.加载网页数据3.获取指定数据 总结 前言 之前的两篇写的是爬取静态网页的内容&#xff0c;比较简单。接下来呢给大家讲一下如何去…

用户行为分析遇到的问题-ubantu16,hadoop3.1.3

用户行为分析传送门 我的版本 ubantu16 hadoop 3.1.3 habse 2.2.2 hive3.1.3 zookeeper3.8.3 sqoop 1.46/1.47 我sqoop把MySQL数据往hbase导数据时候有问题 重磅&#xff1a;大数据课程实验案例&#xff1a;网站用户行为分析&#xff08;免费共享&#xff09; 用户行为分析-小…

OpenCV技术应用(8)— 如何将视频分解

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本节课就手把手教大家如何将一幅图像转化成热力图&#xff0c;希望大家学习之后能够有所收获~&#xff01;&#x1f308; 目录 &#x1f680;1.技术介绍 &#x1f680;2.实现代码 &#x1f680;1.技术介绍 视频是…

STM32——时钟树与滴答计时器

STM32——时钟树与滴答计时器 使用的开发板为stm32F407VET6的芯片,主要介绍stm32的时钟树与滴答计时器的一些理论和一个自己编写的delay函数。 时钟树的结构图可以在STM32F4xx中文参考手册.pdf中的时钟这块找到。而滴答计时器是内核资源&#xff0c;需要到Cortex M3与M4权威指南…

图片转excel:二种合并方式,有何区别?

图片怎么转为可编辑的excel&#xff0c;并且将转换结果合并为一个表&#xff1f;打开眼精星表格文字识别电脑客户端&#xff0c;我们可以看到顶部有一个功能&#xff0c;名为“表格合并”&#xff0c;而在表格识别模块提交选项里&#xff0c;我们会发现有“合并”选项&#xff…

Win10电脑退出安全模式的两种方法

在Win10电脑中&#xff0c;大家可以点击进入系统安全模式&#xff0c;完成相对应的系统设置。但是&#xff0c;很多用户进入安全模式完成设置后&#xff0c;不知道怎么操作才能成功退出安全模式&#xff1f;接下来小编给大家分享两种简单的方法&#xff0c;帮助大家成功退出Win…

【改进YOLOv8】磁瓦缺陷分类系统:改进LSKNet骨干网络的YOLOv8

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 近年来&#xff0c;随着智能制造产业的不断发展&#xff0c;基于人工智能与机器视觉的自动化产品缺陷检测技术在各行各业中得到了广泛应用。磁瓦作为永磁电机的主…

JVM-6-HotSpot的算法细节实现

根节点枚举 迄今为止&#xff0c;所有收集器在根节点枚举这一步骤时都是必须暂停用户线程的&#xff0c;因此毫无疑问根节点枚举与之前提及的整理内存碎片一样会面临相似的“Stop The World”的困扰。 即使是号称停顿时间可控&#xff0c;或者&#xff08;几乎&#xff09;不…

深入解析Guava范围类(Range)

第1章&#xff1a;范围类Range的重要性 大家好&#xff0c;我是小黑&#xff0c;今天咱们聊聊一个在Java编程世界里非常实用但又被低估的角色——Guava库中的Range类。你知道吗&#xff0c;在处理涉及到数值范围的问题时&#xff0c;Range类就像是咱们的救星。不论是判断某个数…

Python3中_和__的用途和区别

目录 一、_&#xff08;下划线&#xff09; 1、临时变量&#xff1a; 2、未使用的变量&#xff1a; 二、__&#xff08;双下划线&#xff09; 1、私有属性&#xff1a; 2、私有方法&#xff1a; 三、__的一些特殊用途。 总结 Python3中的_和__是两个特殊的标识符&#…

MongoDB的数据库引用

本文主要介绍MongoDB的数据库引用。 目录 MongoDB的数据库引用 MongoDB的数据库引用 MongoDB是一种面向文档的NoSQL数据库&#xff0c;它使用BSON&#xff08;Binary JSON&#xff09;格式存储和查询数据。在MongoDB中&#xff0c;数据库引用是一种特殊的数据类型&#xff0c;…