royB
royB

Reputation: 12977

Unable to process parts as no multi-part configuration has been provided

I wrote a simple controller for uploading files:

@RestEndpoint
public class ImageController {
    @Autowired
    GridFsTemplate mTemplate;

    @RequestMapping(value = "images", method = RequestMethod.POST)
    public @ResponseBody String testPhoto(@RequestParam String name, @RequestParam String directory, @RequestParam MultipartFile file) throws IOException {

        if(!file.isEmpty()){
            final byte[] bytes = file.getBytes();
            InputStream inputStream = new ByteArrayInputStream(bytes);
            mTemplate.store(inputStream, "name");

            return "uploaded photo";
        }

        return "failed";
    }

} 

@RestEndpoint annotation is:

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
public @interface RestEndpoint
{
    String value() default "";
}

My ContextCOnfiguration class is:

@Configuration
@EnableWebMvc
@ComponentScan(
    basePackages = "com.questter.site",
    useDefaultFilters = false,
    includeFilters =
    @ComponentScan.Filter({RestEndpoint.class, RestEndpointAdvice.class})
)
public class RestServletContextConfiguration extends WebMvcConfigurerAdapter {
    @Bean
    public CommonsMultipartResolver multiPartResolver(){

        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        return resolver;
    }
...
}

--- UPDATED ---

web.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">

    <display-name>Spring Application</display-name>

    <jsp-config>
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <url-pattern>*.jspf</url-pattern>
            <page-encoding>UTF-8</page-encoding>
            <scripting-invalid>true</scripting-invalid>
            <include-prelude>/WEB-INF/jsp/base.jspf</include-prelude>
            <trim-directive-whitespaces>true</trim-directive-whitespaces>
            <default-content-type>text/html</default-content-type>
        </jsp-property-group>
    </jsp-config>

    <!--<context-param>-->
        <!--<param-name>spring.profiles.active</param-name>-->
        <!--<param-value>development</param-value>-->
    <!--</context-param>-->

    <session-config>
        <session-timeout>30</session-timeout>
        <cookie-config>
            <http-only>true</http-only>
        </cookie-config>
        <tracking-mode>COOKIE</tracking-mode>
    </session-config>

    <distributable />

</web-app>

---- UPDATED ----

public class Bootstrap implements WebApplicationInitializer
{

    @Override
    public void onStartup(ServletContext container) throws ServletException
    {
        container.getServletRegistration("default").addMapping("/resource/*");

        AnnotationConfigWebApplicationContext rootContext =
            new AnnotationConfigWebApplicationContext();
        rootContext.register(RootContextConfiguration.class);
        container.addListener(new ContextLoaderListener(rootContext));

        AnnotationConfigWebApplicationContext webContext =
            new AnnotationConfigWebApplicationContext();
        webContext.register(WebServletContextConfiguration.class);
        ServletRegistration.Dynamic dispatcher = container.addServlet(
            "springWebDispatcher", new DispatcherServlet(webContext)
        );
        dispatcher.setLoadOnStartup(1);
        dispatcher.setMultipartConfig(new MultipartConfigElement(
            null, 20_971_520L, 41_943_040L, 512_000
        ));
        dispatcher.addMapping("/");

        AnnotationConfigWebApplicationContext restContext =
                new AnnotationConfigWebApplicationContext();
        restContext.register(RestServletContextConfiguration.class);
        DispatcherServlet servlet = new DispatcherServlet(restContext);
        servlet.setDispatchOptionsRequest(true);
        dispatcher = container.addServlet(
                "springRestDispatcher", servlet
        );
        dispatcher.setLoadOnStartup(2);
        dispatcher.addMapping("/rest/*");

        rootContext.refresh();
        DbBootstrap dbBootstrap = rootContext.getBean(DbBootstrap.class);
        dbBootstrap.init();

    }


}

When perfoming a post request (using postman) i'm getting:

HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalArgumentException:Expected MultipartHttpServletRequest: is a MultipartResolver configured 

I've looked over some similar questions over stackoverflow but none of the answers helped me.

Spring version is: 4.0.4

Any help will be greatly appreciated (with a thumbs up of course).

Thanks

Upvotes: 8

Views: 38458

Answers (4)

Fruitjam
Fruitjam

Reputation: 21

The answer by R. Ali Ashik worked for me.

Following is the relevant part of pom.xml of the project that I am working on:

  <properties>
  <springframework.version>5.0.2.RELEASE</springframework.version>
  <springsecurity.version>5.0.0.RELEASE</springsecurity.version>
  <hibernate.version>5.2.17.Final</hibernate.version>
  <mysql.connector.version>8.0.11</mysql.connector.version>

Since, I have a custom login page with persistent authentication setup, I also needed to have the following:

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

        @Override
        protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
            insertFilters(servletContext, new MultipartFilter());
        }
    }

But the actual clincher was this as pointed out by R. Ali Ashik:

@Bean(name = "filterMultipartResolver")
public CommonsMultipartResolver multiPartResolver(){
    CommonsMultipartResolver resolver = new 
    CommonsMultipartResolver();
    return resolver;
}

The relevant reference material in the context is this: Class MultipartFilter

And the relevant text is as follows:

Looks up the MultipartResolver in Spring's root web application context. Supports a "multipartResolverBeanName" filter init-param in web.xml; the default bean name is "filterMultipartResolver". Looks up the MultipartResolver on each request, to avoid initialization order issues (when using ContextLoaderServlet, the root application context will get initialized after this filter).

Upvotes: 0

Ramjan Ali
Ramjan Ali

Reputation: 530

It is straight forward from the exception that no multi-part configuration is found. Though you have provided multipartResolver bean.

The problem is that while specifying the MultipartFilter before the Spring Security filter, It tries to get the multipartResolver bean but can't find it. Because it expect the bean name/id as filterMultipartResolver instead of multipartResolver.

Do yourself a favor. Please change the bean configuration like following -

@Bean
public CommonsMultipartResolver filterMultipartResolver(){
    CommonsMultipartResolver resolver = new 
    CommonsMultipartResolver();
    return resolver;
}

or

@Bean(name = "filterMultipartResolver")
public CommonsMultipartResolver multiPartResolver(){
    CommonsMultipartResolver resolver = new 
    CommonsMultipartResolver();
    return resolver;
}

Upvotes: 2

user4022749
user4022749

Reputation:

allowCasualMultipartParsing="true"

on context tag inside context.xml, it's work for me

Upvotes: 4

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279970

I don't know why they did this, but the MultipartResolver bean in the context needs to be named multipartResolver. Rename your @Bean method to

public CommonsMultipartResolver multipartResolver(){ // lowercase 'P'

Or give it the name explicitly

@Bean(name = "multipartResolver")
public CommonsMultipartResolver canBeCalledAnything(){

Upvotes: 16

Related Questions