模拟浏览器下载Excel 到本地

1. 文件导出

1.1 导出实现方式

    文件导出功能, 简单来说有两种实现方式:

  • 生成文件并直接下载文件, 导出一步实现;
  • 先生成文件, 再下载文件, 导出分两步实现;

1.2 导出实现场景

    实现场景无非是, 用户触发导出动作, 后端接收请求, 处理业务数据, 引入poi 依赖, 生成Excel 文件;通过IO 流将文件写出, 可上传到服务器备份; 通过读取文件转换为字节流输出实现导出功能;
    如果考虑需要文件存档, 或者重要文件导出权限等功能时, 可以考虑设计导出任务和文件下载中心; 将导出与下载拆分为两个功能, 且可单独设置权限, 下载次数限制, 备份, 导出统计等功能.
    你可以根据具体场景适当的确定是否异步实现, 还是同步实现.

2. 浏览器导出Excel

2.1 废话

    导出功能网上资源其实挺多的, 功能设计, 实现什么的代码也很全. 这里是找一个场景时没有找到合适的. 导致走了弯路, 这就很气.
    上面也说了, Excel 文件通过POI 去生成, 需求比较简单, 浏览器这边直接导出文件即可. 说明一下, 该场景下导出功能的实现和前端请求携带信息与资源请求方式有关.

2.2 导出Excel 接口

此处以Spring Boot 的前后端分离接口为例

2.2.1 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
2.2.2 导出文件Controller 层
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * @ClassName: ExcelDownController
 * @Description: 文件下载服务端演示
 * @author: niaonao
 * @date: 2019/4/15
 */
@RestController
@RequestMapping("/excel")
public class ExcelDownController {
    @PostMapping(value = "/download")
    public void downloadExcelFile(HttpServletResponse response) throws IOException {

        // 获取到服务器要下载文件的文件名和全路径, 此处模拟演示
        String fileName = "表格文件";
        String fileUrl = "D:\\表格文件.xlsx";

        // 清空buffer
        response.reset();
        response.setContentType("application/msexcel;charset=utf-8");
        // 客户使用目标另存为对话框保存指定文件
        response.setHeader("Content-disposition", "attachment;filename= " + URLEncoder.encode(fileName + "_EXCEL.xlsx", "UTF-8"));
        response.addHeader("Cache-Control", "no-cache");
        response.getOutputStream().write(getBytesByFile(fileUrl));
        response.getOutputStream().close();
        // 各种可能出现异常的请自行判断
    }

    // 将文件转换成Byte数组
    public byte[] getBytesByFile(String pathStr) {
        File file = new File(pathStr);
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            byte[] data = bos.toByteArray();
            bos.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

    启动项目即可访问接口.
图2-2-1:

在这里插入图片描述

2.3 Form 表单请求导出Excel

    此处以Form 表单的multipart/form-data 请求为例. 这个实现较为简单.
页面简单写个Html 即可如下

<form 
  action="http://127.0.0.1:8080/excel/download"
  enctype="multipart/form-data"
  method="post">
    <input type="submit" value="ExcelDown">
</form>

    通过浏览器打开html 文件, 点击导出按钮, 导出模拟服务器端的Excel 文件, 效果如下:
图2-3-1:
在这里插入图片描述

2.4 Vue 导出Excel

    Vue 导出文件, 使用Blob 接收, 请求响应数据类型不同于Form 表单的multipart/form-data; 此处调用同样的导出接口, 模拟浏览器导出Excel 文件; Vue 使用Blob 和FileReader 接收文件流, 使用a 超链接处理导出Excel , 效果同图2-3-1

2.4.1 导出调用接口
  // 创建导出任务
  createExportTask: {
    url: 'http://127.0.0.1:8080/excel/download',
    method: 'post',
    responseType: 'blob',
    callback: function (res, resolve, reject) {
      /* 请求成功 */
      if (res.status === 200) {
        resolve(res)
      } else {
        /* 请求失败 */
        reject(res)
      }
    }
  }
2.4.2 导出js 代码
export default {,
  data: function () {
    return {
    }
  },
  props: {
    createExportTaskApi: {
      type: Object,
      default: function () {
        return this.$api.core.common.createExportTask
      }
    }
  },
  methods: {
    /**
       * 确定更新自定义文件名
       */
    onSave: function () {
      this.$http.fetch(this.createExportTaskApi)
        .then((res) => {
          let blob = new Blob([res.data])
          let reader = new FileReader()
          reader.readAsDataURL(blob)
          reader.onload = (e) => {
            let a = document.createElement('a')
            /* 默认文件名 */
            a.download = `表格文件.xlsx`
            a.href = e.target.result
            document.body.appendChild(a)
            a.click()
            document.body.removeChild(a)
          }
        }).catch((resp) => {
          this.$notify.error(resp.msg || '导出文件失败')
        })
    }
  }
}
</script>
©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页