1概要

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

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

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


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.8.7</version>
</dependency>


spring-webmvc

、https://search.maven.org/classic/の最新バージョン#search%7Cga%7C1%7Ca%3A%22hibernate-validator%22[hibernate-validator]およびhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22jackson-databind%22[jackson-databind]はMaven Centralからダウンロードできます。


3 Spring MVCを使用した検証

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

Spring MVCは、

JSR 349 Bean Validation

specificationアノテーションを使用してサーバーサイドの検証をサポートします。この例では、

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

を除いて、

JSR 349

仕様に属しています。


3.2. Spring MVCコントローラー

新しい

User

オブジェクトを

List

に保存するために使用される

/user

エンドポイントを定義するコントローラクラスを作成しましょう。

リクエストパラメータを通して受け取った

User

オブジェクトの検証を有効にするには、宣言の前に

@ Valid

アノテーションを付ける必要があり、検証エラーは

BindingResult

インスタンスに保持されます。

オブジェクトに無効な値が含まれているかどうかを判断するには、

BindingResult



hasErrors()

メソッドを使用します。


hasErrors()



true

を返す場合、合格しなかった検証に関連するエラーメッセージを含む

JSON array

を返すことができます。

そうでなければ、オブジェクトをリストに追加します。

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

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

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

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

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";
}

AngularJSセクションで、

user.html

ページを詳しく見ていきます。


3.3. Spring MVCの設定

基本的な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

を使用したSpring MVC検証のテスト

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の場合にのみサービスメソッドが呼び出されることがわかります。それでも、この場合、重複したEメールの追加チェックがあります。これはサーバー上でのみ実行でき、

error()

関数で個別に処理されます。

また、フォームが送信されたかどうかを通知する

submitted

変数が定義されています。

最初、この変数は

false

になり、

saveUser()

メソッドが呼び出されると

true

になります。ユーザーがフォームを送信する前に検証メッセージを表示したくない場合は、これを防ぐために

submitted

変数を使用できます。


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>

  • デフォルトのHTML 5検証を防ぎ、独自のものに置き換えるためには、フォームに

    novalidate

    属性を設定する必要があることに注意してください。


sub-subted

変数の値が

true

の場合、

ng-class

属性は

form-error

CSSクラスを動的にフォームに追加します。


ng-submit

属性は、フォームが送信されたときに呼び出されるAngularJSコントローラ関数を定義します。

ng-click

の代わりに

ng-submit

を使用すると、ENTERキーを使用してフォームを送信することにも反応するという利点があります。

それでは、User属性に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、

    そして

    ng-trim


email

フィールドには、クライアント側の電子メール検証に

type

属性と値

email

を使用します。

  • 各フィールド** に対応するエラーメッセージを追加するために、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

    で、

    submitted

    変数も

    true

    です。

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


$ valid

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

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

AngularJS検証では、

ng-valid



ng-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;
}

すべてをまとめてから、有効値と無効値を組み合わせて入力したときのクライアント側フォーム検証の様子の例を見てみましょう。

リンク:/uploads/angularjs-form-validation-260×300.png%20260w[]


5結論

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

いつものように、例のための完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/spring-mvc-forms-jsp[GitHubの上に]を見つけることができます。

アプリケーションを表示するには、実行後に

/userPage

URLにアクセスします。