Is there any possibility to validate StandardMultipartHttpServletRequest using standard @Valid annotation and custom Validator?
I've implemented such validator, annotated method param in controller the validator is not invoked.
71 Answer
I've figured it out myself. To make it work you need a DTO:
import lombok.Getter; import lombok.Setter; import org.springframework.web.multipart.MultipartFile; import java.util.List; @Getter @Setter public class NewOrderFilesDTO { List<MultipartFile> files; } Then, a validator:
import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springframework.web.multipart.MultipartFile; import java.util.List; import static org.springframework.util.CollectionUtils.isEmpty; @Component public class NewOrderFilesValidator implements Validator { private static final String MIME_TYPE_PDF = "application/pdf"; private static final long ALLOWED_SIZE = 3 * 1024 * 1024; @Override public void validate(Object target, Errors errors) { if (target == null) { return; } NewOrderFilesDTO newOrderFilesDTO = (NewOrderFilesDTO) target; List<MultipartFile> newOrderFiles = newOrderFilesDTO.getFiles(); if (isEmpty(newOrderFiles)) { return; } for (MultipartFile file : newOrderFiles) { if (!MIME_TYPE_PDF.equals(file.getContentType())) { errors.rejectValue(file.getName(), file.getName(), "'application/pdf' files allowed only!"); } if (file.getSize() > ALLOWED_SIZE) { errors.rejectValue(file.getName(), file.getName(), "File size allowed up to 3MB!"); } } } @Override public boolean supports(Class<?> cls) { return NewOrderFilesDTO.class.equals(cls); } } And finally a controller:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import javax.validation.Valid; import static org.springframework.http.HttpStatus.NO_CONTENT; import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; import static org.springframework.web.bind.annotation.RequestMethod.POST; @Controller class OrderController { private final NewOrderFilesValidator newOrderFilesValidator; @Autowired OrderController(NewOrderFilesValidator newOrderFilesValidator) { this.newOrderFilesValidator = newOrderFilesValidator; } @InitBinder("newOrderFiles") void initOrderFilesBinder(WebDataBinder binder) { binder.addValidators(newOrderFilesValidator); } @ResponseStatus(NO_CONTENT) @RequestMapping(value = ORDERS_PATH, method = POST, consumes = MULTIPART_FORM_DATA_VALUE) void createOrder( @Valid @ModelAttribute NewOrderFilesDTO newOrderFiles ) { } } With the configuration above the DTO will be validated automatically by spring.
3