Spring Standardmultiparthttpservletrequest Validation

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.

7

1 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Sarah Jenkins

Sarah Jenkins

Senior Technology Editor & AI Specialist

Sarah Jenkins is a veteran tech journalist with over 12 years of experience covering artificial intelligence, mobile innovations, and digital ethics. Her insights have appeared in leading technology publications worldwide.

Share this article
Twitter Facebook Pinterest