Web Uploader分片上传文件

  • 本文参考了网络上大牛写的文档稍加改造,如侵权请联系
总体结构

在这里插入图片描述

配置文件
#webUploader参数配置
spring:
  thymeleaf:
    prefix: classpath:/paga/
    suffix: .html
  http:
    multipart:
      max-file-size: 100000Mb
      max-request-size: 100000Mb
server:
  port: 80
async : false

#文件保存路径
filepath: 'E:/test/'
前端页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:th="http://www.thymeleaf.org" 
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
	<meta charset="UTF-8" />
	<title>文件上传</title>
	<link type="text/css" th:href="@{bootstrap.min.css}" rel="stylesheet" />
	<link type="text/css" th:href="@{webuploader.css}" rel="stylesheet" />
	<!--<link rel="stylesheet" href="../static/bootstrap.min.css"/>-->
	<!--<link rel="stylesheet" href="../static/webuploader.css"/>-->
</head>
<body >

	<div id="uploader" class="wu-example" >
		<!--用来存放文件信息-->
		<div id="thelist" class="uploader-list" style="width:500px;"></div>
		<div class="btns">
			<div id="picker">选择文件</div>
		</div>
		<!--<div id="StopBtn" class="webuploader-pick"-->
			 <!--style="float: left; margin-right: 10px" status="suspend" >暂停上传-->
		<!--</div>-->
	</div>

<script th:src="@{jquery-3.1.1.min.js}"></script>
<script th:src="@{md5.js}"></script>
<script th:src="@{webuploader.min.js}"></script>

<!--<script src="../static/jquery-3.1.1.min.js"></script>-->
<!--<script src="../static/md5.js"></script>-->
<!--<script src="../static/webuploader.min.js"></script>-->
<script type="text/javascript">

	//页面初始化
    // $(function(){
    //    $("#StopBtn").hide(); //隐藏暂停按钮
    // });

	var md5File; 
	//监听分块上传过程中的时间点  
	var register = WebUploader.Uploader.register({
	    "before-send-file":"beforeSendFile",  // 整个文件上传前
	    "before-send":"beforeSend",  // 每个分片上传前
	    "after-send-file": "afterSendFile"  // 分片上传完毕
	},{
	    //时间点1:所有分块进行上传之前调用此函数 ,检查文件存不存在
	    beforeSendFile:function(file){
	    	var deferred = WebUploader.Deferred();
	    	file.md5File = hex_md5(file.name+file.size);
	    	$.ajax({
	            type:"POST",
	            url:"/checkFile",
	            data:{
	                md5File: file.md5File, //文件唯一标记
					name:file.name         //文件名,在后台拼接完整的文件路径
	            },
	            async: true,  // 同步
	            dataType:"json",
	            success:function(response){
	                if(response){  //文件存在,跳过,提示文件存在
						$('#' + file.id).find('p.state').text("该文件已存在");
                       // WebUploader.Uploader.destroy(file);
						deferred.reject(file);
	                }else{
	                    deferred.resolve();  //文件不存在或不完整,发送该文件
	                }
	            }
	        } , function (jqXHR, textStatus, errorThrown) { //任何形式的验证失败,都触发重新上传
	        	deferred.resolve();
	        } );
	        return deferred.promise();
	    },

	    //时间点2:如果有分块上传,则每个分块上传之前调用此函数,判断分块存不存在
	    beforeSend:function(block){
	        var deferred = WebUploader.Deferred();
	        $.ajax({
	            type:"POST",
	            url:"/checkChunk",
	            data:{
	                md5File: block.file.md5File,  //文件唯一标记
	                chunk:block.chunk,  //当前分块下标
	            },
	            dataType:"json",
	            success:function(response){
	                if(response){
	                    deferred.reject(); //分片存在,跳过
	                }else{
	                    deferred.resolve();  //分块不存在或不完整,重新发送该分块内容
	                }
	            }
	        }, function (jqXHR, textStatus, errorThrown) { //任何形式的验证失败,都触发重新上传
	        	deferred.resolve();
	        });
	        return deferred.promise();
	    },

	    //时间点3:分片上传完成后,通知后台合成分片
	    afterSendFile: function (file) {
	        console.log("=====",file)
	        var chunksTotal = Math.ceil(file.size / (5*1024*1024));
	        if (chunksTotal >= 1) {
	            //合并请求
	            var deferred = WebUploader.Deferred();
	            $.ajax({
	                type: "POST",
	                url: "/merge",
	                data: {
	                	name: file.name,
	                	md5File: file.md5File,
	                    chunks: chunksTotal
	                },
	                cache: false,
	                async: false,  // 同步
	                dataType: "json",
		            success:function(response){
		                if(response){
		                	$('#' + file.id).find('p.state').text('上传成功');
		                	$('#' + file.id).find('.progress').fadeOut();
                            $("#picker").show();//显示上传按钮
                            //$("#StopBtn").hide();//隐藏暂停按钮
		                }else{
		                	$('#' + file.id).find('p.state').text('上传失败');
		                	//进度条变红
                            $('#' + file.id).find(".progress").find(".progress-bar").attr("class", "progress-bar progress-bar-danger");
			            	deferred.reject();
		                }
		            }
	            })
	            return deferred.promise();
	        }
	    }
	});

	var uploader = WebUploader.create({
		auto: true,// 选完文件后,是否自动上传。
	    swf: '../static/Uploader.swf',// swf文件路径
	    server: '/upload',// 文件接收服务端。
	    pick: '#picker',// 选择文件的按钮。可选。
	    chunked:true,//开启分片上传
	    chunkSize:5*1024*1024,//5M
	    chunkRetry: 3,//错误重试次数
        threads: 100, //上传并发数
        // fileSizeLimit: 2000 * 1024 * 1024,//最大10GB
        // fileSingleSizeLimit: 2000 * 1024 * 1024,
        //fileNumLimit: 100 // 最大上传并发数
	});

    // $("#StopBtn").click(function () {
    //     console.log($('#StopBtn').attr("status"));
    //     var status = $('#StopBtn').attr("status");
    //     if (status == "suspend") {
    //         console.log("当前按钮是暂停,即将变为继续");
    //         $("#StopBtn").html("继续上传");
    //         $("#StopBtn").attr("status", "continuous");
    //         console.log("当前所有文件==="+uploader.getFiles());
    //         console.log("=============暂停上传==============");
    //         uploader.stop(true);
    //         console.log("=============所有当前暂停的文件=============");
    //         console.log(uploader.getFiles("interrupt"));
    //     } else {
    //         console.log("当前按钮是继续,即将变为暂停");
    //         $("#StopBtn").html("暂停上传");
    //         $("#StopBtn").attr("status", "suspend");
    //         console.log("===============所有当前暂停的文件==============");
    //         console.log(uploader.getFiles("interrupt"));
    //         uploader.upload(uploader.getFiles("interrupt"));
    //     }
    // });
	
	//上传添加参数
	uploader.on('uploadBeforeSend', function (block, data, headers) {
		 data.md5File=block.file.md5File;

     });
	
	// 当有文件被添加进队列的时候
	uploader.on( 'fileQueued', function( file ) {
		//$("#picker").hide();//隐藏上传按钮
        //$("#StopBtn").show();//显示暂停按钮
		$("#thelist").append( '<div id="' + file.id + '" class="item">' +
	        '<h4 class="info">' + file.name + '</h4>' +
	        '<p class="state"></p>' +
	    '</div>' );
	});

	// 文件上传过程中创建进度条实时显示。
	uploader.on( 'uploadProgress', function( file, percentage ) {
	    var $li = $( '#'+file.id ),
	        $percent = $li.find('.progress .progress-bar');

	    // 避免重复创建
	    if ( !$percent.length ) {
	        $percent = $('<div class="progress progress-striped active">' +
	          '<div class="progress-bar" role="progressbar" style="width: 0%"></div>' +
	        '</div>').appendTo( $li ).find('.progress-bar');
	    }
	    $li.find('p.state').text('上传中。。。');
	    $percent.css( 'width', percentage * 100 + '%' );
	});
	
</script>
</body>
</html>
Controller
package com.uda.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * 文件上传controller
 */
@Controller
public class Uploader {

	//注入文件保存的路径
	@Value("${filepath}")
	private String filepath;

	@GetMapping( "/")
    public String page(){
        return "upload";
	} 

	/**
	 * 检查文件存在与否
	 */
	@PostMapping("checkFile")
    @ResponseBody
    public Boolean checkFile(
    		//@RequestParam(value = "md5File") String md5File,
			@RequestParam(value = "name") String name) {
		//合并后的文件
		File file = new File(filepath + name);
		//判断该文件是否目录(目录表示文件已经分片并合并成功/已经上传)
		boolean exists = file.exists();

		System.out.println("======" + file.getPath());
		System.out.println(exists);

		return exists;
	}

	/**
	 * 检查分片存不存在
	 */
	@PostMapping("checkChunk")
	@ResponseBody
	public Boolean checkChunk(@RequestParam(value = "md5File") String md5File,
            @RequestParam(value = "chunk") Integer chunk) {
		Boolean exist = false;
		String path = filepath + md5File + "/";	//分片存放目录
		String chunkName = chunk+ ".tmp";	//分片文件名
		File file = new File(path+chunkName);
        if (file.isDirectory()) {
        	exist = true;
        }
        return exist;
	}

	/**
	 * 修改上传
	 */
	@PostMapping("upload")
	@ResponseBody
	public Boolean upload(@RequestParam(value = "file") MultipartFile file,
				@RequestParam(value = "md5File") String md5File,
                @RequestParam(value = "chunk",required= false) Integer chunk) { //第几片,从0开始
		String path = filepath+md5File+"/";
		File dirfile = new File(path);
		if (!dirfile.exists()) {	//目录不存在,创建目录
			dirfile.mkdirs();
		}
		String chunkName;
		if(chunk == null) {			//表示是小文件,还没有一片
			chunkName = "0.tmp";
        }else {
        	chunkName = chunk+ ".tmp";
        }
		String filePath = path+chunkName;
		File savefile = new File(filePath);

		try {
			if (!savefile.exists()) {
				savefile.createNewFile();	//文件不存在,则创建
			}
			file.transferTo(savefile);		//将文件保存
		} catch (IOException e) {
			return false;
		}
		return true;
	}

	/**
	 * 合成分片
	 */
	@PostMapping("merge")
    @ResponseBody
    public Boolean  merge(@RequestParam(value = "chunks",required =false) Integer chunks,
    		    @RequestParam(value = "md5File") String md5File,
    		    @RequestParam(value = "name") String name) throws Exception {
		long start = System.currentTimeMillis();
		FileOutputStream fileOutputStream = new FileOutputStream(filepath+name);  //合成后的文件
		try {
			byte[] buf = new byte[1024];
	        for(long i=0;i<chunks;i++) {
	             String chunkFile=i+".tmp";
	             File file = new File(filepath+md5File+"/"+chunkFile);
	             InputStream inputStream = new FileInputStream(file);
	             int len = 0;
	             while((len=inputStream.read(buf))!=-1){
	                 fileOutputStream.write(buf,0,len);
	             }
	             inputStream.close();
	         }
	        //删除md5目录及临时文件
			File file = new File(filepath+md5File);
			File[] files = file.listFiles();
			for (File f : files) {
				f.delete();
			}
			file.delete();

		} catch (Exception e) {
			System.out.println(System.currentTimeMillis() - start);
			return false;
		}finally {
			fileOutputStream.close();
		}
		System.out.println(System.currentTimeMillis() - start);
		return true;
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值