`
lbyzx123
  • 浏览: 477910 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

SpringMVC 大文件上传踩过的坑

    博客分类:
  • java
阅读更多
   使用spring mvc的MultipartFile对象上传文件时,发现上传1G的文件需要差不多1分钟左右才能进入到对应的Controller,而最可气的是我们上传文件时Header信息里面的Token认证信息,也是1分钟后才收到,导致我们Token认证信息经常验证超时(Token的有效期为30秒)。我们的Token验证时在拦截器里面进行的,先验证Token然后再处理上传逻辑。查看日志,发现上传时进入拦截器的时间与进入Controller的时间相差5毫秒,近乎同时。然而,我们项目上希望先验证Token,然后再上传文件,如果Token验证不通过,则直接返回验证失败,不要等文件上传完然后再提示验证失败。因为没有深入看spring mvc的源码,一时间找不到解决办法,请教了一个高手说改成Servlet上传就可以。于是照做:

Java源码:

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.FileCleanerCleanup;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileCleaningTracker;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * @author Administrator
 */
public class UploadServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private static final int BUFFER_SIZE = 1024*1024;

    private static final int MAX_SIZE_PER_REQUEST = 1024*1024*1056;

    private static final int MAX_SIZE_PER_FILE = 1024*1024*1024;

    public UploadServlet() {
        super();
    }
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        doPost(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)  {
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        if (isMultipart) {
            ServletContext servletContext = this.getServletConfig().getServletContext();
            FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(servletContext);
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //清理临时文件
            factory.setFileCleaningTracker(fileCleaningTracker);
            File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
            //设置缓存大小
            factory.setSizeThreshold(BUFFER_SIZE);
            factory.setRepository(repository);
            ServletFileUpload upload = new ServletFileUpload(factory);
            //将页面请求传递信息最大值设置为1056M
            upload.setSizeMax(MAX_SIZE_PER_REQUEST);
            //将单个上传文件信息最大值设置为1024M
            upload.setFileSizeMax(MAX_SIZE_PER_FILE);
            try {
                List<FileItem> items = upload.parseRequest(request);
                for (int i = items.size()-1; i >= 0 ; i--) {
                    FileItem item = items.get(i);
                    if (item.isFormField()) {
                        String fieldName = item.getFieldName();
                        String fieldValue = item.getString("utf-8");
                        System.out.println("FileItem " + i + ":[fieldName:"+fieldName+",fieldValue:"+fieldValue+"]");
                    }else{
                        String saveDir = request.getSession().getServletContext().getRealPath("/upload");
                        File file = new File(saveDir, item.getName());
                        item.write(file);
                    }
                }
            } catch (FileUploadException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

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>
<h1>文件上传</h1>


<form method="POST" enctype="multipart/form-data" action="upload" name="uploadForm">
    选择一个文件: <input type="file" name="upfile"><br/>
    <br/>
    <input type="submit" value="上传">
</form>


</body>
</html>

web.xml

 <servlet>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>com.mingcloud.ams.controller.UploadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/upload</url-pattern>
  </servlet-mapping>

   进行断点调试,发现局域网上传1G文件时,立即进入Servlet的doPost里面,可以立即获取到Token,然后进行验证,但是 执行upload.parseRequest(request)时73.182秒,执行到  item.write(file);时耗时1.277秒,整个上传过程耗时1.2分钟,计算了一下发现是10M/s的处理速度,局域网基本上就这样了。查看了parseRequest方法,发现是进行流的拷贝操作,原有这里这么耗时。在没有问高人前,一直怀疑是tomcat组包成request导致的时间长,现在一想tomcat太牛逼了,一个G的对象很快转换,估计是1秒内甚至是毫秒级完成。问题是解决了,还是想想为什么spring mvc那么久才进入controller吧。

   查了些资料,说spring mvc 在进入controller 前先用SpringMVC解析器解析request请求参数并绑定数据到Controller的入参上,原来是将请求parseRequest后才形成MultipartFile;还有为什么spring mvc的拦截器进去时间和进入controller的时间相差无几,大胆猜想spring mvc的拦截器肯定是在SpringMVC解析器解析request请求参数并绑定数据到Controller的入参之后和进入controller之前拦截的,看来遇到问题还是要多看源码啊,多了解http协议的本质很重要。
    
性能测试:
文件大小<=255KB     80张/秒
文件大小<=1.44MB    50张/秒
文件大小<=826MB     [20,30]并发请求都在处理,基本半小时都能够上传成功

 

<dependency>
	<groupId>com.github.mwiede</groupId>
	<artifactId>jsch</artifactId>
	<version>0.2.8</version>
</dependency>

TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="enp65s0f0"
UUID="94b2fde3-e7e1-42fc-b0a1-344efb8f1462"
DEVICE="enp65s0f0"
ONBOOT=yes
IPADDR=192.168.1.168
NETMASK=255.255.255.0
GATEWAY=192.168.1.254
ZONE=public
IPV6ADDR=2400:777:666:0:a:27ff:fed0:168
IPV6_DEFAULTGW=2400::1

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 


 

分享到:
评论

相关推荐

    SpringMVC文件上传,多文件上传实例

    在处理文件上传时,可能会遇到各种异常,如文件过大、文件类型不合法等。因此,我们需要捕获并处理这些异常,例如`MaxUploadSizeExceededException`、`InvalidMimeTypeException`等。 8. **安全考虑**: 在实现...

    IDEA SpringMVC 实现文件的上传下载

    在SpringMVC框架中,实现文件的上传与下载是常见的需求。IntelliJ IDEA作为流行的Java开发集成环境,为开发者提供了高效便捷的开发体验。在这个项目中,我们使用IDEA来构建一个基于SpringMVC的系统,实现了文件的...

    基于springmvc实现文件上传下载 基于AOP的日志功能

    基于springmvc实现文件上传下载 基于AOP的日志功能基于springmvc实现文件上传下载 基于AOP的日志功能基于springmvc实现文件上传下载 基于AOP的日志功能基于springmvc实现文件上传下载 基于AOP的日志功能基于...

    springMvc单文件多文件上传

    springMvc 文件上传,springMvc 支持单文件和多文件上传,

    SpringMVC单文件上传、多文件上传、文件列表显示、文件下载

    本文将详细讲解如何实现SpringMVC中的单文件上传、多文件上传、文件列表显示以及文件下载。 首先,我们需要理解SpringMVC处理文件上传的基本原理。在SpringMVC中,文件上传通常涉及到`CommonsMultipartResolver`...

    基于springMVC的文件上传功能

    为了提高用户体验,应处理可能出现的异常,如文件过大、文件类型不匹配等,将错误信息返回给用户。 7. **安全考虑** 在实际应用中,要注意文件上传的安全性,防止恶意文件上传,比如通过限制文件类型、大小,以及...

    springMVC 上传文件方式

    springMVC 上传文件方式springMVC 上传文件方式springMVC 上传文件方式

    尚硅谷SpringMVC上传文件

    在使用springMVC进行系统实现时,springMVC默认的解析器里面是没有加入对文件上传的解析的,这可以方便我们实现自己的文件上传。但如果你想使用springMVC对文件上传的解析器来处理文件上传的时候就需要在spring的...

    SpringMVC上传文件 SSH上传文件

    3. **流式传输**:为了提高性能,应该使用流式传输技术来处理大文件,避免一次性加载整个文件到内存中。 4. **错误处理**:提供良好的错误处理机制,当文件不存在或下载过程中发生问题时,能够给用户清晰的反馈。 ...

    JavaEE企业级开发-----SpringMVC实现 文件的上传下载实验报告.docx

    在JavaEE企业级开发中,SpringMVC框架是广泛用于构建Web应用程序的工具,它提供了丰富的功能,包括...在实际应用中,还需要考虑安全性、性能优化等方面的问题,例如限制文件大小、检查文件类型、使用异步处理大文件等。

    SpringMVC+Ajax异步文件上传

    `SpringMVC`作为Java后端的一个强大框架,提供了处理文件上传的能力。而`Ajax`技术则使得页面可以在不刷新的情况下与服务器进行交互,实现异步上传,极大地提升了用户体验。在本教程中,我们将探讨如何结合`...

    springmvc带进度条上传源码

    - 使用异步上传以改善用户体验,特别是在上传大文件时。 - 实现错误处理和重试机制,提高上传的成功率。 通过上述步骤,我们可以创建一个完整的Spring MVC文件上传系统,同时具备进度条展示。在提供的"springmvc...

    SpringMVC文件上传Demo代码

    在SpringMVC中实现文件上传是一项常见的任务,它允许用户通过表单将本地文件发送到服务器进行存储或处理。这个"SpringMVC文件上传Demo代码"是一个实例,演示了如何配置和使用SpringMVC来实现这一功能。 首先,我们...

    springMVC文件上传demo(亲测有效)

    其中,`maxUploadSize`属性用来限制上传文件的大小,防止过大文件导致服务器资源耗尽。 3. **前端表单** 在HTML页面中,创建一个`&lt;form&gt;`元素,并设置`enctype="multipart/form-data"`,表示这是一个支持文件上传...

    springMVC上传文件.zip_springmvc_上传文件_文件上传

    使用异步处理大文件,提高性能;考虑使用第三方库如Apache Commons FileUpload或Spring Boot的`FileSystemResource`来简化文件操作。 通过以上步骤,我们可以构建一个完整的SpringMVC文件上传系统。在实际项目中,...

    Springmvc上传文件.docx

    SpringMVC 上传文件详解 SpringMVC 框架中上传文件是非常常见的操作,今天我们来详细讲解 SpringMVC 中的文件上传过程。 文件上传的必要条件 在 SpringMVC 中,文件上传需要满足以下几个条件: 1. 表单的 ...

    springMVC文件上传所需jar包

    在处理文件上传功能时,SpringMVC需要依赖一些特定的库,这些库通常是以jar(Java Archive)文件的形式存在的。在这个压缩包中包含的两个关键jar文件——`com.springsource.org.apache.commons.io-1.4.0.jar`和`...

    springmvc实现文件上传jar包

    在Spring MVC框架中,文件上传是一项常见的功能,用于允许用户通过Web应用程序上传文件。要实现这一功能,我们需要依赖一些特定的库和配置。本篇文章将详细介绍如何在Spring MVC中实现文件上传,并涉及到所需的jar包...

    webuploader+springMVC实现大文件上传.zip

    在本项目中,我们主要探讨的是如何利用WebUploader插件结合SpringMVC框架来实现大文件及多文件的上传功能。这是一个常见的需求,特别是在需要用户提交大量数据或媒体内容的Web应用中。以下是对相关知识点的详细说明...

Global site tag (gtag.js) - Google Analytics