整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          springboot:實現文件上傳下載實時進度條功能「附帶源碼」

          . 引言

          記得剛入行的時候,做了一個文件上傳的功能,因為上傳時間較久,為了用戶友好性,想要添加一個實時進度條,顯示進度。奈何當時技術有限,查了許久也沒用找到解決方案,最后不了了之。

          近來偶然想到這個問題,于是決定整理一下實現方式,也為和我曾經一樣碰壁的同學,提供一些思路。

          1. 思路

          1、首先我們這里實現的是一個實時的進度條,并不是一個純前端的進度條,它需要根據后端的處理進度來實時反饋進度條長度,那么必然要與后端交互。

          當然這里容易陷入一個誤區,覺得與后端交互的,那么這個功能的重點一定在后端,但實際上這個功能的重點在前端。

          不難想到,我們要知道實時進度,那么一定需要不斷的請求后端,得到響應反饋,前后端請求比較常用的是ajax,但除它之外,我們還有更基礎的xhr(XMLHttpRequest)。作為后端同學可能對xhr有些陌生,實際上ajax就是基于xhr實現的。

          2、xhr可以讓我們在不重新加載頁面的情況下更新網頁,在頁面已經加載后從后端請求并接受數據,這樣就可以無感的讓我們后端文件的上傳進度了。

          3、為了監聽文件上傳下載進度,我們主要使用到xhr的三個進度事件:

          • progress: 在接收響應期間持續不斷地觸發
          • load: 在接收到完整的響應數據時觸發
          • error: 在請求發生錯誤時觸發

          當然除上述三個事件之外,還有其他的進度事件,這不是本文的重點,大家可自行拓展學習XHR對象的進度事件

          XMLHttpRequest簡介

          4、基于上述三個進度事件,我們可以通過process事件持續不斷地發送請求獲取文件上傳下載的進度,load事件用于文件上傳下載完成后的處理,比如提示成功。error用于請求發送錯誤時的處理。

          5、有了上述的思路之后,我們來進行實際演示。

          2. 實操

          2.1 實現文件上傳實時進度條功能

          1、創建springboot項目,引入spring web、lombok、文件上傳commons-fileupload依賴

          xml復制代碼<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、創建MultipartResolver的bean,用來將普通的請求封裝成擁有文件上傳功能的請求

          java復制代碼@Component
          public class FileUpLoadConfig {
          
              @Bean(name="multipartResolver")
              public MultipartResolver multipartResolver(){
                  return new CommonsMultipartResolver();
              }
          }
          

          3、創建一個文件上傳接口:這里我單純做個演示,就直接在controller層中書寫了,實際生產要將上傳方法提取為工具類,在service中進行具體業務處理。

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

          java復制代碼@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);
                  }
              }
          }
          

          4、后端接口完成后,進入我們的重點,我們來實現前端進度條

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

          6、實現一個上傳的頁面,這里利用了html5的progress標簽,該標簽用于實現進度條,支持兩個屬性:value和max,分別為當前進度值和最大進度值

          html復制代碼<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>
          

          7、書寫進度監聽方法,即progress方法

          js復制代碼        //進度條更新
                  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、書寫load,error方法

          js復制代碼        //上傳完成處理函數
                  function uploadSuccess(e) {
                      alert("上傳完成");
                  };
                  //上傳出錯處理函數
                  function uploadFail(e) {
                      alert("上傳失敗");
                  };
          

          9、實現上傳方法upload

          js復制代碼        // 文件上傳
                  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;
                              }
                          }
                      });
                  }
          

          10、運行項目,訪問上傳頁,我這里直接書寫在index.html中了

          11、測試:如下圖所示,可以正常顯示進度

          12、上傳成功后,后臺資源文件夾中也能看到對應的上傳文件,演示成功!

          2.2 實現文件下載實時進度條功能

          上述我們講解了如何實現上傳進度條功能,有了這個思路,我們再實現下載功能:

          1、同樣,我們實現一個簡單的進度條頁面

          html復制代碼    <!-- 文件下載   -->
              <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>
          

          2、實現下載方法

          這里我們不再采用ajax的方法,而是直接通過xhr請求,并且因為要在瀏覽器中下載該文件,所以以window.URL.revokeObjectURL方法來下載并釋放該文件。

          js復制代碼   // 文件下載
              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("下載失敗");
              };
          

          3、實現后端下載文件接口

          這里與上傳文件不同的是,前端在進行文件上傳時,是可以獲取到文件的總大小的,而下載文件時因為是流式下載,前端是不知道要下載的文件一共有多少大小的。

          因此也就無法估算總體的進度比例。所以我們后端接口中要通過Content-Length響應頭指定文件的總大小

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

          java復制代碼    @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);
              }
          

          4、運行項目

          5、測試:文件成功下載,進度也實時顯示

          3. 項目源碼

          以上演示源碼可在如下地址下載: https://gitee.com/wuhanxue/progress_bar_demo

          4. 總結

          以上我們就完成了文件的上傳和下載的實時進度監控,雖然這個功能的重點在前端,但是后端通過這個功能點,也能更好的理解前后端請求的交互。

          最后我們拋出一個思考問題:如何實時監控后端自定義功能的執行進度?

          作者:wu55555
          鏈接:https://juejin.cn/post/7238886731058642999

          ysq5.7.44源代碼方式

          下載安裝配置

          官網文檔

          https://dev.mysql.com/doc/refman/5.7/en/installing-source-distribution.html

          mysql下載

          打開mysql官網網站 https://www.mysql.com/,點擊download進入下載頁面。

          在下載頁面中找到mysql社區服務器版本,點擊“MySQL Community (GPL) Downloads ?”進入社區服務器版的下載頁面。

          點擊社區服務器版“MySQL Community Server”

          點擊存檔“Archives”,選擇操作系統,操作系統版本,找到源碼。

          源安裝先決條件

          gcc-c++編譯器

          yum install -y gcc-c++

          CMake編譯工具

          CMake是一個跨平臺的開源構建工具,用于構建mysql軟件。他寫CMakeLists.txt文件來描述項目的結構,用cmake生成makefile文件,共make編譯使用。

          yum install cmake

          cmake官網下載 https://cmake.org/download/,源碼編譯見軟件包中的readme文件。

          查看cmake版本

          cmake --version

          make編譯工具

          一般系統自帶這個編譯工具,可以通過make --version查看版本。

          OpenSSL 庫

          需要 SSL 庫來支持加密連接、隨機數生成。

          yum install openssl-devel

          Boost C++ 庫

          Boost是一個由C++社區開發和維護的開源C++庫集合,旨在擴展C++語言的功能和性能。

          構建 MySQL 需要 Boost C++ 庫,必須安裝Boost 1.59.0,安裝 Boost 后,根據調用WITH_BOOST在CMake 時為選項設置的值告訴構建系統 Boost 文件的放置位置。

          見以下兩個選項:

          -DDOWNLOAD_BOOST=1 \

          -DWITH_BOOST=/usr/local/boost

          ncurses 庫

          ncurses庫是一個用于創建文本用戶界面(TUI)的開發庫。

          yum install ncurses-devel

          Perl庫

          如果您打算運行測試腳本,則需要 Perl。

          mysql安裝

          創建mysql用戶和組

          groupadd mysql

          useradd -r -g mysql -s /bin/false mysql

          安裝

          解壓

          cd /soft

          tar zxvf mysql-5.7.44.tar.gz

          cd mysql-5.7.44

          創建構建目錄

          mkdir build

          cd build

          構建make編譯文件

          cmake .. \

          -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \

          -DMYSQL_DATADIR=/home/mysql \

          -DSYSCONFDIR=/etc \

          -DDEFAULT_CHARSET=utf8mb4 \

          -DDEFAULT_COLLATION=utf8mb4_general_ci \

          -DMYSQL_TCP_PORT=3306 \

          -DDOWNLOAD_BOOST=1 \

          -DWITH_BOOST=/usr/local/boost

          說明:

          -DCMAKE_INSTALL_PREFIX:配置安裝到特定路徑

          -DMYSQL_DATADIR:配置數據目錄

          -DSYSCONFDIR:配置選項文件的目錄

          -DDEFAULT_CHARSET:配置mysql服務字符集,默認字符是latin1(cp1252西歐)字符集

          -DDEFAULT_COLLATION:服務器排序規則。默認排序規則使用 latin1_swedish_ci。

          -DMYSQL_TCP_PORT:服務器偵聽 TCP/IP 連接的端口號。默認值為 3306。

          -DDOWNLOAD_BOOST:檢查是否有boost庫

          重新構建時運行以下命令清楚歷史構建信息

          make clean

          rm -rf CMakeCache.txt

          編譯&安裝

          make

          make install

          mysql設置

          創建mysql用戶和組

          groupadd mysql

          useradd -r -g mysql -s /bin/false mysql

          添加環境變量

          echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile

          source /etc/profile

          echo $PATH

          初始化數據目錄

          切換到mysql軟件根目錄

          cd /usr/local/mysql

          創建mysql-files目錄

          mkdir mysql-files

          chown mysql:mysql mysql-files

          mysql-files目錄提供了一個方便的位置來用作系統變量的值 secure_file_priv,這將導入和導出操作限制到特定目錄。

          創建mysql配置文件

          vi /etc/my.cnf

          [mysqld]

          basedir=/usr/local/mysql

          datadir=/home/mysql

          MySQL安裝完成后,必須初始化數據目錄。

          bin/mysqld --defaults-file=/etc/my.cnf \

          --initialize \

          --user=mysql

          --defaults-file:指定初始化時的配置文件,必須在選項的第一位。(配置文件中只能有basedir和datadir,其他選項需要在初始化后才能加入)

          --initialize:初始化

          --user:指定mysql軟件運行用戶

          注意:初始化數據庫目錄時,除了使用--basedir、--datadir、--user選項外,不應該使用其他選項。其他選項可以在初始化完成后再my.cnf中指定,然后重啟mysql服務。意思就是說初始化數據庫目錄時最多只能使用--basedir、--datadir、--user選項。

          部署自動支持安全連接的服務器

          bin/mysql_ssl_rsa_setup

          啟動服務器

          bin/mysqld_safe --user=mysql &

          對于使用 RPM 包安裝 MySQL 的 Linux 系統,服務器啟動和關閉是使用 systemd 而不是mysqld_safe管理的,并且 不安裝mysqld_safe 。

          開機啟動啟動服務器

          cd support-files/

          cp mysql.server /etc/init.d/mysql

          chmod +x /etc/init.d/mysql

          chkconfig --add mysql

          啟動停止和重啟

          service mysql start

          service mysql stop

          service mysql restart

          修改root密碼

          登錄mysql后運行如下命令修改密碼,登錄密碼在初始化數據目錄時有顯示。

          ALTER USER 'root'@'localhost' IDENTIFIED BY 'Welcome123#';

          查看用戶

          查看默認存在的用戶

          select user,host from mysql.user;

          使用systemd管理MySQL服務器

          創建MySQL的systemd服務單元文件

          你需要在“/etc/systemd/system/”創建一個“mysql.service”的文件,告訴systemd如何管理MySQL服務。

          文件內容如下:

          [Unit]

          Description=MySQL Server

          After=network.target

          [Service]

          ExecStart=/usr/local/mysql/bin/mysqld_safe --user=mysql

          ExecStop=/usr/local/mysql/bin/mysqladmin shutdown

          User=mysql

          Group=mysql

          Restart=always

          [Install]

          WantedBy=multi-user.target

          說明:

          After=network.target 是systemd服務單元文件中的一個指令,它指定了服務單元所依賴的其他單元。具體來說,network.target 是一個systemd的單元,表示網絡服務已經啟動并可用。

          Restart=always 意味著當服務意外退出(即非正常退出)時,systemd會自動嘗試重新啟動該服務。

          WantedBy=multi-user.target 是systemd服務單元文件中的一個指令,它定義了服務的啟動級別(run level)。在systemd中,系統的啟動級別通過一個稱為 target 的單元來表示。multi-user.target 是系統的多用戶運行級別,通常用于大多數服務器環境,表示系統已經啟動到了可以提供多用戶登錄和運行多個服務的階段。WantedBy=multi-user.target 指定了MySQL服務的啟動級別,并告訴systemd在系統啟動到多用戶運行級別時啟動MySQL服務。

          重新加載systemd管理器配置

          創建完服務單元文件后,需要通知systemd重新加載它的配置,以便識別到新的MySQL服務單元。

          systemctl daemon-reload

          TML大文件上傳源代碼,HTML大文件上傳解決方案,HTML大文件上傳思路,HTML大文件上傳實例,HTML大文件分塊上傳,HTML大文件分片上傳,HTML大文件批量上傳,HTML大文件加密上傳,HTML文件夾上傳,HTML大文件多線程上傳,


          隨著視頻網站和大數據應用的普及,特別是高清視頻和4K視頻應用的到來,超大文件上傳已經成為了日常的基礎應用需求。

          但是在很多情況下,平臺運營方并沒有大文件上傳和斷點續傳的開發經驗,往往在網上找一些簡單的PHP或者Java程序來實現基本的上傳功能,然而在實際使用中會發現,這些基于腳本語言實現的上傳功能模塊性能很弱,一是不支持2GB以上的內容上傳;二是無法支持斷點續傳;三是效率極低,單臺服務器最多支持幾十個并發上傳連接。

          當前我們要搭建一個運營級的視頻服務平臺,在嘗試了各種產品均無法滿足要求,因此最后花精力自主用C++語言實現了這一高性能上傳服務器。

          而基于PHP、JAVA等技術實現的文件上傳服務天生無法支持超大文件上傳,無法逾越2GB的最大文件尺寸瓶頸;

          支持4GB以上超大文件上傳,文件大小不受限制;

          支持斷點續傳,斷網、關機重啟均不受影響;

          對于大文件的處理,無論是用戶端還是服務端,如果一次性進行讀取發送、接收都是不可取,很容易導致內存問題。所以對于大文件上傳,采用切塊分段上傳

          從上傳的效率來看,利用多線程并發上傳能夠達到最大效率。

          文件上傳頁面的前端可以選擇使用一些比較好用的上傳組件,例如百度的開源組件WebUploader,這些組件基本能滿足文件上傳的一些日常所需功能,如異步上傳文件,文件夾,拖拽式上傳,黏貼上傳,上傳進度監控,文件縮略圖,甚至是大文件斷點續傳,大文件秒傳。

          在web項目中上傳文件夾現在已經成為了一個主流的需求。在OA,或者企業ERP系統中都有類似的需求。上傳文件夾并且保留層級結構能夠對用戶行成很好的引導,用戶使用起來也更方便。能夠提供更高級的應用支撐。


          導入項目:
          導入到Eclipse:
          http://www.ncmem.com/doc/view.aspx?id=9da9c7c2b91b40b7b09768eeb282e647
          導入到IDEA:http://www.ncmem.com/doc/view.aspx?id=9fee385dfc0742448b56679420f22162
          springboot統一配置:http://www.ncmem.com/doc/view.aspx?id=7768eec9284b48e3abe08f032f554ea2



          下載示例:

          https://gitee.com/xproer/up6-jsp-eclipse/tree/6.5.40/




          工程



          NOSQL

          NOSQL示例不需要任何配置,可以直接訪問測試



          創建數據表

          選擇對應的數據表腳本,這里以SQL為例




          修改數據庫連接信息


          訪問頁面進行測試



          文件存儲路徑

          up6/upload/年/月/日/guid/filename






          相關問題:
          1.javax.servlet.http.HttpServlet錯誤
          2.項目無法發布到tomcat
          3.md5計算完畢后卡住
          4.服務器找不到config.json文件

          相關參考:

          文件保存位置


          源碼工程文檔:https://drive.weixin.qq.com/s?k=ACoAYgezAAw1dWofra

          源碼報價單:https://drive.weixin.qq.com/s?k=ACoAYgezAAwoiul8gl



          OEM版報價單:https://drive.weixin.qq.com/s?k=ACoAYgezAAwuzp4W0a

          產品源代碼:https://drive.weixin.qq.com/s?k=ACoAYgezAAwbdKCskc
          授權生成器:https://drive.weixin.qq.com/s?k=ACoAYgezAAwTIcFph1


          主站蜘蛛池模板: 日本在线视频一区| 春暖花开亚洲性无区一区二区| 无人码一区二区三区视频| 亚洲国产一区二区a毛片| 无码少妇一区二区三区浪潮AV| 久久综合亚洲色一区二区三区| 久久se精品一区二区| 无码一区二区三区中文字幕| 久久91精品国产一区二区| 2021国产精品一区二区在线| 国产Av一区二区精品久久| 无码精品人妻一区二区三区影院| 国产午夜精品一区理论片飘花| 久久精品午夜一区二区福利| 日韩精品福利视频一区二区三区| 国产精品免费一区二区三区| 在线播放国产一区二区三区 | 精品国产亚洲一区二区三区在线观看 | 精品成人一区二区三区四区| 久久精品道一区二区三区| 韩国一区二区三区视频| 精品国产不卡一区二区三区 | 好吊妞视频一区二区| 99精品高清视频一区二区| 精品一区二区三区四区在线播放 | 中文字幕人妻丝袜乱一区三区 | 中文字幕精品无码一区二区三区| 亚洲一区无码中文字幕乱码| 久99精品视频在线观看婷亚洲片国产一区一级在线 | 一区二区三区在线看| 亚洲国产激情在线一区| 一区二区三区久久精品| 中文字幕日韩一区二区不卡| 久久精品人妻一区二区三区| 无码人妻精品一区二区三区9厂 | 国产一区二区三区在线免费| 无码欧精品亚洲日韩一区| 四虎一区二区成人免费影院网址| 亚洲国产成人精品无码一区二区| 精品一区二区三区在线观看| 免费高清av一区二区三区|