2016-02-10 15 views
8

: http://docs.spring.io/spring-data/rest/docs/current/reference/html/#validationBahar Veri istirahat Doğrulama Karışıklık

:

Burada yay veri dinlenme geçerliliği hususunda dokümanlar ile kafam karıştı

@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(); 
} 
: Ben düzgün bu kuruluşu var yeni bir Şirket işletmeye bırakmıştır

kurtarmaya çalıştığı bir POST çağrısı için doğrulama ile başa çıkmak için çalışıyorum API/Şirketlere

...

ve bu 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 İsteği:

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

} 

Ben boş adla bir POST çıkardığımızda aşağıdaki dinlenme yanıt almak httpcode 500

{"timestamp": 1455131008472, "status": 500, "error": "İç Sunucu Hatası", "exception": "javax.validation.ConstraintViolationException", "karmaşa age ":" Gruplar için süreklilik süresi [val.alan.Company] için doğrulama başarısız oldu [javax.validation.groups.Default,] \ nYazılım ihlallerinin listesi: [\ n \ tConstraintViolationImpl {interpolatedMessage = 'boş olamaz' , propertyPath = name, rootBeanClass = class com.domain.Company, messageTemplate = '{javax.validation.constraints.NotNull.message}'} \ n] "," yol ":"/api/şirketler/"}

aşağıdaki fasulye oluşturmaya çalıştı, ama asla bir şey yapmak görünüyor:

@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"); 


} 

} 

ve işe bile, bu uygun bir http kodu ve anlaşılır json yanıt ile daha iyi bir hata yanıtını geliştirmede bana yardımcı olacağını nasıl ? Daha önce devam JPA düzeyinde gerçekleştirilir - 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> 

cevap

3

kullanılarak

çok karışık

Ben senin sorunun fasulye doğrulama çok geç oluyor olduğunu düşünüyorum. Bir denetleyici metodu çalıştırıldığında, yay mvc - yay-veri-gerisi aksine, fasulye validasyonu yapmadığını buldum. Bunun için fazladan bir yapılandırmaya ihtiyacınız olacak.

Fasonuzu doğrulamak için yaylı veri istemi istiyorsanız, bu size güzel hata iletileri yanıtları ve uygun bir http dönüş kodu verecektir.

: Böyle bir yükle kötü istek -

@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); 
    } 
} 

fasulye doğrulama ve/veya benim özel doğrulayıcı bir 400 almak hataları bulmak Ne zaman:

böyle yay veri geri kalanında benim doğrulama yapılandırılmış
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

süper Btw otomatik olarak zaten var \t @Override \t public void validate (Object nesnesini hatalar hataları) { \t \t \t: jsr 303 ek açıklamalar ne işim 'manuel' şeyler yerine kontrol ettikten 210 Şirket şirketi = (Şirket) nesne; \t \t \t \t if (StringUtils.isEmpty (company.getName())) { \t \t \t errors.rejectValue ("isim", "name.required", "Ad alanı eksik"); \t \t} \t \t \t \t \t} – 1977

+0

Ben de size üzerinde sınıf hazırda doğrulayıcı varsa bu kısıtlamayı kullanmak gerekir Ek açıklamalar düşünüyorum - örneğin 'org.hibernate.validator.constraints.NotEmpty' –

+0

Çözümünüzün neden olduğu gibi güncellemelerin yanı sıra güncellemeler için de neden çalıştığını merak ettim (bir BeforeSaveCompanyValidator eklemedim ...) .. bu yüzden denemeye başladım ... Görünüşe göre LocalValidatorFactoryBean yapılandırma çekirdeği her şeyi ele aldığından bir BeforeCreateCompanyValidator veya BeforeUpdateCompanyValidator'a bile ihtiyacım yok. Sınıfınızın yeni sürümünü yukarıdaki orijinal gönderide yayınlayacağım. Harika çalışıyor ama yine de biraz kafam karışmış görünüyor ... – 1977

6

@Mathias ben bile nee yok (jsr 303 ek açıklamalar kontrol edilecek için aşağıdaki yeterlidir görünüyor ve bunun için otomatik güzel mesajları ile 400 http kodu döndürebilir d BeforeCreateCompanyValidator veya BeforeSaveCompanyValidator sınıfları):

@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); 
} 

}

yanıt 404, { "hatalar": [{ "varlık": "Company" "mesaj":, "boş olmayabilir" "invalidValue ":" null "," property ":" name "}, {" entity ":" Şirket "," message ":" null olmayabilir "," invalidValue ":" null "," property ":" address " }]}

+0

Doğru - sadece açıklamalı kısıtlamalarınız varsa yeterlidir - eğer daha karmaşık bir doğrulamaya ihtiyacınız varsa, özel bir doğrulayıcı getireceksin - ve bunun nasıl olacağını göstermek istedim . –

+0

Bu cevap için teşekkürler, bu beni neredeyse saatlerce rahatsız ediyor. LocalValidatorFactoryBean yapmak için hiçbir zaman tahmin edemezdim –

0

@Mathias ve @ 1977 tarafından verilen cevaplar, normal Spring Data REST çağrıları için yeterlidir. Ancak, @RequestBody ve @Valid JSR-303 kullanılarak özel @RepositoryRestController s yazmanız gerektiğinde, ek açıklamalar benim için çalışmadı.

Yani, @RequestBody ve @Valid ek açıklama ile özel @RepositoryRestController s durumunda cevap bir ek olarak ben @ControllerAdvice aşağıdaki ekledik: Bir çekicilik çalıştı

/** 
* 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; 
     } 
    }