首页 > 开发 > Java > 正文

SpringBoot+fileUpload获取文件上传进度

2024-07-14 08:42:10
字体:
来源:转载
供稿:网友

我本人在网上找了很多关于文件上传进度获取的文章,普遍基于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;@Componentpublic 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;@Componentpublic 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 来获取最新的上传进度并返回展示即可。

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


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表