Spring MVC file upload - Unable to process parts as no multi-part configuration has been provided - spring

So I'm a newbie to Spring and I'm trying to get file upload working for my project (I'm using Spring Tool Suite btw.) and when submitting a form all I'm getting is:
HTTP Status 500 - Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
Stack trace from browser:
type Exception report
message Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
description The server encountered an internal error that prevented it from fulfilling this request.
exception
org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:100)
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.(StandardMultipartHttpServletRequest.java:78)
org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:75)
org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:108)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)
root cause
java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
org.apache.catalina.connector.Request.parseParts(Request.java:2676)
org.apache.catalina.connector.Request.getParts(Request.java:2643)
org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1083)
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:85)
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.(StandardMultipartHttpServletRequest.java:78)
org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:75)
org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:108)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:106)
note The full stack trace of the root cause is available in the Apache Tomcat/8.0.27 logs.
This is the form tag in jsp:
<form:form class="form-horizontal" role="form" method="post"
action="newArtist.html" modelAttribute="artist" enctype="multipart/form-data">
Input part:
<div class="form-group">
<div class="col-lg-3">
<label for="photo">Artist photo:</label>
<form:input type="file" id="photo" path="photo"></form:input>
</div>
</div>
Photo is stored in this field in Artist object:
#Lob
private byte[] photo;
Controller mapping methods:
#RequestMapping(value = "/newArtist", method = RequestMethod.GET)
public String showAddArtistForm(Model model)
{
model.addAttribute("artist", new Artist());
return "newArtist";
}
#RequestMapping(value = "/newArtist", method = RequestMethod.POST)
public String addArtist(#ModelAttribute("artist") #Valid Artist artist, BindingResult result,
#RequestParam("photo") MultipartFile photo) throws IOException
{
if (result.hasErrors())
return "newArtist";
if(photo.getBytes() != null)
artist.setPhoto(photo.getBytes());
artistService.addArtist(artist);
return "redirect:artists.html";
}
Multipart resolver configuration in servlet-context.xml:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10000000"/>
</bean>
Filters in web.xml:
<filter>
<filter-name>MultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Dependencies:
<!-- Apache Commons FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Apache Commons IO -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
I also imported Tomcat's config file context.xml to META-INF/context.xml and edited Context tag like so:
<Context allowCasualMultipartParsing="true">
Nothing seems to be working, any help will be greatly appreciated.

Actually you don't need any filter on the web.xml in order to upload your multipart file with Spring MVC. I've the same configuration in my project and it worked (${spring.version} = 4.3.4.RELEASE):
POM
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Apache Commons FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Apache Commons IO -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
HTML
<form method="POST" enctype="multipart/form-data" action="uploadAction">
<table>
<tr><td>File to upload:</td><td><input type="file" name="file" /></td></tr>
<tr><td></td><td><input type="submit" value="Upload" /></td></tr>
</table>
</form>
Spring context
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10000000"/>
</bean>
Spring controller
#PostMapping("/uploadAction")
public String handleFileUpload(#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
File out = new File("outputfile.pdf");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(out);
// Writes bytes from the specified byte array to this file output stream
fos.write(file.getBytes());
System.out.println("Upload and writing output file ok");
} catch (FileNotFoundException e) {
System.out.println("File not found" + e);
} catch (IOException ioe) {
System.out.println("Exception while writing file " + ioe);
} finally {
// close the streams using close method
try {
if (fos != null) {
fos.close();
}
} catch (IOException ioe) {
System.out.println("Error while closing stream: " + ioe);
}
//storageService.store(file);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
return "redirect:/";
}
}

None of the answers address the issue properly. As per Tomcat documentation, on the configuration of allowCasualMultipartParsing:
Set to true if Tomcat should automatically parse multipart/form-data request bodies when HttpServletRequest.getPart* or HttpServletRequest.getParameter* is called, even when the target servlet isn't marked with the #MultipartConfig annotation (See Servlet Specification 3.0, Section 3.2 for details). Note that any setting other than false causes Tomcat to behave in a way that is not technically spec-compliant. The default is false.
So, what's the compliant way? Reading the official JEE 6 tutorial gives a hint. If you want to use a spec-compliant way with Servlet 3 or newer, your servlet must have a MultipartConfig. You have three choices, depending on how you configure your servlet:
With programmatic configuration: context.addServlet(name, servlet).setMultipartConfig(new MultipartConfigElement("your_path").
With annotations, annotate the servlet's class with #javax.servlet.annotation.MultipartConfig.
With XML configuration, add this to the WEB-INF/web.xml descriptor, in the section of your servlet:
<multipart-config>
<location>/tmp</location>
<max-file-size>20848820</max-file-size>
<max-request-size>418018841</max-request-size>
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>

For those who get the same exception for PUT method handlers: use POST instead. PUT is incompatible with the multi-part.
More details can be found in the respective answer

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 id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10000000"/>
</bean>

Add In your config file as:
#Bean(name = "multipartResolver")
public CommonsMultipartResolver CanBeAnyName() {
//configuration
}

I have something similar, but what i did is just send a file without mapping it with any attribute in my model, in your case i would modify this:
<div class="form-group">
<div class="col-lg-3">
<label for="photo">Artist photo:</label>
<input type="file" id="photo" name="file"/>
</div>
</div>
In your controller
#RequestMapping(value = "/newArtist", method = RequestMethod.POST)
public String addArtist(#ModelAttribute("artist") #Valid Artist artist, BindingResult result,
#RequestParam("file") MultipartFile file) throws IOException
//Here read the file and store the bytes into your photo attribute
...

Had the same issue in a Spring Boot application, this exceptions occur several times:
org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is
java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field multipartFile exceeds its maximum permitted size of 1048576 bytes
org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field multipartFile exceeds its maximum permitted size of 1048576 bytes.
Get rid of the tomcat exception with this, with copy catting from http://www.mkyong.com/spring-boot/spring-boot-file-upload-example/
Tomcat large file upload connection reset. Need to let {#link #containerCustomizer()} work properly, other wise exception will occur several times, RequestMapping for uploadError will fail.
#Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbedded() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
//-1 means unlimited
((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});
return tomcat;
}

If anyone is using J2EE and not spring framework and still facing issue
what you can try is adding #MultipartConfig annotation on servlet and add enctype="multipart/form-data" inside form tag

If you are using Tomcat 8.
Configure the following in Tomcat's conf/context.xml
Add allowCasualMultipartParsing="true" attribute to context node
Add <Resources cachingAllowed="true" cacheMaxSize="100000" /> inside context node

Related

Unstable Primefaces fileupload listener call

Having a Spring Boot project working with JDK11, Primefaces 8.0, Spring Boot 2.3.0.
deploying it on tomcat 9.0.35. In some deployments my fileupload component is able to trigger the listener method well. In some other, it can't trigger it leaving no error message or log.
I have tried some restarts producing every time same results (fail to upload) with the same build. But despite having not touched the source, another build can make it work.
On another test, I have built & deployed 4-5 times the project with exactly same source code, seeing upload is working in all of them. And for a last test, I just added a space character after a java statement's ';' to change the binary and rebuilt, redeployed and noticed file upload not working.
I can't find out why the behaviour is not stable.
I am stuck and have no idea how to debug it, identify the problem. Any suggestion will be welcomed
At pom.xml having:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.20</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.20</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>8.0</version>
</dependency>
<dependency>
<groupId>com.google.code</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.0</version>
</dependency>
FileUpload component on page:
<h:form id="bulkDataInsertForm" enctype="multipart/form-data">
.
.
<p:fileUpload id="datafileuploader"
listener="#{bulkDataInsertBean.handleFileUpload}"
uploadLabel="upload file"
cancelLabel="cancel"
label="choose file"
update=":bulkDataInsertForm:bulkDataInsertgrowl :bulkDataInsertForm:listFileUploadPanel :bulkDataInsertForm:errorText"
allowTypes="/(\.|\/)(xlsx)$/"
sizeLimit="10485760"
multiple="false"
invalidFileMessage="file type error"
mode="advanced" dragDropSupport="true"
ajax="true">
</p:fileUpload>
.
.
</h:form>
I have <h:head> in parent page as told here: How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null / throws an error / not usable.
And ServletInitializer:
#EnableEncryptableProperties
#SpringBootApplication
#ComponentScan({ "com.myapp" })
public class WebApplication extends SpringBootServletInitializer {
#Bean
public ServletRegistrationBean kaptchaServletRegistration() {
ServletRegistrationBean bean = new ServletRegistrationBean(new KaptchaServlet(), "/kaptcha.jpg");
return bean;
}
#Bean
public ServletRegistrationBean facesServletRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean<>(new FacesServlet(), "*.xhtml");
registration.setLoadOnStartup(1);
return registration;
}
#Bean
public ServletContextInitializer servletContextInitializer() {
return servletContext -> {
servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
servletContext.setInitParameter("primefaces.THEME", "blitzer");
servletContext.setInitParameter("primefaces.CLIENT_SIDE_VALIDATION", Boolean.TRUE.toString());
servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", Boolean.TRUE.toString());
servletContext.setInitParameter("primefaces.FONT_AWESOME", Boolean.TRUE.toString());
servletContext.setInitParameter("javax.faces.ENABLE_CDI_RESOLVER_CHAIN", Boolean.TRUE.toString());
};
#Bean
public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
return new ServletListenerRegistrationBean<>(new ConfigureListener());
}
//for setting fileUploadFilter to in front of filterChain - so uploaded file not consumed by other filter
#Bean
public FilterRegistrationBean primeFacesFileUploadFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean(new org.primefaces.webapp.filter.FileUploadFilter(), facesServletRegistration());
registration.addUrlPatterns("/*");
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD);
registration.setName("primeFacesFileUploadFilter");
registration.setOrder(1);
return registration;
}
}
Note: On some forums, I have read fileupload filter order can be changed, so some other filters may consume the file stream being uploaded, leaving fileupload filter with no input.
It must also accept Forwarded requests. So I added "primeFacesFileUploadFilter" shown above, but it did not help:
This is the order of filterchain during ServletContextInitializer after added the code:
Filter names at FilterChain by order: [requestContextFilter, Tomcat WebSocket (JSR356) Filter, errorPageFilter, primeFacesFileUploadFilter, characterEncodingFilter, springSecurityFilterChain, formContentFilter]
Specifying
servletContext.setInitParameter("primefaces.UPLOADER", "native");
at servletContextInitializer resulted in sometimes successful and sometimes failing(listener untriggered) fileuploads.
But after specifiying:
servletContext.setInitParameter("primefaces.UPLOADER", "commons");
instead of "native", I did nearly 10 builds, deploys, tests in which all fileuploads triggered properly. Of course I can't still guarantee its the absolute solution but
its highly likely.

Swagger implemetation Spring Web MVC not display model Schema

I am trying to implementing Spring Web MVC with Swagger but problem is I could not getting model Schema.
I am attaching code with question which is given blow.
I'm following the below link:
http://raibledesigns.com/rd/entry/documenting_your_spring_api_with
the issue was that Swagger UI was displaying but for the post request it was not displaying the model schema.
POM.XML:
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>0.5.2</version>
</dependency>
Spring.xml:
<mvc:annotation-driven />
<context:component-scan base-package="com.ga" />
<mvc:default-servlet-handler />
<bean id="documentationConfig" class="com.mangofactory.swagger.configuration.DocumentationConfig" />
<context:property-placeholder location="classpath:spring/application.properties"
system-properties-mode="OVERRIDE" />
Customer Controller.java:
#Api(value="CustomerController",description="Customer Controller")
#RestController
public class CustomerController {
#ApiOperation(value="save",notes="These Method is used to Save all Customer Details with its Deployment ")
#RequestMapping(value = "/save", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Customer> saveCustomerDetails(#RequestBody Customer customer) throws CustomerException {
}
}
Application properties:
documentation.services.version=1.0
documentation.services.basePath=http://localhost:9090/XYZ
I just found the solution of the above issue.I just configure the swagger in my code internally.
i followed these link to configure the swagger.
https://github.com/ufasoli/spring-mvc-swagger-tutorial.
These really works for me.

Spring CommonsMultipartResolver always return null for the MultipartFile

If I use StandardServletMultipartResolver, I get the file properly, but if I use CommonsMultipartResolver I get null for the file. Even without any additional configuration, just replacing new StandardServletMultipartResolver(); with new CommonsMultipartResolver(); the files are not received. I wanted to enforce maxUploadSizePerFile and hence used CommonsMultipartResolver.
In my WebContext Configuration file, I have the following:
#Override
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
Long maxFileSize = environment.getRequiredProperty(PropertyConstants.MAX_FILE_UPLOAD_SIZE, Long.class);
multipartResolver.setMaxUploadSizePerFile(maxFileSize);
return multipartResolver;
}
If I just replace the CommonsMultipartResolver with StandardServletMultipartResolver, things start to work. I have commons-fileupload in mvn dependency and the application gets launched without any error.
I am using Tomcat 9.0.0.M1 and Spring 4.2.2.
Is there some configuration I am missing for CommonsMultipartResolver to work?
I have encountered the same issue, but I note that it only occurs when CommonsFileUploadSupport stores the file in memory. As a workaround I found setting maxInMemorySize to 0 works e.g.
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- max upload size in bytes -->
<property name="maxUploadSize" value="20971520" /> <!-- 20MB -->
<!-- max size of file in memory (in bytes) -->
<!-- oddly, the MultipartFile passed as a RequestParam gets set to null if I allow it to use memory
rather than disk! -->
<property name="maxInMemorySize" value="0" />
</bean>
Go to the Servers repertory and Try to add allowCasualMultipartParsing="true" in the context.xml of Tomcat Server in your workspace project.

How to configure Jcache with Ecache as Provider in Spring application-context.xml?

Spring documentation provides below information.
<bean id="cacheManager"
class="org.springframework.cache.jcache.JCacheCacheManager"
p:cache-manager-ref="jCacheManager"/>
<!-- JSR-107 cache manager setup -->
<bean id="jCacheManager" .../>
I want to know exactly how to configure this jcacheManager bean (with EhCache as provider) in spring application context xml.
I have already configured dependency, as below, in pom.xml which is fine.
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>jcache</artifactId>
<version>1.0.1</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
It really depends how you want to configure it. If you're using Spring Boot 1.3, it will be automatically created for you. Maybe you could have a look to the source of JCacheCacheConfiguration?
You can retrieve the default javax.cache.CacheManager via Caching.getCachingProvider().getCacheManager()
It's not convenient for us to integrate Ehache3.x with Spring4.x now. Spring boot does it, and it rewrites some codes:
<bean id="cacheManager"
class="org.springframework.cache.jcache.JCacheCacheManager"
in Spring boot, it's:
#Bean
public JCacheCacheManager cacheManager(CacheManager jCacheCacheManager) {
return new JCacheCacheManager(jCacheCacheManager);
}
and it needs a javax.cache.CacheManager instance,
<!-- JSR-107 cache manager setup -->
<bean id="jCacheManager" .../>
Ehcache have no in-depth introduction for us.
Spring boot does like:
#Bean
#ConditionalOnMissingBean
public CacheManager jCacheCacheManager() throws IOException {
CacheManager jCacheCacheManager = createCacheManager();
List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!CollectionUtils.isEmpty(cacheNames)) {
for (String cacheName : cacheNames) {
jCacheCacheManager.createCache(cacheName, getDefaultCacheConfiguration());
}
}
customize(jCacheCacheManager);
return jCacheCacheManager;
}
It's a normal operation to create javax.cache.CacheManager just follows the Ehcache document.

How to integrate MyFaces with Spring

In my logon.xhtml, I have following code that involve my backing bean to perform correspopnding logon through spring security.
<h:commandButton type="submit" id="login" value="Login"
action="#{logonController.doLogin}" />
My backing bean defines as the following.
#Component
#ManagedBean(name="logonController")
#SessionScoped
public class LogonController
{
. . .
public String doLogin() throws ServletException, IOException {
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
.getRequestDispatcher("/j_spring_security_check");
dispatcher.forward((ServletRequest) context.getRequest(),
(ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
logger.debug("in LogonPageController ");
return null;
}
}
In order to integrate spring with JSF, I have also added the following to the faces-config.xml.
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
Moreover, two standard spring listeners have also be inclued in the web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
I have tried the above setting in mojarra + tomcat and it should be able to trigger the logon() function of my backing bean when user click on the Logon button. However, when I swith to TomEE with MyFaces, this won't work. I have the following maven dependency in my pom.xml.
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-api</artifactId>
<version>${myfaces-version}</version>
</dependency>
<dependency>
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-impl</artifactId>
<version>${myfaces-version}</version>
</dependency>
Is there any thing that I need to add in order to make it work with MyFaces?
Thanks for your help.

Resources