【问题标题】:Changing file size limit (maxUploadSize) depending on the controller根据控制器更改文件大小限制 (maxUploadSize)
【发布时间】:2013-05-11 06:05:24
【问题描述】:

我有一个 Spring MVC 网络,它有两个不同的页面,它们有不同的表单来上传不同的文件。其中一个应该有 2MB 的限制,而另一个应该有 50MB 的限制。

现在,我的 app-config.xml 中有这个限制:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- one of the properties available; the maximum file size in bytes (2097152 B = 2 MB) -->
    <property name="maxUploadSize" value="2097152 "/>
</bean>

我可以像这样在我的主控制器中解决 maxUploadSize 异常:

@Override
public @ResponseBody
ModelAndView resolveException(HttpServletRequest arg0,
        HttpServletResponse arg1, Object arg2, Exception exception) {
    ModelAndView modelview = new ModelAndView();
        String errorMessage = "";
        if (exception instanceof MaxUploadSizeExceededException) {
            errorMessage =  String.format("El tamaño del fichero debe ser menor de  %s", UnitConverter.convertBytesToStringRepresentation(((MaxUploadSizeExceededException) exception)
                    .getMaxUploadSize()));

        } else {
            errorMessage = "Unexpected error: " + exception.getMessage();
        }
        saveError(arg0, errorMessage);
        modelview = new ModelAndView();
        modelview.setViewName("redirect:" + getRedirectUrl());
    }
    return modelview;
}

但这显然只控制了 2MB 的限制。我怎么能限制 20MB 的呢? 我试过这个解决方案:https://stackoverflow.com/a/11792952/1863783,它更新了运行时的限制。但是,这会为每个会话和每个控制器更新它。因此,如果一个用户正在为第一个表单上传文件,那么另一个在第二个表单中使用上传的用户应该有第一个的限制......

有什么帮助吗?谢谢

【问题讨论】:

标签: java spring-mvc upload


【解决方案1】:

作为 Commons Fileupload 的主要作者和维护者,关于您的用例,我提出以下建议:

  • 有两个 FileUploadBase 实例,一个最大为 2MB,另一个为 20MB。根据请求详细信息(例如,通过查看 URI),使用一个或另一个实例。
  • 如果您不直接使用 FileUpload(而是使用 Spring、Struts 或前面的任何东西),那么很可能对 Fileupload 进行更改是不够的,因为前端不支持可能的新功能,至少最初不是。在这种情况下,我建议您开始推动前端开发人员支持您的需求。他们可以通过为每个请求创建一个 FileUploadBase 实例来轻松做到这一点。 (它是一个轻量级对象,只要您不使用文件跟踪器或类似的高级功能,就没有问题。)
  • 我已准备好审查并可能接受您或其他人的补丁,这些补丁将当前对 maxUploadSize 的检查替换为 Predicate 或类似的东西。

乔辰

【讨论】:

    【解决方案2】:

    乍一看,这似乎不是最佳解决方案,但这取决于您的要求。

    您可以为所有控制器设置一个具有最大上传大小的全局选项,并为特定控制器使用较小的值覆盖它。

    application.properties 文件(Spring Boot)

    spring.http.multipart.max-file-size=50MB
    

    使用检查上传控制器

    public void uploadFile(@RequestPart("file") MultipartFile file) {
        final long limit = 2 * 1024 * 1024;    // 2 MB
        if (file.getSize() > limit) {
            throw new MaxUploadSizeExceededException(limit);
        }
        StorageService.uploadFile(file);
    }
    

    如果文件大于 2MB,您将在日志中看到此异常:

    org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size of 2097152 bytes exceeded
    

    【讨论】:

    • 这会让整个文件在处理之前上传吗?看起来它会浪费带宽并使您遭受 ddos​​ 攻击?
    • @user1560335 我理解您的担忧,但我没有在此答案中检查我的代码以了解 DDoS 可持续性。欢迎您自行研究或在 StackOverflow 上ask a new question。
    【解决方案3】:
    public class BaseDispatcherServlet extends DispatcherServlet {
        @Override
        protected void doService(final HttpServletRequest request, final HttpServletResponse response) {
            CommonsMultipartResolver multipartResolver = (CommonsMultipartResolver) getMultipartResolver();
            if (requestURI.contains("uriWithLargeFileSize")) {
                multipartResolver.setMaxUploadSize(100 * 100L);
            }
        }
    }                                                                                                                                                                                                                                                                                                                                                                                                                               
    

    【讨论】:

      【解决方案4】:

      这里有一个优雅的解决方案Spring Boot: ClassNotFoundException when configuring maxUploadSize of CommonMultipartResolver

      您可以修改您的应用程序 application.properties 文件以根据需要更改最大上传大小

      【讨论】:

        【解决方案5】:

        这是可能的:覆盖DispatcherServlet 类。一个示例可能如下所示:

        public class CustomDispatcherServlet extends DispatcherServlet {
        
            private Map<String, MultipartResolver> multipartResolvers;
        
            @Override
            protected void initStrategies(ApplicationContext context) {
                    super.initStrategies(context);
                    initMultipartResolvers(context);
            }
        
            private void initMultipartResolvers(ApplicationContext context) {
                    try {
                            multipartResolvers = new HashMap<>(context.getBeansOfType(MultipartResolver.class));
                    } catch (NoSuchBeanDefinitionException ex) {
                            // Default is no multipart resolver.
                            this.multipartResolvers = Collections.emptyMap();
                    }
            }
        
            @Override
            protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
                    if (this.multipartResolvers.isEmpty() && this.multipartResolvers.get(0).isMultipart(request)) {
                            if (request instanceof MultipartHttpServletRequest) {
                                    logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, "
                                            + "this typically results from an additional MultipartFilter in web.xml");
                            } else {
                                    MultipartResolver resolver = getMultipartResolverBasedOnRequest(request);
                                    return resolver.resolveMultipart(request);
                            }
                    }
                    // If not returned before: return original request.
                    return request;
            }
        
            private MultipartResolver getMultipartResolverBasedOnRequest(HttpServletRequest request) {
                    // your logic to check the request-url and choose a multipart resolver accordingly.
                    String resolverName = null;
                    if (request.getRequestURI().contains("SomePath")) {
                            resolverName = "resolver1";
                    } else {
                            resolverName = "resolver2";
                    }
                    return multipartResolvers.get(resolverName);
            }
        }
        

        假设您在应用程序上下文中配置了多个 MultipartResolver(在示例代码中可能命名为“resolver1”和“resolver2”)。

        当然,当您在web.xml 中配置DispatcherServlet 时,您使用此类而不是Spring DispatcherServlet。

        另一种方式:也可以使用MultipartFilter。只需覆盖lookupMultipartResolver(HttpServletRequest request) 方法并自己查找所需的解析器。但是,有一些如果和但是。在使用它之前查看文档。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-05-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-06
          • 2016-03-16
          相关资源
          最近更新 更多