spring-mvc 内で一般的な問題と思われるものがあります。ドメイン オブジェクトのいくつかには更新できないフィールドがあるため、私の見解ではこれらのフィールドをバインドしていません。 便宜上、これらをビューから除外する方法は、spring-roo scaffolded ビューを編集して、パラメーターの render 属性を false に設定することです。
spring-mvc は既存のオブジェクトを更新するのではなく、オブジェクトの新しいインスタンスを作成するため、これらのフィールドは null です。ただし、これは、コントロールがコントローラーに到達する前に、オブジェクトが検証に失敗することを意味します。
私のエンティティの多くには、ビューで更新できない追加のフィールドがあるため、同じ作業を何度も繰り返し行う (DRY に違反する) のではなく、一般的な解決策を考え出すことができるようにしたいと考えています。
フィールドがビューから省略されている場合、一貫した方法で検証を行うにはどうすればよいでしょうか?
@RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String UserController.update(@Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, user);
return "admin/users/update";
}
uiModel.asMap().clear();
user.merge();
return "redirect:/admin/users/" + encodeUrlPathSegment(user.getId().toString(), httpServletRequest);
}
可能な解決策:
コントローラーから @Valid アノテーションを省略します。
長所
- 実装が簡単。
- わかりやすい。
短所
- すべてのオブジェクトの更新ごとにコントローラーメソッドを変更することを意味します。
- 検証は、アプリケーションの残りのすべてと同じ場所では発生していません。
- バインディング エラーをビューに戻す簡単な方法がない (後でオブジェクトを検証する必要がある)
省略されたフィールドが必要なメソッドのカスタム バリデーターを追加する
例:
@InitBinder
public void initBinder(WebDataBinder binder, HttpServletRequest request) {
if (request.getMethod().equals("PUT")) {
binder.setDisallowedFields("registrationDate", "password");
Validator validator = binder.getValidator();
Validator userUpdateValidator = new UserUpdateValidator();
binder.setValidator(userUpdateValidator);
}
}
長所
- 清流。
短所
- DRYの問題にひどく苦しんでいます。これは、ドメイン オブジェクトが何らかの方法で変更された場合、再検証する必要があることを意味します。
- フィールドの検証は、保存時の Hibernate の検証とは異なります。
- 検証を省略して手動で検証するよりも具体的な利点はありません。
もしあれば検討しますか?
- カスタムバリデーターは、標準の JSR-303 バリデーターに委任できますが、フィールドを省略できます。
ドメイン オブジェクトから JSR-303 アノテーションを削除する
オプションではありません。これは、オブジェクトを保存する前に検証が行われないことを意味します。さらに悪いことに、データベース用に作成された DDL に影響を与え、DB 自体から制約が取り除かれると思います。完全を期すためにここに入れるだけです
検証が行われる前にドメイン オブジェクトをルックアップする
このソリューションの考え方は、更新する前に既存のドメイン オブジェクトを検索することです。null 以外のフィールドをリクエストから古いオブジェクトにコピーします。 長所 - 検証は通常のサイクルで実行できます。- 意味するメソッドに応じて検証を変更する必要はありません。
短所
- コントローラーを叩く前のデータベースアクセスはちょっと臭い。
- これを実装する方法がわかりません。
- オブジェクトのライフサイクルの他の段階で省略する必要があるフィールドでは機能しません。たとえば、作成中にタイムスタンプを追加する場合。
標準の JSR-303 バリデーターに委任するバリデーターを実装する方法、またはオブジェクトを変更する前にルックアップする方法を知りたいです。または、他に考えられる解決策があれば教えてください。
これらのソリューションのいずれかにより、複数のオブジェクトに対して処理を一貫させることができます。
うまくいけば、次のような注釈を追加できるようになります。@RooCreateOnly は、ドメイン オブジェクトにアノテーションを付けて、すべての検証定義を 1 か所に残すことができることを意味します。