天天看点

VUE下载文件,原以为很简单

文件下载不就是个链接

测试平台有个对比功能要上传个文件,一向理解的文件下载,就是在前端设置个超链接,能链接到文件地址就可以下载了。于是就照着这个思路开始写,先是前端来个超链接,

简单。下面就是文件放置地址了,想过放前端,可是太不规范,我们还是要按规矩来,放到后端webapp目录下。放置好后,怎么拼装链接都拿不到文件,都是404,很小白的问题,后端没有暴露API,不可能这样直接能获取文件(其实配置tomcat成文件服务器也可以,本篇不讲)。

后端设置文件下载接口

那就增加个接口吧

@RequestMapping(value = "compare")
    public void addDBConfig(HttpServletResponse response, HttpServletRequest request) {
    	// 从项目根目录开始获取文件,path必须是文件名,而不是上级目录
        String filePath = System.getProperty("webapp.root") + "file/template.xlsx";
        logger.info("获取文件路径:" + filePath);
        String fileName = "template.xlsx";
        String userAgent = request.getHeader("USER-AGENT");
        boolean result = myDownLoad(filePath, fileName, userAgent, response);
        if (!result)
            logger.error("对比文件下载有误");
    }
           

通用下载方法,后续有其他下载时可用。

重点关注是返回要设置头信息,文件要输出成流,以及编码统一防止乱码。

//下载方法
    public boolean myDownLoad(String filePath, String fileName, String userAgent, HttpServletResponse response) {
        File f = new File(filePath);
        if (!f.exists()) {
            try {
                response.sendError(404, "File not found!");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
        String type = fileName.substring(fileName.lastIndexOf(".") + 1);
        //判断下载类型 xlsx 或 xls 现在只实现了xlsx、xls两个类型的文件下载
        if (type.equalsIgnoreCase("xlsx") || type.equalsIgnoreCase("xls")) {
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
//            response.setContentType("application/force-download;charset=UTF-8");
            try {
                if (StringUtils.contains(userAgent, "MSIE") || StringUtils.contains(userAgent, "Edge")) {// IE浏览器
                    fileName = URLEncoder.encode(fileName, "UTF8");
                } else if (StringUtils.contains(userAgent, "Mozilla")) {// google,火狐浏览器
                    fileName = new String(fileName.getBytes(), "ISO8859-1");
                } else {
                    fileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
                }
                response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            } catch (UnsupportedEncodingException e) {
                logger.error(e.getMessage(), e);
                return false;
            }
            InputStream in = null;
            OutputStream out = null;
            try {

                //获取要下载的文件输入流
                in = new FileInputStream(filePath);
                int len = 0;
                //创建数据缓冲区
                byte[] buffer = new byte[1024];
                //通过response对象获取outputStream流
                out = response.getOutputStream();
                //将FileInputStream流写入到buffer缓冲区
                while ((len = in.read(buffer)) > 0) {
                    //使用OutputStream将缓冲区的数据输出到浏览器
                    out.write(buffer, 0, len);
                }
                //这一步走完,将文件传入OutputStream中后,页面就会弹出下载框

            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                return false;
            } finally {
                try {
                    if (out != null)
                        out.close();
                    if (in != null)
                        in.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
            return true;
        } else {
            logger.error("不支持的下载类型!");
            return false;
        }
    }
           

很好,调用链接能正常下载。

前后端部署的问题

开心的提交部署,咦,怎么下载不下来了。一顿排查,发现链接本地没问题,服务器也可以做到没问题,但问题是啥;服务器上部署的后端在tomcat下tank_be目录,本地是直接ROOT目录,前端设置的链接为固定链接,两边不一致就只能保证一边的正确性。

那其他前后端交互接口是如何操作的呢?在前端lib/axiosConfig.js里的设置前缀:

// 基础url前缀
  baseURL: '/tank_be/tank/',
  // baseURL: '/tank/',
           

只要前端发起的axios请求都能自动拼装前缀,发布到不同目录,修改这里配置即可。

好,那就把前端固定链接也改装成axios请求,链接也配置成el-link。

重点关注要把返回设置成blob文件形式。

<el-link type='primary' @click='download' title="下载">模板下载</el-link>
download () {
      let config = {responseType: 'blob'}
      axios
        .get(`/download/compare`, config)
        .then(data => {
          if (!data) {
            this.$message.error('模板下载异常')
          }
          let url = window.URL.createObjectURL(new Blob([data]))
          let link = document.createElement('a')
          link.style.display = 'none'
          link.href = url
          link.setAttribute('download', 'template.xlsx')
          document.body.appendChild(link)
          link.click()
        })
    },
           

如此,不管是服务器还是本地都能拼装链接,正常请求到后端下载文件。相信还有其他更方便的方式解决,等后续再来补充。

前端实现

后端实现