1. 程式人生 > 其它 >SpringBoot檔案上傳+進度條(thymeleaf)

SpringBoot檔案上傳+進度條(thymeleaf)

1. 環境搭建

新建springboot專案,新增web 和 thymeleaf 依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
   

2. 介面編寫

package com.xie.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * @Description
 * @Date 2022-05-10 9:36
 * @Author xie
 */
@RestController
@RequestMapping("/file")
public class FileController {

    private static final String TMP_PATH = "D:/projects/tmp";

    @PostMapping("/upload")
    public String upload(@RequestParam("uploadFile") MultipartFile file, HttpServletRequest request, HttpServletResponse response) {
        if (file.isEmpty()) {
            return "檔案為空";
        }
        
        // 獲取當前時間
        String currentDate = new SimpleDateFormat("/yyyy/MM/dd").format(new Date());
        // 儲存檔案的目錄
        String folderPath = TMP_PATH + currentDate;
        System.out.println("儲存的路徑地址:" + folderPath);
        // 判斷是否需要建立目錄
        File folderFile = new File(folderPath);
        if (!folderFile.exists()) {
            folderFile.mkdirs();
        }

        // 檔名
        String fileName = file.getOriginalFilename();
        fileName = String.valueOf(UUID.randomUUID()).replace("-", "") + fileName.substring(fileName.lastIndexOf("."));

        try {
            File destFile = new File(folderFile, fileName);
            System.out.println(destFile.getAbsolutePath());
            // 核心
            file.transferTo(destFile);
            String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/img" + currentDate + fileName;
            System.out.println(String.format("上傳成功,圖片路徑:%s", url));
            return "上傳成功";
        } catch (IOException e) {
            return "上傳失敗";
        }
    }
}

3. 前端頁面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>檔案上傳</title>
    <style type="text/css">
        progress {
            background-color: #56BE64;
        }

        progress::-webkit-progress-bar {
            background: #ccc;
        }

        progress::-webkit-progress-value {
            background: #56BE64;
        }

        percentage {
            position: fixed;
            left: 160px;
        }

    </style>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<h1>Spring Boot file upload example</h1>
<form id="FileuploadForm" method="POST" action="/file/upload" enctype="multipart/form-data">
    <input type="file" name="uploadFile" id="uploadFile"/><br/>
    <br/> <input type="button" id="btnUpload" value="上傳檔案" onclick="upload()"/>
    <div id="msg"></div>
</form>
<!--進度條部分(預設隱藏)-->
<div style="display: none;" class="progress-body">
    <div>
        <span style="width: 100px; display: inline-block; text-align: right">上傳進度:</span>
        <progress></progress>
        <percentage>0%</percentage>
    </div>
    <div>
        <span style="width: 100px; display: inline-block; text-align: right">上傳速度:</span>
        <span style="width: 300px;" class="progress-speed">0 M/S, 0/0M</span>
    </div>
    <div>
        <span style="width: 100px; display: inline-block; text-align: right">上傳狀態:</span>
        <span style="width: 300px;" class="progress-info">請選擇檔案並點選上傳檔案按鈕</span>
    </div>
</div>
<script>
    // 上傳檔案
    function upload() {
        $("#msg").text("");
        var checkFile = $("#uploadFile").val();
        var msgInfo = "";
        if (null == checkFile || "" == checkFile) {
            $("#msg").text("檔案為空,請選擇檔案!");
        } else {
            var formData = new FormData(document.getElementById("FileuploadForm"));
            $.ajax({
                type: "POST",
                enctype: 'multipart/form-data',
                url: 'file/upload',
                data: formData,
                cache: false,
                processData: false,
                contentType: false,
                error: function (result) {
                    console.log("error");
                    console.log(result);
                    flag = false;
                    $("#msg").text("訪問伺服器錯誤,請重試!");
                },
                success: function (result) {
                    console.log("success");
                },
                xhr: function () {
                    var xhr = $.ajaxSettings.xhr();
                    if (xhr.upload) {
                        $("#btnUpload").attr("disabled", true);
                        $("#uploadFile").attr("disabled", true);
                        //處理進度條的事件
                        xhr.upload.addEventListener("progress", progressHandle, false);
                        //載入完成的事件
                        xhr.addEventListener("load", completeHandle, false);
                        //加載出錯的事件
                        xhr.addEventListener("error", failedHandle, false);
                        //載入取消的事件
                        xhr.addEventListener("abort", canceledHandle, false);
                        //開始顯示進度條
                        showProgress();
                        return xhr;
                    }
                }
            }, 'json');
        }
    }

    var start = 0;

    //顯示進度條的函式
    function showProgress() {
        start = new Date().getTime();
        $(".progress-body").css("display", "block");
    }

    //隱藏進度條的函式
    function hideProgress() {
        $("#uploadFile").val('');
        $('.progress-body .progress-speed').html("0 M/S, 0/0M");
        $('.progress-body percentage').html("0%");
        $('.progress-body .progress-info').html("請選擇檔案並點選上傳檔案按鈕");
        $("#btnUpload").attr("disabled", false);
        $("#uploadFile").attr("disabled", false);
        //$(".progress-body").css("display", "none");
    }

    //進度條更新
    function progressHandle(e) {
        $('.progress-body progress').attr({value: e.loaded, max: e.total});
        var percent = e.loaded / e.total * 100;
        var time = ((new Date().getTime() - start) / 1000).toFixed(3);
        if (time == 0) {
            time = 1;
        }
        $('.progress-body .progress-speed').html(((e.loaded / 1024) / 1024 / time).toFixed(2) + "M/S, " + ((e.loaded / 1024) / 1024).toFixed(2) + "/" + ((e.total / 1024) / 1024).toFixed(2) + " MB. ");
        $('.progress-body percentage').html(percent.toFixed(2) + "%");
        if (percent == 100) {
            $('.progress-body .progress-info').html("上傳完成,後臺正在處理...");
        } else {
            $('.progress-body .progress-info').html("檔案上傳中...");
        }
    };

    //上傳完成處理函式
    function completeHandle(e) {
        $('.progress-body .progress-info').html("上傳檔案完成。");
        setTimeout(hideProgress, 2000);
    };

    //上傳出錯處理函式
    function failedHandle(e) {
        $('.progress-body .progress-info').html("上傳檔案出錯, 服務不可用或檔案過大。");
        setTimeout(hideProgress, 2000);
    };

    //上傳取消處理函式
    function canceledHandle(e) {
        $('.progress-body .progress-info').html("上傳檔案取消。");
        setTimeout(hideProgress, 2000);
    };
</script>
</body>
</html>

4. 測試上傳

4.1 SpringBoot 預設配置的 最大檔案上傳大小 和 最大請求大小 都是10MB,為了能夠清楚看到進度條效果配置成500MB。

spring:
  http:
    multipart:
      max-file-size: 500MB # -1 代表不限制
      max-request-size: 500MB # -1 代表不限制
  thymeleaf:
    cache: false
    encoding: UTF-8