Upload a file through spring forms returning HTTP Status 405 - Request method 'POST' not supported, Spring Security is Enabled
Java Based Configuration
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
}
Model
@Entity
@Table(name="alumni")
public class Alumni implements Serializable{
private static final long serialVersionUID = 1L;
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@NotEmpty
@Column(name="studentName", nullable=false)
private String studentName;
@NotEmpty
@Column(name="program", nullable=false)
private String program;
@Transient
private MultipartFile file;
@Column(name="content")
@Lob
private Blob content;
@Column(name="contentType", nullable=false)
private String contentType;
@Column(name="fileName", nullable=false)
private String fileName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getProgram() {
return program;
}
public void setProgram(String program) {
this.program = program;
}
public Blob getContent() {
return content;
}
public void setContent(Blob content) {
this.content = content;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
}
Controller
@RequestMapping(value={"/alumni"}, method=RequestMethod.POST)
public String saveAlumni(@Valid Alumni alumni, BindingResult result, ModelMap model) {
System.out.println("Alumni : "+alumni);
if (result.hasErrors()) {
model.addAttribute("errors", result.getAllErrors());
return "alumni_u";
} else {
Verification verification = verificationService.getByTypeAndVerificationOn(VerificationType.EMAIL.getVerificationType(), alumni.getEmail());
if(verification!=null && verification.getCode().equals(alumni.getEmailVerificationCode())){
if(alumni.getFile()!=null){
try{
if(Arrays.asList(imageArray).contains(alumni.getFile().getContentType())){
alumni.setContent(new SerialBlob(alumni.getFile().getBytes()));
alumni.setContentType(alumni.getFile().getContentType());
alumni.setFileName(alumni.getFile().getOriginalFilename());
alumniService.save(alumni);
}else{
model.addAttribute("errors", messageSource.getMessage("NotAllowed.alumni.image.format", null, null));
return "alumni_u";
}
}catch(Exception e){
logger.error(messageSource.getMessage("Error.alumni.file.blob", null, null));
e.printStackTrace();
model.addAttribute("errors", messageSource.getMessage("Error.alumni.file.blob", null, null));
return "alumni_u";
}
}else{
alumniService.save(alumni);
}
}else{
model.addAttribute("errors", messageSource.getMessage("Invalid.alumni.verificationCode.email", new Object[] {alumni.getEmail()}, null));
return "alumni_u";
}
model.addAttribute("success", messageSource.getMessage("success.alumni.form.submition", null, null));
return "alumniSuccess_u";
}
}
Form
<form:form method="POST" modelAttribute="alumni" enctype="multipart/form-data" >
<form:errors path="*" class="has-error" />
<form:input type="hidden" path="id" id="id" />
<ul>
<li class="alumni-leftinput clear">
<label>Name* :</label>
<form:input type="text" path="studentName" id="studentName" onkeypress="return keyRestrict(event, 'char');"/>
<div class="has-error">
<form:errors path="studentName" class="help-inline"/>
</div>
</li>
<li class="alumni-leftinput clear">
<label>Department/Program* :</label>
<form:select path="program" class="form-control input-sm" onchange="getAlumniCourse();">
<form:option value="" label="--- Select ---" />
<form:option value="Under Graduate" label="Under Graduate - UG"/>
<form:option value="Post Graduate" label="Post Graduate - PG"/>
</form:select>
<div class="has-error">
<form:errors path="program" class="help-inline"/>
</div>
</li>
<li class="full-width clear">
<label>Recent color photograph (Image dimensions 2" x 2") :</label>
<form:input type="file" path="file" id="file" />
<span>Upload Bitmap / jpeg / gif / png formats only. Size below 2MB</span>
</li>
<li class="clear">
<button type="submit" class="dt-sc-button noborder" value="Submit">Submit</button>
</li>
</ul>
Getting CSRF Value from Spring form
<input type="hidden" name="_csrf" value="7ba6b5a7-7fed-4bb6-b54e-a781576e85e3">
Application Configuration
@Bean
public CommonsMultipartResolver multipartResolver() throws IOException{
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("utf-8");
resolver.setMaxUploadSizePerFile(5242880);//5MB
return resolver;
}
Request Header
POST /urce/alumni HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 96286
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrAL3hxUGtppolJFd
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Referer: http://localhost:8080/urce/alumni
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: JSESSIONID=1ED3DB210F38EC734E99CE420E16042B; _ga=GA1.1.1771599779.1532604925; _gid=GA1.1.1755993342.1534396304; _gat=1
DNT: 1
Response Header
HTTP/1.1 405 Method Not Allowed
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Allow: GET
Content-Type: text/html;charset=ISO-8859-1
Content-Language: en
Content-Length: 1047
Date: Fri, 17 Aug 2018 08:49:28 GMT
Solution
By Specifying the @Bean(name="filterMultipartResolver") annotation on top of public CommonsMultipartResolver getMultipartResolver() method in Application Configuratuin which extends WebMvcConfigurerAdapter resoved my Issue
Make sure that the bean is name called filterMultipartResolver (name="filterMultipartResolver") as any other bean name is not picked up by MultipartFilter.
My initial configuration was not working because this bean was named as name="multipartResolver" and I also tested by removing name in @Bean annotation
I followed the solution provided in this link
@Bean(name="filterMultipartResolver")
public CommonsMultipartResolver getMultipartResolver() throws IOException{
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("utf-8");
resolver.setMaxUploadSizePerFile(5242880);//5MB
return resolver;
}