Изменение ограничения размера файла (maxUploadSize) в зависимости от контроллера

У меня есть веб-сайт Spring MVC с двумя разными страницами, которые имеют разные формы для загрузки разных файлов. У одного из них должно быть ограничение на 2 МБ, а у другого должно быть ограничение на 50 МБ.

Прямо сейчас, у меня есть это ограничение в моем 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;
}

Но это, очевидно, контролирует только ограничение 2 МБ. Как я могу сделать ограничение для 20 МБ одного? Я пробовал это решение: qaru.site/info/687536/..., который обновляет ограничение во время выполнения. Однако это обновляет его для каждой сессии и каждого контроллера. Итак, если один пользователь загружает файл для первой формы, другой, использующий загрузку во второй форме, должен иметь ограничение первого...

Любая помощь? спасибо

Ответ 1

Это может показаться не лучшим решением с первого взгляда, но оно зависит от ваших требований.

Вы можете установить глобальную опцию с максимальным размером загрузки для всех контроллеров и переопределить ее с меньшим значением для определенных контроллеров.

файл application.properties(Spring Загрузка)

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);
}

В случае файла размером более 2 МБ вы получите это исключение в журнале:

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

Ответ 2

Вот как это возможно: переопределите класс 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);
    }
}

Предполагая, что вы сконфигурировали несколько MultipartResolvers в вашем приложении-контексте (предположительно называемый "resolver1" и "resolver2" в примере кода).

Конечно, когда вы настраиваете DispatcherServlet в своем web.xml, вы используете этот класс вместо Spring DispatcherServlet.

Другой способ: MultipartFilter также можно использовать. Просто переопределите метод lookupMultipartResolver (запрос HttpServletRequest) и самостоятельно найдите необходимый распознаватель. Однако, есть некоторые ifs и buts к этому. Прежде чем использовать это, просмотрите документацию.

Ответ 4

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);
        }
    }
}                                                                                                                                                                                                                                                                                                                                                                                                                               

Ответ 5

Как основной автор и сопровождающий Commons Fileupload, я бы предложил следующее в отношении вашего варианта использования:

  • Есть два экземпляра FileUploadBase, один с максимальным размером 2 МБ, а другой с 20 МБ. В зависимости от деталей запроса (например, просматривая URI), используйте один или другой экземпляр.
  • Если вы не используете FileUpload напрямую (но Spring, Struts или что-то еще впереди), то, скорее всего, изменения в Fileupload вам не хватит, потому что Frontend не будет поддерживать возможную новую функцию, по крайней мере не изначально. В этом случае я предлагаю вам подтолкнуть разработчиков веб-интерфейса поддержать ваши требования. Они могут легко сделать это, создавая экземпляр FileUploadBase для каждого запроса. (Это легкий объект, если вы не используете файловые трекеры или подобные расширенные функции, так что никаких проблем с этим нет.)
  • Я готов рассмотреть и, возможно, принять патчи, сделанные вами или другими лицами, которые заменяют текущую проверку maxUploadSize предикатом или чем-то подобным.

Jochen