• 技术文章 >Java >java教程

    Java与WebUploader相结合实现文件上传功能代码详解

    黄舟黄舟2017-03-30 10:11:32原创1609
    这篇文章主要介绍了Java结合WebUploader实现文件上传功能,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友可以参考下

    之前自己写小项目的时候也碰到过文件上传的问题,没有找到很好的解决方案。虽然之前网找各种解决方案的时候也看到过WebUploader,但没有进一步深究。这次稍微深入了解了些,这里也做个小结。

    简单的文件和普通数据上传并保存

    jsp页面:

    <%@ 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>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
     <form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
      文件:<input type="file" value="请选择文件" name="file" /> <br/>
      信息:<input type="text" name="info" /> <br/>
      <input type="submit" value="提交" />
     </form>
    </body>
    </html>

    servlet:

    package com.yihengliu.web.action;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    import org.apache.commons.io.FileUtils;
    /**
     * Servlet user to accept file upload
     */
    public class FileUploadServlet extends HttpServlet {
     private static final long serialVersionUID = 1L;
     private String serverPath = "e:/";
     protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException {
      response.getWriter().append("Served at: ").append(request.getContextPath());
      System.out.println("进入后台...");
      // 1.创建DiskFileItemFactory对象,配置缓存用
      DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
      // 2. 创建 ServletFileUpload对象
      ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
      // 3. 设置文件名称编码
      servletFileUpload.setHeaderEncoding("utf-8");
      // 4. 开始解析文件
      try {
       List<FileItem> items = servletFileUpload.parseRequest(request);
       for (FileItem fileItem : items) {
        if (fileItem.isFormField()) { // >> 普通数据
         String info = fileItem.getString("utf-8");
         System.out.println("info:" + info);
        } else { // >> 文件
         // 1. 获取文件名称
         String name = fileItem.getName();
         // 2. 获取文件的实际内容
         InputStream is = fileItem.getInputStream();
         // 3. 保存文件
         FileUtils.copyInputStreamToFile(is, new File(serverPath + "/" + name));
        }
       }
      } catch (Exception e) {
       e.printStackTrace();
      }
     }
     protected void doPost(HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException {
      doGet(request, response);
     }
    }

    使用WebUploader组件上传

    分片、并发,预览、压缩,多途径添加文件夹(文件多选,拖拽等),妙传

    页面样式使用

    <html>
    <title>使用webuploader上传</title>
    <!-- 1.引入文件 -->
    <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath }/js/webuploader.css" rel="external nofollow" >
    <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-2.1.4.min.js"></script>
    <script type="text/javascript" src="${pageContext.request.contextPath }/js/webuploader.js"></script>
    </head>
    <body>
     <!-- 2.创建页面元素 -->
     <p id="upload">
      <p id="filePicker">文件上传</p>
     </p>
     <!-- 3.添加js代码 -->
     <script type="text/javascript">
      var uploader = WebUploader.create(
       {
        swf:"${pageContext.request.contextPath }/js/Uploader.swf",
        server:"${pageContext.request.contextPath }/FileUploadServlet",
        pick:"#filePicker",
        auto:true
       }  
      );
     </script>
    </body>
    </html>
    // 生成缩略图和上传进度
    uploader.on("fileQueued", function(file) {
      // 把文件信息追加到fileList的p中
      $("#fileList").append("<p id='" + file.id + "'><img/><span>" + file.name + "</span><p><span class='percentage'><span></p></p>")
      // 制作缩略图
      // error:不是图片,则有error
      // src:代表生成缩略图的地址
      uploader.makeThumb(file, function(error, src) {
       if (error) {
        $("#" + file.id).find("img").replaceWith("<span>无法预览 </span>");
       } else {
        $("#" + file.id).find("img").attr("src", src);
       }
      });
     }
    );
    // 监控上传进度
    // percentage:代表上传文件的百分比
    uploader.on("uploadProgress", function(file, percentage) {
     $("#" + file.id).find("span.percentage").text(Math.round(percentage * 100) + "%");
    });
    <style type="text/css">
     #dndArea {
      width: 200px;
      height: 100px;
      border-color: red;
      border-style: dashed;
     }
    </style>  
    <!-- 创建用于拖拽的区域 -->
    <p id="dndArea"></p>

    屏蔽拖拽区域外的响应

    开启粘贴功能

    var uploader = WebUploader.create(
     {  swf:"${pageContext.request.contextPath }/js/Uploader.swf",
    server:"${pageContext.request.contextPath }/FileUploadServlet",
      pick:"#filePicker",
      auto:true,
      // 开启拖拽
      dnd:"#dndArea",
      // 屏蔽拖拽区域外的响应
      disableGlobalDnd:true,
      // 
     }  
    );

    前端根据需要发送的文件生成一个md5字符串发送给后台,后台创建以该md5字符串命名的文件夹。前端分块发送文件并发送文件块序号给后台,后台接收到文件后按序号名称保存。前端发送完成后通知后台合并文件。

    // 上传基本配置
    var uploader = WebUploader.create(
    {
     swf:"${pageContext.request.contextPath }/js/Uploader.swf",
     server:"${pageContext.request.contextPath }/FileUploadServlet",
     pick:"#filePicker",
     auto:true,
     dnd:"#dndArea",
     disableGlobalDnd:true,
     paste:"#uploader",
    
     // 分块上传设置
     // 是否分块
     chunked:true,
     // 每块文件大小(默认5M)
     chunkSize:5*1024*1024,
     // 开启几个并非线程(默认3个)
     threads:3,
     // 在上传当前文件时,准备好下一个文件
     prepareNextFile:true
    }  
    );

    可以分为三个时间点:

    可以在该方法中获取文件的md5字符串作为后台保存分块文件的目录名

    可以在该方法中发送md5字符串到后台,后台判断是否已经存在分块决定是否发送以达到断点续传的功能

    可以在该方法中通知后台合并所有分块

     // 监听分块上传的时间点,断点续传
    var fileMd5;
    WebUploader.Uploader.register({
     "before-send-file":"beforeSendFile",
     "before-send":"beforeSend",
     "after-send-file":"afterSendFile"
     },{
      beforeSendFile:function(file) {
       // 创建一个deffered,用于通知是否完成操作
       var deferred = WebUploader.Deferred();
       // 计算文件的唯一标识,用于断点续传和妙传
       (new WebUploader.Uploader()).md5File(file, 0, 5*1024*1024)
        .progress(function(percentage){
         $("#"+file.id).find("span.state").text("正在获取文件信息...");
        })
        .then(function(val) {
         fileMd5 = val;
         $("#" + file.id).find("span.state").text("成功获取文件信息");
         // 放行
         deferred.resolve();
        });
       // 通知完成操作
       return deferred.promise();
      },
      beforeSend:function() {
       var deferred = WebUploader.Deferred();
       // 发送文件md5字符串到后台
       this.owner.options.formData.fileMd5 = fileMd5;
       deferred.resolve();
       return deferred.promise();
      },
      afterSendFile:function() {
      }
     }
    );

    添加state标签

    $("#fileList").append("<p id='" + file.id + "'>
    <img/>
    <span>" + file.name + "</span>
    <p>
    <span class='state'>
    </span>
    </p>
    <p>
    <span class='percentage'>
    </span>
    </p>
    </p>");

    保存文件

    // 4. 开始解析文件
    // 文件md5获取的字符串
    String fileMd5 = null;
    // 文件的索引
    String chunk = null;
    try {
      List<FileItem> items = servletFileUpload.parseRequest(request);
      for (FileItem fileItem : items) {
        if (fileItem.isFormField()) { // >> 普通数据
          String fieldName = fileItem.getFieldName();
          if ("info".equals(fieldName)) {
            String info = fileItem.getString("utf-8");
            System.out.println("info:" + info);
          }
          if ("fileMd5".equals(fieldName)) {
            fileMd5 = fileItem.getString("utf-8");
            System.out.println("fileMd5:" + fileMd5);
          }
          if ("chunk".equals(fieldName)) {
            chunk = fileItem.getString("utf-8");
            System.out.println("chunk:" + chunk);
          }
        } else { // >> 文件
          /*// 1. 获取文件名称
          String name = fileItem.getName();
          // 2. 获取文件的实际内容
          InputStream is = fileItem.getInputStream();
          // 3. 保存文件
          FileUtils.copyInputStreamToFile(is, new File(serverPath + "/" + name));*/
          // 如果文件夹没有创建文件夹
          File file = new File(serverPath + "/" + fileMd5);
          if (!file.exists()) {
            file.mkdirs();
          }
          // 保存文件
          File chunkFile = new File(serverPath + "/" + fileMd5 + "/" + chunk);
          FileUtils.copyInputStreamToFile(fileItem.getInputStream(), chunkFile);
        }
      }

    前端增加:

    // 通知合并分块
    $.ajax(
      {
        type:"POST",
        url:"${pageContext.request.contextPath}/UploadActionServlet?action=mergeChunks",
        data:{
          fileMd5:fileMd5
        },
        success:function(response){
        }
      }
    );

    新增合并action:

    package com.yihengliu.web.action;
    import java.io.File;
    import java.io.FileFilter;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.channels.FileChannel;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    import java.util.UUID;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     * 合并上传文件
     */
    public class UploadActionServlet extends HttpServlet {
      private static final long serialVersionUID = 1L;
      private String serverPath = "e:/";
      protected void doGet(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
        System.out.println("进入合并后台...");
        String action = request.getParameter("action");
        if ("mergeChunks".equals(action)) {
          // 获得需要合并的目录
          String fileMd5 = request.getParameter("fileMd5");
          // 读取目录所有文件
          File f = new File(serverPath + "/" + fileMd5);
          File[] fileArray = f.listFiles(new FileFilter() {
            // 排除目录,只要文件
            @Override
            public boolean accept(File pathname) {
              if (pathname.isDirectory()) {
                return false;
              }
              return true;
            }
          });
          // 转成集合,便于排序
          List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));
          // 从小到大排序
          Collections.sort(fileList, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
              if (Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())) {
                return -1;
              }
              return 1;
            }
          });
          // 新建保存文件
          File outputFile = new File(serverPath + "/" + UUID.randomUUID().toString() + ".zip");
          // 创建文件
          outputFile.createNewFile();
          // 输出流
          FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
          FileChannel outChannel = fileOutputStream.getChannel();
          // 合并
          FileChannel inChannel;
          for (File file : fileList) {
            inChannel = new FileInputStream(file).getChannel();
            inChannel.transferTo(0, inChannel.size(), outChannel);
            inChannel.close();
            // 删除分片
            file.delete();
          }
          // 关闭流
          fileOutputStream.close();
          outChannel.close();
          // 清除文件加
          File tempFile = new File(serverPath + "/" + fileMd5);
          if (tempFile.isDirectory() && tempFile.exists()) {
            tempFile.delete();
          }
          System.out.println("合并文件成功");
        }
      }
      protected void doPost(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
        doGet(request, response);
      }
    }

    前端页面发送前添加校验,校验是否已经上传分块

    beforeSend:function(block) {
            var deferred = WebUploader.Deferred();
            // 支持断点续传,发送到后台判断是否已经上传过
            $.ajax(
              {
                type:"POST",
                url:"${pageContext.request.contextPath}/UploadActionServlet?action=checkChunk",
                data:{
                  // 文件唯一表示                
                  fileMd5:fileMd5,
                  // 当前分块下标
                  chunk:block.chunk,
                  // 当前分块大小
                  chunkSize:block.end-block.start
                },
                dataType:"json",
                success:function(response) {
                  if(response.ifExist) {
                    // 分块存在,跳过该分块
                    deferred.reject();
                  } else {
                    // 分块不存在或不完整,重新发送
                    deferred.resolve();
                  }
                }
              }
            );
            // 发送文件md5字符串到后台
            this.owner.options.formData.fileMd5 = fileMd5;
            return deferred.promise();
          }
    else if ("checkChunk".equals(action)) {
        // 校验文件是否已经上传并返回结果给前端
        // 文件唯一表示                
        String fileMd5 = request.getParameter("fileMd5");
        // 当前分块下标
        String chunk = request.getParameter("chunk");
        // 当前分块大小
        String chunkSize = request.getParameter("chunkSize");
        // 找到分块文件
        File checkFile = new File(serverPath + "/" + fileMd5 + "/" + chunk);
        // 检查文件是否存在,且大小一致
        response.setContentType("text/html;charset=utf-8");
        if (checkFile.exists() && checkFile.length() == Integer.parseInt((chunkSize))) {
          response.getWriter().write("{\"ifExist\":1}");
        } else {
          response.getWriter().write("{\"ifExist\":0}");
        }
      }

    以上就是Java与WebUploader相结合实现文件上传功能代码详解的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:java实现把对象数组通过excel方式导出的功能的示例代码分享 下一篇:详细介绍Java实现文件或文件夹的复制到指定目录的实例
    20期PHP线上班

    相关文章推荐

    精选22门好课,价值3725元,开通VIP免费学习!• SpringCloud Tencent 全套解决方案一• 详细介绍Java虚拟机:JVM垃圾回收器• 实例详解Java实现简易版的图书管理系统• Java知识归纳之JVM详解• JAVA接口与抽象类详细解析
    1/1

    PHP中文网