当前位置:   article > 正文

springboot easyexcel 导出excel案例及文件无法打开_easyexcel post 无法打开文件

easyexcel post 无法打开文件


  导出数据是后端经典模块之一,从原有的poi到现在的easyexcel等等都在努力的帮助开发们缩小数据与excel之间的鸿沟。但是在简单的导出也会遇到一些有的没的问题,特地写个文章记录下~

背景介绍

一般导出流程图如下:

组装数据
导出

组装数据: 包括excel中表头、数据及样式
导出: 文件流

easyexcel 表头及数据

官方文档总结的都是经典~

表头: 分为固定表头和动态表头,然后再可以继续划分简单版本和复杂版本,其中复杂版本类似有三四级表头(以前写poi硬编码写到爆炸=_=||)~ 示例如下(图片来源):
在这里插入图片描述
数据: 随表头变更

表头

简单

在这里插入图片描述

固定表头,可声明一个实体类进行定义,如下:

@Data
public class TitleData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

动态表头,只能自己手动写代码进行定义,如下:

// 外层数组,一个值代表一列
List<List<String>> headList = new ArrayList<List<String>>();
List<String> head0 = new ArrayList<String>();
head0.add("字符串标题");
headList.add(head0);

List<String> head1 = new ArrayList<String>();
head1.add("日期标题");
headList.add(head1);

List<String> head2 = new ArrayList<String>();
head2.add("数字标题");
headList.add(head2);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
合并

在这里插入图片描述

@Data
public class ComplexHeadData {
    @ExcelProperty({"主标题", "字符串标题"})
    private String string;
    @ExcelProperty({"主标题", "日期标题"})
    private Date date;
    @ExcelProperty({"主标题", "数字标题"})
    private Double doubleData;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

web项目导出方式

web项目一般有两种导出方式:

  • 提供下载链接(异步):先生成excel并上传至oss/文件服务器,返回文件链接给前端,由前端自行下载
  • 文件流(同步):生成excel并塞入response流中

本文主要关注文件流方式,示例代码如下:

// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

实践出真知

简单动态表头案例

本案例比较简单,根据请求参数time来动态定义表头和创建数据,并以文件流方式返回给前端。 效果如下:
效果图
pom中添加依赖:

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>2.2.7</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

业务逻辑代码如下:

@RestController
public class ResultController {
    
	@PostMapping(value = "/export")
    public void export(@RequestParam Integer time) {
    
    	try {
			HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
			response.setHeader("Content-Disposition", "attachment; filename=export.xlsx");
	        // 响应类型,编码
	        response.setContentType("application/vnd.ms-excel;charset=utf-8");
	        response.setCharacterEncoding("utf-8");
			EasyExcel.write(response.getOutputStream()).head(getHead(time)).sheet("数据").doWrite(getData(time));
		} catch (IOException e) {
			log.error("导出问卷数据失败!错误信息为:{}", e.getMessage());
			e.printStackTrace();
		}
    }
    
    /**
     * 获取excel标题栏(姓名、手机号、提交时间)
     * @param questionnaireId
     * @return
     */
    private List<List<String>> getHead(Integer time) {
    	
    	// 外层数组,一个值代表一列
    	List<List<String>> headList = new ArrayList<List<String>>();
    	List<String> nameList = new ArrayList<String>();
    	nameList.add("姓名");
    	headList.add(nameList);
    	
    	List<String> telList = new ArrayList<String>();
    	telList.add("手机号");
    	headList.add(telList);
    	
    	List<String> submitDTList = new ArrayList<String>();
    	submitDTList.add("提交时间");
    	headList.add(submitDTList);
    	
    	for (int i = 0 ; i < time ; i ++ ) {
    		List<String> list = new ArrayList<String>();
    		list.add("动态标题" + i);
        	headList.add(list);
    	}
    	
    	return headList;
    }
    
    /**
	 * 获取excel表格数据
	 * @return
	 */
	private List<List<Object>> getData(Integer time) {
		
		// 将填写结果 + 提交时间合并为一行数据
		List<List<Object>> resultList = new ArrayList<List<Object>>();
		for (int i = 0 ; i < 3 ; i ++ ) {
			
			List<Object> list = new ArrayList<Object>();
			list.add("花卷" + i);
			list.add("1347000000" + i);
			list.add("2022-01-18 14:54:00");
			
			for (int j = 0 ; j < time ; j ++ ) {
	    		list.add("动态内容" + j);
	    	}
			
			resultList.add(list);
		}
		return resultList;
	}
  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

遇到的问题

前端联调时excel无法打开

问题描述: 后台用postman调试都ok,能正常打开excel!但是前端调试时下载的excel提示有破损,无法打开!!!
Tips: 勇敢(不怕死)的质疑前端,你代码有BUG!
解决方案: 前端需在request和response中添加responseType: blob设置

以下伪代码,请重点关注responseType设置即可

  1. 前端request应该设置responseType为arraybuffer或blob
return request({
url: '/platform/export',
method: 'post',
responseType: 'blob',
headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
},
data: qs.stringify(data)

})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  1. 前端以blob格式接收response,并设置type为application/msexcel
handleExport(){
  exportData({id: this.id}).then(res => {
    if(res){
      const fileName = this.name + '.xlsx';
        var blob = new Blob([res], {
        type: "application/msexcel;charset=utf-8",
      });
      const URL = window.URL || window.webkitURL;
      const downloadElement = document.createElement("a");
      const href = URL.createObjectURL(blob); // 创建下载的链接
      downloadElement.href = href;
      downloadElement.download = fileName; // 下载后文件名
      document.body.appendChild(downloadElement);
      downloadElement.click(); // 点击下载
      document.body.removeChild(downloadElement); // 下载完成移除元素
      URL.revokeObjectURL(href); // 释放掉blob对象
    }
  })
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

下载文件接口有时返回文件流有时返回json的情况

测试小姐姐提了个单,token超时后,点击下载按钮还是能正常导出,excel内容是后端认证系统返回的错误码json串 =_=|| ,网上查找一番也找大佬们讨论了下,对于将文件流封装成系统设定的统一返回json方式不可取,最后抱着前端小姐姐的细腿求解决喽
解决方法:前端获取response后根据 content-type进行区分
网上参考文档
在这里插入图片描述



未完待续......
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/998868
推荐阅读
相关标签
  

闽ICP备14008679号