EasyExcel:web端导出并下载

192 阅读1分钟

场景:页面按钮点击导出,后台处理数据后,返回字节流,通过浏览器能够自动下载

后台EasyExcel导出

@ApiOperation("导出")
@PostMapping("/export")
public void export(@RequestBody ExportSummaryParam param, HttpServletResponse response) {
    exportService.exportSummary(param,response);
}

public interface IExportService {
    void exportSummary(ExportSummaryParam param, HttpServletResponse response);
}

@Service
public class ExportServiceImpl implements IExportService {
    @Override
    public void exportSummary(ExportSummaryParam param, HttpServletResponse response) {
        // 校验参数
        // 查询提货汇总表
        try {
            // 设置响应头信息
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader("content-Length",String.valueOf(file.length()));
            
            // 导出Excel
            EasyExcel.write(response.getOutputStream(), SummaryExport.class)
                    .sheet("提货汇总")
                    .doWrite(exportList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

前端请求导出

exportValid() {
  console.log('param:', this.queryParam)
  this.exportLoading = true
  api.exportSummary(this.queryParam)
  .then(res => {
    if (res) {
      this.$CommonUtils.downloadFileWithOptions({
        data: res,
        prefix: 'xxx',
        extension: 'xlsx',
        onSuccess: () => {
          this.$message.success('导出成功!')
        },
        onError: (error) => {
          this.$message.error('导出失败:' + error.message)
        }
      })
    } else {
      this.$message.error('导出失败!')
    }
  })
  .finally(() => {
    this.exportLoading = false
  })
}

导出API

// 导出API
export function exportSummary(parameter) {
  return request({
    url: '/export',
    method: 'post',
    data: parameter,
    responseType: 'blob'//很重要
  })
}

下载工具类

// 下载工具类
/**
 * 高级文件下载方法
 * @param {Object} options - 下载配置项
 * @param {Blob|ArrayBuffer} options.data - 文件数据
 * @param {string} [options.prefix] - 文件名前缀
 * @param {string} [options.extension] - 文件扩展名
 * @param {string} [options.fileName] - 完整文件名(如果提供则忽略prefix和extension)
 * @param {string} [options.timestamp] - 时间戳格式
 * @param {Function} [options.onSuccess] - 下载成功回调
 * @param {Function} [options.onError] - 下载失败回调
 */
export function downloadFileWithOptions(options) {
  const {
    data,
    prefix = 'file',
    extension = 'xlsx',
    fileName,
    timestamp = 'YYYYMMDDHHmmss',
    onSuccess,
    onError
  } = options
  try {
    const finalFileName = fileName || `${prefix}${moment().format(timestamp)}.${extension}`
    const blob = new Blob([data], {
      type: getContentType(extension)
    })
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
      // 针对 IE
      window.navigator.msSaveOrOpenBlob(blob, finalFileName)
    } else {
      // 现代浏览器
      const url = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.style.display = 'none'
      link.href = url
      link.download = finalFileName
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      window.URL.revokeObjectURL(url)
    }
    // 处理成功回调
    if (typeof onSuccess === 'function') {
      onSuccess()
    }
    return true
  } catch (error) {
    console.error('文件下载失败:', error)
    // 处理错误回调
    if (typeof onError === 'function') {
      onError(error)
    }
    return false
  }
}

/**
 * 获取文件类型
 * @param {string} extension - 文件扩展名
 * @returns {string} MIME类型
 */
function getContentType(extension) {
  const mimeTypes = {
    xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    xls: 'application/vnd.ms-excel',
    pdf: 'application/pdf',
    doc: 'application/msword',
    docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    txt: 'text/plain',
    csv: 'text/csv'
    // 可以根据需要添加更多类型
  }
  return mimeTypes[extension] || 'application/octet-stream'
}