Goyo
Goyo

Reputation: 455

Changing file size limit (maxUploadSize) depending on the controller

I have a Spring MVC web with two different pages that have different forms to upload different files. One of them should have a limitation of 2MB, while the other should have a 50MB limitation.

Right now, I have this limitation in my 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>

And I could resolve the maxUploadSize exception in my main controller like that:

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

But this, obviously, only controlls the 2MB limit. How could I make the limitation for the 20MB one? I've tried this solution: https://stackoverflow.com/a/11792952/1863783, which updates the limitation in runtime. However, this updates it for every session and every controller. So, if one user is uploading a file for the first form, another using uploading in the second form should have the limitation of the first one...

Any help? thanks

Upvotes: 15

Views: 40044

Answers (5)

JochenW
JochenW

Reputation: 1053

As the main author, and maintainer of Commons Fileupload, I'd propose the following, with regard to your usecase:

  • Have two instances of FileUploadBase, one with a max size of 2MB, and another with 20MB. Depending on the request details (for example, by looking on the URI), use one, or the other instance.
  • If you aren't using FileUpload directly (but Spring, Struts, or whatever in front), then, most likely, a change in Fileupload wouldn't suffice for you, because the Frontend won't support a possible new feature, at least not initially. In that case, I suggest that you start pushing the frontend developers to support your requirement. They can easily do that by creating an instance of FileUploadBase per request. (It's a lightweight object, as long as you're not using file trackers, or similar advanced features, so no problem with that.)
  • I am ready to review, and possibly accept patches by you, or others, that replace the current check for maxUploadSize with a Predicate, or something similar.

Jochen

Upvotes: 0

naXa stands with Ukraine
naXa stands with Ukraine

Reputation: 37916

It may seem like not the best solution at first sight, but it depends on your requirements.

You can set a global option with maximum upload size for all controllers and override it with lower value for specific controllers.

application.properties file (Spring Boot)

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

Upload controller with check

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

In case of a file bigger than 2MB you'll get this exception in log:

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

Upvotes: 8

isank-a
isank-a

Reputation: 1675

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

Upvotes: 0

Mina Wissa
Mina Wissa

Reputation: 10971

There is an elegant solution here Spring Boot: ClassNotFoundException when configuring maxUploadSize of CommonMultipartResolver

you can modify your application application.properties file to change the max upload size as you want

Upvotes: 0

Bhashit Parikh
Bhashit Parikh

Reputation: 3131

This is how it is possible: Override the DispatcherServlet class. An example would probably looke like the following:

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

Assuming that you have configured multiple MultipartResolvers in your application-context (presumably named 'resolver1' and 'resolver2' in the example code).

Of course, when you configure the DispatcherServlet in your web.xml, you use this class instead of the Spring DispatcherServlet.

Another way: A MultipartFilter could be used as well. Just override the lookupMultipartResolver(HttpServletRequest request) method and look up the required resolver yourself. However, there are some ifs and buts to that. Look up the documentation before using that.

Upvotes: 4

Related Questions