欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能(附源碼)

 更新時(shí)間:2022年10月24日 08:45:32   作者:wu@55555  
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下

0. 引言

記得剛?cè)胄械臅r(shí)候,做了一個(gè)文件上傳的功能,因?yàn)樯蟼鲿r(shí)間較久,為了用戶友好性,想要添加一個(gè)實(shí)時(shí)進(jìn)度條,顯示進(jìn)度。奈何當(dāng)時(shí)技術(shù)有限,查了許久也沒(méi)用找到解決方案,最后不了了之。

近來(lái)偶然想到這個(gè)問(wèn)題,于是決定整理一下實(shí)現(xiàn)方式,也為和我曾經(jīng)一樣碰壁的同學(xué),提供一些思路。

1. 思路

1、首先我們這里實(shí)現(xiàn)的是一個(gè)實(shí)時(shí)的進(jìn)度條,并不是一個(gè)純前端的進(jìn)度條,它需要根據(jù)后端的處理進(jìn)度來(lái)實(shí)時(shí)反饋進(jìn)度條長(zhǎng)度,那么必然要與后端交互。

當(dāng)然這里容易陷入一個(gè)誤區(qū),覺(jué)得與后端交互的,那么這個(gè)功能的重點(diǎn)一定在后端,但實(shí)際上這個(gè)功能的重點(diǎn)在前端。

不難想到,我們要知道實(shí)時(shí)進(jìn)度,那么一定需要不斷的請(qǐng)求后端,得到響應(yīng)反饋,前后端請(qǐng)求比較常用的是ajax,但除它之外,我們還有更基礎(chǔ)的xhr(XMLHttpRequest)。作為后端同學(xué)可能對(duì)xhr有些陌生,實(shí)際上ajax就是基于xhr實(shí)現(xiàn)的。

2、xhr可以讓我們?cè)诓恢匦录虞d頁(yè)面的情況下更新網(wǎng)頁(yè),在頁(yè)面已經(jīng)加載后從后端請(qǐng)求并接受數(shù)據(jù),這樣就可以無(wú)感的讓我們后端文件的上傳進(jìn)度了。

3、為了監(jiān)聽(tīng)文件上傳下載進(jìn)度,我們主要使用到xhr的三個(gè)進(jìn)度事件:

  • progress: 在接收響應(yīng)期間持續(xù)不斷地觸發(fā)
  • load: 在接收到完整的響應(yīng)數(shù)據(jù)時(shí)觸發(fā)
  • error: 在請(qǐng)求發(fā)生錯(cuò)誤時(shí)觸發(fā)

當(dāng)然除上述三個(gè)事件之外,還有其他的進(jìn)度事件,這不是本文的重點(diǎn),大家可自行拓展學(xué)習(xí)XHR對(duì)象的進(jìn)度事件

XMLHttpRequest簡(jiǎn)介

4、基于上述三個(gè)進(jìn)度事件,我們可以通過(guò)process事件持續(xù)不斷地發(fā)送請(qǐng)求獲取文件上傳下載的進(jìn)度,load事件用于文件上傳下載完成后的處理,比如提示成功。error用于請(qǐng)求發(fā)送錯(cuò)誤時(shí)的處理。

5、有了上述的思路之后,我們來(lái)進(jìn)行實(shí)際演示。

2. 實(shí)操

2.1 實(shí)現(xiàn)文件上傳實(shí)時(shí)進(jìn)度條功能

1、創(chuàng)建springboot項(xiàng)目,引入spring weblombok、文件上傳commons-fileupload依賴(lài)

<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>

2、創(chuàng)建MultipartResolver的bean,用來(lái)將普通的請(qǐng)求封裝成擁有文件上傳功能的請(qǐng)求

@Component
public class FileUpLoadConfig {

    @Bean(name="multipartResolver")
    public MultipartResolver multipartResolver(){
        return new CommonsMultipartResolver();
    }
}

3、創(chuàng)建一個(gè)文件上傳接口:這里我單純做個(gè)演示,就直接在controller層中書(shū)寫(xiě)了,實(shí)際生產(chǎn)要將上傳方法提取為工具類(lèi),在service中進(jìn)行具體業(yè)務(wù)處理。

如下代碼為將文件上傳后,保存到資源文件夾下

@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 {
            // 獲取資源文件存放路徑,用于臨時(shí)存放生成的excel文件
            String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
            // 文件名
            String fileName = path + file.getOriginalFilename();
            // 創(chuàng)建目標(biāo)文件
            File dest = new File(fileName);
            // 向指定路徑寫(xiě)入文件
            file.transferTo(dest);
            // 返回文件訪問(wèn)路徑
            return new ResponseEntity<>(fileName, HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            log.info(String.format("文件上傳失敗,原因:%s",e));
            return new ResponseEntity<>("文件上傳失敗", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

4、后端接口完成后,進(jìn)入我們的重點(diǎn),我們來(lái)實(shí)現(xiàn)前端進(jìn)度條

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

6、實(shí)現(xiàn)一個(gè)上傳的頁(yè)面,這里利用了html5的progress標(biāo)簽,該標(biāo)簽用于實(shí)現(xiàn)進(jìn)度條,支持兩個(gè)屬性:value和max,分別為當(dāng)前進(jìn)度值和最大進(jìn)度值

<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">上傳進(jìn)度:</label>
            <div >
                <!--進(jìn)度條-->
                <div id="progress-body">
                    <progress></progress>
                    <div id="progress-bar">0%</div>
                </div>
            </div>
        </div>
    </form>

</div>

7、書(shū)寫(xiě)進(jìn)度監(jiān)聽(tīng)方法,即progress方法

        //進(jìn)度條更新
        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 + "%");
        };

8、書(shū)寫(xiě)load,error方法

        //上傳完成處理函數(shù)
        function uploadSuccess(e) {
            alert("上傳完成");
        };
        //上傳出錯(cuò)處理函數(shù)
        function uploadFail(e) {
            alert("上傳失敗");
        };

9、實(shí)現(xiàn)上傳方法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不要去處理發(fā)送的數(shù)據(jù)
                contentType : false, // 告訴jQuery不要去設(shè)置Content-Type請(qǐng)求頭
                success : function(data) {
                    console.log(data);
                },
                xhr : function() {
                    var xhr = $.ajaxSettings.xhr();
                    // xhr.upload專(zhuān)用于上傳事件監(jiān)聽(tīng)
                    if (xhr.upload) {
                        //處理進(jìn)度條的事件
                        xhr.upload.addEventListener("progress", progressHandle,
                            false);
                        //加載完成的事件
                        xhr.addEventListener("load", uploadSuccess, false);
                        //加載出錯(cuò)的事件
                        xhr.addEventListener("error", uploadFail, false);
                        return xhr;
                    }
                }
            });
        }

10、運(yùn)行項(xiàng)目,訪問(wèn)上傳頁(yè),我這里直接書(shū)寫(xiě)在index.html中了

11、測(cè)試:如下圖所示,可以正常顯示進(jìn)度

12、上傳成功后,后臺(tái)資源文件夾中也能看到對(duì)應(yīng)的上傳文件,演示成功!

2.2 實(shí)現(xiàn)文件下載實(shí)時(shí)進(jìn)度條功能

上述我們講解了如何實(shí)現(xiàn)上傳進(jìn)度條功能,有了這個(gè)思路,我們?cè)賹?shí)現(xiàn)下載功能:

1、同樣,我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的進(jìn)度條頁(yè)面

    <!-- 文件下載   -->
    <form id="dialogForm" class="form-horizontal">
        <div class="form-group">
            <label class="control-label">下載進(jìn)度:
            </label>
            <div>
                <!--進(jìn)度條-->
                <div id="progress-body">
                    <progress></progress>
                    <div id="progress-bar">0%</div>
                </div>
            </div>
        </div>
        <button type="button" onclick="download()">下載</button>
    </form>

2、實(shí)現(xiàn)下載方法

這里我們不再采用ajax的方法,而是直接通過(guò)xhr請(qǐng)求,并且因?yàn)橐跒g覽器中下載該文件,所以以window.URL.revokeObjectURL方法來(lái)下載并釋放該文件。

   // 文件下載
    function download() {
        var xhr = new XMLHttpRequest();
        //處理進(jìn)度條的事件
        xhr.addEventListener("progress", progressHandle, false);
        //加載出錯(cuò)的事件
        xhr.addEventListener("error", uploadFail, false);
        xhr.open("POST","/file/download");
        //設(shè)置響應(yīng)類(lèi)型
        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();
    }

    //進(jìn)度條更新
    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 + "%");
    };
    
    //上傳出錯(cuò)處理函數(shù)
    function uploadFail(e) {
        alert("下載失敗");
    };

3、實(shí)現(xiàn)后端下載文件接口

這里與上傳文件不同的是,前端在進(jìn)行文件上傳時(shí),是可以獲取到文件的總大小的,而下載文件時(shí)因?yàn)槭橇魇较螺d,前端是不知道要下載的文件一共有多少大小的。

因此也就無(wú)法估算總體的進(jìn)度比例。所以我們后端接口中要通過(guò)Content-Length響應(yīng)頭指定文件的總大小

我這里為了演示方便,直接下載上述上傳的文件。實(shí)際應(yīng)用可更改為你自己的文件下載路徑。

    @PostMapping("/download")
    @ResponseBody
    public ResponseEntity<String> download(HttpServletResponse response) throws IOException {
        // 獲取資源文件存放路徑,用于臨時(shí)存放生成的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<>("文件為空,請(qǐng)先上傳文件", 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"));
                // 設(shè)置一個(gè)總長(zhǎng)度,否則無(wú)法估算進(jìn)度
                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);
    }

4、運(yùn)行項(xiàng)目

5、測(cè)試:文件成功下載,進(jìn)度也實(shí)時(shí)顯示

3. 項(xiàng)目源碼

以上演示源碼可在如下地址下載:

文件上傳下載實(shí)時(shí)進(jìn)度源碼

4. 總結(jié)

以上我們就完成了文件的上傳和下載的實(shí)時(shí)進(jìn)度監(jiān)控,雖然這個(gè)功能的重點(diǎn)在前端,但是后端通過(guò)這個(gè)功能點(diǎn),也能更好的理解前后端請(qǐng)求的交互。

最后我們拋出一個(gè)思考問(wèn)題:如何實(shí)時(shí)監(jiān)控后端自定義功能的執(zhí)行進(jìn)度?

以上就是SpringBoot實(shí)現(xiàn)文件上傳下載實(shí)時(shí)進(jìn)度條功能(附源碼)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot文件上傳下載實(shí)時(shí)進(jìn)度條的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java仿QQ連連看游戲

    java仿QQ連連看游戲

    這篇文章主要為大家詳細(xì)介紹了java仿QQ連連看游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Java8學(xué)習(xí)教程之lambda表達(dá)式語(yǔ)法介紹

    Java8學(xué)習(xí)教程之lambda表達(dá)式語(yǔ)法介紹

    眾所周知lambda表達(dá)式是JAVA8中提供的一種新的特性,它支持Java也能進(jìn)行簡(jiǎn)單的“函數(shù)式編程”。 下面這篇文章主要給大家介紹了關(guān)于Java8學(xué)習(xí)教程之lambda表達(dá)式語(yǔ)法的相關(guān)資料,需要的朋友可以參考下。
    2017-09-09
  • java的三種IO模型詳解(BIO、NIO、AIO)

    java的三種IO模型詳解(BIO、NIO、AIO)

    本文介紹了BIO、NIO和AIO三種不同的IO模型,分別分析了它們的工作機(jī)制、實(shí)現(xiàn)方式以及與BIO的對(duì)比,BIO是阻塞的,每個(gè)連接需要一個(gè)線程;NIO是同步非阻塞的,通過(guò)緩沖區(qū)和選擇器實(shí)現(xiàn)I/O多路復(fù)用;AIO是異步的,操作系統(tǒng)處理IO操作,完成后通知應(yīng)用程序
    2024-11-11
  • Java實(shí)現(xiàn)優(yōu)雅停止線程的有效方法詳解

    Java實(shí)現(xiàn)優(yōu)雅停止線程的有效方法詳解

    這篇文章主要為大家詳細(xì)如何安全有效停止 Java 線程的,確保多線程應(yīng)用程序平穩(wěn)運(yùn)行并實(shí)現(xiàn)最佳資源管理,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • IDEA中設(shè)置代碼自動(dòng)提示為Alt+/的具體做法

    IDEA中設(shè)置代碼自動(dòng)提示為Alt+/的具體做法

    很多公司都強(qiáng)制性要求使用Intellij?IDEA,其實(shí)Intellij?IDEA也確實(shí)很好用,但是一下子從Eclipse跳轉(zhuǎn)到Intellij?IDEA轉(zhuǎn)也是需要一段時(shí)間的,為了迎合之前的習(xí)慣,就需要在Intellij?IDEA中改變一些設(shè)置,如代碼自動(dòng)生成,本文給大家分享設(shè)置方法,感興趣的朋友一起看看吧
    2023-01-01
  • SpringBoot2.3新特性優(yōu)雅停機(jī)詳解

    SpringBoot2.3新特性優(yōu)雅停機(jī)詳解

    這篇文章主要介紹了SpringBoot2.3新特性優(yōu)雅停機(jī)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Java實(shí)現(xiàn)Treap樹(shù)的示例代碼

    Java實(shí)現(xiàn)Treap樹(shù)的示例代碼

    本文主要介紹了Java實(shí)現(xiàn)Treap樹(shù)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Spring Bean三種注入方式詳解

    Spring Bean三種注入方式詳解

    本篇文章主要介紹了Spring Bean三種注入方式詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • Java中的分割字符串?split(“.”)無(wú)效問(wèn)題

    Java中的分割字符串?split(“.”)無(wú)效問(wèn)題

    這篇文章主要介紹了Java中的分割字符串?split(“.”)無(wú)效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 使用Java實(shí)現(xiàn)驗(yàn)證碼程序

    使用Java實(shí)現(xiàn)驗(yàn)證碼程序

    這篇文章主要為大家詳細(xì)介紹了使用Java實(shí)現(xiàn)驗(yàn)證碼程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評(píng)論