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

SpringBoot+fileUpload获取文件上传进度

程序员文章站 2024-02-26 08:04:46
我本人在网上找了很多关于文件上传进度获取的文章,普遍基于spring mvc 框架通过 fileupload 实现,对于spring boot 通过 fileupload...

我本人在网上找了很多关于文件上传进度获取的文章,普遍基于spring mvc 框架通过 fileupload 实现,对于spring boot 通过 fileupload 实现的帖子非常少,由于小弟学艺不精,虽然 spring boot 和 spring mvc 相差不大,只是配置方式的差别,还是搞了很久,上传此文章的目的是希望自己作为文本保留,以便日后查看备忘,并且希望通过我的例子可以帮助到其他人而已,如果各位大佬发现小弟对于某些知识有误解,还请不吝赐教,先谢谢各位前辈了!

写此篇文章之前我查了很多关于spring mvc 框架通过 fileupload 实现进度条的帖子和文章,在此对各位作者表示感谢!

本功能基于commons fileupload 组件实现

1.首先,不能在程序中直接使用 fileupload.parserequest(request)的方式来获取 request 请求中的 multipartfile 文件对象,原因是因为在 spring 默认的文件上传处理器 multipartresolver 指向的类commonsmultipartresolver 中就是通过 commons fileupload 组件实现的文件获取,因此,在代码中再次使用该方法,是获取不到文件对象的,因为此时的 request 对象是不包含文件的,它已经被commonsmultipartresolver 类解析处理并转型。

commonsmultipartresolver 类中相关源码片段:

protected multipartparsingresult parserequest(httpservletrequest request) throws multipartexception {
    string encoding = determineencoding(request);
    fileupload fileupload = preparefileupload(encoding);
    try {
      list<fileitem> fileitems = ((servletfileupload) fileupload).parserequest(request);
      return parsefileitems(fileitems, encoding);
    }
    catch (fileuploadbase.sizelimitexceededexception ex) {
      throw new maxuploadsizeexceededexception(fileupload.getsizemax(), ex);
    }
    catch (fileuploadbase.filesizelimitexceededexception ex) {
      throw new maxuploadsizeexceededexception(fileupload.getfilesizemax(), ex);
    }
    catch (fileuploadexception ex) {
      throw new multipartexception("failed to parse multipart servlet request", ex);
    }
}

2.由于spring 中的 commonsmultipartresolver 类中并没有加入 processlistener 文件上传进度监听器,所以,直接使用 commonsmultipartresolver 类是无法监听文件上传进度的,如果我们需要获取文件上传进度,就需要继承 commonsmultipartresolver 类并重写 parserequest 方法,在此之前,我们需要创建一个实现了 processlistener 接口的实现类用于监听文件上传进度。

processlistener接口实现类:

import javax.servlet.http.httpsession;
import org.apache.commons.fileupload.progresslistener;
import org.springframework.stereotype.component;

@component
public class uploadprogresslistener implements progresslistener{

  private httpsession session; 

  public void setsession(httpsession session){ 
    this.session=session; 
    progressentity status = new progressentity(); 
    session.setattribute("status", status); 
  } 

  /* 
   * pbytesread 到目前为止读取文件的比特数 pcontentlength 文件总大小 pitems 目前正在读取第几个文件 
   */ 
  @override
  public void update(long pbytesread, long pcontentlength, int pitems) { 
    progressentity status = (progressentity) session.getattribute("status"); 
    status.setpbytesread(pbytesread); 
    status.setpcontentlength(pcontentlength); 
    status.setpitems(pitems); 
  } 
}

progressentity 实体类:

import org.springframework.stereotype.component;

@component
public class progressentity { 
  private long pbytesread = 0l;  //到目前为止读取文件的比特数  
  private long pcontentlength = 0l;  //文件总大小  
  private int pitems;        //目前正在读取第几个文件 

  public long getpbytesread() { 
    return pbytesread; 
  } 
  public void setpbytesread(long pbytesread) { 
    this.pbytesread = pbytesread; 
  } 
  public long getpcontentlength() { 
    return pcontentlength; 
  } 
  public void setpcontentlength(long pcontentlength) { 
    this.pcontentlength = pcontentlength; 
  } 
  public int getpitems() { 
    return pitems; 
  } 
  public void setpitems(int pitems) { 
    this.pitems = pitems; 
  } 
  @override 
  public string tostring() { 
    float tmp = (float)pbytesread; 
    float result = tmp/pcontentlength*100; 
    return "progressentity [pbytesread=" + pbytesread + ", pcontentlength=" 
        + pcontentlength + ", percentage=" + result + "% , pitems=" + pitems + "]"; 
  } 
} 

最后,是继承 commonsmultipartresolver 类的自定义文件上传处理类:

import java.util.list; 
import javax.servlet.http.httpservletrequest; 
import org.apache.commons.fileupload.fileitem; 
import org.apache.commons.fileupload.fileupload; 
import org.apache.commons.fileupload.fileuploadbase; 
import org.apache.commons.fileupload.fileuploadexception; 
import org.apache.commons.fileupload.servlet.servletfileupload; 
import org.springframework.beans.factory.annotation.autowired; 
import org.springframework.web.multipart.maxuploadsizeexceededexception; 
import org.springframework.web.multipart.multipartexception; 
import org.springframework.web.multipart.commons.commonsmultipartresolver; 

public class custommultipartresolver extends commonsmultipartresolver{

  @autowired
  private uploadprogresslistener uploadprogresslistener;

  @override
  protected multipartparsingresult parserequest(httpservletrequest request) throws multipartexception {
    string encoding = determineencoding(request);
    fileupload fileupload = preparefileupload(encoding);
    uploadprogresslistener.setsession(request.getsession());//问文件上传进度监听器设置session用于存储上传进度
    fileupload.setprogresslistener(uploadprogresslistener);//将文件上传进度监听器加入到 fileupload 中
    try {
      list<fileitem> fileitems = ((servletfileupload) fileupload).parserequest(request);
      return parsefileitems(fileitems, encoding);
    }
    catch (fileuploadbase.sizelimitexceededexception ex) {
      throw new maxuploadsizeexceededexception(fileupload.getsizemax(), ex);
    }
    catch (fileuploadbase.filesizelimitexceededexception ex) {
      throw new maxuploadsizeexceededexception(fileupload.getfilesizemax(), ex);
    }
    catch (fileuploadexception ex) {
      throw new multipartexception("failed to parse multipart servlet request", ex);
    }
  }

}

3.此时,所有需要的类已经准备好,接下来我们需要将 spring 默认的文件上传处理类取消自动配置,并将 multipartresolver 指向我们刚刚创建好的继承 commonsmultipartresolver 类的自定义文件上传处理类。

import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.enableautoconfiguration;
import org.springframework.boot.autoconfigure.web.multipartautoconfiguration;
import org.springframework.boot.web.servlet.servletcomponentscan;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
import org.springframework.web.multipart.multipartresolver;

import com.example.listener.custommultipartresolver;

/*
 * 将 spring 默认的文件上传处理类取消自动配置,这一步很重要,没有这一步,当multipartresolver重新指向了我们定义好
 * 的新的文件上传处理类后,前台传回的 file 文件在后台获取会是空,加上这句话就好了,推测不加这句话,spring 依然
 * 会先走默认的文件处理流程并修改request对象,再执行我们定义的文件处理类。(这只是个人推测)
 * exclude表示自动配置时不包括multipart配置
 */
@enableautoconfiguration(exclude = {multipartautoconfiguration.class})

@configuration
@componentscan(basepackages = {"com.example"})
@servletcomponentscan(basepackages = {"com.example"})
public class uploadprogressapplication {

/*
 * 将 multipartresolver 指向我们刚刚创建好的继承 commonsmultipartresolver 类的自定义文件上传处理类
 */
@bean(name = "multipartresolver")
public multipartresolver multipartresolver() {
  custommultipartresolver custommultipartresolver = new custommultipartresolver();
  return custommultipartresolver;
}

public static void main(string[] args) {
  springapplication.run(uploadprogressapplication.class, args);
}
}

至此,准备工作完成,我们再创建一个测试用的 controller 和 html 页面用于文件上传。

controller:

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.servlet.modelandview;

@controller
@requestmapping("/uploadprogress")
public class uploadcontroller {

  @requestmapping(value = "/showupload", method = requestmethod.get)
  public modelandview showupload() {
    return new modelandview("/uploadprogressdemo");
  }

  @requestmapping("/upload")
  @responsebody
  public void uploadfile(multipartfile file) {
    system.out.println(file.getoriginalfilename());
  }

}

html:

<!doctype html>
<html>
<head>
  <meta charset="utf-8"></meta>
  <title>测试</title>这里写代码片
</head>
<body>
  这是文件上传页面
  <form action="/uploadprogress/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/>
    <br/>
    <input type="submit" value="提交"/>
  </form>
</body>
</html>

经本人测试,确实可以获取文件上传进度,前台页面修改进度条进度可以采用前台页面轮询的方式访问后台,在相应action中通过存储在session中的对象 status 来获取最新的上传进度并返回展示即可。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。