当前位置:首页 > JavaScript > 正文内容

React中如何实现文件下载功能

flowstone5年前 (2021-01-05)JavaScript707

场景描述

在前端页面中,经常会使用到文件下载功能,我们如何实现下载功能呢?

开发环境

  • React ^16.12.0

  • Ant Design ^5.0.12

  • SpringBoot 2.3.0

问题分析

首先,想到下载,肯定要涉及文件流(字节流),后端接口返回文件流,前端页面把文件流保存成对应的文件。

后端接口设计

写一个无返回值的方法,方法参数是HttpServletResponse,代码如下所示

//SmsTemplateController.java@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
    smsTemplateService.download(response);
}

接口的具体实现,如下所示

//SmsTemplateServiceImpl.java
 @Overridepublic void download(HttpServletResponse response) throws IOException {    
   //设置字符集
    response.setCharacterEncoding("utf-8");    
    //response.setContentType("application/vnd.ms-excel");
    //设置响应的头
    response.setHeader("Content-Disposition", "attachment;filename = " + "helloworld.png");    
    //获得响应的字节流
    OutputStream outputStream = response.getOutputStream();    
    //文件写死,根据需求改变
    File file = new File("/Users/simonxue/Developer/Temp/file.png");    
    //把文件内容复制到字节输出流中
    FileIoUtil.copyFile(file, outputStream);
}


我们的文件流主要是放在接口响应中,其中涉及到一个工具类,如下所示

//FileIoUtil.java
/**
 * 复制file中的内容到输出流中
 * @param file 文件内容
 * @param out 输出流
 * @throws IOException
 */
public static void copyFile(File file, OutputStream out) throws IOException {
    InputStream input = null;
    try {
        input = new FileInputStream(file);
        byte[] buf = new byte[1024];
        int bytesRead;
        while ((bytesRead = input.read(buf)) > 0) {
            out.write(buf, 0, bytesRead);
        }
    } finally {
        input.close();
        out.close();
    }
}


使用Postman调用接口,效果如下

接口响应体中,包含了大量的乱码,如果出现这个效果,则代表接口已返回文件流。

前端页面设计

首先,创建一个下载按钮,如下所示

//index.tsx
<Button type="primary" onClick={downloadOnClick}>
    下载
</Button>


并且绑定一个点击事件,如下所示

//index.tsxconst 
downloadOnClick = async () => {    
    await imgDownload();
};


下载文件具体操作,如下所示

//service.ts
export const imgDownload = (data?: any) =>
    new Promise((resolve, reject) => {
    axios
    //接口请求地址
    .get('/smsTemp/download', {
        //请求参数中,带上响应类型,否则文件损坏
        responseType: 'blob',
    })
    //接口响应成功后
    .then(res => {
        const content = res.data;
        const blob = new Blob([content], { type: 'charset=utf-8' });
        //定义文件名称,写死,根据需求自行更改
        const fileName = 'helloworld.png';
        //判断是不是IE浏览器
        if (!window.navigator.msSaveOrOpenBlob) {
        // 创建一个a标签
        const downlink = document.createElement('a');
        // 设置a标签download属性
        downlink.download = fileName;
        // 设置a标签display属性
        downlink.style.display = 'none';
        // 设置a标签href属性
        downlink.href = URL.createObjectURL(blob);
        // 添加a标签到Body中
        document.body.appendChild(downlink);
        //点击a标签
        downlink.click();
        //清除a标签中的href属性
        URL.revokeObjectURL(downlink.href);
        //从body中删除该a标签
        document.body.removeChild(downlink);
    } else {
        //IE浏览器
        window.navigator.msSaveBlob(blob, fileName);
    }
    })
    //异常处理
    .catch(e => {
    reject('下载失败');
    });
});


扫描二维码推送至手机访问。

版权声明:本文由薛尧的博客发布,如需转载请注明出处。

本文链接:https://flowstone.sourceforge.io/?id=62

分享给朋友:

相关文章

JS特效-轮播图

效果如下功能分析每隔1秒换一张图片鼠标移入停止切换、鼠标离开继续切换鼠标移入到数字上面的时候,显示和数字对应的图片,并且停止切换,被选中的数字,背景显示橙色鼠标离开数字,从该数字后面继续显示代码如下<!DOCTYPE htm...

Ajax自定义日历

需求分析在一些购物网站中,都会有促销活动,这些活动都在日历上标注出来,如何通过Ajax让日历通过读取数据库中的信息,正确的把促销活动标注在日历上,本文通过自定义日历来实现这个问题。技术难点日历的布局日历的初始化日历的动态变化日历的促销定制实...

AngularJS动态特效之验证码按钮倒计时

功能需求当用户注册或者找回密码时,输入注册的手机号发送验证码到手机中,点击发送验证码按钮倒计时这个功能是如何实现呢?效果如下表单代码如下<div class="signup" ng-app=&q...

React Ant框架中分页的快速使用

使用环境ReactAnt DesignSpringBootSpring Data JPA前端页面首先,我们要查看Ant官方文档,一般涉及到分页的页面都是列表查询,在表格组件中找到API,可以从API中看到使用方法,查看文档后,编写代码如下&...

React中useState如何给对象中的某一个属性赋值

问题描述在React文件中使用了useState,定义了查询条件,这个查询条件实际上是一个对象,如下所示const [requestParam, setRequestParam] = useState...

JS中绑定方法加括号和不加括号的区别

问题描述在React开发中,遇到一个页面不停调用接口问题,如下图所示 问题解决查找哪里调用了接口,最后在刷新按钮上找到了问题所在,如下所示<Button     type="...