Arip Hidayat Arip Hidayat - 6 months ago 140
Java Question

Spring MVC 4 Upload File Blocked by Spring Security

Im trying upload file in my Spring MVC 4 project via Spring Form, but when I submit form with my log say :

Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@527de1e2
and
Invalid CSRF token found
.

And I found solution from Spring Security Reference
, but After I placing Multipart Filter before Spring security, my Model Attrbute are returning NULL.

Here is my codes :

JSP Snippet :

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

<html>
<body>
<div>
<form:form action="save?${_csrf.parameterName}=${_csrf.token}"
method="post" modelAttribute="book" enctype="multipart/form-data">
<table>
<form:input type="hidden" path="id" />
<tr>
<td>ISBN:</td>
<td><form:input path="isbn" autofocus="autofocus"/></td>
</tr>
<tr>
<td>Title:</td>
<td><form:input path="title" /></td>
</tr>
<tr>
<td>Author:</td>
<td><form:input path="author" /></td>
</tr>
<tr>
<td>Publisher:</td>
<td><form:input path="publisher" /></td>
</tr>
<tr>
<td>Call Number:</td>
<td><form:input path="callNumber" /></td>
</tr>
<tr>
<td>Pages:</td>
<td><form:input path="pages" /></td>
</tr>
<tr>
<td>Pages:</td>
<td><form:input path="imageFile" type="file" /></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Save">
</td>
</tr>
</table>
</form:form>
</div>





Model

@Entity
@Table(name="books")
public class Book implements Serializable {

private static final long serialVersionUID = 4235334951865878125L;

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;

@NotNull
@NotEmpty
@Size(min = 1, max = 25)
@Column(name = "isbn")
private String isbn;

@NotNull
@NotEmpty
@Size(min = 1, max = 50)
@Column(name = "title")
private String title;

@Size(max = 50)
@Column(name = "author")
private String author;

@Size(max = 50)
@Column(name = "publisher")
private String publisher;

@Size(max = 25)
@Column(name = "call_number")
private String callNumber;

@Column(name = "pages")
private int pages;

@Column(name = "image_file")
private byte[] imageFile;

//Setter & Getter
}


Controller Snippet :

@RequestMapping(value = "/save", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority('BOOK_ADD', 'BOOK_EDIT')")
public String saveBook(@ModelAttribute @Valid Book book, BindingResult result) {
bookValidator.validate(book, result);

if (result.hasErrors()) {
return "book/form";
}
if (bookService.getBook(book.getId()) == null) {
bookService.save(book);
} else {
bookService.update(book);
}
return "redirect:/book";
}


Servlet Configuration :

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("UTF-8");
return resolver;
}


Spring Security Initializer :

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


SQL Table :

CREATE TABLE `books` (
`id` INT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
`isbn` VARCHAR(25) NOT NULL,
`title` VARCHAR(50) NOT NULL,
`author` VARCHAR(50) NULL DEFAULT NULL,
`publisher` VARCHAR(50) NULL DEFAULT NULL,
`call_number` VARCHAR(25) NULL DEFAULT NULL,
`pages` INT(5) NULL DEFAULT NULL,
`image_file` MEDIUMBLOB NULL,
PRIMARY KEY (`id`)
)


and Library Snippet Im Using :

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency.
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>

Answer

You can add a new MultipartFile attribute in Book class like what other people suggest, and make it transient. When this attribute is set, and set your imageFile as well.

@Column(name = "image_file")
private byte[] imageFile;

@Transient
private MultipartFile multiPartFile;

public void setMultiPartFile(MultipartFile multiPartFile) {
    this.multiPartFile = multiPartFile;
    if(multiPartFile != null){
        this.setImageFile(multiPartFile.getBytes());
    }
}
Comments