Vue 前端导出后端返回的excel文件方式

目录
  • 前端导出后端返回的excel文件
  • 处理文件的下载(后端Excel导出)
    • 后端文件流
    • 通过 Blob 下载
    • 拼接 URL 下载

前端导出后端返回的excel文件

在网上搜索了一番之后,决定采用Blob方式,这也是大家推荐的一种的方式,特此做下记录。

页面:

先筛选,向后端请求接口返回excel文件,代码如下:

    const apiUrl = this.Global.httpUrl + '/laima/export/new/exportTackOutOrder'
    console.log(this.form)
    let param = new URLSearchParams();
    param.append("startDate", "2019-01-01");
    param.append("endDate", "2019-02-01");
    this.$axios.post(apiUrl, param,{responseType: 'blob'}).then((res) => {
        console.log( res.data)
        const link = document.createElement('a')
        let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'});
        link.style.display = 'none'
        link.href = URL.createObjectURL(blob);
        let num = ''
        for(let i=0;i < 10;i++){
            num += Math.ceil(Math.random() * 10)
        }
        link.setAttribute('download', '外卖统计_' + num + '.xlsx')
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
    })

仔细看axios请求加了个responseType: 'blob'配置,这是很重要的

可以看到请求返回了一个Blob对象,你如果没有正确的加上responseType: 'blob’这个参数,返回的就不是个Blob对象,而是字符串了。

然后就自动下载了!

处理文件的下载(后端Excel导出)

大概有两种方法(通常对应的是需要不需要携带 token),原理都是通过 a 标签下载

  • 通过 Ajax 请求,拿到 response ,转换为 blob 格式(主要是为了处理 type),为其生成下载链接,下载即可
  • 直接拼接 URL,拼出来对应请求链接,直接访问即可(不需要二次 token 认证)

后端文件流

首先点击导出 Excel ,这里调用接口成功

接下来看一下后台返回的数据是什么样,是文件流格式(OutputStream)

在处理之前,说几个要注意的点!!!

1.注意:后端在这里一般会设置如下几个请求头

后端还可能开启 jwt token 验证,如果开启请移步第 2 点请求拦截设置 headers

注意: 由于跨域浏览器处于安全考虑不让自定义响应头通过 JS 获取 ,也就是说 Content-Disposition 前端在 Network 里是能看到的,但是无法通过 JS 获取到,这里后端需要将其暴露出去

跨域情况默认只暴露:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma 六个属性

// 设置返回类型为excel
response.setContentType("application/vnd.ms-excel; charset=UTF-8");
// 设置返回文件名为filename.xls
response.setHeader("Content-Disposition", "filename.xls");
// 请求或响应消息不能走缓存
response.setHeader("Cache-Control", "no-cache");
// 将Content-Disposition暴露出去,这样就可以用过JS获取到了
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");

2.注意:前端在 Axios 请求和响应拦截的时候,需要对其进行处理

请求拦截一般我们都是会设置 headers,这里只是简单处理一下,实际会根据不同情况设置 headers

响应拦截一般我们都是把 response.data 进行返回,但是这里我们需要把整个 response 返回(因为文件名在 headers 里面)

import axios from 'axios'
import { getToken } from '@/utils/auth'
import { AUTHOR_KEY } from '@/global'
const service = axios.create({
  baseURL: process.env.NODE_ENV === 'development' ? '' : 'http://127.0.0.1:9999'
  withCredentials: true,
  timeout: 5000
})
// 请求拦截器
service.interceptors.request.use(
  config => {
    config.headers[AUTHOR_KEY] = getToken()
    return config
  },
  error => console.log(error)
)
// 响应拦截器
service.interceptors.response.use(
  response => {
    if (response.config.responseType === 'blob') {
      return response
    }
    return response.data
  },
  error => console.log(error)
)
export default service

接下来要处理这个文件流,大概有两种方法(通常对应的是需要不需要携带 token),原理都是通过 a 标签下载

  • 通过 Ajax 请求,拿到 response ,转换为 blob 格式(主要是为了处理 type),为其生成下载链接,下载即可
  • 拼接 URL,拼出来对应请求链接,直接访问即可

通过 Blob 下载

Blob 通常用于存储大文件,典型的 Blob 内容是一张图片或一个音频

默认情况下 axios 不会处理二进制数据,即请求可以正常被浏览器接收,但 axios 不会去处理。需要在请求的时候设置 responseType: 'blob' 才可以

  • 拿到文件流之后,需要生成一个 URL 才可以下载,可以通过URL.createObjectURL()方法生成一个链接
  • a 标签添加文件名
  • 正常情况下,通过 window.location = url 就可以下载文件。浏览器判断这个链接是一个资源而不是页面的时候,就会下载文件。但是通过文件流生成的 url 对应的资源是没有文件名的,需要添加文件名。这时候可以用到 download 属性指定下载的文件名

由于有浏览器问题可能会出现 content-disposition 匹配不到,最好做一下判断看 content-disposition 和 Content-Disposition 哪个能取到

const mimeMap = {
  xlsx: 'application/vnd.ms-excel',
  zip: 'application/zip',
}
export const toExcel = params => {
  return request({
    method: 'get',
    url: '/dayReportToExcel/toExcel',
    responseType: 'blob',
    params
  }).then(res => resolveBlob(res, mimeMap.xlsx))
export function resolveBlob(res, mimeType) {
  // 创建a标签,并处理二级制数据
  const aLink = document.createElement('a')
  const blob = new Blob([res.data], { type: mimeType })
  // 生成下载链接
  const URL = window.URL || window.webkitURL
  aLink.href = URL.createObjectURL(blob)
  // 设置下载文件名称
  let fileName = ''
  if (res.headers['content-disposition']) fileName = res.headers['content-disposition']
  if (res.headers['Content-Disposition']) fileName = res.headers['Content-Disposition']
  aLink.setAttribute('download', fileName)
  // 下载
  document.body.appendChild(aLink)
  aLink.click()
  // 释放URL对象
  window.URL.revokeObjectURL(aLink.href)
  document.body.removeChild(aLink)
}

注意:一般情况下文件名都是需要匹配的,后端传过来的可能是这样的,首选需要 decodeURI 解码一下,再用正则把文件名匹配出来(替换设置下载文件名那里即可)

export function resolveBlob(res, mimeType) {
  const aLink = document.createElement('a')
  const blob = new Blob([res.data], { type: mimeType })
  const pat = new RegExp('filename=([^;]+\\.[^\\.;]+)')
  let contentDisposition
  if (res.headers['content-disposition']) contentDisposition = res.headers['content-disposition']
  if (res.headers['Content-Disposition']) contentDisposition = res.headers['Content-Disposition']
  const result = pat.exec(decodeURI(contentDisposition))
  let fileName = result && result[1]
  const URL = window.URL || window.webkitURL
  aLink.href = URL.createObjectURL(blob)
  // 如果Content-Disposition没有暴露,给文件一个默认名字
  if (fileName == null) fileName = '日报表'
  aLink.setAttribute('download', fileName)
  document.body.appendChild(aLink)
  aLink.click()
  // 释放URL对象
  window.URL.revokeObjectURL(aLink.href)
  document.body.removeChild(aLink)
}

拼接 URL 下载

如果可以直接通过 URL 下载文件,则可以不需要发送 Ajax 请求(前提是没有 token、headers 验证),直接下载

可以使用 a 标签进行下载

import qs from 'qs'
export function downloadExcel(params) {
  const url = window.location.origin + '/dayReportToExcel/toExcel?' + qs.stringify(params)
  const aLink = document.createElement('a')
  aLink.setAttribute('download', '')
  aLink.setAttribute('target', '_blank')
  aLink.href = url
  aLink.click()
}

可以使用 window.open(url, '_blank')

import qs from 'qs'
export function downloadExcel(params) {
  const url = window.location.origin + '/dayReportToExcel/toExcel?' + qs.stringify(params)
  window.open(url, '_blank')
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Vue结合后台导入导出Excel问题详解

    最近Vue项目中用到了导入导出功能,在网上搜索了一番之后,决定采用Blob方式,这也是大家推荐的一种的方式,特此做下记录. 导出Excel功能 这里不谈别人怎么实现的,我是从后台生成了Excel流文件返回给前端的. 下面具体看一下后台的代码: /** * 批量导出用户 * @param condition * @param response */ @PostMapping("/exportUser") public void exportUser(@RequestBody UserQu

  • Vue前端导出Excel文件的详细实现方案

    目录 一.技术选型 二.技术实现 使用 vue-json-excel 插件实现 1.安装 vue-json-excel 依赖 2.注册插件到 vue 实例 3.使用方式 基于 sheetJS-xlsx 解析器的 xlsx-style 实现(推荐) 1.安装依赖 2.使用方法 三.参考资料 总结 一.技术选型 1.使用 vue-json-excel 插件实现 优点:简单便捷,易上手,开箱即用: 缺点:不支持 excel 表格样式设置,且支持功能比较单一: 2.基于 sheetJS-xlsx 解析器

  • vue中后端做Excel导出功能返回数据流前端的处理操作

    项目中有一个导出功能的实现,用博客来记录一下.因为需求对导出表格的数据格式和样式有要求,所以这个导出功能放到后端来做,而且后端返回的是数据流,所以需要处理成想要的表格并导出来. 先看下效果图: 页面效果: 点击 导出Excel 调用导出接口成功了: 后台返回的数据流,一堆看不懂的乱码: 接下来要处理这堆乱码,因为用到的地方多,所以在util.js文件里封装了一个公共方法并抛出: 虽然vue里有封装好的请求接口的方法,但这里要单独用axios,所以先在util.js里引入axios import

  • Vue 前端导出后端返回的excel文件方式

    目录 前端导出后端返回的excel文件 处理文件的下载(后端Excel导出) 后端文件流 通过 Blob 下载 拼接 URL 下载 前端导出后端返回的excel文件 在网上搜索了一番之后,决定采用Blob方式,这也是大家推荐的一种的方式,特此做下记录. 页面: 先筛选,向后端请求接口返回excel文件,代码如下: const apiUrl = this.Global.httpUrl + '/laima/export/new/exportTackOutOrder' console.log(this

  • 前端使用xlsx库导出带有样式的excel文件

    目录 需求分析 常用的库 ExcleJS 具体实现 结果展示 整个函数展示 最后 需求分析 最近遇到一个需求:前端导出excel文件,其中有部分数据用户不能操作,部分列数据可以筛选,并且存在前一列的数据值会影响后一列数据值的输入范围的情况. 需要导出的前端表格如上图所示,其中: Group.Type.Region可筛选 红色框内的数据用户不可操作,绿色框内用户可以操作 当Type的值为BOOL时,Region的有效输入为:["Holding Register","Input

  • vue 如何打开接口返回的HTML文件

    目录 一.后端接口 二.前端 前言:接口测试平台,后端使用django,前端使用vue+element.项目接口平台测试完成,需要把后台产生的测试报告返回给前端展示. 一.后端接口     1.配置下django的template的参数,templates文件夹是放在project的目录下面的,是项目中或者说项目中所有的应用公用的一些模板 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', '

  • C#导出GridView数据到Excel文件类实例

    本文实例讲述了C#导出GridView数据到Excel文件类.分享给大家供大家参考.具体如下: 这段C#代码自定义了一个封装类,用于将GridView数据导出到Excel文件 using System; using System.Web; using System.Web.UI; using System.IO; using System.Web.UI.WebControls; namespace DotNet.Utilities { public class ExportExcel { pro

  • Vue将将后端返回的list数据转化为树结构的实现

    下载 cnpm i -S array-to-tree 引入 import arrayToTree from "array-to-tree"; 使用 const pidData = [ { name: "aa", id: "1", pid: null }, { name: "bb", id: 2, pid: 1 }, { name: "cc", id: 3, pid: "" }, { na

  • vue实现把接口单独存放在一个文件方式

    第一步:在src/router目录下,建立一个js文件(文件名:httpConfig.js): 第二步:在httpConfig.js文件里面写上 const aa = 'http://192.168.1.123';//本地测试 const config = { bb: aa+ '/article/articleListPage',//所需的接口 } //需要让外部拿到 export default config; 第三步:掉接口 _this.$http({ url: _this.$httpCon

  • PHP导出MySQL数据到Excel文件(fputcsv)

    这里的方法是利用fputcsv写CSV文件的方法,直接向浏览器输出Excel文件. 复制代码 代码如下: // 输出Excel文件头,可把user.csv换成你要的文件名 header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment;filename="user.csv"'); header('Cache-Control: max-age=0'); // 从数据库中获取

  • 前端axios下载excel文件(二进制)的处理方法

    需求:通过后端接口下载excel文件,后端没有文件地址,返回二进制流文件 实现:axios(ajax类似) 主要代码: axios:设置返回数据格式为blob或者arraybuffer 如: var instance = axios.creat({ ... //一些配置 responseType: 'blob', //返回数据的格式,可选值为arraybuffer,blob,document,json,text,stream,默认值为json }) 请求时的处理: getExcel().then

  • 前端如何更好的展示后端返回的十万条数据

    目录 前置工作 后端搭建 前端页面 直接渲染 setTimeout分页渲染 requestAnimationFrame 文档碎片 + requestAnimationFrame 懒加载 今天跟大家来唠唠嗑,如果后端真的返回给前端10万条数据,咱们前端要怎么优雅地展示出来呢? 前置工作 先把前置工作给做好,后面才能进行测试 后端搭建 新建一个 server.js 文件,简单起个服务,并返回给前端 10w 条数据,并通过 nodemon server.js 开启服务 没有安装 nodemon 的同学

随机推荐