2016-02-10 24 views
8

Nhìn đối với một số giúp đỡ với dữ liệu mùa xuân còn lại xác nhận liên quan đến việc xử lý đúng lỗi xác nhận:mùa xuân dữ liệu Nghỉ ngơi Validation Lẫn lộn

Tôi rất bối rối với các tài liệu liên quan đến xác nhận mùa xuân-dữ liệu còn lại ở đây: http://docs.spring.io/spring-data/rest/docs/current/reference/html/#validation

tôi cố gắng để đối phó đúng với xác nhận cho một cuộc gọi POST mà cố gắng để tiết kiệm một thực thể công ty mới

tôi đã tổ chức này:

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

...

và RestResource này 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 Yêu cầu api/Công ty:

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

} 

Khi tôi phát hành một POST với một tên null, tôi nhận được câu trả lời còn lại sau với httpcode 500

{"dấu thời gian": 1455131008472, "trạng thái": 500, "lỗi": "Lỗi máy chủ nội bộ", "ngoại lệ": "javax.validation.ConstraintViolationException", "mess tuổi ":" Xác thực không thành công cho các lớp [com.domain.Company] trong thời gian tồn tại cho các nhóm [javax.validation.groups.Default,] \ nDanh sách các vi phạm ràng buộc: [\ n \ tConstraintViolationImpl {interpolatedMessage = 'có thể không rỗng' , propertyPath = name, rootBeanClass = class com.domain.Company, messageTemplate = '{javax.validation.constraints.NotNull.message}'} \ n] "," đường dẫn ":"/api/companies/"}

tôi đã cố gắng tạo ra các hạt sau, nhưng nó không bao giờ có vẻ làm bất cứ điều gì:

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


} 

} 

và thậm chí nếu nó đã làm việc, làm thế nào nó sẽ giúp tôi trong việc phát triển một phản ứng lỗi tốt hơn với một mã http phù hợp và đáp ứng json hiểu ?

rất bối rối

sử dụng 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> 

Trả lời

3

Tôi nghĩ vấn đề của bạn là hợp lệ đậu đang xảy ra quá muộn - nó được thực hiện trên mức JPA trước vẫn tồn tại. Tôi thấy rằng - không giống như mùa xuân mvc - spring-data-rest không thực hiện xác thực bean khi một phương thức điều khiển được gọi. Bạn sẽ cần một số cấu hình bổ sung cho việc này.

Bạn muốn phần còn lại dữ liệu của mùa xuân để xác thực bean của bạn - điều này sẽ cung cấp cho bạn phản hồi thư lỗi đẹp và mã trả về http thích hợp.

tôi cấu hình xác nhận của tôi trong mùa xuân-dữ liệu còn lại như thế này:

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

Khi xác đậu và/hoặc validator tùy chỉnh của tôi tìm thấy lỗi tôi nhận được một 400 - yêu cầu xấu với một tải trọng như thế này:

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

siêu mà làm việc một nét duyên dáng, btw là có anyway để tự động đã JSR 303 chú thích kiểm tra thay vì những thứ 'thủ công' tôi đang làm ở đây: \t @ Override \t public void xác nhận (đối tượng Object, lỗi lỗi) { \t \t \t \t Công ty công ty = (Công ty) đối tượng; \t \t \t \t if (StringUtils.isEmpty (company.getName())) { \t \t \t errors.rejectValue ("tên", "name.required", "điền ô Name là mất tích"); \t \t} \t \t \t \t \t} – 1977

+0

Tôi nghĩ rằng nếu bạn có ngủ đông-validator trên classpath bạn sẽ có thể sử dụng các chế chú thích cũng - ví dụ 'org.hibernate.validator.constraints.NotEmpty' –

+0

Tôi đã tự hỏi tại sao giải pháp của bạn vẫn hoạt động để tạo cũng như cập nhật (vì tôi chưa thêm một BeforeSaveCompanyValidator ..) .. vì vậy tôi bắt đầu thử nghiệm ... Có vẻ như Tôi thậm chí không cần một BeforeCreateCompanyValidator hoặc BeforeUpdateCompanyValidator vì bean cấu hình LocalValidatorFactoryBean xử lý tất cả. Tôi sẽ đăng phiên bản mới của lớp học của bạn trong bài đăng gốc ở trên. Nó dường như làm việc tuyệt vời nhưng vẫn còn một chút nhầm lẫn ... – 1977

6

@Mathias có vẻ như sau đây là đủ cho JSR 303 chú thích để được kiểm tra và cho nó tự động trả về một mã http 400 với những thông điệp tốt đẹp (tôi không thậm chí nee d BeforeCreateCompanyValidator hoặc BeforeSaveCompanyValidator lớp):

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

}

phản ứng 404, { "lỗi": [{ "thực thể": "Công ty", "message": "có thể không được null", "invalidValue ":" null "," property ":" name "}, {" entity ":" Company "," message ":" không được rỗng "," invalidValue ":" null "," property ":" address " }]}

+0

Đúng - nó là đủ nếu bạn chỉ có các ràng buộc có chú thích - nếu bạn cần xác nhận phức tạp hơn, bạn sẽ giới thiệu một trình xác nhận tùy chỉnh - và tôi chỉ muốn hiển thị nó sẽ hoạt động như thế nào . –

+0

Cảm ơn câu trả lời này, điều này đã khiến tôi nhớ đến gần như bây giờ. Tôi sẽ không bao giờ đoán để làm cho một LocalValidatorFactoryBean –

0

Câu trả lời của @Mathias và @ 1977 là đủ cho các cuộc gọi Spring Data REST thông thường. Tuy nhiên, trong trường hợp bạn cần viết các chú thích tùy chỉnh @RepositoryRestController s bằng cách sử dụng các chú thích @RequestBody@Valid JSR-303 không hoạt động đối với tôi.

Vì vậy, như một sự bổ sung cho câu trả lời, trong trường hợp tùy chỉnh @RepositoryRestController s với @RequestBody@Valid chú thích Tôi đã thêm sau @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; 
     } 
    } 
Các vấn đề liên quan