赞
踩
以上是症状,实际的关键做法是在发送请求的时候,加上一个参数:responseType:"blob"
网上的做法或者声称的解决方案,好多都没用,所以我整理了一个保姆教程。
因为我是基于vue2+ElementUi做的前端 Maven+springboot做的后台,所以技术栈不契合的,请自行补课。
前端代码:
vue页面:
- <!--elementUi中的按钮组件-->
- <el-button type="primary" @click="exportData">导出今日数据</el-button>
vue生命周期中的methods内,完成导出函数
- //导入请求api,这里解构的方法是下方调用的方法
- import { exportData } from '@/api/orders'
-
- //这个是自定义的文件下载js,下面会贴出完整代码
- import { download } from '@/utils/downloadfile'
-
-
- methods: {
-
- exportData(){
- let _this=this;
- //api中声明请求后台的方法
- exportData().then(response => {
- download(response,"data.xlsx"); //启动下载方法,这里的文件名可自定义,但是后缀一定得是“.xlsx”
- })
- }
- }
@/api/orders.js中的请求方法
- //网络请求及鉴权组件(elementUi自带)
- import request from '@/utils/request'
- import { getToken,setToken } from '@/utils/auth'
- const state = {
- token: getToken()
- }
-
-
- //api请求
- export function exportData(){
- return request({
- url: '/orders/exportData',//因为要用后台的response返回文件流,所以这个跳转的后台方法返回值要设置为void
- method: 'get',
- responseType:"blob",//我在这里卡了2个多小时,几乎95%以上的教程都没提到需要设置这个参数
- params:{
- token:getToken() //也可在封装的request.js中挂载token,看个人爱好
- }
- })
- }
上面还会有个问题,因为ElementUi集成的网络请求,要求服务端返回响应状态码。但是后端方法设置返回值为void,导致框架无法正常获取响应状态码,所以在处理响应的时候,要考虑一下这里的特殊情况!!!
@/unit/request.js
- // response interceptor
- service.interceptors.response.use(
- /**
- * If you want to get http information such as headers or status
- * Please return response => response
- */
-
- /**
- * Determine the request status by custom code
- * Here is just an example
- * You can also judge the status by HTTP Status Code
- */
- response => {
- const res = response.data;
-
- //如果没有返回code则直接向调用端返回response.data
- //当然我这里只是做个提醒,相关返回操作您可以根据自己的实际需要,做的更优雅一些
- if (res.code==undefined){
- return res;
- }
-
- // if the custom code is not 200, it is judged as an error.
- if (res.code !== 200) {
- Message({
- message: res.message || 'Error',
- type: 'error',
- duration: 5 * 1000
- })
-
- return Promise.reject(new Error(res.message || 'Error'))
- } else {
- return res
- }
- },
- error => {
- console.log('err' + error) // for debug
- Message({
- message: error.message,
- type: 'error',
- duration: 5 * 1000
- })
- return Promise.reject(error)
- }
- )
@/utils/downloadfile.js 下载工具
- //主要作用是将返回的文件流以blob的方式,模拟生成下载链接并模拟点击,完成下载
- export function download(data, filename) {
- let blob = new Blob([data], { type: 'application/x-www-form-urlencoded' });
- let blobUrl = window.URL.createObjectURL(blob);
- const aElement = document.createElement('a');
- document.body.appendChild(aElement);
- aElement.style.display = 'none';
- aElement.href = blobUrl;
- aElement.download = filename;
- aElement.click();
- document.body.removeChild(aElement);
- }
后台代码:
pom.xml中引入Excel相关依赖
- <dependencies>
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi</artifactId>
- <version>4.1.2</version>
- </dependency>
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml</artifactId>
- <version>4.1.2</version>
- </dependency>
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml-schemas</artifactId>
- <version>4.1.2</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>easyexcel</artifactId>
- <version>2.2.6</version>
- </dependency>
- </dependencies>
设置导出实体类,其中继承了Excel设置
注意:该类可以是项目原来的对象类加Excel注解,如果有需要的话,也可以自己写一个导出类,方便导出数据格式化。
- import com.alibaba.excel.annotation.ExcelProperty;
- import com.alibaba.excel.annotation.write.style.ColumnWidth;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import lombok.ToString;
-
- import java.io.Serializable;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @ToString
- public class exportData implements Serializable {
-
- @ColumnWidth(10)
- @ExcelProperty(value = "序号", index = 0)
- private Integer id;
-
- @ColumnWidth(15)
- @ExcelProperty(value = "用户姓名", index = 1)
- private String cusname;
-
- @ColumnWidth(25)
- @ExcelProperty(value = "用户电话", index = 2)
- private String cusphoneNo;
-
- }
这里还有个坑:如果导出的数据中有null值,也会导致Excel导出异常,所以sql语句配置要处理一下null值。
下方为mybatis/Mapper文件中的查询设置:
- <!--(@i:=@i+1) AS 'id'/(SELECT @i:=0) AS itable 这部分是生成行号的操作,因为数据id不一定是连续的,导出的文件中不加行号比较不易阅读-->
- <!--IFNULL(cusphoneNo,'') AS 'cusphoneNo' 将空值转为空字符串,用来填充文件-->
-
- <select id="toexport" resultType="com.hz.entity.exportData">
- SELECT (@i:=@i+1) AS 'id',cusname AS 'cusname',IFNULL(cusphoneNo,'') AS 'cusphoneNo' from orders,(SELECT @i:=0) AS itable;
- </select>
后台导出方法
- @GetMapping("/exportData")
- @ApiOperation(value = "导出数据")
- @ResponseBody //实现数据接口
- public void exportData(HttpServletResponse response) {
- try{
- response.setContentType("application/vnd.ms-excel");
- response.setCharacterEncoding("utf-8");
-
- // URLEncoder.encode防止中文乱码
- String filName = URLEncoder.encode("导出的数据表", "utf-8");
- response.setHeader("Content-disposition", "attachment;filename=" + filName +".xlsx");
- //用model层处理数据,mybatis做相关数据操作,这里就不细说了,别说你连不上数据库
- List<exportData> etlst = ordersService.toexport();
- EasyExcel.write(response.getOutputStream(),exportData.class).excelType(ExcelTypeEnum.XLSX).sheet("sheet1").doWrite(etlst);
-
- }catch (Exception e){
- System.out.println(e.getMessage());
- }
-
- }
注意的坑:
1、前端请求时一定要带要求返回的类型,即responseType:"blob"
2、因为要用后台的response返回文件流,所以后台导出方法返回值要设置为void,让EasyExcel的write和response输出流进行主动返回。
3、mybatis中的查询及返回给导出类的映射数据不能为空,所以如果可能出现空值的字段,要提前做好处理。
总之,导出的Excel文件无法打开,不是数据格式有问题,就是文件格式有问题,但是照我写的来,基本都能成功。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。