一、前言

本文采用前后端分离式的架构,其中涉及到文件下载的需求,文件下载在任何系统中都是比较常见的。对于前后端分离架构的文件下载与往常的写法有些许不同(试过直接使用a标签,href填上下载地址,发现行不通),所以经过查找与尝试,以下文件下载前后端实现流程供大家参考。

二、准备

前端:vue + ViewUI

后端:springboot

三、文件下载

1、准备一个文件下载接口,返回文件流

@GetMapping("/download")
public void downloadFile(HttpServletResponse response) {
    // 读取resource目下文件
    String templatePath = "classpath:file/test.txt";
    String filename = " test.txt ";

    File file = null;
    try {
        file = ResourceUtils.getFile(templatePath);
    } catch (FileNotFoundException e) {
        log.warn("文件不存在 {}", filename);
        // todo, 可以在流中返回“文件不存在“,这样用户可以下载到文件,但是内容为”文件不存在”
        return;
    }

    if (file.isFile()) {
        byte[] fileNameBytes = filename.getBytes(StandardCharsets.UTF_8);
        filename = new String(fileNameBytes, 0, fileNameBytes.length, StandardCharsets.ISO_8859_1);
    
        response.reset();
        response.setContentType("application/force-download");
        response.setCharacterEncoding("utf-8");
        response.setContentLength((int) file.length());
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
    
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
            byte[] buff = new byte[1024];
            OutputStream os = response.getOutputStream();
            int i;
            while ((i = bis.read(buff)) != -1) {
                os.write(buff, 0, i);
                os.flush();
            }
        } catch (IOException e) {
            log.error("下载出错 {},错误原因 {}", filename, e.getMessage());
        }
    } else {
        log.warn("文件不存在 {}", filename);
        // todo, 可以在流中返回“文件不存在“,这样用户可以下载到文件,但是内容为”文件不存在”
    }
}

2、前端定义一个button标签,通过点击按钮实现文件下载

<Button type="text" @click.stop.prevent="downloadFile">下载</Button>

3、下载按钮点击事件

downloadFile (){
    let downloadUrl = "/download"

    axios({
        url: downloadUrl,
        method: 'get',
        responseType: 'arraybuffer'
    }).then(res => {
        const blob = new Blob([res.data]);
        //创建一个<a></a>标签
        let a = document.createElement("a");
        // 将流文件写入a标签的href属性值
        a.href = URL.createObjectURL(blob);
        //设置文件名
        a.download = "template.py";
        // 隐藏a标签
        a.style.display = "none";
        // 将a标签追加到文档对象中
        document.body.appendChild(a); 
        // 模拟点击了a标签,会触发a标签的href的读取,浏览器就会自动下载了
        a.click();
        //用完就删除a标签
        a.remove();
    })
}

通过以上的做法,就能够在前后端分离架构中实现文件下载啦!

四、文件上传

1、后端准备一个上传文件接口

@PostMapping("/upload")
public Boolean uploadFile(FileVO fileVO) throws Exception {
    String location = "D:\\file";
    String user = "001";
    // 创建存放文件目录,一个用户一个目录
    File dir = Paths.get(location, user).toFile();
    if (!dir.isDirectory()) {
        boolean mkdirs = dir.mkdirs();
        if (!mkdirs) {
            log.error("脚本文件保存目錄創建失敗,目录:{}", dir);
            return false;
        }

        // 保存脚本文件
        MultipartFile file = fileVO.getFile();
        try {
            file.transferTo(Paths.get(location, user,       file.getOriginalFilename()));
        } catch (Exception e) {
            log.error("脚本文件: {} 保存失敗,錯誤原因: {}", file.getOriginalFilename(), e.getMessage());
            return false;
        }
        return true;
    }
}
public class ScriptVO {

    /**
     *文件
     */
    private MultipartFile file;

}

2、定义一个上传标签,通过点击按钮实现文件上传(如果不是使用ViewUI,那么请使用对应前端框架提供的标签)

<div>
    <Upload
        :before-upload="handleUpload"
        type="drag">
        <div style="padding: 20px 0">
        <Icon type="ios-cloud-upload" size="52" style="color: #3399ff"></Icon>
            <p>点击或拖拽选择Python脚本文件</p>
        </div>
    </Upload>
</div>
<div>
    <Button
        type="primary"
        style="margin-left: 8px;"
        @click="submit"
    >确认</Button>
</div>

3、上传按钮点击事件

handleUpload (file) {
    this.uploadFile = file;
    return false;
},
submit(){
    const formData = new FormData();
    formData.append("file", uploadFile);
    axios.post('/upload',formData,{
        'Content-type' : 'multipart/form-data'
    }).then(res=>{
        res = res.data
        // 上传成功后的处理
        if (res == true) {
        // 上传成功
        }
        else {
        // 上传失败
        }
    })
}

通过以上的做法,就能够在前后端分离架构中实现文件上传啦!

Logo

前往低代码交流专区

更多推荐