5

の取り扱いにおいてスプリングブート結合および検証エラーがRESTコントローラ

{ "gender":"INVALID_INPUT" } 

私のRESTコントローラでは、バインディングエラー(genderプロパティの無効なenum値)と検証エラー(nameプロパティはnullにはできません)の両方を処理したいです。

次コントローラのメソッドは動作しません:

@RequestMapping(method = RequestMethod.POST) 
public Profile insert(@Validated @RequestBody Profile profile, BindingResult result) { 
    ... 
} 

これは、結合または検証が行われる前にcom.fasterxml.jackson.databind.exc.InvalidFormatException直列化エラーが発生します。いくつかのあいた後

は、私が何をしたいんこのカスタムコードを思い付いた:

@RequestMapping(method = RequestMethod.POST) 
public Profile insert(@RequestBody Map values) throws BindException { 

    Profile profile = new Profile(); 

    DataBinder binder = new DataBinder(profile); 
    binder.bind(new MutablePropertyValues(values)); 

    // validator is instance of LocalValidatorFactoryBean class 
    binder.setValidator(validator); 
    binder.validate(); 

    // throws BindException if there are binding/validation 
    // errors, exception is handled using @ControllerAdvice. 
    binder.close(); 

    // No binding/validation errors, profile is populated 
    // with request values. 

    ... 
} 

は、基本的にこのコードが何をするか、一般的なマップの代わりに、モデルにシリアライズして、バインドにカスタムコードを使用していますエラーをモデル化してチェックします。

私は、次の質問がある:

  1. は、カスタムコードは、ここに行くための方法ですか春ブーツでこれを行うためのより標準的な方法はありますか?
  2. @Validated注釈はどのように機能しますか?カスタムバインディングコードをカプセル化するために、@Validatedのように機能する独自のカスタムアノテーションを作成するにはどうすればよいですか?

答えて

1

通常、Spring MVCがhttpメッセージ(リクエスト本体など)の読み込みに失敗した場合、例外はHttpMessageNotReadableExceptionという例外をスローします。だから、春があなたのモデルにバインドできない場合、それはその例外をスローする必要があります。また、を使用しない場合メソッドパラメータの各検証対象モデルの後にBindingResultを定義します。検証エラーの場合、春はMethodArgumentNotValidException例外をスローします。このすべてで、ControllerAdviceを作成して、この2つの例外を受け取り、望ましい方法で処理します。

@ControllerAdvice(annotations = {RestController.class}) 
public class UncaughtExceptionsControllerAdvice { 
    @ExceptionHandler({MethodArgumentNotValidException.class, HttpMessageNotReadableException.class}) 
    public ResponseEntity handleBindingErrors(Exception ex) { 
     // do whatever you want with the exceptions 
    } 
} 
+1

デメリットは、バインディングエラーが発生したときにあなたがBindingResultを得ないということです。私。 'MethodArgumentNotValidException'例外で' ex.getBindingResult() 'を実行できますが、' HttpMessageNotReadableException'例外では実行できません。 –

+0

バインディングが失敗した場合、バインディングの結果を得ることができなかったため、後者は妥当と思われます。拘束力はありません。 –

+0

私の見解では、Stringをintフィールドに入れたり、間違ったEnum値を入れたりするようなバインディングエラーは、検証エラーとして扱われるべきです。また、 'DataBinder'スタンドアロンを使用すると、バインディングフィールドエラーが' BindingResult'にありますので、サービスはより詳細なエラー応答を返すことができます。 –

1

私はこれをあきらめました。多くのカスタムコードなしで@RequestBodyを使用してバインディングエラーを取得することはできません。 @RequestBodyはSpringデータバインダーの代わりにJacksonを使用するため、これは単純なJavaBeansの引数にバインドするコントローラーとは異なります。

は、これは私が春ブーツでREST APIを検証するための私のプロジェクトの一つで使用しているどのようなコードであるhttps://jira.spring.io/browse/SPR-6740?jql=text%20~%20%22RequestBody%20binding%22

3

を参照してください、これはあなたが要求と同じではありませんが、同じ..ですこれは

を助けているかどうかを確認
@RequestMapping(value = "/person/{id}",method = RequestMethod.PUT) 
@ResponseBody 
public Object updatePerson(@PathVariable Long id,@Valid Person p,BindingResult bindingResult){ 
    if (bindingResult.hasErrors()) { 
     List<FieldError> errors = bindingResult.getFieldErrors(); 
     List<String> message = new ArrayList<>(); 
     error.setCode(-2); 
     for (FieldError e : errors){ 
      message.add("@" + e.getField().toUpperCase() + ":" + e.getDefaultMessage()); 
     } 
     error.setMessage("Update Failed"); 
     error.setCause(message.toString()); 
     return error; 
    } 
    else 
    { 
     Person person = personRepository.findOne(id); 
     person = p; 
     personRepository.save(person); 
     success.setMessage("Updated Successfully"); 
     success.setCode(2); 
     return success; 
    } 

Success.java

public class Success { 
int code; 
String message; 

public int getCode() { 
    return code; 
} 

public void setCode(int code) { 
    this.code = code; 
} 

public String getMessage() { 
    return message; 
} 

public void setMessage(String message) { 
    this.message = message; 
} 
} 

エラー。Javaの

public class Error { 
int code; 
String message; 
String cause; 

public int getCode() { 
    return code; 
} 

public void setCode(int code) { 
    this.code = code; 
} 

public String getMessage() { 
    return message; 
} 

public void setMessage(String message) { 
    this.message = message; 
} 

public String getCause() { 
    return cause; 
} 

public void setCause(String cause) { 
    this.cause = cause; 
} 

} 

あなたもここで見ることができます。ここSpring REST Validation

関連する問題