现在大部分的系统都采用前后端分离的方式来实现系统的开发,以前我们实现下载excel的时候,我们直接使用GET的方法的方式直接将数据写到页面上,用户直接下载即可,但是使用前后端分离的方式就不能使用传统的方式来实现文件的下载,这时候我们就会遇到各种坑,接下来我将带大家来了解里面遇到的各种坑以及相应的解决方案。
1、创建后端工程
首先我们创建一个后端的springboot的工程,然后再引入以下的maven依赖:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.0</version>
</dependency>
<!-- swagger插件 -->
<dependency>
<groupId>com.didispace</groupId>
<artifactId>spring-boot-starter-swagger</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
2、swagger2开启
接着我们先开启我们的swagger2的接口测试工具,直接在主入口类上加上以下的注解即可:
@SpringBootApplication
@EnableSwagger2Doc
public class PoiDemoApplication {
public static void main(String[] args) {
SpringApplication.run(PoiDemoApplication.class, args);
}
}
3、编写测试方法
最后我们创建一个PoiController的测试的类,代码如下:
@Controller
@RequestMapping("poi")
public class PoiController {
/**
* 功能描述: 正确的下载xlsx的方式
* @param response
* @throws UnsupportedEncodingException
*/
@PostMapping(value = "downloadXlsWright" ,produces = MediaType.APPLICATION_OCTET_STREAM_VALUE )
public void downloadXlsWright(HttpServletResponse response) throws UnsupportedEncodingException {
// 设置当前的xlsx最大长度为1000行
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
// 设置文件后缀
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String fn = "xlsx" + sdf.format(new Date()).toString() + ".xlsx";
//设置表格名称
SXSSFSheet sheet = wb.createSheet("sheet1");
// 设置默认的宽度为30个字符
sheet.setDefaultColumnWidth(30);
SXSSFRow row = sheet.createRow(0);
for (int i = 0; i < 10; i++) {
// 遍历插入表头
SXSSFCell cell = row.createCell(i);
cell.setCellValue("测试表头" + i);
}
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fn, "UTF-8"));
OutputStream os = null;
try {
os = response.getOutputStream();
wb.write(os);
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (wb != null) {
wb.dispose();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 功能描述: 错误的下载xlsx的方式
* @param response
* @throws UnsupportedEncodingException
*/
@PostMapping("downloadXlsWrong")
public void downloadXlsWrong(HttpServletResponse response) throws UnsupportedEncodingException {
// 设置当前的xlsx最大长度为1000行
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
// 设置文件后缀
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String fn = "xlsx" + sdf.format(new Date()).toString() + ".xlsx";
//设置表格名称
SXSSFSheet sheet = wb.createSheet("sheet1");
// 设置默认的宽度为30个字符
sheet.setDefaultColumnWidth(30);
SXSSFRow row = sheet.createRow(0);
for (int i = 0; i < 10; i++) {
// 遍历插入表头
SXSSFCell cell = row.createCell(i);
cell.setCellValue("测试表头" + i);
}
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fn, "UTF-8"));
OutputStream os = null;
try {
os = response.getOutputStream();
wb.write(os);
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (wb != null) {
wb.dispose();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
也许大家发现了这两个方法唯一不同的地方就是在PostMapping的注解上加了这个配置,这个配置的作用就是告诉请求的接口,你调用我这个接口的时候,我将为你返回的类型是文件下载的类型,若不设置默认是application/json的类型返回。
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE
4、验证结果
这时候我们就可以启动我们的工程,然后用浏览器打开以下的地址来验证我们的结果了。
我们分别响应以上的两个请求,这时候大家可以看到如下的页面:
然后我们分别下载上面的两个xlsx文件,这时候我们使用专门的excel软件打开这两个文件,大家会发现downloadXlsWrong这个请求的接口打开的时候回报如下的错误:
5、追根溯源
那是什么原因导致了我们两个接口一样的请求导致一个文件可以打开一个文件打不开,这时候我们可以使用F12的方式来看下这两个请求的区别:
唯一的区别就是在Request Headers上面一个是*/另外一个是application/octest-stream,这两个的区别就是默认为/*前端默认认为是json因此使用文本的方式去处理的数据导致出来的信息已经不是我们需要的信息了,因此最后下载下来的文件无法打开,那么这一章我们就完成了后端篇的实现,下一篇将为大家讲解前端篇该如何去响应这个请求,同时实现文件的下载,若需要获取本章的demo例子,大家可以直接扫描我的公众号,然后回复【poi-demo-1】就可以拿到本章的源代码了: