Vue+springboot实现excel导出和zip导出,需二进制返回及跨域问题

我遇到三个问题
1、ts封装axios,responseType设置 blob 但加上去无效。
2、vue main.js用到了mock ,加上去responseType返回类型会自动去掉。
3、下载压缩文件时 报错Access-Control-Allow-Origin

index.vue重要部分代码

//导出zip文件
  getCertificateCode(formModel.value.pcid).then((response) => {
    
    const name=((1+Math.random())*0x10000)
        const link = document.createElement('a') 
        const blob = new Blob([response.data], { type: 'application/zip' })
        const url = window.URL.createObjectURL(blob)
        link.href = url
        link.download = [name, '.zip'].join('') // 重命名文件
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
  })
    .catch((e) => {
      Message.error('暂无相关证书');
    });
};

//导出xls文件
const downloadscore = () => {
  if (!formModel.value.pcid) {
    Message.error('请选择批次');
    return;
  }
  getScoreCodescore(formModel.value.pcid)
    .then((res) => {
      const name=((1+Math.random())*0x10000)
          const elink = document.createElement('a')
          elink.style.display = 'none'
          const blob = new Blob([res.data])
          const blobUrl = URL.createObjectURL(blob)
          elink.href = blobUrl
          elink.download = [name, '.xls'].join('') // 重命名文件
          document.body.appendChild(elink)
          elink.click()
          document.body.removeChild(elink)
    })
    .catch((e) => {
      console.log(e);
      Message.error('暂无相关文件');
    });
};

js 部分代码,我用的是ts封装axios 提供了多种方式

export class Axios {
  constructor(config?: AxiosRequestConfig);
  defaults: AxiosDefaults;
  interceptors: {
    request: AxiosInterceptorManager<AxiosRequestConfig>;
    response: AxiosInterceptorManager<AxiosResponse>;
  };
  getUri(config?: AxiosRequestConfig): string;
  request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
  get<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  delete<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  head<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  options<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  put<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  patch<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
}

//调用zip流的接口

export function getCertificateCode(pcid) {
  return axios.request({
    url: '/sria/certificateCode',
    method: 'get',
    params:{ pcid:pcid },
    responseType:'blob',
  })
}

//调用xls流的接口

export function getScoreCodescore(pcid) {
  return axios.request({
    url: '/sria/scoreCode',
    method: 'get',
    params:{ pcid:pcid },
    responseType:'blob',
  })
}

response返回结果判断并返回

// add response interceptors
axios.interceptors.response.use(
  (response) => {
	......省略代码......
    if(response.status===200){
      if (response.request.responseType ===  'blob' || response.request.responseType ===  'arraybuffer') {
        return response;
      }
    }
	......省略代码......
    return res;
  },
  (error) => {
    Message.error({
      content: error.msg,
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);

依赖导入
在pom文件中添加对应的依赖

<!--用来处理POL相关的操作:easypol-->
<dependency>
	<groupId>cn.afterturn</groupId>
	<artifactId>easypoi-base</artifactId>
	<version>4.2.0</version>
</dependency>
<dependency>
	<groupId>cn.afterturn</groupId>
	<artifactId>easypoi-web</artifactId>
	<version>4.2.0</version>
</dependency>
<dependency>
	<groupId>cn.afterturn</groupId>
	<artifactId>easypoi-annotation</artifactId>
	<version>4.2.0</version>
</dependency>

java重要代码

@GetMapping("/certificateCode")
public void certificateDownload(@RequestParam("pcid") String pcid,HttpServletResponse response)throws Exception{
    JwtUser user = (JwtUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    String code= IdUtil.fastSimpleUUID();
    if(StringUtils.isNotBlank(pcid) && StringUtils.isNotBlank(code)){
        String pdfPath="文件夹路径";
        if(pdfPath!=null){
	//压缩文件
            if(FileToZip.fileToZip1(pdfPath, pdfPath, code)){
	//下载文件
                FileToZip.download(pdfPath+"/"+code+".zip",response);
            }
	//删除文件
            FileToZip.deletefile(pdfPath);
        }
    }
}

@GetMapping("/scoreCode")
public void scoreDownload(@RequestParam("pcid") String pcid,HttpServletResponse response)throws Exception{
    JwtUser user = (JwtUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    String code= IdUtil.fastSimpleUUID();
    List<ScoreVo> list= new ArrayList<>();
    ScoreVo s=new ScoreVo();
    s.setName("123456");
    s.setNote("111111");
    list.add(s);
    try {
        //导出操作
        ExcelUtil.exportExcel(list,null,"sheet", ScoreVo.class,code+".xlsx",response);
    } catch (Exception e) {
        e.getMessage();

    }
}

实体类ScoreVo

@Data
public class ScoreVo{
    @Excel(name="姓名")
    private String name;
    @Excel(name="状态")
    private String note;
}

Excel导入导出工具类

public class ExcelUtil {

    /**
     * 导出工具类
     * @param list
     * @param title
     * @param sheetName
     * @param pojoClass
     * @param fileName
     * @param isCreateHeader
     * @param response
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,
                                   String fileName, boolean isCreateHeader, HttpServletResponse response){
        ExportParams exportParams = new ExportParams(title, sheetName);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /**
     * 导出工具类
     * @param list
     * @param title
     * @param sheetName
     * @param pojoClass
     * @param fileName
     * @param response
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,String fileName,
                                   HttpServletResponse response){
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    }

    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response){
        defaultExport(list, fileName, response);
    }

    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName,
                                      HttpServletResponse response, ExportParams exportParams) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams,pojoClass,list);
        if (workbook != null); downLoadExcel(fileName, response, workbook);
    }

    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            //throw new NormalException(e.getMessage());
        }
    }

    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        if (workbook != null);
        downLoadExcel(fileName, response, workbook);
    }

    public static <T> List<T> importExcel(String filePath,Integer titleRows,Integer headerRows, Class<T> pojoClass){
        if (StringUtils.isBlank(filePath)){
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        }catch (NoSuchElementException e){
            //throw new NormalException("模板不能为空");
        } catch (Exception e) {
            e.printStackTrace();
            //throw new NormalException(e.getMessage());
        } return list;
    }

    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass){
        if (file == null){ return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        }catch (NoSuchElementException e){
            // throw new NormalException("excel文件不能为空");
        } catch (Exception e) {
            //throw new NormalException(e.getMessage());
            System.out.println(e.getMessage());
        }
        return list;
    }

}

压缩文件工具类 FileToZip.java

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public final class FileToZip {  

    private FileToZip(){}  

    /** 
     * 将存放在sourceFilePath目录下的源文件,打包成fileName名称的zip文件,并存放到zipFilePath路径下 
     * @param sourceFilePath :待压缩的文件路径 
     * @param zipFilePath :压缩后存放路径 
     * @param fileName :压缩后文件的名称 
     * @return 
     * @throws IOException
     */  
    public static boolean fileToZip(String sourceFilePath, String zipFilePath, String fileName) throws IOException {
    	boolean flag = false;
        File sourceFile = new File(sourceFilePath);
        if(sourceFile.exists() == false) {
            System.out.println(">>>>>> 待压缩的文件目录:" + sourceFilePath + " 不存在. <<<<<<");
            flag = false;
            return flag;
        } else {
            try {
                File zipFile = new File(zipFilePath + "/" + fileName + ".zip");
                if(zipFile.exists()) {
                    System.out.println(">>>>>> " + zipFilePath + " 目录下存在名字为:" + fileName + ".zip" + " 打包文件. <<<<<<");
                } else {
                    File[] sourceFiles = sourceFile.listFiles();
                    String[] filelist = sourceFile.list();
                    if(filelist.length<1){//二次开发2021-05-11 判断文件夹下面是否存在文件否文件夹
                    //if( null == sourceFiles || sourceFiles.length < 1) {
                        System.out.println(">>>>>> 待压缩的文件目录:" + sourceFilePath + " 里面不存在文件,无需压缩. <<<<<<");
                        flag = false;
                        return flag;
                    } else {
                        ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile))); //用到时才申明,否则容易出现问题,记得先开后关,后开先关
                        byte[] bufs = new byte[1024*10];               //缓冲块
                        for(int i=0;i<sourceFiles.length;i++) {// 创建ZIP实体,并添加进压缩包
                            ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
                            zos.putNextEntry(zipEntry);// 读取待压缩的文件并写进压缩包里
                            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFiles[i]),1024*10);   //用到时才申明,否则容易出现问题,记得先开后关,后开先关
                            int read = 0;
                            while((read=(bis.read(bufs, 0, 1024*10))) != -1) {
                                zos.write(bufs, 0, read);
                            }
                            if(null != bis) bis.close();  //关闭
                        }
                        flag = true;
                        if(null != zos) zos.close();  //关闭
                    }

                }

            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        return flag;

    } 
    /***
     * 下载文件
     * @param path
     * @param response
     * @return
     */
    public static void download(String path, HttpServletResponse response) {
        try {
            // path是指欲下载的文件的路径。
            File file = new File(path);
            // 取得文件名。
            String filename = file.getName();
            // 取得文件的后缀名。
            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();
            //支持中文名
            filename = URLEncoder.encode(filename,"UTF-8");

            // 以流的形式下载文件
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" +filename);
            response.addHeader("Content-Length", "" + buffer.length);
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            response.setHeader("Access-Control-Allow-Origin", "*");//这个地方一定要设置,解决跨域问题,我在配置文件中加上跨域没有作用
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        //return response;
    }
    /**
     * 删除某个文件夹下的所有文件夹和文件
     *
     * @param delpath
     * @throws FileNotFoundException IOException
     * @return boolean
     */
    public static boolean deletefile(String delpath) throws Exception {
        File file = new File(delpath);
        if (file.isDirectory()) {
            String[] filelist = file.list();
            for (String delFile : filelist) {
                File delfile = new File(delpath + File.separator + delFile);
                if (delfile.isDirectory()) {
                    deletefile(delpath + File.separator + delFile);
                } else
                    System.out.println("正在删除文件:" + delfile.getPath() + ",删除是否成功:" + delfile.delete());
            }
            System.out.println("正在删除空文件夹:" + file.getPath() + ",删除是否成功:" + file.delete());
        } else
            System.out.println("正在删除文件:" + file.getPath() + ",删除是否成功:" + file.delete());
        return true;
    }
    public static boolean fileToZip1(String sourceFilePath, String zipFilePath, String fileName) throws IOException {
        boolean flag = false;
        File sourceFile = new File(sourceFilePath);
        if(sourceFile.exists() == false) {
            System.out.println(">>>>>> 待压缩的文件目录:" + sourceFilePath + " 不存在. <<<<<<");
            flag = false;
            return flag;
        } else {
            try {
                File zipFile = new File(zipFilePath + "/" + fileName + ".zip");
                FileOutputStream fos1 = new FileOutputStream(zipFile);
                toZip(fileName + ".zip",zipFilePath, fos1,true);
                flag=true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        return flag;
    }
        /**
         * 压缩成ZIP 方法1
         * @param srcDir 压缩文件夹路径
         * @param out    压缩文件输出流
         * @param KeepDirStructure  是否保留原来的目录结构,true:保留目录结构;
         *false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
         * @throws RuntimeException 压缩失败会抛出运行时异常
         */
    public static void toZip(String fileName, String srcDir, OutputStream out, boolean KeepDirStructure)
        throws RuntimeException {
        long start = System.currentTimeMillis();
        ZipOutputStream zos = null ;
        try {
            zos = new ZipOutputStream(out);
            File sourceFile = new File(srcDir);
            compress(fileName,sourceFile,zos,sourceFile.getName(),KeepDirStructure);
            long end = System.currentTimeMillis();
            System.out.println("压缩完成,耗时:" + (end - start) +" ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils",e);
        }finally{
            if(zos != null){
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 递归压缩方法
     * @param sourceFile 源文件
     * @param zos        zip输出流
     * @param name       压缩后的名称
     * @param KeepDirStructure  是否保留原来的目录结构,true:保留目录结构;
     * false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    private static void compress(String fileName, File sourceFile, ZipOutputStream zos, String name,
                                 boolean KeepDirStructure) throws Exception {
        byte[] buf = new byte[2 * 1024];
        if(sourceFile.isFile()){
            if(name.indexOf(fileName)==-1) {
                // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
                zos.putNextEntry(new ZipEntry(name));
                // copy文件到zip输出流中
                int len;
                FileInputStream in = new FileInputStream(sourceFile);
                while ((len = in.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                }
                // Complete the entry
                zos.closeEntry();
                in.close();
            }
        } else {
            File[] listFiles = sourceFile.listFiles();
            if(listFiles == null || listFiles.length == 0){
                // 需要保留原来的文件结构时,需要对空文件夹进行处理
                if(KeepDirStructure){
                    // 空文件夹的处理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 没有文件,不需要文件的copy
                    zos.closeEntry();
                }
            }else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (KeepDirStructure) {
                        // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
                        compress(fileName,file, zos, name + "/" + file.getName(),KeepDirStructure);
                    } else {
                        compress(fileName,file, zos, file.getName(),KeepDirStructure);
                    }
                }
            }
        }
    }
}

vue 中main.js文件,如果有mock,一定要去掉,要不然会自动删除responseType类型

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值