2016-02-10 15 views
8

検証エラーの適切な取り扱いに関する春データ、残りの検証といくつかの助けを探して:春データ休憩検証混乱

私はここに春・データ・休息妥当性に関するドキュメントを持つので、混乱している:http://docs.spring.io/spring-data/rest/docs/current/reference/html/#validation

@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(); 
} 
:私は、私は、このエンティティを持って適切に新会社エンティティに

を保存しようとPOST呼び出しの検証に対処しようとしていますAPI /企業へ

...

この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リクエスト:

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

} 

私がnullの名前のPOSTを発行すると、私は次の休みの応答を取得httpコード500

{"タイムスタンプ":1455131008472、 "ステータス":500、 "エラー": "内部サーバーエラー"、 "例外": "javax.validation.ConstraintViolationException"、 "混乱グループの持続時間中にクラス[com.domain.Company]の検証が失敗しました[nu \ tConstraintViolationImpl {interpolatedMessage = 'nullではない可能性があります' \\] "、" path ":"/api/companies/"}

私は、次のBeanを作成してみましたが、何もするらしいことはありません:

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


} 

} 

、それは仕事をした場合でも、どのようにそれが適切なHTTPコードで理解しやすいJSONレスポンスと優れたエラー応答の開発に私を助けるだろう? 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> 

答えて

3

を使用して

ので混乱し、私はあなたの問題は、Beanの検証が遅すぎる起こっていることだと思う - 持続する前には、JPAのレベルで行われています。私は、springメソッドとは異なり、springメソッドは、コントローラメソッドが呼び出されたときにbean検証を実行していないことを発見しました。これにはいくつかの追加設定が必要です。

あなたはbean-data-restがあなたのbeanを検証するようにしたいと思います。これは素晴らしいエラーメッセージ応答と適切なhttpリターンコードを与えます。

私はこのような春-データ-残りの部分で私の検証を構成し:豆の検証および/または私のカスタムバリデータは、私が400受信エラーが見つかったら

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

- このようなペイロードを持つ不正な要求を:

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

スーパーは、ところで自動的にとにかくあり\t @Override \t公共ボイド検証(Objectオブジェクト、エラー・エラー){ \t \t \tを:JSR 303の注釈は、私がここでやっている '手動' のものの代わりにチェックインしました210会社名=(会社)オブジェクト; \t \t \t \t(StringUtils.isEmpty(company.getName())){ \t \t \t errors.rejectValue場合( "名前"、 "name.required"、 "名前フィールドが欠落しています")。例えば ​​- 私はあなたが休止状態-バリデータを持っている場合は、クラスパス上であなたにもこれらの制約のアノテーションを使用することができるはずだと思う \t \t} \t \t \t \t \t} – 1977

+0

'org.hibernate.validator.constraints.NotEmpty' –

+0

私はBeforeSaveCompanyValidatorを追加していないので、あなたのソリューションがまだ作成と更新のために働いていたのか疑問に思っていました。 BeforeCreateCompanyValidatorまたはBeforeUpdateCompanyValidatorは必要ありません。なぜなら、LocalValidatorFactoryBean構成Beanはそれをすべて処理するからです。上記の元の投稿に新しいバージョンのクラスを投稿します。それは本当にうまくいくが、まだちょっと混乱しているようだ... – 1977

6

@Mathias を私も旧姓いけない(JSR 303の注釈をチェックするために、次は十分にあるようで、それのためのautoに素敵なメッセージと400のHTTPコードを返しますD BeforeCreateCompanyValidator又はBeforeSaveCompanyValidatorクラス):

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

}

応答404、{ "エラー":[{ "エンティティ": "会社"、 "メッセージ": "ヌルではないかもしれない"、「invalidValue "null"、 "invalidValue": "null"、 "property": "address": "null"、 "property": "name" }]}

+0

真実 - それはあなたが唯一の注釈付き制約を持っていれば十分である - あなたがカスタムバリデータを導入するより複雑なバリデーションを必要とするならば - そして、 。 –

+0

これはお返事ありがとうございます。私はLocalValidatorFactoryBeanを作ることを決して想像していないでしょう –

0

普通のSpring Data RESTコールでは@Mathiasと@ 1977による回答で十分です。しかし、@RepositoryRestControllerのカスタムを@RequestBody@Validを使用して記述する必要がある場合は、JSR-303アノテーションが機能しませんでした。

ので、答えに加えて、カスタム@RepositoryRestControllerの場合には、私は次のよう@ControllerAdviceを追加しました@RequestBody@Valid注釈付きの:魅力を働いた

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