带进度条的文件上传

回到首页☞

要实现实时查看上传进度,需要配合Ajax技术,Ajax技术是一个伟大技术,虽然现在web框架不断迭代,理念不断变化,但是ajxa技术却越来越重要。
这个后期再补充,一直都没实验成功。

1、工作原理

服务器端将上传进度信息实时写入session,前端通过Ajax技术另外开一共线程,实时读取session中的数据,不刷新页面,局部刷新。

2、上传进度条

现在有各种插件根据返回数据做展示,练习采用最原始方案即可。

    <style type="text/css">
        #progressbar {
            width: 400px;
            height: 12px;
            background: #FFF;
            border: 1px solid #000;
            padding: 1px;
        }

        #progressbaritem {
            width: 30%;
            height: 100%;
            background: #FF0000;
        }
    </style>
<div id="progressbar">
    <div id="progressbaritem"></div>
</div>

3、上传监听

修改下pom,换下jar包版本,之前版本太低,没有监听接口ProgressListener。
ProgressListener只有一个方法-update

    <dependencies>
        <dependency>
            <groupId>com.github.datastax-oss</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.zenframework.z8.dependencies.commons</groupId>
            <artifactId>commons-fileupload-1.3.1</artifactId>
            <version>2.0</version>
        </dependency>
    </dependencies>

JavaBean和监听器的实现如下:

package com.wht.demo.servlet;

/**
 * @author JDIT
 */
public class UploadStatus {
  private long bytesRead;                               //已上传的字节数,单位:字节
  private long contentLength;                           //所有文件的总长度,单位:字节
  private int items;                                    //正在上传第几个文件
  private long startTime =  System.currentTimeMillis();

  public long getBytesRead() {
    return bytesRead;
  }

  public void setBytesRead(long bytesRead) {
    this.bytesRead = bytesRead;
  }

  public long getContentLength() {
    return contentLength;
  }

  public void setContentLength(long contentLength) {
    this.contentLength = contentLength;
  }

  public int getItems() {
    return items;
  }

  public void setItems(int items) {
    this.items = items;
  }
}

package com.wht.demo.listener;

import com.wht.demo.servlet.UploadStatus;
import org.apache.commons.fileupload.ProgressListener;

/**
 * @author JDIT
 */
public class UploadListener implements ProgressListener {
  private UploadStatus status;

  public UploadListener(UploadStatus status) {
    this.status = status;
  }

  /**
   *
   * @param bytesRead 已上传字节数
   * @param contentLength 上传文件的总长度
   * @param items 上传第几个文件
   */
  public void update(long bytesRead, long contentLength, int items) {
    status.setBytesRead(bytesRead);
    status.setContentLength(contentLength);
    status.setItems(items);
  }
}

4、监听上传进度

我们对上个实例的上传servlet做下改造,嵌入进度监听。

package com.wht.demo.servlet;

import com.wht.demo.listener.UploadListener;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

/**
 * @author JDIT
 */
public class UploadServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    //设置文件上传基本路径
    String savePath = this.getServletContext().getRealPath("/WEB-INF/uploadFiles");
    //设置临时文件路径
    String tempPath = this.getServletContext().getRealPath("/WEB-INF/tempFiles");
    File tempFile = new File(tempPath);
    if (!tempFile.exists()) {
      tempFile.mkdir();
    }

    //定义异常消息
    String errorMessage = "";
    //创建file items工厂
    DiskFileItemFactory factory = new DiskFileItemFactory();
    //设置缓冲区大小
    factory.setSizeThreshold(1024 * 100);
    //设置临时文件路径
    factory.setRepository(tempFile);
    //创建文件上传处理器
    ServletFileUpload upload = new ServletFileUpload(factory);
    //监听文件上传进度
    UploadStatus status = new UploadStatus();
    ProgressListener progressListener = new UploadListener(status);
    request.getSession().setAttribute("uploadStatus",status);
    upload.setProgressListener(progressListener);

    //解决上传文件名的中文乱码
    upload.setHeaderEncoding("UTF-8");
    //判断提交上来的数据是否是上传表单的数据
    if (!ServletFileUpload.isMultipartContent(request)) {
      //按照传统方式获取数据
      return;
    }

    //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
    upload.setFileSizeMax(100 * 1024 * 1024);
    //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
    upload.setSizeMax(1024 * 1024 * 1024);

    try {
      //使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
      List<FileItem> items = upload.parseRequest(request);
      Iterator<FileItem> iterator = items.iterator();
      while (iterator.hasNext()) {
        FileItem item = iterator.next();

        //判断jsp提交过来的是不是文件
        if (item.isFormField()) {
          errorMessage = "请提交文件!";
          break;
        } else {
          //文件名
          String fileName = item.getName();
          if (fileName == null || fileName.trim() == "") {
            System.out.println("文件名为空!");
          }
          //处理不同浏览器提交的文件名带路径问题
          fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
          //文件扩展名
          String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1);
          //判断扩展名是否合法
          if (!validExtension(fileExtension)) {
            errorMessage = "上传文件非法!";
            item.delete();
            break;
          }
          //获得文件输入流
          InputStream in = item.getInputStream();
          //得到保存文件的名称
          String saveFileName = createFileName(fileName);
          //得到文件保存路径
          String realFilePath = createRealFilePath(savePath, saveFileName);
          //创建文件输出流
          FileOutputStream out = new FileOutputStream(realFilePath);
          //创建缓冲区
          byte buffer[] = new byte[1024];
          int len = 0;
          while ((len = in.read(buffer)) > 0) {
            //写文件
            out.write(buffer, 0, len);
          }
          //关闭输入流
          in.close();
          //关闭输出流
          out.close();
          //删除临时文件 TODO
          item.delete();
          //将上传文件信息保存到附件表中 TODO
        }

      }

    } catch (FileUploadBase.FileSizeLimitExceededException e) {
      System.out.println("单个文件超出最大值!!!");
    } catch (FileUploadBase.SizeLimitExceededException e) {
      System.out.println("上传文件的总的大小超出限制的最大值!!!");
    } catch (FileUploadException e) {
      System.out.println("文件上传失败!!!");
    }

    request.setAttribute("errorMessage", "上传成功!!");

    request.getRequestDispatcher("pages/upload/upload.jsp").forward(request, response);


  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doGet(request, response);
  }

  private boolean validExtension(String fileExtension) {
    String[] exts = {"jpg", "txt", "doc", "pdf"};
    for (int i = 0; i < exts.length; i++) {
      if (fileExtension.equals(exts[i])) {
        return true;
      }

    }

    return false;
  }

  private String createFileName(String fileName) {
    return UUID.randomUUID().toString() + "_" + fileName;
  }

  /**
   * 根据基本路径和文件名称生成真实文件路径,基本路径\\年\\月\\fileName
   *
   * @param basePath
   * @param fileName
   * @return
   */
  private String createRealFilePath(String basePath, String fileName) {
    Calendar today = Calendar.getInstance();
    String year = String.valueOf(today.get(Calendar.YEAR));
    String month = String.valueOf(today.get(Calendar.MONTH) + 1);


    String upPath = basePath + File.separator + year + File.separator + month + File.separator;
    File uploadFolder = new File(upPath);
    if (!uploadFolder.exists()) {
      uploadFolder.mkdirs();
    }

    String realFilePath = upPath + fileName;

    return realFilePath;
  }
}

读取上传进度

后台已经把状态保存在了session中,上传文件使用的是post方法,我们可以使用Ajax调用doGet获取上传进度。

package com.wht.demo.servlet;

import com.wht.demo.listener.UploadListener;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

/**
 * @author JDIT
 */
public class UploadServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //禁止浏览器缓存
    response.setHeader("Cache-Control", "no-store");
    response.setHeader("Pragrma", "no-cache");
    response.setDateHeader("Expires", 0);

    UploadStatus status = (UploadStatus) request.getSession(true).getAttribute("uploadStatus");

    if (status == null) {
      response.getWriter().println("没有上传信息");
    }

    long startTime = status.getStartTime();
    long currentTime = System.currentTimeMillis();
    long time = (currentTime - startTime) / 1000 + 1;
    double velocity = ((double) status.getBytesRead()) / ((double) time);
    double totalTime = status.getContentLength() / velocity;
    double timeLeft = totalTime - time;
    int percent = (int) (status.getBytesRead() / status.getContentLength());
    double length = status.getBytesRead() / 1024 / 1024;
    double totalLength = status.getContentLength() / 1024 / 1024;

    String value = percent + "||" + length + "||" + totalLength + "||" + velocity + "||" + time + "||" + totalTime + "||" + timeLeft + "||" + status.getItems();
    response.getWriter().println(value);
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //设置文件上传基本路径
    String savePath = this.getServletContext().getRealPath("/WEB-INF/uploadFiles");
    //设置临时文件路径
    String tempPath = this.getServletContext().getRealPath("/WEB-INF/tempFiles");
    File tempFile = new File(tempPath);
    if (!tempFile.exists()) {
      tempFile.mkdir();
    }

    //定义异常消息
    String errorMessage = "";
    //创建file items工厂
    DiskFileItemFactory factory = new DiskFileItemFactory();
    //设置缓冲区大小
    factory.setSizeThreshold(1024 * 100);
    //设置临时文件路径
    factory.setRepository(tempFile);
    //创建文件上传处理器
    ServletFileUpload upload = new ServletFileUpload(factory);
    //监听文件上传进度
    UploadStatus status = new UploadStatus();
    ProgressListener progressListener = new UploadListener(status);
    request.getSession().setAttribute("uploadStatus", status);
    upload.setProgressListener(progressListener);

    //解决上传文件名的中文乱码
    upload.setHeaderEncoding("UTF-8");
    //判断提交上来的数据是否是上传表单的数据
    if (!ServletFileUpload.isMultipartContent(request)) {
      //按照传统方式获取数据
      return;
    }

    //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
    upload.setFileSizeMax(100 * 1024 * 1024);
    //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
    upload.setSizeMax(1024 * 1024 * 1024);

    try {
      //使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
      List<FileItem> items = upload.parseRequest(request);
      Iterator<FileItem> iterator = items.iterator();
      while (iterator.hasNext()) {
        FileItem item = iterator.next();

        //判断jsp提交过来的是不是文件
        if (item.isFormField()) {
          errorMessage = "请提交文件!";
          break;
        } else {
          //文件名
          String fileName = item.getName();
          if (fileName == null || fileName.trim() == "") {
            System.out.println("文件名为空!");
          }
          //处理不同浏览器提交的文件名带路径问题
          fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
          //文件扩展名
          String fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1);
          //判断扩展名是否合法
          if (!validExtension(fileExtension)) {
            errorMessage = "上传文件非法!";
            item.delete();
            break;
          }
          //获得文件输入流
          InputStream in = item.getInputStream();
          //得到保存文件的名称
          String saveFileName = createFileName(fileName);
          //得到文件保存路径
          String realFilePath = createRealFilePath(savePath, saveFileName);
          //创建文件输出流
          FileOutputStream out = new FileOutputStream(realFilePath);
          //创建缓冲区
          byte buffer[] = new byte[1024];
          int len = 0;
          while ((len = in.read(buffer)) > 0) {
            //写文件
            out.write(buffer, 0, len);
          }
          //关闭输入流
          in.close();
          //关闭输出流
          out.close();
          //删除临时文件 TODO
          item.delete();
          //将上传文件信息保存到附件表中 TODO
        }

      }

    } catch (FileUploadBase.FileSizeLimitExceededException e) {
      System.out.println("单个文件超出最大值!!!");
    } catch (FileUploadBase.SizeLimitExceededException e) {
      System.out.println("上传文件的总的大小超出限制的最大值!!!");
    } catch (FileUploadException e) {
      System.out.println("文件上传失败!!!");
    }

    request.setAttribute("errorMessage", "上传成功!!");

    request.getRequestDispatcher("pages/upload/upload.jsp").forward(request, response);
  }

  private boolean validExtension(String fileExtension) {
    String[] exts = {"jpg", "txt", "doc", "pdf"};
    for (int i = 0; i < exts.length; i++) {
      if (fileExtension.equals(exts[i])) {
        return true;
      }

    }

    return false;
  }

  private String createFileName(String fileName) {
    return UUID.randomUUID().toString() + "_" + fileName;
  }

  /**
   * 根据基本路径和文件名称生成真实文件路径,基本路径\\年\\月\\fileName
   *
   * @param basePath
   * @param fileName
   * @return
   */
  private String createRealFilePath(String basePath, String fileName) {
    Calendar today = Calendar.getInstance();
    String year = String.valueOf(today.get(Calendar.YEAR));
    String month = String.valueOf(today.get(Calendar.MONTH) + 1);


    String upPath = basePath + File.separator + year + File.separator + month + File.separator;
    File uploadFolder = new File(upPath);
    if (!uploadFolder.exists()) {
      uploadFolder.mkdirs();
    }

    String realFilePath = upPath + fileName;

    return realFilePath;
  }
}

显示上传进度

全局刷新触发页面跳转,文件上传没完会阻塞在后天,导致前端白屏,所以要对页面进行改造。

回到首页☞

发布了164 篇原创文章 · 获赞 11 · 访问量 8298

猜你喜欢

转载自blog.csdn.net/weixin_38280568/article/details/104150934