android系统定制开发springboot:实现文件上传下载实时进度条功能【附带源码】

0. 引言

android系统定制开发记得刚入行的时候,android系统定制开发做了一个文件上传的功能,android系统定制开发因为上传时间较久,android系统定制开发为了用户友好性,android系统定制开发想要添加一个实时进度条,显示进度。android系统定制开发奈何当时技术有限,查了许久也没用找到解决方案,最后不了了之。

近来偶然想到这个问题,于是决定整理一下实现方式,也为和我曾经一样碰壁的同学,提供一些思路。

1. 思路

1、首先我们这里实现的是一个实时的进度条,并不是一个纯前端的进度条,它需要根据后端的处理进度来实时反馈进度条长度,那么必然要与后端交互。

当然这里容易陷入一个误区,觉得与后端交互的,那么这个功能的重点一定在后端,但实际上这个功能的重点在前端。

不难想到,我们要知道实时进度,那么一定需要不断的请求后端,得到响应反馈,前后端请求比较常用的是ajax,但除它之外,我们还有更基础的xhr(XMLHttpRequest)。作为后端同学可能对有些陌生,实际上ajax就是基于xhr实现的。

2、xhr可以让我们在不重新加载页面的情况下更新网页,在页面已经加载后从后端请求并接受数据,这样就可以无感的让我们后端文件的上传进度了。

3、为了监听文件上传下载进度,我们主要使用到xhr的三个进度事件:

  • progress: 在接收响应期间持续不断地触发
  • load: 在接收到完整的响应数据时触发
  • error: 在请求发生错误时触发

当然除上述三个事件之外,还有其他的进度事件,这不是本文的重点,大家可自行拓展学习XHR对象的进度事件

4、基于上述三个进度事件,我们可以通过process事件持续不断地发送请求获取文件上传下载的进度,load事件用于文件上传下载完成后的处理,比如提示成功。error用于请求发送错误时的处理。

5、有了上述的思路之后,我们来进行实际演示。

2. 实操

2.1 实现文件上传实时进度条功能

1、,引入spring weblombok、文件上传commons-fileupload依赖

<dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId></dependency><dependency>            <groupId>org.projectlombok</groupId>            <artifactId>lombok</artifactId>            <optional>true</optional></dependency><dependency>            <groupId>commons-fileupload</groupId>            <artifactId>commons-fileupload</artifactId>            <version>1.4</version></dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2、创建MultipartResolver的bean,用来将普通的请求封装成拥有文件上传功能的请求

@Componentpublic class FileUpLoadConfig {    @Bean(name="multipartResolver")    public MultipartResolver multipartResolver(){        return new CommonsMultipartResolver();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3、创建一个文件上传接口:这里我单纯做个演示,就直接在controller层中书写了,实际生产要将上传方法提取为工具类,在service中进行具体业务处理。

如下代码为将文件上传后,保存到资源文件夹下

@RestController@RequestMapping("file")public class FileController {    private final static Logger log = LoggerFactory.getLogger(FileController.class);    @PostMapping("/upload")    @ResponseBody    public ResponseEntity<String> fileUpload(@RequestParam("file") MultipartFile file) {        try {            // 获取资源文件存放路径,用于临时存放生成的excel文件            String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();            // 文件名            String fileName = path + file.getOriginalFilename();            // 创建目标文件            File dest = new File(fileName);            // 向指定路径写入文件            file.transferTo(dest);            // 返回文件访问路径            return new ResponseEntity<>(fileName, HttpStatus.OK);        } catch (Exception e) {            e.printStackTrace();            log.info(String.format("文件上传失败,原因:%s",e));            return new ResponseEntity<>("文件上传失败", HttpStatus.INTERNAL_SERVER_ERROR);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

4、后端接口完成后,进入我们的重点,我们来实现前端进度条

5、首先引入,我这里使用了3.6.1版本

6、实现一个上传的页面,这里利用了html5的progress标签,该标签用于实现进度条,支持两个属性:value和max,分别为当前进度值和最大进度值

<div class="modal-body form ">    <!-- 文件上传   -->    <form id="dialogForm" class="form-horizontal">        <div class="form-group">            <label class="control-label">文件:</label>            <div >                <input type="file" name="file" id="file" onchange="upload()">            </div>        </div>        <div class="form-group">            <label class="control-label">上传进度:</label>            <div >                <!--进度条-->                <div id="progress-body">                    <progress></progress>                    <div id="progress-bar">0%</div>                </div>            </div>        </div>    </form></div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

7、书写进度监听方法,即progress方法

        //进度条更新        function progressHandle(e) {            $('#progress-body progress').attr({                value : e.loaded,                max : e.total            });            var percent = (e.loaded / e.total * 100).toFixed(2);            $('#progress-body #progress-bar').html(percent + "%");        };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

8、书写load,error方法

        //上传完成处理函数        function uploadSuccess(e) {            alert("上传完成");        };        //上传出错处理函数        function uploadFail(e) {            alert("上传失败");        };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

9、实现上传方法upload

        // 文件上传        function upload() {            var formData = new FormData();            formData.append("file", $("#file")[0].files[0]);            $.ajax({                url : "/file/upload",                type : "POST",                data : formData,                processData : false, // 告诉jQuery不要去处理发送的数据                contentType : false, // 告诉jQuery不要去设置Content-Type请求头                success : function(data) {                    console.log(data);                },                xhr : function() {                    var xhr = $.ajaxSettings.xhr();                    // xhr.upload专用于上传事件监听                    if (xhr.upload) {                        //处理进度条的事件                        xhr.upload.addEventListener("progress", progressHandle,                            false);                        //加载完成的事件                        xhr.addEventListener("load", uploadSuccess, false);                        //加载出错的事件                        xhr.addEventListener("error", uploadFail, false);                        return xhr;                    }                }            });        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

10、运行项目,访问上传页,我这里直接书写在index.html中了

11、测试:如下图所示,可以正常显示进度

12、上传成功后,后台资源文件夹中也能看到对应的上传文件,演示成功!

2.2 实现文件下载实时进度条功能

上述我们讲解了如何实现上传进度条功能,有了这个思路,我们再实现下载功能:

1、同样,我们实现一个简单的进度条页面

    <!-- 文件下载   -->    <form id="dialogForm" class="form-horizontal">        <div class="form-group">            <label class="control-label">下载进度:            </label>            <div>                <!--进度条-->                <div id="progress-body">                    <progress></progress>                    <div id="progress-bar">0%</div>                </div>            </div>        </div>        <button type="button" onclick="download()">下载</button>    </form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

2、实现下载方法

这里我们不再采用ajax的方法,而是直接通过xhr请求,并且因为要在浏览器中下载该文件,所以以window.URL.revokeObjectURL方法来下载并释放该文件。

   // 文件下载    function download() {        var xhr = new XMLHttpRequest();        //处理进度条的事件        xhr.addEventListener("progress", progressHandle, false);        //加载出错的事件        xhr.addEventListener("error", uploadFail, false);        xhr.open("POST","/file/download");        //设置响应类型        xhr.responseType = 'blob';        xhr.onload = function (e) {            if (this.status === 200) {                // 截取掉'attachment;filename='                var filename = xhr.getResponseHeader("Content-disposition").slice(20);                var blob = this.response;                var a = document.createElement('a');                var url = URL.createObjectURL(blob);                a.href = url;                a.download = filename;                document.body.appendChild(a);                a.click();                window.URL.revokeObjectURL(url);            }        }        xhr.send();    }    //进度条更新    function progressHandle(e) {        $('#progress-body progress').attr({            value: e.loaded,            max: e.total        });        var percent = (e.loaded / e.total * 100).toFixed(2);        $('#progress-body #progress-bar').html(percent + "%");    };        //上传出错处理函数    function uploadFail(e) {        alert("下载失败");    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

3、实现后端下载文件接口

这里与上传文件不同的是,前端在进行文件上传时,是可以获取到文件的总大小的,而下载文件时因为是流式下载,前端是不知道要下载的文件一共有多少大小的。

因此也就无法估算总体的进度比例。所以我们后端接口中要通过Content-Length响应头指定文件的总大小

我这里为了演示方便,直接下载上述上传的文件。实际应用可更改为你自己的文件下载路径。

    @PostMapping("/download")    @ResponseBody    public ResponseEntity<String> download(HttpServletResponse response) throws IOException {        // 获取资源文件存放路径,用于临时存放生成的excel文件        String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();        File pathFile = new File(path);        File[] files = pathFile.listFiles();        if (ObjectUtils.isEmpty(files)) {            return new ResponseEntity<>("文件为空,请先上传文件", HttpStatus.OK);        }        InputStream inputStream = null;        ServletOutputStream ouputStream = null;        try {            for (File file : files) {                if(file.isDirectory()){                    continue;                }                inputStream = new FileInputStream(file);                response.setContentType("application/x-msdownload");                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));                // 设置一个总长度,否则无法估算进度                response.setHeader("Content-Length",String.valueOf(file.length()));                ouputStream = response.getOutputStream();                byte b[] = new byte[1024];                int n;                while ((n = inputStream.read(b)) != -1) {                    ouputStream.write(b, 0, n);                }                ouputStream.flush();                break;            }        } catch (Exception e) {            e.printStackTrace();        } finally {            if(inputStream != null){                inputStream.close();            }            if(ouputStream != null){                ouputStream.close();            }        }        return new ResponseEntity<>("文件下载成功", HttpStatus.OK);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

4、运行项目

5、测试:文件成功下载,进度也实时显示

3. 项目源码

以上演示源码可在如下地址下载:

4. 总结

以上我们就完成了文件的上传和下载的实时进度监控,虽然这个功能的重点在前端,但是后端通过这个功能点,也能更好的理解前后端请求的交互。

最后我们抛出一个思考问题:如何实时监控后端自定义功能的执行进度?

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发