2015-12-01 9 views
5

mamWiosna walidacja parametrów RequestBody zmierzały do ​​zbiorów w metodach Controller

jednostka:

package org.ibp.soq; 

public class MyEntity { 

    private String field1; 
    private String field2; 

    //..getters and setters 

} 

Validator dla podmiotu:

package org.ibp.soq; 

import org.springframework.stereotype.Component; 
import org.springframework.validation.Errors; 
import org.springframework.validation.Validator; 

@Component 
public class MyEntityValidator implements Validator { 

    @Override 
    public boolean supports(Class<?> clazz) { 
     return MyEntity.class.equals(clazz); 
    } 

    @Override 
    public void validate(Object target, Errors errors) { 
     MyEntity myEntity = (MyEntity) target; 
     // Logic to validate my entity 
     System.out.print(myEntity); 
    } 

} 

i

Kontroler REST metodą PUT nasypowa:

package org.ibp.soq; 

import java.util.List; 

import javax.validation.Valid; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.web.bind.WebDataBinder; 
import org.springframework.web.bind.annotation.InitBinder; 
import org.springframework.web.bind.annotation.RequestBody; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
import org.springframework.web.bind.annotation.RestController; 

@RestController 
@RequestMapping("/myEntity") 
public class MyEntityRestResource { 

    @Autowired 
    private MyEntityValidator myEntityValidator; 

    @InitBinder 
    protected void initBinder(final WebDataBinder binder) { 
     binder.addValidators(this.myEntityValidator); 
    } 

    @RequestMapping(method = RequestMethod.PUT) 
    public void bulkCreate(@RequestBody @Valid List<MyEntity> myEntities) { 
     // Logic to bulk create entities here. 
     System.out.print(myEntities); 
    } 
} 

Kiedy złożyć wniosek oddany do tego zasobu o następującej treści żądania:

[ 
    { 
    "field1": "AA", 
    "field2": "11" 
    }, 

    { 
    "field1": "BB", 
    "field2": "22" 
    } 
] 

Błąd pojawia się:

"Invalid target for Validator [[email protected]]: [[email protected], [email protected]]" 

Rozumiem, że to dlatego, że MyEntityValidator "obsługuje" pojedynczą weryfikację MyEntity, a nie walidę dla ArrayList<MyEntity>.

MyEntityValidator działa idealnie, jeśli mam pojedynczy obiekt MyEntity w treści żądania i odpowiednią metodę kontrolera z parametrem @RequestBody @Valid MyEntity myEntity.

W jaki sposób konfigurator poprawności, którego użyłem, zostanie przedłużony na potrzeby obsługi sprawdzania poprawności kolekcji MyEntity?

Odpowiedz

1

Jak można się domyślić, nie można tego osiągnąć za pomocą Spring Validation. Spring Validation implementuje sprawdzanie poprawności fasoli (JSR 303/349) w przeciwieństwie do sprawdzania poprawności obiektu. Niestety kolekcja nie jest Java Bean. Masz dwie opcje

  • Wrap listy wewnątrz Java Bean
  • Wezwania walidatora ręcznie w swojej masie stworzyć metodę myEntityValidator. validate(targetObject, errors).
10

Roztwór utworzyć niestandardowy Validator dla Collection i @ControllerAdvice że rejestrów Validator w WebDataBinders.

Validator:

import java.util.Collection; 

import org.springframework.validation.Errors; 
import org.springframework.validation.ValidationUtils; 
import org.springframework.validation.Validator; 
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 

/** 
* Spring {@link Validator} that iterates over the elements of a 
* {@link Collection} and run the validation process for each of them 
* individually. 
* 
* @author DISID CORPORATION S.L. (www.disid.com) 
*/ 
public class CollectionValidator implements Validator { 

    private final Validator validator; 

    public CollectionValidator(LocalValidatorFactoryBean validatorFactory) { 
    this.validator = validatorFactory; 
    } 

    @Override 
    public boolean supports(Class<?> clazz) { 
    return Collection.class.isAssignableFrom(clazz); 
    } 

    /** 
    * Validate each element inside the supplied {@link Collection}. 
    * 
    * The supplied errors instance is used to report the validation errors. 
    * 
    * @param target the collection that is to be validated 
    * @param errors contextual state about the validation process 
    */ 
    @Override 
    @SuppressWarnings("rawtypes") 
    public void validate(Object target, Errors errors) { 
    Collection collection = (Collection) target; 
    for (Object object : collection) { 
     ValidationUtils.invokeValidator(validator, object, errors); 
    } 
    } 
} 

ControllerAdvice:

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 
import org.springframework.web.bind.WebDataBinder; 
import org.springframework.web.bind.annotation.ControllerAdvice; 
import org.springframework.web.bind.annotation.InitBinder; 

/** 
* Controller advice that adds the {@link CollectionValidator} to the 
* {@link WebDataBinder}. 
* 
* @author DISID CORPORATION S.L. (www.disid.com) 
*/ 
@ControllerAdvice 
public class ValidatorAdvice { 

    @Autowired 
    protected LocalValidatorFactoryBean validator; 


    /** 
    * Adds the {@link CollectionValidator} to the supplied 
    * {@link WebDataBinder} 
    * 
    * @param binder web data binder. 
    */ 
    @InitBinder 
    public void initBinder(WebDataBinder binder) { 
    binder.addValidators(new CollectionValidator(validator)); 
    } 
} 
+0

Dzięki! Z pewnością wypróbuję to podejście. –

+2

Użyj \ @ControllerAdvice zastosuje CollectionValidator do wszystkich kontrolerów. Co spowoduje wyjątek "java.lang.IllegalStateException: Niepoprawny cel dla Validatora", jeśli masz kolejną \ @Valid adnotację na obiekcie, który nie zbiera. –

+0

Zamiast tego użyj \ @InitBinder ("attrName") lub wykonaj initBinder w określonym kontrolerze. –

0

Właściwie, to można osiągnąć stosując Wiosna Walidacja i JSR303.

  • Narażenie fasoli MethodValidationPostProcessor.
  • Opisz swoją klasę kontrolera za pomocą @Validated (org.springframework.validation.annotation.Zatwierdzony)
  • Użyj adnotacji sprawdzania poprawności JSR303 w polach/metodach MyEntity.
  • Opisuj swój argument RequestBody za pomocą @Valid (już to zrobiłeś w twoim przykładzie).
  • Dodaj metodę @ExceptionHandler do obsługi wyjątku MethodArgumentNotValidException. Można to zrobić w kontrolerze lub w klasie @ControllerAdvice.
Powiązane problemy