1. 概要

検証は、私たちが期待するほど簡単ではありません。 そしてもちろん、ユーザーがアプリケーションに入力した値を検証することは、データの整合性を維持するために非常に重要です。

Webアプリケーションのコンテキストでは、データ入力は通常HTMLフォームを使用して行われ、クライアント側とサーバー側の両方の検証が必要です。

このチュートリアルでは、 AngularJSを使用したフォーム入力のクライアント側検証の実装と、SpringMVCフレームワークを使用したサーバー側検証について説明します。

この記事では、SpringMVCに焦点を当てています。 私たちの記事SpringBootでの検証では、SpringBootで検証を行う方法について説明しています。

2. Mavenの依存関係

まず、次の依存関係を追加しましょう。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.4.0.Final</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>

spring-webmvc hibernate-validator 、およびjackson-databindの最新バージョンはMavenCentralからダウンロードできます。

3. SpringMVCを使用した検証

これは簡単に回避できるため、アプリケーションはクライアント側の検証だけに依存することはできません。 誤った値や悪意のある値が保存されたり、アプリケーションロジックが不適切に実行されたりするのを防ぐには、サーバー側でも入力値を検証することが重要です。

Spring MVCは、 JSR 349 BeanValidation仕様アノテーションを使用してサーバー側の検証をサポートします。 この例では、仕様のリファレンス実装であるhibernate-validatorを使用します。

3.1. データモデル

適切な検証アノテーションが付けられたプロパティを持つUserクラスを作成しましょう。

public class User {

    @NotNull
    @Email
    private String email;

    @NotNull
    @Size(min = 4, max = 15)
    private String password;

    @NotBlank
    private String name;

    @Min(18)
    @Digits(integer = 2, fraction = 0)
    private int age;

    // standard constructor, getters, setters
}

上記で使用されているアノテーションは、hibernate-validatorに固有の@Email@NotBlank を除いて、 JSR349仕様に属しています。 ライブラリ。

3.2. SpringMVCコントローラー

/ user エンドポイントを定義するコントローラークラスを作成しましょう。これは、新しいUserオブジェクトをListに保存するために使用されます。

リクエストパラメータを介して受信したUserオブジェクトの検証を有効にするには、宣言の前に @Valid アノテーションを付ける必要があり、検証エラーはBindingResultに保持されます。 インスタンス。

オブジェクトに無効な値が含まれているかどうかを判断するには、 BindingResulthasErrors()メソッドを使用できます。

hasErrors() true を返す場合、合格しなかった検証に関連するエラーメッセージを含むJSON配列を返すことができます。 それ以外の場合は、オブジェクトをリストに追加します。

@PostMapping(value = "/user")
@ResponseBody
public ResponseEntity<Object> saveUser(@Valid User user, 
  BindingResult result, Model model) {
    if (result.hasErrors()) {
        List<String> errors = result.getAllErrors().stream()
          .map(DefaultMessageSourceResolvable::getDefaultMessage)
          .collect(Collectors.toList());
        return new ResponseEntity<>(errors, HttpStatus.OK);
    } else {
        if (users.stream().anyMatch(it -> user.getEmail().equals(it.getEmail()))) {
            return new ResponseEntity<>(
              Collections.singletonList("Email already exists!"), 
              HttpStatus.CONFLICT);
        } else {
            users.add(user);
            return new ResponseEntity<>(HttpStatus.CREATED);
        }
    }
}

ご覧のとおり、サーバー側の検証には、クライアント側では不可能な追加のチェックを実行できるという利点があります。

この場合、同じ電子メールを持つユーザーがすでに存在するかどうかを確認できます。その場合は、ステータス409CONFLICTを返します。

また、ユーザーのリストを定義し、いくつかの値で初期化する必要があります。

private List<User> users = Arrays.asList(
  new User("[email protected]", "pass", "Ana", 20),
  new User("[email protected]", "pass", "Bob", 30),
  new User("[email protected]", "pass", "John", 40),
  new User("[email protected]", "pass", "Mary", 30));

ユーザーのリストをJSONオブジェクトとして取得するためのマッピングも追加しましょう。

@GetMapping(value = "/users")
@ResponseBody
public List<User> getUsers() {
    return users;
}

Spring MVCコントローラーに必要な最後の項目は、アプリケーションのメインページを返すためのマッピングです。

@GetMapping("/userPage")
public String getUserProfilePage() {
    return "user";
}

user.html ページについては、AngularJSセクションで詳しく説明します。

3.3. SpringMVC構成

基本的なMVC構成をアプリケーションに追加しましょう。

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.baeldung.springmvcforms")
class ApplicationConfiguration implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(
      DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Bean
    public InternalResourceViewResolver htmlViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/WEB-INF/html/");
        bean.setSuffix(".html");
        return bean;
    }
}

3.4. アプリケーションの初期化

WebApplicationInitializerインターフェイスを実装してアプリケーションを実行するクラスを作成しましょう。

public class WebInitializer implements WebApplicationInitializer {

    public void onStartup(ServletContext container) throws ServletException {

        AnnotationConfigWebApplicationContext ctx
          = new AnnotationConfigWebApplicationContext();
        ctx.register(ApplicationConfiguration.class);
        ctx.setServletContext(container);
        container.addListener(new ContextLoaderListener(ctx));

        ServletRegistration.Dynamic servlet 
          = container.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.setLoadOnStartup(1);
        servlet.addMapping("/");
    }
}

3.5. Curlを使用したSpringMVC検証のテスト

AngularJSクライアントセクションを実装する前に、次のコマンドでcURLを使用してAPIをテストできます。

curl -i -X POST -H "Accept:application/json" 
  "localhost:8080/spring-mvc-forms/user?email=aaa&password=12&age=12"

応答は、デフォルトのエラーメッセージを含む配列です。

[
    "not a well-formed email address",
    "size must be between 4 and 15",
    "may not be empty",
    "must be greater than or equal to 18"
]

4. AngularJSの検証

クライアント側の検証は、有効なデータを正常に送信する方法に関する情報をユーザーに提供し、ユーザーがアプリケーションとの対話を継続できるようにするため、ユーザーエクスペリエンスを向上させるのに役立ちます。

AngularJSライブラリは、フォームフィールドに検証要件を追加し、エラーメッセージを処理し、有効なフォームと無効なフォームのスタイルを設定するための優れたサポートを備えています。

まず、検証メッセージに使用されるngMessagesモジュールを挿入するAngularJSモジュールを作成しましょう。

var app = angular.module('app', ['ngMessages']);

次に、前のセクションで構築したAPIを使用するAngularJSサービスとコントローラーを作成しましょう。

4.1. AngularJSサービス

私たちのサービスには、MVCコントローラーメソッドを呼び出す2つのメソッドがあります。1つはユーザーを保存するためのもので、もう1つはユーザーのリストを取得するためのものです。

app.service('UserService',['$http', function ($http) {
	
    this.saveUser = function saveUser(user){
        return $http({
          method: 'POST',
          url: 'user',
          params: {email:user.email, password:user.password, 
            name:user.name, age:user.age},
          headers: 'Accept:application/json'
        });
    }
	
    this.getUsers = function getUsers(){
        return $http({
          method: 'GET',
          url: 'users',
          headers:'Accept:application/json'
        }).then( function(response){
        	return response.data;
        } );
    }

}]);

4.2. AngularJSコントローラー

UserCtrl コントローラーは、 UserService を挿入し、サービスメソッドを呼び出し、応答メッセージとエラーメッセージを処理します。

app.controller('UserCtrl', ['$scope','UserService', function ($scope,UserService) {
	
	$scope.submitted = false;
	
	$scope.getUsers = function() {
		   UserService.getUsers().then(function(data) {
		       $scope.users = data;
	       });
	   }
    
    $scope.saveUser = function() {
    	$scope.submitted = true;
    	  if ($scope.userForm.$valid) {
            UserService.saveUser($scope.user)
              .then (function success(response) {
                  $scope.message = 'User added!';
                  $scope.errorMessage = '';
                  $scope.getUsers();
                  $scope.user = null;
                  $scope.submitted = false;
              },
              function error(response) {
                  if (response.status == 409) {
                    $scope.errorMessage = response.data.message;
            	  }
            	  else {
                    $scope.errorMessage = 'Error adding user!';
            	  }
                  $scope.message = '';
            });
    	  }
    }
   
   $scope.getUsers();
}]);

上記の例では、userForm$validプロパティがtrueの場合にのみサービスメソッドが呼び出されることがわかります。 それでも、この場合、重複する電子メールの追加チェックがあります。これはサーバー上でのみ実行でき、 error()関数で個別に処理されます。

また、フォームが送信されたかどうかを示すsubmitd変数が定義されていることに注意してください。

最初、この変数は false になり、 saveUser()メソッドを呼び出すと、trueになります。 ユーザーがフォームを送信する前に検証メッセージを表示したくない場合は、submitt変数を使用してこれを防ぐことができます。

4.3. AngularJS検証を使用したフォーム

AngularJSライブラリとAngularJSモジュールを利用するには、user.htmlページにスクリプトを追加する必要があります。

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js">
</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-messages.js">
</script>
<script src="js/app.js"></script>

次に、ng-appおよびng-controllerプロパティを設定して、モジュールとコントローラーを使用できます。

<body ng-app="app" ng-controller="UserCtrl">

HTMLフォームを作成しましょう:

<form name="userForm" method="POST" novalidate 
  ng-class="{'form-error':submitted}" ng-submit="saveUser()" >
...
</form>

デフォルトのHTML5検証を防ぎ、独自の検証に置き換えるには、フォームにnovalidate属性を設定する必要があることに注意してください。

ng-class 属性は、submitt変数の値がtrueの場合、 form-errorCSSクラスをフォームに動的に追加します。

ng-submit 属性は、フォームが送信されたときに呼び出されるAngularJSコントローラー関数を定義します。 ng-clickの代わりにng-submitを使用すると、ENTERキーを使用したフォームの送信にも応答するという利点があります。

次に、ユーザー属性の4つの入力フィールドを追加しましょう。

<label class="form-label">Email:</label>
<input type="email" name="email" required ng-model="user.email" class="form-input"/>

<label class="form-label">Password:</label>
<input type="password" name="password" required ng-model="user.password" 
  ng-minlength="4" ng-maxlength="15" class="form-input"/>

<label class="form-label">Name:</label>
<input type="text" name="name" ng-model="user.name" ng-trim="true" 
  required class="form-input" />

<label class="form-label">Age:</label>
<input type="number" name="age" ng-model="user.age" ng-min="18"
  class="form-input" required/>

各入力フィールドには、ng-model属性を介してuser変数のプロパティへのバインドがあります。

検証ルールの設定には、HTML5 required 属性といくつかのAngularJS固有の属性( ng-minglength、ng-maxlength、ng-min、、)を使用します。 X176X]ng-trim。

email フィールドでは、クライアント側の電子メール検証にemailの値を持つtype属性も使用します。

各フィールドに対応するエラーメッセージを追加するために、AngularJSは ng-messages ディレクティブを提供します。このディレクティブは、入力の $ errors オブジェクトをループし、に基づいてメッセージを表示します。各検証ルール。

入力定義の直後にemailフィールドのディレクティブを追加しましょう。

<div ng-messages="userForm.email.$error" 
  ng-show="submitted && userForm.email.$invalid" class="error-messages">
    <p ng-message="email">Invalid email!</p>
    <p ng-message="required">Email is required!</p>
</div>

他の入力フィールドにも同様のエラーメッセージを追加できます。

ブール式のng-showプロパティを使用して、emailフィールドのディレクティブがいつ表示されるかを制御できます。 この例では、フィールドに無効な値がある場合、つまり $invalidプロパティがtrueであり、submited変数もである場合にディレクティブを表示します。 ]true

フィールドに対して一度に表示されるエラーメッセージは1つだけです。

$ valid プロパティに応じて、フィールドが有効な場合は、入力フィールドの後にチェックマーク記号(HEXコード文字✓で表される)を追加することもできます。

<div class="check" ng-show="userForm.email.$valid"></div>

AngularJS検証では、ng-validng-invalidなどのCSSクラス、またはng-invalid-requiredなどのより具体的なクラスを使用したスタイリングもサポートされます。 ]ng-invalid-minlength

フォームのform-errorクラス内の無効な入力に対して、CSSプロパティ border-color:redを追加しましょう。

.form-error input.ng-invalid {
    border-color:red;
}

CSSクラスを使用してエラーメッセージを赤で表示することもできます。

.error-messages {
    color:red;
}

すべてをまとめた後、有効な値と無効な値を組み合わせて入力した場合に、クライアント側のフォーム検証がどのように表示されるかの例を見てみましょう。

5. 結論

このチュートリアルでは、AngularJSとSpringMVCを使用してクライアント側とサーバー側の検証を組み合わせる方法を示しました。

いつものように、例の完全なソースコードはGitHubにあります

アプリケーションを表示するには、実行後に / userPageURLにアクセスします。