热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

SpringBoot+fileUpload获取文件上传进度

这篇文章主要为大家详细介绍了SpringBoot+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 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 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:




  
  这里写代码片


  这是文件上传页面
  
    
    

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

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


推荐阅读
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • Final关键字的含义及用法详解
    本文详细介绍了Java中final关键字的含义和用法。final关键字可以修饰非抽象类、非抽象类成员方法和变量。final类不能被继承,final类中的方法默认是final的。final方法不能被子类的方法覆盖,但可以被继承。final成员变量表示常量,只能被赋值一次,赋值后值不再改变。文章还讨论了final类和final方法的应用场景,以及使用final方法的两个原因:锁定方法防止修改和提高执行效率。 ... [详细]
  • 本文介绍了求解gcdexgcd斐蜀定理的迭代法和递归法,并解释了exgcd的概念和应用。exgcd是指对于不完全为0的非负整数a和b,gcd(a,b)表示a和b的最大公约数,必然存在整数对x和y,使得gcd(a,b)=ax+by。此外,本文还给出了相应的代码示例。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 电销机器人作为一种人工智能技术载体,可以帮助企业提升电销效率并节省人工成本。然而,电销机器人市场缺乏统一的市场准入标准,产品品质良莠不齐。创业者在代理或购买电销机器人时应注意谨防用录音冒充真人语音通话以及宣传技术与实际效果不符的情况。选择电销机器人时需要考察公司资质和产品品质,尤其要关注语音识别率。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
author-avatar
手机用户2502937805
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有