かなり長い間、SpringMVCアプリケーションのどこでユーザー入力の検証を行うべきかを理解しようとしています。多くのオンラインブログやチュートリアルでは、基本的に、コントローラーがユーザー入力を検証し、無効な場合はエラーメッセージを含むページを表示してユーザーに応答する必要があることを読みました。ただし、SpringおよびSpring MVCレイヤーシステムについての私の現在の理解は、コントローラーはアプリケーションロジック(サービスレイヤー)と「Webワールド」の間の唯一の浅いインターフェイスであり、Webからサービスレイヤーを使用できるようにすることです。また、私が見る限り、SpringMVCはコントローラーでの検証に適したツールしか提供していません。
検証がコントローラーで行われる場合、後でアプリケーションロジックを「Webワールド」から切り離したい場合は、検証ロジックを新しい環境(Swingを使用するデスクトップアプリケーションなど)に再実装する必要があります。私の意見では、ドメインオブジェクトで「有効」な操作と、そのようなオブジェクトが持つ可能性のある「有効な」状態を決定する機能は、サービスレイヤーのコア部分であり、アプリケーションの他の部分の問題ではありません(例:コントローラー)。
このコンテキストで、入力検証ロジックをサービスレイヤーではなくコントローラーレイヤーに配置することが「グッドプラクティス」であるのはなぜですか。
一般的なアプローチは、両方の場所で検証を行うことです。しかし、@ Validについて話している場合、私の経験から、コントローラーレベルに置く方が良いでしょう。
また、話している検証ロジックの種類によっても異なります。あなたが豆を持っているとしましょう:
@Data
public class MyBean {
@NotNull private UUID someId;
@NotEmpty private String someName;
}
このBeanにコントローラーレベルで@Valid
の注釈を付けて、サービスに到達しないようにすることは理にかなっています。 @Valid
をサービスメソッドに配置するメリットはありません。コントローラーですぐにその種類が有効かどうかを判断できるのに、なぜそれをさらに伝播するのでしょうか。
次に、2番目のタイプの検証があります。ビジネスロジック検証です。同じBeanについて、someIdプロパティがtimeUUidであり、そのタイムスタンプはイベントが発生してから最大2日である必要があるとします。それ以外の場合、Beanはサービスによって破棄される必要があります。
これはビジネスロジックの検証ケースのように思えます。なぜなら、Beanを見るだけでは、何らかのロジックを適用しない限り、それを検証することはできないからです。
検証への両方のアプローチは実際には異なるものを検証するため、MVCコンポーネント(モデル、ビュー、コントローラー)のそれぞれが独自の検証を行うことは明らかであり、他のコンポーネントに依存することなく検証するものについて合理的である必要があります。
ユーザーにエラーを表示することに関しては、はい、 Errors オブジェクトは、実際にはコントローラーレベルでのBean検証に使用することを目的としていますが、任意のレベルで例外をキャッチし、きれいな形式にするフィルターを設計できます。ユーザーのために。それには多くのアプローチがあり、Springが他よりも優れているとSpringが規定しているかどうかはわかりません。
さまざまな解決メカニズム(たとえば、jstlやjacksonなど)に応じて、あなたはおそらく別の方法で検証を処理する傾向があります。たとえば、従来の jstlビューリゾルバー はエラーを使用するコントラクションでうまく機能しますが、 ジャクソンリゾルバー はおそらく @ ResponseBody およびエラーをキャッチし、それらを応答オブジェクトの事前定義されたエラー部分に配置するフィルター。
以前のプロジェクトの1つでは、非常に複雑なロジックを備えた巨大なフォームがあり、コードの検証が多くなりました。そこで、3番目の種類のソリューションを使用しました。すべてのコントローラーについて、ヘルパークラスを自動配線しました。例:
myview <-> MyController <- MyService <- MyDAO
^
|
MyHelper
Controllers
はビューの解決を処理しました。Services
は、dto-sからビュー用のモデルオブジェクトへのマッピング、およびその逆のマッピングを処理しました。DAO-s
データベーストランザクションを処理し、Helpers
は、検証を含む他のすべてを処理しました。
もし誰かがフロントエンドをウェブから他のものに変えたいと思っていたら、それはずっと簡単だったでしょう、そして同時に、私たちはサービス実装クラスを過度に膨らませませんでした。