I have a Spring MVC application with a file upload form.
I would like to be able to display validation errors to a user if the upl
If you are using Java Bean Validation (JSR 303) you can make annotation that validates content type. See code below.
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* The annotated element must have specified content type.
*
* Supported types are:
* <ul>
* <li><code>MultipartFile</code></li>
* </ul>
*
* @author Michal Kreuzman
*/
@Documented
@Retention(RUNTIME)
@Constraint(validatedBy = {ContentTypeMultipartFileValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
public @interface ContentType {
String message() default "{com.kreuzman.ContentType.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* Specify accepted content types.
*
* Content type example :
* <ul>
* <li>application/pdf - accepts PDF documents only</li>
* <li>application/msword - accepts MS Word documents only</li>
* <li>images/png - accepts PNG images only</li>
* </ul>
*
* @return accepted content types
*/
String[] value();
}
/**
* Validator of content type. This is simple and not complete implementation
* of content type validating. It's based just on <code>String</code> equalsIgnoreCase
* method.
*
* @author Michal Kreuzman
*/
public class ContentTypeMultipartFileValidator implements ConstraintValidator<ContentType, MultipartFile> {
private String[] acceptedContentTypes;
@Override
public void initialize(ContentType constraintAnnotation) {
this.acceptedContentTypes = constraintAnnotation.value();
}
@Override
public boolean isValid(MultipartFile value, ConstraintValidatorContext context) {
if (value == null || value.isEmpty())
return true;
return ContentTypeMultipartFileValidator.acceptContentType(value.getContentType(), acceptedContentTypes);
}
private static boolean acceptContentType(String contentType, String[] acceptedContentTypes) {
for (String accept : acceptedContentTypes) {
// TODO this should be done more clever to accept all possible content types
if (contentType.equalsIgnoreCase(accept)) {
return true;
}
}
return false;
}
}
public class MyModelAttribute {
@ContentType("application/pdf")
private MultipartFile file;
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
}
@RequestMapping(method = RequestMethod.POST)
public String processUploadWithModelAttribute(@ModelAttribute("myModelAttribute") @Validated final MyModelAttribute myModelAttribute, final BindingResult result, final Model model) throws IOException {
if (result.hasErrors()) {
// Error handling
return "fileupload";
}
return "fileupload";
}
I got the answer to my question Spring community forums:
Here is the controller method:
@RequestMapping(method = RequestMethod.POST)
public String processUploadWithModelAttribute(@ModelAttribute("myModelAttribute") final MyModelAttribute myModelAttribute, final BindingResult result, final Model model) throws IOException {
String mimeType = determineMimeType(myModelAttribute.getFile().getBytes());
if (mimeType.equalsIgnoreCase("application/pdf")){
result.addError(new ObjectError("file", "pdf not accepted"));
}
return "fileupload";
}
And the model attribute class:
public class MyModelAttribute {
private MultipartFile file;
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
}
The idea is to put the MultipartFile into the ModelAttribute as an attribute.