1. 程式人生 > >前段WebUploader;JavaEE大檔案分片上傳接收

前段WebUploader;JavaEE大檔案分片上傳接收

Web大檔案分片上傳
Web環境中大檔案上傳不能再用form表單一次上傳了,這樣效率太低;
我在不斷嘗試SpringMVC環境下分片接受檔案,最終失敗;原因目測是 SpringMVC、Struts框架是不支援HTML5方式上傳的(這類框架只能支援Form表單方式的檔案上傳,或者FLash)

那我們可以使用Servlet和SpringMVC結合整合方式實現大檔案分片上傳;

一、來看看我們的web.xml的配置
這裡寫圖片描述

很明顯兩個servlet,上面一個配置的是SpringMVC的入口,下面servlet是視訊上傳;
他們倆的url-pattern 不能衝突;

二、先來看看WebUploader 的前端程式碼
這裡寫圖片描述


以下是程式碼:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base
    href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"
>
<script type="text/javascript" src="webuploader/jquery-1.7.2.js"></script> <script type="text/javascript" src="webuploader/webuploader.min.js"></script> <link href="webuploader/webuploader.css" type="css/text" /> </head> <body> <h2>Hello World!</h2>
<div id="thelist" class="uploader-list"></div> <div style="margin: 20px 20px 20px 0;"> <div id="picker" class="form-control-focus">選擇檔案</div> </div> <button id="btnSync" type="button" class="btn btn-warning">開始同步</button> <script> var uploader = WebUploader.create({ // swf檔案路徑 swf : 'webuploader/Uploader.swf', // 檔案接收服務端。 server : 'UploadVideoServlet', // 選擇檔案的按鈕。可選。 // 內部根據當前執行是建立,可能是input元素,也可能是flash. pick : '#picker', threads:2, chunked: true, //分片處理 chunkSize: 5 * 1024 * 1024, //每片5M threads:1,//上傳併發數。允許同時最大上傳程序數。 // 不壓縮image, 預設如果是jpeg,檔案上傳前會壓縮一把再上傳! resize : false }); // 當有檔案被新增進佇列的時候 uploader.on('fileQueued', function(file) { //alert(123); $("#thelist").append( '<div id="' + file.id + '" class="item">' + '<h4 class="info">' + file.name + '</h4>' + '<p class="state">等待上傳...</p>' + '</div>'); }); uploader.on('uploadSuccess', function(file) { alert(uploader.options.formData.guid); alert(Math.ceil(file.size/(5*1024*1024))); alert(file.name); $('#' + file.id).find('p.state').text('已上傳'); $.post("UploadSuccessServlet", { "guid": uploader.options.formData.guid,chunks:Math.ceil(file.size/(5*1024*1024)),fileName:file.name}, function(data){ }, "json"); }); uploader.on('uploadError', function(file) { $('#' + file.id).find('p.state').text('上傳出錯'); }); uploader.on('uploadComplete', function(file) { $('#' + file.id).find('.progress').fadeOut(); }); $("#btnSync").on('click', function() { if ($(this).hasClass('disabled')) { return false; } uploader.options.formData.guid = Math.random(); uploader.upload(); }); </script> </body> </html>

三、servlet分片獲取
分片就是前段將檔案分成多個,每片都是一個post請求,有多少片就請求多少次servlet;
我們以獲取的guid為檔名 建立臨時資料夾,以chunk(片序號)為檔名來儲存檔案;
這裡寫圖片描述

以下為程式碼:

package com.airodlcx;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

/**
 * Servlet implementation class UploadVideo
 */
public class UploadVideoServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public UploadVideoServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String path = request.getSession().getServletContext().getRealPath("/upload");
        System.out.println(path);
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 2、建立一個檔案上傳解析器
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 解決上傳檔名的中文亂碼
        upload.setHeaderEncoding("UTF-8");
        // 3、判斷提交上來的資料是否是上傳表單的資料
        if (!ServletFileUpload.isMultipartContent(request)) {
            return;
        }
        // 4、使用ServletFileUpload解析器解析上傳資料,解析結果返回的是一個List<FileItem>集合,每一個FileItem對應一個Form表單的輸入項
        List<FileItem> list = null;
        try {
            list = upload.parseRequest(request);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }

        HashMap<String, String> map = new HashMap<String, String>();

        System.out.println("-------------------------------------------------------------");
        for (FileItem item : list) {
            if (item.isFormField()) {
                /**
                 * 表單資料
                 */
                String name = item.getFieldName();
                // 解決普通輸入項的資料的中文亂碼問題
                String value = item.getString("UTF-8");
                // value = new String(value.getBytes("iso8859-1"),"UTF-8");
                System.out.println(name + "=" + value);
                map.put(name, value);// 放入map集合
            } else {
                /**
                 * 檔案上傳
                 */

                File fileParent = new File(path + "/" + map.get("guid"));//以guid建立臨時資料夾
                System.out.println(fileParent.getPath());
                if (!fileParent.exists()) {
                    fileParent.mkdir();
                }


                String filename = item.getName();
                if (filename == null || filename.trim().equals("")) {
                    continue;
                }
                // 注意:不同的瀏覽器提交的檔名是不一樣的,有些瀏覽器提交上來的檔名是帶有路徑的,如:
                // c:\a\b\1.txt,而有些只是單純的檔名,如:1.txt
                // 處理獲取到的上傳檔案的檔名的路徑部分,只保留檔名部分
                filename = filename.substring(filename.lastIndexOf("\\") + 1);

                //建立檔案
                File file;
                if (map.get("chunks") != null) {
                    file = new File(fileParent, map.get("chunk"));
                } else {
                    file = new File(fileParent, "0");
                }

                //copy
                FileUtils.copyInputStreamToFile(item.getInputStream(), file);

            }
        }
    }
}

四、前端WebUploader上傳完畢觸發uploadSuccess事件

uploader.on('uploadSuccess', function(file) {
            alert(uploader.options.formData.guid);
            alert(Math.ceil(file.size/(5*1024*1024)));
            alert(file.name);
            $('#' + file.id).find('p.state').text('已上傳');
            $.post("UploadSuccessServlet", { "guid": uploader.options.formData.guid,chunks:Math.ceil(file.size/(5*1024*1024)),fileName:file.name},
               function(data){

            }, "json");
        });

請求servlet去合併之前的guid資料夾下的分片檔案,post請求中的分片數量可以用來校驗,獲取的分片是否正確,也可以前端傳遞md5,後臺校驗;

五、後臺獲取的log

這裡寫圖片描述
這裡寫圖片描述
圖:上傳的GUID命名的資料夾
這裡寫圖片描述
圖:資料夾下的分片檔案
每個分割線包住的地方是一個servlet請求,最後在success 請求的servlet是進行檔案校驗併合並檔案即可;程式碼見下:
六、java檔案合併
程式碼見下:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = request.getSession().getServletContext().getRealPath("/upload");

        String guid = request.getParameter("guid");
        int chunks = Integer.parseInt(request.getParameter("chunks"));
        String fileName = request.getParameter("fileName");

        System.out.println("start...!guid="+guid+";chunks="+chunks+";fileName="+fileName);
        /**
         * 進行檔案合併
         */
        File file = new File(path+"/"+guid);
        /**
         * 判斷分片數量是否正確
         */
        if(file.list().length != chunks){
            return;
        }

        new File("F://upload"+"/"+guid).mkdir();
        /**
         * 進行檔案合併
         */
        File newFile = new File("F://upload"+"/"+guid+"/"+fileName);
        FileOutputStream outputStream = new FileOutputStream(newFile, true);//檔案追加寫入

        byte[] byt = new byte[10*1024*1024];
        int len;
        FileInputStream temp = null;//分片檔案
        for(int i = 0 ; i<chunks ; i++){
            temp = new FileInputStream(new File(path+"/"+guid+"/"+i));
            while((len = temp.read(byt))!=-1){
                System.out.println(len);
                outputStream.write(byt, 0, len);
            }
            temp.close();
        }
        /**
         * 當所有追加寫入都寫完  才可以關閉流
         */
        outputStream.close();
        //temp.close(); 寫錯了 移到for迴圈
        System.out.println("success!guid="+guid+";chunks="+chunks+";fileName="+fileName);
    }

資料夾以guid命名,資料庫儲存guid的名字,後期資料移動,只需要更改前端顯示的路徑;
在這裡up遇到一個問題,上傳報錯:IOException:磁碟空間不足;然而我上傳的磁碟還有20G;原因是系統盤空間不足;up重灌系統就好了;

注:
1、進度條的顯示就很容易了
引入bootstrap的進度條

<div class="progress">
      <div id="progress" class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
        <span class="sr-only">60% Complete</span>
      </div>
</div>

2.新增uploadProgress事件監聽

uploader.on('uploadProgress', function(file,percentage) {
    $("#progress").css("width",parseInt(percentage*100)+"%");
});

percentage:當前上傳的進度,小數,數值為1是上傳完畢;
效果如下:
PS:UI簡陋還請見諒!

QQ:346640094 Email:[email protected];

相關推薦

前段WebUploaderJavaEE檔案分片接收

Web大檔案分片上傳 Web環境中大檔案上傳不能再用form表單一次上傳了,這樣效率太低; 我在不斷嘗試SpringMVC環境下分片接受檔案,最終失敗;原因目測是 SpringMVC、Struts框架是不支援HTML5方式上傳的(這類框架只能支援Form表單

webuploader在springMVC+jquery+Java開發環境下的檔案分片

參考的文章http://blog.csdn.net/new_sara/article/details/51604997 因為從網上看到的總是和自己專案開發有些許差別,所以也是在除錯了很久之後,發現適合自己專案的程式碼,現在把過程記錄下來,以便以後查閱. 注意: 1,web

在瀏覽器進行檔案分片(java服務端實現)

最近在做web網盤的系統,網盤最基本的功能便是檔案上傳,但是檔案上傳當遇到大檔案的時候,在web端按傳統方式上傳簡直是災難,所以大檔案上傳可以採用分片上傳的辦法。其主要思路是:1.大檔案上傳時進行分片;2.分片上傳;3.對分片檔案進行合併。 思路比較清晰簡單,但一些問題在於:1.大檔案如何進

PHP檔案分片的實現方法

一、前言 在網站開發中,經常會有上傳檔案的需求,有的檔案size太大直接上傳,經常會導致上傳過程中耗時太久,大量佔用頻寬資源,因此有了分片上傳。 分片上傳主要是前端將一個較大的檔案分成等分的幾片,標識當前分片是第幾片和總共幾片,待所有的分片均上傳成功的時候,在後臺進行合成檔案即可。 二、

網頁內實現檔案分片、斷點續

最近做公司的專案,需要在後臺控制系統中新增一個功能-------向伺服器傳送程式更新包;這些程式更新包大小不固定,但基本都在1G到4G之間,剛開始還真是難倒我了,因為之前的專案中沒有上傳過這麼大的檔案,還要斷點續傳,後來經過查資料,寫DEMO,這個問題終於解決了; 解決辦法: 使用XMLHt

java springboot 檔案分片處理

這裡只寫後端的程式碼,基本的思想就是,前端將檔案分片,然後每次訪問上傳介面的時候,向後端傳入引數:當前為第幾塊問價,和分片總數 下面直接貼程式碼吧,一些難懂的我大部分都加上註釋了: 上傳檔案實體類: /** * 檔案傳輸物件 * @ApiModel和@ApiModelProperty及C

eggJS檔案分片與合併

前臺上傳使用vue+axios 前臺程式碼: // 計算分片總數 for (let i = 0; i < Math.ceil(this.file.size / this.uploadFragment.fragment); i++) { this.uploadFra

php檔案分片

HTML <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="widt

iOS檔案分片和斷點續

總結一下大檔案分片上傳和斷點續傳的問題。因為檔案過大(比如1G以上),必須要考慮上傳過程網路中斷的情況。http的網路請求中本身就已經具備了分片上傳功能,當傳輸的檔案比較大時,http協議自動會將檔案切片(分塊),但這不是我們現在說的重點,我們要做的事是保證在網路中斷後1G

Android 檔案分片斷點續任務管理實現

Transer 是一個傳輸框架,目前支援: - 支援 HTTP/HTTPS 斷點續傳下載 - 支援 HTTP/HTTPS 大檔案分片上傳 - 支援 類EventBus的task狀態變更通知,支援三種執行緒的訂閱模式 - 支援 任務分組,分使用者

js實現檔案分片的方法

<input type="file" name="file" id="file"> <button id="upload" onClick="upload()">upload</button>var bytesPerPiece = 1024

Node + js實現檔案分片基本原理及實踐(一)

閱讀目錄 一:什麼是分片上傳? 二:理解Blob物件中的slice方法對檔案進行分割及其他知識點 三. 使用 spark-md5 生成 md5檔案 四. 使用koa+js實現大檔案分片上傳實踐 回到頂部 一:什麼是分片上傳? 分片上傳是把一個大的檔案分成若干塊,一塊一塊的傳輸。這

nodeJs + js 檔案分片

簡單的檔案上傳 一、準備檔案上傳的條件: 1、安裝nodejs環境 2、安裝vue環境 3、驗證環境是否安裝成功 二、實現上傳步驟 1、前端部分使用 vue-cli 腳手架,搭建一個 demo 版本,能夠實現簡單互動: <template> <div id="app">

.NET Core Web APi檔案分片研究

前言 前兩天發表利用FormData進行檔案上傳,然後有人問要是大檔案幾個G上傳怎麼搞,常見的不就是分片再搞下斷點續傳,動動手差不多也能搞出來,只不過要深入的話,考慮的東西還是很多。由於斷點續傳之前寫個幾篇,這裡試試利用FormData來進行分片上傳。 .NET Core Web APi檔案分片上傳 這裡我們

WebUploader-----檔案列表

大家好   在這裡 給大家介紹一下款適用於大檔案傳輸的外掛--------------------WebUploader  首先呢 我先給出該外掛需要的引數文件   官網地址:http://fex.baidu.com/webuploader

PHP檔案分割 PHP分片

這篇文章主要為大家詳細介紹了PHP大檔案分割上傳,PHP分片上傳,具有一定的參考價值,感興趣的小夥伴們可以參考一下 服務端為什麼不能直接傳大檔案?跟php.ini裡面的幾個配置有關 upload_max_filesize = 2M //PHP最大能接受的檔案大小 post_max_siz

分片 多執行緒檔案接收端)

package com.controller; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; i

【轉】Android-使用Socket進行檔案斷點

在Android中上傳檔案可以採用HTTP方式,也可以採用Socket方式,但是HTTP方式不能上傳大檔案,這裡介紹一種通過Socket方式來進行斷點續傳的方式,服務端會記錄下檔案的上傳進度,當某一次上傳過程意外終止後,下一次可以繼續上傳,這裡用到的其實還是J2SE裡的知識。   這個上傳程式的

【效能優化的祕密】Hadoop如何將TB級檔案效能優化百倍

往期文章1、 拜託!面試請不要再問我Spring Cloud底層原理2、 【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?3、 【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰4、 微服務架構如何保障雙11狂歡下的99.99%

【效能優化的祕密】Hadoop如何將TB級檔案效能優化百倍?

一、寫在前面 上一篇文章,我們聊了一下Hadoop中的NameNode裡的edits log寫機制。 主要分析了edits log寫入磁碟和網路的時候,是如何通過分段加鎖以及雙緩衝的機制,大幅度提升了多執行緒併發寫edits log的吞吐量,從而支援高併發的訪問。 如果沒看那