2016-02-10 23 views
8

szuka pomocy danych z wiosennej walidacji spoczynku dotyczące właściwego obchodzenia się z błędami Walidacja:Wiosna danych Reszta Validation Zamieszanie

Jestem więc mylić z docs dotyczących walidacji wiosna-data-reszta tutaj: http://docs.spring.io/spring-data/rest/docs/current/reference/html/#validation

staram się właściwie do czynienia z walidacji za wywołanie POST, który stara się uratować nowego podmiotu Spółka

mam ten podmiot:

@Entity 
public class Company implements Serializable { 

@Id 
@GeneratedValue 
private Long id; 

@NotNull 
private String name; 

private String address; 

private String city; 

private String country; 

private String email; 

private String phoneNumber; 

@OneToMany(cascade = CascadeType.ALL, mappedBy = "company") 
private Set<Owner> owners = new HashSet<>(); 

public Company() { 
    super(); 
} 

...

i to RestResource dao

import org.springframework.data.repository.PagingAndSortingRepository; 
import org.springframework.data.rest.core.annotation.RestResource; 

import com.domain.Company; 

@RestResource 
public interface CompanyDao extends PagingAndSortingRepository<Company, Long> { 


} 

POST Żądanie API/firm:

{ 
    "address" : "One Microsoft Way", 
    "city" : "Redmond", 
    "country" : "USA", 
    "email" : "[email protected]", 
    "phoneNumber" : "(425) 703-6214" 

} 

Kiedy wystawić POST z pustą nazwą, mam następującą odpowiedź odpoczynku z httpcode 500

{"znacznik czasu": 1455131008472, "status": 500, "błąd": "Wewnętrzny błąd serwera", "wyjątek": "javax.validation.ConstraintViolationException", "bałagan" age ":" Sprawdzanie poprawności nie powiodło się dla klas [com.domain.Company] podczas czasu utrzymywania dla grup [javax.validation.groups.Default,] \ nLista naruszenia ograniczeń: [\ n \ tConstraintViolationImpl {interpolatedMessage = 'nie może być pusty " , propertyPath = name, rootBeanClass = class com.domain.Company, messageTemplate = '{javax.validation.constraints.NotNull.message}'} \ n] "," path ":"/api/companies/"}

próbowałem tworzyć następujące fasoli, ale to nigdy nie wydaje się do niczego:

@Component(value="beforeCreateCompanyValidator") 
public class BeforeCreateCompanyValidator implements Validator{ 

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

@Override 
public void validate(Object arg0, Errors arg1) { 
    System.out.println("xxxxxxxx"); 


} 

} 

a nawet jeśli to nie działa, jak to mi pomóc w tworzeniu lepszej odpowiedzi błędzie z odpowiednim kodem hTTP i zrozumiałej odpowiedzi json ?

tak pomylić

użyciu 1.3.2.RELEASE

<parent> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-parent</artifactId> 
    <version>1.3.2.RELEASE</version> 
    <relativePath/> <!-- lookup parent from repository --> 
</parent> 

Odpowiedz

3

Myślę, że problemem jest to, że walidacja fasoli dzieje się zbyt późno - to odbywa się na poziomie JPA przed utrzymywać. Zauważyłem, że - w przeciwieństwie do sprężynowego mvc - spring-data-rest nie wykonuje sprawdzania fasoli po wywołaniu metody kontrolera. Będziesz potrzebował dodatkowej konfiguracji.

Chcesz reszty danych źródłowych, aby zweryfikować swój komponent - to da ci dobre odpowiedzi na komunikaty o błędach i właściwy kod powrotu HTTP.

skonfigurowałem moje walidacji na wiosnę-data-reszta tak:

@Configuration 
public class MySpringDataRestValidationConfiguration extends RepositoryRestConfigurerAdapter { 

    @Bean 
    @Primary 
    /** 
    * Create a validator to use in bean validation - primary to be able to autowire without qualifier 
    */ 
    Validator validator() { 
     return new LocalValidatorFactoryBean(); 
    } 

    @Bean 
    //the bean name starting with beforeCreate will result into registering the validator before insert 
    public BeforeCreateCompanyValidator beforeCreateCompanyValidator() { 
     return new BeforeCreateCompanyValidator(); 
    } 

    @Override 
    public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) { 
     Validator validator = validator(); 
     //bean validation always before save and create 
     validatingListener.addValidator("beforeCreate", validator); 
     validatingListener.addValidator("beforeSave", validator); 
    } 
} 

Po walidacji fasola i/lub mój zwyczaj walidator znaleźć błędy otrzymam 400 - złe wniosek o ładowności tak:

Status = 400 
    Error message = null 
    Headers = {Content-Type=[application/hal+json]} 
    Content type = application/hal+json 
    Body = { 
    "errors" : [ { 
    "entity" : "siteWithAdminUser", 
    "message" : "may not be null", 
    "invalidValue" : "null", 
    "property" : "adminUser" 
    } ] 
    } 
+0

Super który pracował urok, btw czy jest tak, aby automatycznie adnotacje JSR 303 zostały sprawdzone zamiast 'ręcznego' rzeczy robię tutaj: \t @Override \t public void sprawdzania poprawności (object Object błędy błędy) { \t \t \t \t Firma firmy = (Firma) obiekt; \t \t \t \t if (StringUtils.isEmpty (company.getName())) { \t \t \t errors.rejectValue ("nazwa", "name.required", "Pole Nazwa brakuje"); \t \t} \t \t \t \t \t} – 1977

+0

myślę, że jeśli masz hibernate-walidator na ścieżce klasy powinien być w stanie wykorzystać te ograniczenia adnotacji, a także - na przykład 'org.hibernate.validator.constraints.NotEmpty' –

+0

Zastanawiałem się, dlaczego Twoje rozwiązanie wciąż działa w przypadku tworzenia, a także aktualizacji (ponieważ nie dodałem funkcji BeforeSaveCompanyValidator ..) .. więc zacząłem eksperymentować ... Wygląda na to, Nie potrzebuję nawet funkcji BeforeCreateCompanyValidator lub BeforeUpdateCompanyValidator, ponieważ komponent bean LocalValidatorFactoryBean obsługuje to wszystko. Opublikuję nową wersję twojej klasy w oryginalnym wpisie powyżej. Wygląda na to, że działa świetnie, ale wciąż jest nieco zagmatwany ... – 1977

6

@Mathias wydaje następujące wystarcza JSR 303 adnotacje mają być sprawdzane i za to auto zwraca kod hTTP 400 z ładnymi wiadomości (i nawet nie Nee d BeforeCreateCompanyValidator lub BeforeSaveCompanyValidator klas):

@Configuration 
public class RestValidationConfiguration extends RepositoryRestConfigurerAdapter{ 

@Bean 
@Primary 
/** 
* Create a validator to use in bean validation - primary to be able to autowire without qualifier 
*/ 
Validator validator() { 
    return new LocalValidatorFactoryBean(); 
} 


@Override 
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) { 
    Validator validator = validator(); 
    //bean validation always before save and create 
    validatingListener.addValidator("beforeCreate", validator); 
    validatingListener.addValidator("beforeSave", validator); 
} 

}

odpowiedź 404, { "błędy" [{ "podmiot": "Company", "informacja" "może być zerowy", "invalidValue ":" null "," property ":" name "}, {" entity ":" Company "," message ":" nie może być pusty "," invalidValue ":" null "," property ":" address " }]}

+0

To prawda - wystarczy, jeśli masz tylko przypisane ograniczenia - jeśli potrzebujesz bardziej złożonej weryfikacji, możesz wprowadzić własny weryfikator - i chciałem tylko pokazać, jak to zadziała. . –

+0

Dziękuję za tę odpowiedź, która mnie podsłuchuje już prawie godzinę. Nigdy bym nie zgadł, aby utworzyć LocalValidatorFactoryBean –

0

Odpowiedzi @Mathias i @ 1977 wystarczą dla regularnych połączeń Spring Data REST. Jednak w przypadkach, w których trzeba pisać niestandardowe @RepositoryRestController s przy użyciu @RequestBody i @Valid adnotacji JSR-303 nie działa dla mnie.

Tak, jako dodatek do odpowiedzi, w przypadku niestandardowych @RepositoryRestController sz @RequestBody i @Valid adnotacji Dodałem następujące @ControllerAdvice:

/** 
* Workaround class for making JSR-303 annotation validation work for controller method parameters. 
* Check the issue <a href="https://jira.spring.io/browse/DATAREST-593">DATAREST-593</a> 
*/ 

    @ControllerAdvice 
    public class RequestBodyValidationProcessor extends RequestBodyAdviceAdapter { 

     private final Validator validator; 

     public RequestBodyValidationProcessor(@Autowired @Qualifier("mvcValidator") final Validator validator) { 
      this.validator = validator; 
     } 

     @Override 
     public boolean supports(final MethodParameter methodParameter, final Type targetType, final Class<? extends 
       HttpMessageConverter<?>> converterType) { 
      final Annotation[] parameterAnnotations = methodParameter.getParameterAnnotations(); 
      for (final Annotation annotation : parameterAnnotations) { 
       if (annotation.annotationType().equals(Valid.class)) { 
        return true; 
       } 
      } 

      return false; 
     } 

     @Override 
     public Object afterBodyRead(final Object body, final HttpInputMessage inputMessage, final MethodParameter 
       parameter, final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType) { 
      final Object obj = super.afterBodyRead(body, inputMessage, parameter, targetType, converterType); 
      final BindingResult bindingResult = new BeanPropertyBindingResult(obj, obj.getClass().getCanonicalName()); 
      validator.validate(obj, bindingResult); 
      if (bindingResult.hasErrors()) { 
       throw new RuntimeBindException(bindingResult); 
      } 

      return obj; 
     } 
    }