欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于WebUploader、SpringMVC的断点续传

程序员文章站 2024-02-19 08:31:40
...

页面引用:

 

 
 
<!--引用tag标签路径,并定义为sys-->
<%@ taglib prefix="sys" tagdir="/WEB-INF/tags/sys" %>

<!--以下两个隐藏域为spring标签,可以用常规html代替,用以存放上传文件返回的文件真实地址和文件访问地址-->
<form:hidden id="hzzqtysUrl" path="hzzqtysUrl" htmlEscape="false" maxlength="255" class="input-xlarge required"/>
<form:hidden id="hzzqtysTitle" path="hzzqtysTitle"  htmlEscape="false" maxlength="255" class="input-xlarge"/>
<!--前端引用tag组件方法-->
<sys:webuploader input="hzzqtysUrl" label="hzzqtysTitle" type="all"/>

tag组件:webuploader.tag

 

<%@ tag language="java" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
<%@ attribute name="input" type="java.lang.String" required="true" description="文件路径用'|'分割组成"%>
<%@ attribute name="label" type="java.lang.String" required="true" description="文件名称用'|'分割组成"%>
<%@ attribute name="type" type="java.lang.String" required="true" description="images、docs、all"%>
<%@ attribute name="fileSingleSizeLimit" type="java.lang.String" required="false" description="单文件最大尺寸(kb)"%>
<%@ attribute name="fileSizeLimit" type="java.lang.String" required="false" description="文件总大小最大尺寸(kb)"%>
<%@ attribute name="chunkSize" type="java.lang.String" required="false" description="分片大小(kb),默认大小为5M"%>
<%@ attribute name="fileNumLimit" type="java.lang.Integer" required="false" description="文件总数量"%>
<%@ attribute name="readonly" type="java.lang.Boolean" required="false" description="是否查看模式"%>
<%@ attribute name="maxWidth" type="java.lang.String" required="false" description="最大宽度"%>
<%@ attribute name="maxHeight" type="java.lang.String" required="false" description="最大高度"%>
<link href="${ctxStatic }/webuploader-0.1.5/webuploader.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="${ctxStatic }/webuploader-0.1.5/webuploader.js"></script>

<input id="${input}jindutiao" type="hidden" />
<input id="${input}fileIds" type="hidden" />
<div id="${input}uploader" class="wu-example">
    <div class="btns">
        <div id="${input}filePicker" class="webuploader-container">
            <div class="webuploader-pick">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上传&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
                <input id="${input}file_bp" name="file"
                       class="webuploader-element-invisible" type="file" />
        </div>
        <!-- 文件列表:选择文件后在该div显示 -->
        <ol id="${input}fileList"></ol>
        <label class="text-right"
               style="font-weight: 100; float: left; margin-left: 15px; width: 144px; margin-right: 15px;"></label>
    </div>
</div>


<script type="text/javascript">
    var preShowPath = $("#preShowPath").val();//访问文件前缀
    var ${input}_$md5Array = new Array(), // 文件的MD5
        ${input}_$nameArray = new Array(), // 文件名称
        ${input}_count = 0, // 正在上传的文件在上传列表中的位置
        ${input}_success=0,//上传成功的文件数
        ${input}_map={},//key存储文件id,value存储该文件上传过的进度
        ${input}_uploader; // Web Uploader实例
    var ${input}_webUploader = WebUploader;
   $(function() {

        // 监听分块上传的三个事件
        ${input}_webUploader.Uploader.register({
            "before-send-file" : "${input}_beforeSendFile", // 所有分块上传之前
            "before-send" : "${input}_beforeSend", // 每个分块上传之前
            "after-send-file" : "${input}_afterSendFile" // 所有分块上传完成后
        },{
            ${input}_beforeSendFile : function(file){
                var deferred = ${input}_webUploader.Deferred();
                // 计算文件的MD5
                ${input}_uploader.md5File(file,0,10*1024*1024)
                // 及时显示进度
                    .progress(function(percentage) {
                        // $('#'+file.id ).find('p.state').text('正在读取文件信息...');
                    })
                    // 计算完成,继续下一步
                    .then(function(val) {
                        // $('#'+file.id ).find("p.state").text("成功获取文件信息...");
                        ${input}_$md5Array.push(val);
                        ${input}_$nameArray.push(file.name);
                        deferred.resolve();
                    });
                return deferred.promise();
            },
            ${input}_beforeSend : function(block){
                var deferred = ${input}_webUploader.Deferred();
                // 每个分块上传之前校验是否已上传
                var url = "${ctx}/uploadBig/check",
                    param = {
                        fileName : ${input}_$nameArray[${input}_count],
                        fileMd5 : ${input}_$md5Array[${input}_count],
                        jindutiao:$("#${input}jindutiao").val(),
                        chunk : block.chunk,
                        chunkSize : block.end - block.start
                    };
                // 同步校验,防止没校验完就上传了
                $.ajaxSetup({async : false});
                $.post(url,param,function(data){
                    var res = eval('('+data+')');
                    // 已上传则跳过,否则继续上传
                    if(res.ifExist){
                        deferred.reject();
                    }else{
                        deferred.resolve();
                    }
                },"json");
                $.ajaxSetup({async : true});
                this.owner.options.formData.fileMd5 = ${input}_$md5Array[${input}_count];
                deferred.resolve();
                return deferred.promise();
            },
            ${input}_afterSendFile : function(file){
                // 所有分块上传完毕,通知后台合并分块
                var url = "${ctx}/uploadBig/merge",
                    // 上传前设置其它参数
                    param = {
                        fileMd5 : ${input}_$md5Array[${input}_count],
                        fileName : ${input}_$nameArray[${input}_count]
                    };
                $.ajaxSetup({async : false});
                $.post(url,param,function(data){

                    var urlFilePaths =data.fileUrl;
                    var urlFileNames = file.name;
                    var fileIds = file.id;
                    preShowPath = data.preShowPath;

                    //单选或多选模式
                    <c:if test="${fileNumLimit eq 1}">
                    $("#${input}").val(urlFilePaths);
                    $("#${label}").val(urlFileNames);
                    $("#${input}fileIds").val(fileIds);
                    </c:if>

                    <c:if test="${fileNumLimit ne 1}">
                    var origFilePaths = $("#${input}").val();
                    var origFileNames = $("#${label}").val();
                    var origFileIds = $("#${input}fileIds").val();

                    if(""==origFilePaths){
                        $("#${input}").val(urlFilePaths);
                    }else{
                        $("#${input}").val(origFilePaths + "|"+ urlFilePaths);
                    }

                    if(""==origFileNames){
                        $("#${label}").val(urlFileNames);
                    }else{
                        $("#${label}").val(origFileNames + "|"+ urlFileNames);
                    }

                    if(""==origFileIds){
                        $("#${input}fileIds").val(fileIds);
                    }else{
                        $("#${input}fileIds").val(origFileIds + "|"+ fileIds);
                    }
                    </c:if>

                    ${input}Preview(${input}_map[file.id]);

                    ${input}_count++;

                    ${input}_uploader.upload(file);

                },"json");
                $.ajaxSetup({async : true});
            }
        });

        // 初始化Web Uploader PS:IE使用的flash上传,真心慢,大文件还是用Chrome上传比较靠谱
        ${input}_uploader = ${input}_webUploader.create({
            auto : true, // 自动上传
            swf : '${ctxStatic}/webuploader-0.1.5/Uploader.swf',
            server : '${ctx}/uploadBig/upload', // 文件接收服务端
            threads : 1, // 只运行1个线程传输
            duplicate : false, // 是否重复上传(单次选择同样的文件)
            prepareNextFile : true, // 允许在文件传输时提前把下一个文件准备好
            chunked : true, // 是否要分片处理大文件上传
            <c:if test="${not empty chunkSize}">
            chunkSize : ${chunkSize}, // 如果要分片,分多大一片? 10M默认大小为5M
            </c:if>
            fileNumLimit : ${empty fileNumLimit? 10:fileNumLimit}, // 文件总数量
            <c:if test="${not empty fileSingleSizeLimit}">
            fileSingleSizeLimit : ${fileSingleSizeLimit}, // 单个文件大小限制
            </c:if>
            <c:if test="${not empty fileSizeLimit}">
            fileSizeLimit : ${fileSizeLimit}, // 文件总大小限制
            </c:if>
            pick : {
                id : '#${input}filePicker', // 选择文件的按钮
                multiple : false // 是否允许同时选择多个文件
            },
            compress: false, // 不压缩文件
            <c:if test="${type eq 'images'}">
            accept : {
                extensions: "gif,jpg,jpeg,bmp,png",
                mimeTypes: '.gif,.jpg,.jpeg,.bmp,.png',
            }
            </c:if>
            <c:if test="${type eq 'docs'}">
            accept : {
                extensions: "txt,pdf,cebx,doc,docx,ppt,pptx,xls,xlsx",
                mimeTypes: '.txt,.pdf,.cebx,.doc,.docx,.ppt,.pptx,.xls,.xlsx',
            }
            </c:if>
            <c:if test="${type eq 'all'}">
            accept : {
                // 常见视频文件格式:avi,wmv,mpeg,mp4,mov,mkv,flv,f4v,m4v,rmvb,rm,3gp,dat,ts,mts,vob
                extensions: "txt,gif,jpg,jpeg,bmp,png,zip,rar,war,pdf,cebx,doc,docx,ppt,pptx,xls,xlsx",
                mimeTypes: '.txt,.gif,.jpg,.jpeg,.bmp,.png,.zip,.rar,.war,.pdf,.cebx,.doc,.docx,.ppt,.pptx,.xls,.xlsx',
            }
            </c:if>
        });

        // 当有文件添加进来的时候
        ${input}_uploader.on('fileQueued', function(file) {
            //进度条显示
            $("#mask").css("height",$(document).height());
            $("#mask").css("width",$(document).width());
            $("#mask").show();

            ${input}_success++;

            $.ajax({
                type:"POST",
                url:"${ctx}/uploadBig/selectProgressByFileName",  //先检查该文件是否上传过,如果上传过,上传进度是多少
                data:{
                    fileMD5 : ${input}_$md5Array[${input}_count]  //文件MD5
                },
                cache: false,
                async: false,  // 同步
                //dataType:"json",
                success:function(result){
                    var res = eval('('+result+')');

                    //上传过
                    if(res.jindutiao>0){
                        //将上传过的进度存入map集合
                        ${input}_map[file.id]=res.jindutiao/100;
                    }
                    $("#${input}filePicker").append('<div id="${input}'+file.id+'1"></div>');
                }
            });

            ${input}_uploader.stop(true);
        });

        // 上传中
        ${input}_uploader.on('uploadProgress', function (file, percentage) {
            var $li = $( '#${input}'+file.id+'1' ),
                $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%;height:20px; background-color:#2fa4e7;">' +
                    '</div>' +
                    '</div>').appendTo( $li ).find('.progress-bar');
            }

            //将实时进度存入隐藏域
            $("#${input}jindutiao").val(Math.round(percentage * 100));

            //根据fielId获得当前要上传的文件的进度
            var oldJinduValue = ${input}_map[file.id];

            if(percentage<oldJinduValue && oldJinduValue!=1){
                // $li.find('p.state').text('上传中'+Math.round(oldJinduValue * 100) + '%');
                $percent.text(Math.round(oldJinduValue * 100) + '%');
                $percent.css('width', oldJinduValue * 100 + '%');
            }else{
                // $li.find('p.state').text('上传中'+Math.round(percentage * 100) + '%');
                $percent.text(Math.round(percentage * 100) + '%');
                $percent.css('width', percentage * 100 + '%');
            }
        });

        // 文件上传成功
        ${input}_uploader.on('uploadSuccess', function(file) {
            //上传成功去掉进度条
            $('#${input}'+file.id+'1').find('.progress').fadeOut();
            // $('#'+file.id).find('p.state').text('');
            //隐藏进度条
            $("#mask").hide();
        });

        // 文件上传失败
        ${input}_uploader.on('uploadError', function(file) {
            ${input}_uploader.stop(true);
            // $('#'+file.id).find('p.state').text('上传出错,请检查网络连接');
            $.jBox.tip('上传出错,请检查网络连接');
            //隐藏进度条
            $("#mask").hide();
        });
        /**
         * 验证文件格式以及文件大小
         */
        ${input}_uploader.on("error",function (type){
            if (type=="Q_TYPE_DENIED"){
                $.jBox.tip('请上传正确格式的文件');
            }else if(type=="F_EXCEED_SIZE"){
                $.jBox.tip('请上传正确大小的文件');
            }
        });
   });

    function ${input}Del(obj){
        var newFilePaths = "";
        var newFileNames = "";
        var newFileIds = "";
        var url = $(obj).prev().attr("url");
        var origFilePaths = $("#${input}").val().split("|");
        var origFileNames = $("#${label}").val().split("|");
        var origFileIds = $("#${input}fileIds").val().split("|");
        if(origFilePaths.length == origFileNames.length){
            for (var i=0; i<origFilePaths.length; i++){
                if (preShowPath+origFilePaths[i]!=url){
                    if(""==newFilePaths){
                        newFilePaths = origFilePaths[i];
                    }else{
                        newFilePaths +="|"+origFilePaths[i];
                    }

                    if(""==newFileNames){
                        newFileNames = origFileNames[i];
                    }else{
                        newFileNames +="|"+origFileNames[i];
                    }

                    if(""==newFileIds){
                        newFileIds = origFileIds[i];
                    }else{
                        newFileIds +="|"+origFileIds[i];
                    }
                }
            }
        }else{
            $.jBox.alert('数据初始化出现异常: 数组长度不一致', '失败');
        }
        $("#${input}").val(newFilePaths);
        $("#${label}").val(newFileNames);
        $("#${input}fileIds").val(newFileIds);

        try{
            var fileItem = $(obj).parent();
            ${input}_uploader.removeFile($(fileItem).attr("id"), true);
        }catch(err){
            console.log('修改页面默认因为只是显示图片,删除操作可能报错,不影响整体功能');
        }

        ${input}Preview(0);
    }

    function ${input}Preview(bar){
        var tmp, urlFileNames = $("#${label}").val().split("|");
        var li, fileId, urls = $("#${input}").val().split("|")
            ,fileIds = $("#${input}fileIds").val().split("|");

        $("#${input}fileList").children().remove();
        //上传过
        if(bar>0){
            //如果上传过 上传了多少
            var jindutiaoStyle="width:"+bar+"%";
            for (var i=0; i<urls.length; i++){
                if (urls[i]!=""){
                    tmp = urls[i].substring(urls[i].lastIndexOf("/")+1);
                    if(typeof(fileIds[i])=='undefined'){
                        fileId = "WU_FILE_"+i;
                    }else{
                        fileId = fileIds[i];
                    }
                    if(urlFileNames.length==urls.length){
                        tmp = urlFileNames[i];
                    }
                    li = '<li id="'+fileId+'"><a href="'+preShowPath+urls[i]+'?filename='+decodeURIComponent(tmp)+'" url="'+preShowPath+urls[i]+'" target="_blank">';
                    <c:choose>
                    <c:when test="${type eq 'images'}">
                    li += '<img src="'+preShowPath+urls[i]+'" url="'+preShowPath+urls[i]+'" style="max-width:${empty maxWidth ? 200 : maxWidth}px;max-height:${empty maxHeight ? 200 : maxHeight}px;_height:${empty maxHeight ? 200 : maxHeight}px;border:0;padding:3px;">';
                    </c:when>
                    <c:otherwise>
                    li += decodeURIComponent(tmp);
                    </c:otherwise>
                    </c:choose>

                    li += '</a>&nbsp;&nbsp;<c:if test="${!readonly}"><a href="javascript:" onclick="${input}Del(this);">×</a></c:if></li>'+
                        '<div class="progress progress-striped active">' +
                        '<div class="progress-bar" role="progressbar" style="'+jindutiaoStyle+'">';
                    $("#${input}fileList").append(li);
                }
            }
        }else{
            for (var i=0; i<urls.length; i++){
                if (urls[i]!=""){
                    tmp = urls[i].substring(urls[i].lastIndexOf("/")+1);
                    if(typeof(fileIds[i])=='undefined'){
                        fileId = "WU_FILE_"+i;
                    }else{
                        fileId = fileIds[i];
                    }
                    if(urlFileNames.length==urls.length){
                        tmp = urlFileNames[i];
                    }

                    li = '<li id="'+fileId+'"><a href="'+preShowPath+urls[i]+'?filename='+decodeURIComponent(tmp)+'" url="'+preShowPath+urls[i]+'" target="_blank">';
                    <c:choose>
                    <c:when test="${type eq 'images'}">
                    li += '<img src="'+preShowPath+urls[i]+'" url="'+preShowPath+urls[i]+'" style="max-width:${empty maxWidth ? 200 : maxWidth}px;max-height:${empty maxHeight ? 200 : maxHeight}px;_height:${empty maxHeight ? 200 : maxHeight}px;border:0;padding:3px;">';
                    </c:when>
                    <c:otherwise>
                    li += decodeURIComponent(tmp);
                    </c:otherwise>
                    </c:choose>

                    li += "</a>&nbsp;&nbsp;<c:if test="${!readonly}"><a href=\"javascript:\" onclick=\"${input}Del(this);\">×</a></c:if></li>";
                    $("#${input}fileList").append(li);
                }
            }
        }
    }

    ${input}Preview(0);
</script>

 

 

 

java后台代码:BigFileUploadController.java

其中包含上传到FastDFS的方法(如果不需要可以把这部分代码去掉),感觉不太好,因为是先上传到服务器中的临时路径,然后,再用FastDFS上传的,没研究出来分片之后,直接上传到FastDFS服务器中的方法,希望有大神指点。

继承的BaseController类,只是用了里面的记录日志方法和一些url前缀取值,可以忽略。

还有一些Util类,以下只提供FileUtils类,其他Util类比较普遍,项目中应该都会有。

 

package com.senyint.ma.common.web;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.common.servlet.entity.UploadNetStreamCallback;
import com.common.servlet.entity.UploadifyResult;
import com.common.utils.*;
import com.modules.sys.utils.UserUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.jasig.cas.client.util.CommonUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
@RequestMapping(value = "${adminPath}/uploadBig")
public class BigFileUploadController extends BaseController {

   /** Fastdfs configure file **/
   public static final String FASTDFS_CONIFG_FILE = "deploy.properties";

   private static final String FILE_UPLOAD = "upload";

   /** show files path **///e.g.  http://10.66.90.176:8888
   public static String SHOW_PATH = new PropertiesLoader("deploy.properties").getProperty("show_path");

   /** upload files path **/e.g.  windows: d:\\testUpload  linux: /temp
   public static String UPLOAD_PATH = new PropertiesLoader("deploy.properties").getProperty("noFdfs_upload_path");

   /** 上传标识 1.fastdfs 2.ftp 3.aliyun**/
   public static String UPLOAD_FLAG = new PropertiesLoader("deploy.properties").getProperty("uploadFlag");

   /** Fastdfs configure file **/
   protected static String SYS_CLASSES_PATH_FILE = "";

   /** Temporary Path **/
   protected static String SYS_TMP_PATH = "/tmp/";

   protected static String SYS_FASTDFS_TRACKER_HTTP_PORT="";

   /**
    * 保存文件分片
    * @param request HttpServletRequest
    * @param response HttpServletResponse
    */
   @RequestMapping(value = "/upload")
   @ResponseBody
   public String upload(HttpServletRequest request, HttpServletResponse response) {
      // 参数获取
      String fileMd5 = request.getParameter("fileMd5");
      String chunk = request.getParameter("chunk");
      // 临时目录
      String tempPath = request.getSession().getServletContext().getRealPath("/");//"D:\\testUpload\\upload\\";
      // 转换请求对象得到文件对象
      MultipartHttpServletRequest Murequest = (MultipartHttpServletRequest) request;
      Map<String, MultipartFile> files = Murequest.getFileMap();
      if (null != files && !files.isEmpty()) {
         for (MultipartFile item : files.values()) {
            String tempDir = getTempDir(tempPath, fileMd5);
            // 创建临时文件夹
            File dir = new File(tempDir);
            if (!dir.exists()) {
               dir.mkdirs();
            }
            // 创建分片文件并保存
            File chunkFile = new File(tempDir + File.separator + chunk);
            try {
               chunkFile.createNewFile();
               item.transferTo(chunkFile);
            } catch (IllegalStateException e) {
               logger.error("保存分片文件出错:" + e.getMessage());
               e.printStackTrace();
            } catch (IOException e) {
               logger.error("保存分片文件出错:" + e.getMessage());
               e.printStackTrace();
            }
         }
      }
      return "1";
   }

   /**
    * 校验分片是否已上传
    *
    * @Title: checkChunk
    * @param request HttpServletRequest
    * @param response HttpServletResponse
    */
   @RequestMapping(value = "/check",
         method = RequestMethod.POST)
   public void checkChunk(HttpServletRequest request, HttpServletResponse response) {
      // 获取参数
      String fileMd5 = request.getParameter("fileMd5");
      String chunk = request.getParameter("chunk");
      String chunkSize = request.getParameter("chunkSize");
      String jindutiao = request.getParameter("jindutiao");// 文件上传的实时进度
      // 临时文件
      String tempPath = request.getSession().getServletContext().getRealPath("/");//"D:\\testUpload\\upload\\";
      String tempDir = getTempDir(tempPath, fileMd5);
      File chunkFile = new File(tempDir + File.separator + chunk);
      // 将当前进度存入缓存
      CacheUtils.put(FILE_UPLOAD, "jindutiao_" + fileMd5, jindutiao);
//    System.out.println("缓存中的进度条="+jindutiao);
      // 分片文件是否存在,尺寸是否一致
      if (chunkFile.exists() && chunkFile.length() == Integer.parseInt(chunkSize)) {
         writeJSON(response,"{\"ifExist\":1}");
      }else{
         writeJSON(response,"{\"ifExist\":0}");
      }
   }

   /**
    * 合并分片成完整文件
    *
    * @Title: mergeChunks
    * @param request HttpServletRequest
    * @param response HttpServletResponse
    */
   @SuppressWarnings("resource")
   @RequestMapping(value = "/merge",
         method = RequestMethod.POST)
   @ResponseBody
   public String mergeChunks(HttpServletRequest request, HttpServletResponse response) {
      Calendar calendar=Calendar.getInstance();
      String month = "";
      String day = "";
      SimpleDateFormat sdfM = new SimpleDateFormat("MM");
      SimpleDateFormat sdfD = new SimpleDateFormat("dd");
      Date ddM  = Calendar.getInstance().getTime();
      Date ddD  = Calendar.getInstance().getTime();
      month = sdfM.format(ddM);
      day = sdfD.format(ddD);
      String filePath = UPLOAD_PATH + File.separatorChar+calendar.get(Calendar.YEAR)+month+day;//文件存放服务器路径
      String filePathUrl = "/"+calendar.get(Calendar.YEAR)+month+day;//文件访问路径

      // 获取参数
      String fileName = request.getParameter("fileName");
      String fileMd5 = request.getParameter("fileMd5");
      // 获得目标文件夹
      String tempPath = request.getSession().getServletContext().getRealPath("/");//"D:\\testUpload\\upload\\";
      // 创建目标文件夹
      File saveDir = new File(filePath);
      if (!saveDir.exists()) {
         saveDir.mkdirs();
      }

      // 文件临时文件夹"根目录/temp/userName/文件名/MD5"
      String tempDirPath = getTempDir(tempPath, fileMd5);
      File tempDir = new File(tempDirPath);
      // 获得分片文件列表
      File[] fileArray = tempDir.listFiles(new FileFilter() {
         // 只需要文件
         public boolean accept(File pathname) {
            if (pathname.isDirectory()) {
               return false;
            } else {
               return true;
            }
         }
      });
      // 转成集合进行排序后合并文件
      List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));
      Collections.sort(fileList, new Comparator<File>() {
         // 按文件名升序排列
         public int compare(File o1, File o2) {
            if (Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())) {
               return -1;
            } else {
               return 1;
            }
         }
      });

      String extFileName = FileUtils.getFileExtension(fileName);
      String uuid = IdGen.uuid();
      // 目标文件
      File outfile = new File(filePath + File.separator + uuid + "." + extFileName);
      try {
         outfile.createNewFile();
      } catch (IOException e) {
         logger.error("创建目标文件出错:" + e);
      }

      // 执行合并操作
      FileChannel outChannel = null;
      FileChannel inChannel;
      try {
         outChannel = new FileOutputStream(outfile).getChannel();
         for (File file : fileList) {
            inChannel = new FileInputStream(file).getChannel();
            inChannel.transferTo(0, inChannel.size(), outChannel);
            inChannel.close();
            file.delete();
         }
         outChannel.close();
      } catch (FileNotFoundException e) {
         logger.error("合并分片文件出错:文件没找到" + e);
      } catch (IOException e) {
         logger.error("合并分片文件出错:读写错误" + e);
      }

      String fileId = filePath + File.separator + outfile.getName();
      String fileUrl = filePathUrl + "/" + outfile.getName();
      if(UPLOAD_FLAG.equals("fastdfs")){
         fileUrl = "";
         try {
            //初始化FastDFS 开始
            // Classes Path
            File f = new File(this.getClass().getResource("/").getPath());
            String classesPath = f.getAbsolutePath();
            SYS_CLASSES_PATH_FILE = classesPath + File.separator + FASTDFS_CONIFG_FILE;
            // Temporary Path
            String tmpDir = System.getProperty("java.io.tmpdir");
            if (null != tmpDir && tmpDir.trim().length() > 0) {
               SYS_TMP_PATH = tmpDir.trim();
            }
            // Init FastDFS
            ClientGlobal.init(SYS_CLASSES_PATH_FILE);
            // Tracker server host name
//          InetSocketAddress[] isa =ClientGlobal.g_tracker_group.tracker_servers;
   //          SYS_FASTDFS_HOST_NAME = isa[0].getHostName();
            // Tracker server http port
            SYS_FASTDFS_TRACKER_HTTP_PORT = ClientGlobal.getG_tracker_http_port() + "";
            //初始化FastDFS 结束

            String name = outfile.getName();
            // Format
            String extName = FileUtils.getFileExtension(name);

            //byte[] uploadFileBuffer = StreamUtils.InputStreamTOByte(item.getInputStream());
            //System.out.println("network_timeout=" + ClientGlobal.g_network_timeout + "ms");
            //System.out.println("charset=" + ClientGlobal.g_charset);
            // Save it into FastDFS
            TrackerClient tracker = new TrackerClient();
            TrackerServer trackerServer = tracker.getConnection();
            StorageServer storageServer = null;
            StorageClient client = new StorageClient(trackerServer, storageServer);
            // Set Meta data
            NameValuePair[] metaList = new NameValuePair[4];
            metaList[0] = new NameValuePair("fileName", name);
            metaList[1] = new NameValuePair("fileExtName", extName);
            metaList[2] = new NameValuePair("fileLength", String.valueOf(outfile.length()));
            metaList[3] = new NameValuePair("fileUid", this.getUserId());
            // Upload FastDFS
            //String[] fileIds = client.upload_file(local_filename, null, metaList);
            //String[] fileIds = client.upload_file(uploadFileBuffer, extName, metaList);
            long fileSize = outfile.length();
            UploadNetStreamCallback callback= new  UploadNetStreamCallback(new FileInputStream(outfile));
            String[] fileIds = client.upload_file(null, fileSize, callback, extName, metaList);
            for (int i = 0; i < fileIds.length; i++) {
               fileUrl = fileUrl + "/" + fileIds[i];
            }
            fileId = fileUrl.substring(1);
         } catch (Exception ex) {
            logger.error("FastDFS上传失败:",ex);
         }
         //已经由fastdfs存储,删除合并的文件
         saveDir.delete();
      }

      // 删除临时文件夹
      tempDir.delete();

      // 合并成功后删除缓存中的进度信息
      CacheUtils.remove(FILE_UPLOAD, "jindutiao_" + fileMd5);

      UploadifyResult result = new UploadifyResult();
      result.setFileId(fileId);//文件上传路径
      result.setFileUrl(fileUrl);//文件访问路径
      result.setPreShowPath(SHOW_PATH);

      return JSONObject.toJSONString(result);
   }

   @RequestMapping(value = "selectProgressByFileName")
   @ResponseBody
   // 当有文件添加进队列时 通过文件名查看该文件是否上传过 上传进度是多少
   public String selectProgressByFileName(String fileMD5) {
      String jindutiao = "";
      if (StringUtils.isNotBlank(fileMD5)) {
         jindutiao = ObjectUtils.toString(CacheUtils.get(FILE_UPLOAD, "jindutiao_" + fileMD5));
      }
//    System.out.println("显示进度条="+jindutiao);
      return "{jindutiao :'" + jindutiao + "'}";
   }

   /**
    * 获得分片文件临时保存路径
    *
    * @Title: getTempDir
    * @param tempPath 临时文件根目录
    * @param fileMd5 文件MD5
    * @return String 分片临时保存路径
    */
   private String getTempDir(String tempPath, String fileMd5) {
      StringBuilder dir = new StringBuilder(tempPath);
      dir.append(this.getUserId());
      dir.append(fileMd5);
      return dir.toString();
   }

   /**
    * 返回json格式
    * @param response
    * @param object
    */
   public void writeJSON(HttpServletResponse response, Object object){
      try {
         //设定编码
         response.setCharacterEncoding("UTF-8");
         //表示是json类型的数据
         response.setContentType("application/json");
         //获取PrintWriter 往浏览器端写数据
         PrintWriter writer = response.getWriter();

         ObjectMapper mapper = new ObjectMapper(); //转换器
         //获取到转化后的JSON 数据
         String json = mapper.writeValueAsString(object);
         //写数据到浏览器
         writer.write(json);
         //刷新,表示全部写完,把缓存数据都刷出去
         writer.flush();

         //关闭writer
         writer.close();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
         logger.error("response中存json失败",e);
      }
   }

   protected String getUserId() {
      String sUid = "--";
      try {
         String sUidTmp = UserUtils.getUser().getId();
         if (null != sUidTmp && sUidTmp.trim().length() > 0) {
            sUid = sUidTmp.trim();
         }
      } catch (Exception ex) {
      }
      return sUid;
   }
}

UploadNetStreamCallback类:

org.csource.fastdfs包为FastDFS包,需要自行下载引用。

 

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.csource.fastdfs.UploadCallback;

public class UploadNetStreamCallback implements UploadCallback{

   private  InputStream is= null;
   
   public InputStream getIs() {
      return is;
   }

   public void setIs(InputStream is) {
      this.is = is;
   }

   public UploadNetStreamCallback(InputStream is) {
      super();
      this.is = is;
   }
   /**
   * send file content callback function, be called only once when the file uploaded
   * @param out output stream for writing file content
   * @return 0 success, return none zero(errno) if fail
   */
   
   public int send(OutputStream out) throws IOException {

      int readBytes;
      byte[] buff = new byte[8192];
      try {
         while ((readBytes = this.is.read(buff)) >= 0) {
            if (readBytes == 0) {
               continue;
            }
            out.write(buff, 0, readBytes);
         }
      } catch (IOException ex) {
         ex.printStackTrace();
         return -1;
      }

      return 0;
   }

}

UploadifyResult类:

 

public class UploadifyResult implements java.io.Serializable{
   private static final long serialVersionUID = 1L;
   
   private String fileId;
   private String fileName;
   private String fileUrl;
   private String preShowPath;//访问文件前缀

   public String getFileId() {
      return fileId;
   }

   public void setFileId(String fileId) {
      this.fileId = fileId;
   }

   public String getFileName() {
      return fileName;
   }

   public void setFileName(String fileName) {
      this.fileName = fileName;
   }

   public String getFileUrl() {
      return fileUrl;
   }

   public void setFileUrl(String fileUrl) {
      this.fileUrl = fileUrl;
   }

   public String getPreShowPath() {
      return preShowPath;
   }

   public void setPreShowPath(String preShowPath) {
      this.preShowPath = preShowPath;
   }
}

 

FileUtils类:

 

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Enumeration;
import java.util.List;

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

import org.apache.commons.fileupload.FileItem;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;

/**
 * 文件操作工具类
 * 实现文件的创建、删除、复制、压缩、解压以及目录的创建、删除、复制、压缩解压等功能
 * @author 
 * @version 2015-3-16
 */
public class FileUtils extends org.apache.commons.io.FileUtils {
   
   private static Logger logger = LoggerFactory.getLogger(FileUtils.class);

   /**
    * 复制单个文件,如果目标文件存在,则不覆盖
    * @param srcFileName 待复制的文件名
    * @param descFileName 目标文件名
    * @return 如果复制成功,则返回true,否则返回false
    */
   public static boolean copyFile(String srcFileName, String descFileName) {
      return FileUtils.copyFileCover(srcFileName, descFileName, false);
   }

 
   /**
    * 复制整个目录的内容,如果目标目录存在,则不覆盖
    * @param srcDirName 源目录名
    * @param descDirName 目标目录名
    * @return 如果复制成功返回true,否则返回false
    */
   public static boolean copyDirectory(String srcDirName, String descDirName) {
      return FileUtils.copyDirectoryCover(srcDirName, descDirName,
            false);
   }

 
   /**
    * 
    * 删除文件,可以删除单个文件或文件夹
    * 
    * @param fileName 被删除的文件名
    * @return 如果删除成功,则返回true,否是返回false
    */
   public static boolean delFile(String fileName) {
      File file = new File(fileName);
      if (!file.exists()) {
         logger.debug(fileName + " 文件不存在!");
         return true;
      } else {
         if (file.isFile()) {
            return FileUtils.deleteFile(fileName);
         } else {
            return FileUtils.deleteDirectory(fileName);
         }
      }
   }

   /**
    * 
    * 删除单个文件
    * 
    * @param fileName 被删除的文件名
    * @return 如果删除成功,则返回true,否则返回false
    */
   public static boolean deleteFile(String fileName) {
      File file = new File(fileName);
      if (file.exists() && file.isFile()) {
         if (file.delete()) {
            logger.debug("删除文件 " + fileName + " 成功!");
            return true;
         } else {
            logger.debug("删除文件 " + fileName + " 失败!");
            return false;
         }
      } else {
         logger.debug(fileName + " 文件不存在!");
         return true;
      }
   }

   /**
    * 
    * 删除目录及目录下的文件
    * 
    * @param dirName 被删除的目录所在的文件路径
    * @return 如果目录删除成功,则返回true,否则返回false
    */
   public static boolean deleteDirectory(String dirName) {
      String dirNames = dirName;
      if (!dirNames.endsWith(File.separator)) {
         dirNames = dirNames + File.separator;
      }
      File dirFile = new File(dirNames);
      if (!dirFile.exists() || !dirFile.isDirectory()) {
         logger.debug(dirNames + " 目录不存在!");
         return true;
      }
      boolean flag = true;
      // 列出全部文件及子目录
      File[] files = dirFile.listFiles();
      for (int i = 0; i < files.length; i++) {
         // 删除子文件
         if (files[i].isFile()) {
            flag = FileUtils.deleteFile(files[i].getAbsolutePath());
            // 如果删除文件失败,则退出循环
            if (!flag) {
               break;
            }
         }
         // 删除子目录
         else if (files[i].isDirectory()) {
            flag = FileUtils.deleteDirectory(files[i]
                  .getAbsolutePath());
            // 如果删除子目录失败,则退出循环
            if (!flag) {
               break;
            }
         }
      }

      if (!flag) {
         logger.debug("删除目录失败!");
         return false;
      }
      // 删除当前目录
      if (dirFile.delete()) {
         logger.debug("删除目录 " + dirName + " 成功!");
         return true;
      } else {
         logger.debug("删除目录 " + dirName + " 失败!");
         return false;
      }

   }

   /**
    * 创建单个文件
    * @param descFileName 文件名,包含路径
    * @return 如果创建成功,则返回true,否则返回false
    */
   public static boolean createFile(String descFileName) {
      File file = new File(descFileName);
      if (file.exists()) {
         logger.debug("文件 " + descFileName + " 已存在!");
         return false;
      }
      if (descFileName.endsWith(File.separator)) {
         logger.debug(descFileName + " 为目录,不能创建目录!");
         return false;
      }
      if (!file.getParentFile().exists()) {
         // 如果文件所在的目录不存在,则创建目录
         if (!file.getParentFile().mkdirs()) {
            logger.debug("创建文件所在的目录失败!");
            return false;
         }
      }

      // 创建文件
      try {
         if (file.createNewFile()) {
            logger.debug(descFileName + " 文件创建成功!");
            return true;
         } else {
            logger.debug(descFileName + " 文件创建失败!");
            return false;
         }
      } catch (Exception e) {
         e.printStackTrace();
         logger.debug(descFileName + " 文件创建失败!");
         return false;
      }

   }

   /**
    * 创建目录
    * @param descDirName 目录名,包含路径
    * @return 如果创建成功,则返回true,否则返回false
    */
   public static boolean createDirectory(String descDirName) {
      String descDirNames = descDirName;
      if (!descDirNames.endsWith(File.separator)) {
         descDirNames = descDirNames + File.separator;
      }
      File descDir = new File(descDirNames);
      if (descDir.exists()) {
         logger.debug("目录 " + descDirNames + " 已存在!");
         return false;
      }
      // 创建目录
      if (descDir.mkdirs()) {
         logger.debug("目录 " + descDirNames + " 创建成功!");
         return true;
      } else {
         logger.debug("目录 " + descDirNames + " 创建失败!");
         return false;
      }

   }



   /**
    * 获取文件扩展名(返回小写)
    * @param fileName 文件名
    * @return 例如:test.jpg  返回:  jpg
    */
   public static String getFileExtension(String fileName) {
      if ((fileName == null) || (fileName.lastIndexOf(".") == -1) || (fileName.lastIndexOf(".") == fileName.length() - 1)) {
         return null;
      }
      return StringUtils.lowerCase(fileName.substring(fileName.lastIndexOf(".") + 1));
   }

   
}

以上为个人观点,与大家共同学习共同提高。