Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

MultipartFile com Bean Validation

Tentei fazer uma validação com Bean Validation, porém esse constraint nunca é chamado. Tenho que fazer algo?

    @PostMapping
    @Transactional
    @Valid
    public ModelAndView cadastrarProduto(@FileAcceptable(PDF) MultipartFile sumario, @Valid Produto produto, BindingResult bindingResult, RedirectAttributes redirectAttributes){

        System.out.println(sumario.getOriginalFilename());

        if(bindingResult.hasErrors()){
            return exibirCadastroNovoProduto(produto);
        }

        try{
            String pathOfFile = uploadService.write(sumario);
            produto.setSumarioPath(pathOfFile);

            repository.save(produto);
            redirectAttributes.addFlashAttribute("resultadoProcessamento", "Produto cadastrado com sucesso!");

        }catch (RuntimeException e) {
            System.out.println(e.getMessage());
        }

        return new ModelAndView("redirect:/produtos");
    }

package br.com.casadocodigo.loja.validation;

import java.util.List;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;

public class FileAcceptableValidator implements ConstraintValidator<FileAcceptable, MultipartFile> {
    private List<TypeOfFile> typesOfFileAcceptable;

    @Override
    public void initialize(FileAcceptable constraintAnnotation) {
        typesOfFileAcceptable = Lists.newArrayList(constraintAnnotation.value());
    }

    @Override
    public boolean isValid(MultipartFile value, ConstraintValidatorContext context) {

        if(value!=null){
            return typesOfFileAcceptable.stream()
                .filter(type-> type.equals(value.getContentType()))
                .findFirst()
                .isPresent();
        }

        return true;
    }
}

package br.com.casadocodigo.loja.validation;

import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = FileAcceptableValidator.class)
@Retention(RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR})
public @interface FileAcceptable {

    String message() default "{br.com.casadocodigo.loja.validation.FileAcceptable.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    TypeOfFile[] value();
}
3 respostas
solução!

Fala Felipe, tudo bem ?

Você mandou bem. Creio que o único problema é que as constraints que serão aplicadas são as que estão sob o objeto anotado com @Valid. Como o MultipartFile fica a parte não é aplicada sobre ele.

Tente fazer um teste.

public class ProdutoForm {

    @NotBlank
    private String titulo;
    @NotBlank
    private String descricao;
    @Min(50)
    private Integer numberOfPages;

    ...
    @FileAcceptable(PDF)
    private MultipartFile sumario;

    //ggas
}

no controller:

@PostMapping
@Transactional
public ModelAndView cadastrarProduto(@Valid ProdutoForm produtoForm, BindingResult bindingResult, RedirectAttributes redirectAttributes){
    System.out.println(produtoForm.getSumario().getOriginalFilename());
    ...
}

obs: mais os ajustes necessários no form

Espero ter ajudado. Abraço!

Funcionou e ficou show!!

    @PostMapping
    @Transactional
    public ModelAndView cadastrarProduto(@Valid ProdutoComSumario produtoComSumario, BindingResult bindingResult, RedirectAttributes redirectAttributes){

        if(bindingResult.hasErrors()){
            return exibirCadastroNovoProduto(produtoComSumario);
        }

        try{
            String pathOfFile = uploadService.write(produtoComSumario.getSumario());
            produtoComSumario.getProduto().setSumarioPath(pathOfFile);

            repository.save(produtoComSumario.getProduto());
            redirectAttributes.addFlashAttribute("resultadoProcessamento", "Produto cadastrado com sucesso!");

        }catch (RuntimeException e) {
            System.out.println(e.getMessage());
        }
}

public class ProdutoComSumario {
    @Valid
    private Produto produto;
    @FileAcceptable(value=PDF, message="{FileAcceptable.sumario}")
    private MultipartFile sumario;

    public ProdutoComSumario() {
        this.produto = new Produto();
    }

    public MultipartFile getSumario() {
        return sumario;
    }

    public void setSumario(MultipartFile sumario) {
        this.sumario = sumario;
    }
...
}

package br.com.casadocodigo.loja.validation;

import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = FileAcceptableValidator.class)
@Retention(RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR})
public @interface FileAcceptable {

    String message() default "{br.com.casadocodigo.loja.validation.FileAcceptable.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    FileType[] value();
}

package br.com.casadocodigo.loja.validation;

import java.util.List;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;

@Component
public class FileAcceptableValidator implements ConstraintValidator<FileAcceptable, MultipartFile> {
    private List<FileType> fileTypes;

    @Override
    public void initialize(FileAcceptable constraintAnnotation) {
        fileTypes = Lists.newArrayList(constraintAnnotation.value());
    }

    @Override
    public boolean isValid(MultipartFile value, ConstraintValidatorContext context) {

        if(value!=null){
            return fileTypes.stream()
                .filter(type-> type.getContentType().equals(value.getContentType()))
                .findFirst()
                .isPresent();
        }

        return true;
    }
}

Ai sim. Mandou bem Felipe!