Spring Bootでの検証

1. 概要

ユーザー入力の検証に関しては、https://www.baeldung.com/spring-boot [Spring Boot]は、この一般的でありながら重要なタスクをすぐに強力にサポートします。
Spring Bootはカスタムバリデータとのシームレスな統合をサポートしていますが、*検証を実行するための事実上の標準はhttp://hibernate.org/validator/[Hibernate Validator] *、https://www.baeldung.com/javax-validationです[Bean Validation framework ']のリファレンス実装。
このチュートリアルでは、* Spring Bootでドメインオブジェクトを検証する方法を見ていきます*。

参考文献:

Spring Bootのカスタム検証メッセージソース

Spring Bootで検証メッセージ用のカスタムMessageSourceを登録する方法を学びます。
link:/spring-custom-validation-message-source [詳細]↠’

Bean検証における@ NotNull、@ NotEmpty、および@NotBlank制約の違い

Javaでの@ NotNull、@ NotEmpty、および@NotBlank Bean検証アノテーションのセマンティクスとそれらの違いを学びます。
link:/java-bean-validation-not-null-empty-blank [続きを読む]↠’

2. Mavenの依存関係

この場合、Spring Bootでドメインオブジェクトを検証する方法を学習します*基本的なRESTコントローラーを構築します*。
コントローラーは最初にドメインオブジェクトを取得し、次にそれをHibernate Validatorで検証し、最後にインメモリーH2データベースに永続化します。
プロジェクトの依存関係はかなり標準的です:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.197</version>
    <scope>runtime</scope>
</dependency>
上記のように、_https://search.maven.org/search?q = g:org.springframework.boot%20AND%20a:spring-boot-starter-web [spring-boot-starter-web] _を_our pom.xml_ファイル。RESTコントローラーの作成に必要になるためです。 さらに、_https://search.maven.org/search?q = g:org.springframework.boot%20AND%20a:spring-boot-starter-data-jpa [spring-bootの最新バージョンを確認してください-starter-jpa] _およびMaven Central上のhttps://search.maven.org/search?q=g:com.h2database%20AND%20a:h2[H2データベース]。

3. 単純なドメインクラス

プロジェクトの依存関係が既に整っているので、次に、JPAエンティティクラスの例を定義する必要があります。このクラスの役割は、ユーザーをモデル化するだけです。
このクラスを見てみましょう:
@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @NotBlank(message = "Name is mandatory")
    private String name;

    @NotBlank(message = "Email is mandatory")
    private String email;

    // standard constructors / setters / getters / toString

}
_User_エンティティクラスの実装は、実にかなり貧弱です。 しかし、Bean Validationの制約を使用して_name_および_email_フィールドを制約する方法を簡単に示しています。
簡単にするために、https://www.baeldung.com/java-bean-validation-not-null-empty-blank [_ @ NotBlank_]制約のみを使用してターゲットフィールドを制約しました。 また、_message_属性でエラーメッセージを指定しました。
したがって、Spring Bootがクラスインスタンスを検証するとき、制約されたフィールドはnullである必要があり、トリミングされた長さはゼロより大きくなければなりません*。
さらに、https://www.baeldung.com/javax-validation [Bean Validation]は、[email protected]_以外にも多くの便利な制約を提供します。これにより、制約されたクラスに異なる検証ルールを適用および結合できます。 詳細については、https://beanvalidation.org/2.0/ [beanの公式検証ドキュメント]を参照してください。
ユーザーをインメモリH2データベースに保存するためにlink:/the-persistence-layer-with-spring-data-jpa[Spring Data JPA]を使用するため、 _User_オブジェクトに基本的なCRUD機能を持たせるためのシンプルなリポジトリインターフェイス:
@Repository
public interface UserRepository extends CrudRepository<User, Long> {}

4. RESTコントローラーの実装

もちろん、_User_オブジェクトの制約フィールドに割り当てられた値を取得できるようにするレイヤーを実装する必要があります。
したがって、検証結果に応じて、それらを検証し、さらにいくつかのタスクを実行できます。
Spring Bootは、RESTコントローラーの実装により、**この一見複雑なプロセスをすべて非常にシンプルにします**。
RESTコントローラーの実装を見てみましょう。
@RestController
public class UserController {

    @PostMapping("/users")
    ResponseEntity<String> addUser(@Valid @RequestBody User user) {
        // persisting the user
        return ResponseEntity.ok("User is valid");
    }

    // standard constructors / other methods

}
link:/rest-with-spring-series[Spring REST context]では、_addUser()_メソッドの実装はかなり標準的です。
もちろん、最も重要な部分は_ @ Valid_アノテーションの使用です。
  • Spring Bootが_ @ Valid_アノテーションが付けられた引数を見つけると、デフォルトのJSR 380実装– Hibernate Validator –を自動的にブートストラップし、引数を検証します。*

    ターゲット引数が検証に合格しなかった場合、Spring Bootはhttps://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/MethodArgumentNotValidException.html[_MethodArgumentNotValidException_]をスローします例外。

5. _ @ ExceptionHandler_アノテーション

Spring Bootが_addUser()_メソッドに渡された_User_オブジェクトを自動的に検証するのは本当に便利ですが、このプロセスの欠けている側面は検証結果の処理方法です。
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html[[email protected]_]注釈*指定されたタイプの処理を許可します単一のメソッドによる例外。*
したがって、検証エラーの処理に使用できます。
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(
  MethodArgumentNotValidException ex) {
    Map<String, String> errors = new HashMap<>();
    ex.getBindingResult().getAllErrors().forEach((error) -> {
        String fieldName = ((FieldError) error).getField();
        String errorMessage = error.getDefaultMessage();
        errors.put(fieldName, errorMessage);
    });
    return errors;
}
_MethodArgumentNotValidException_例外をlink:/exception-handling-for-rest-with-spring [処理する例外]として指定しました。 その結果、Spring Bootは*指定された_User_オブジェクトが無効な場合に*このメソッドを呼び出します*。
このメソッドは、無効な各フィールドの名前と検証後のエラーメッセージを_Map._に保存します。次に、_Map_をさらに処理するためにJSON表現としてクライアントに送り返します。
簡単に言えば、RESTコントローラーを使用すると、さまざまなエンドポイントへの要求を簡単に処理し、_User_オブジェクトを検証し、JSON形式で応答を送信できます。
この設計は、https://www.baeldung.com/spring-boot-crud-thymeleaf [Thymeleaf]などのテンプレートエンジンから、次のようなフル機能のJavaScriptフレームワークに至るまで、いくつかのWeb層を通じてコン​​トローラーの応答を処理するのに十分な柔軟性を備えています。 https://angular.io/[Angular]として。

6. RESTコントローラーのテスト

link:/spring-boot-testing [統合テスト]を使用して、RESTコントローラーの機能を簡単にテストできます。
_UserController_インスタンスと_https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/web/servlet/MockMvc.htmlとともに、_UserRepository_インターフェース実装のモック/自動配線を始めましょう。 [MockMvc] _オブジェクト:
@RunWith(SpringRunner.class)
@WebMvcTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {

    @MockBean
    private UserRepository userRepository;

    @Autowired
    UserController userController;

    @Autowired
    private MockMvc mockMvc;

    //...

}
Webレイヤーのみをテストしているため、https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.htmlを使用します[_ @ WebMvcTest_]アノテーション。 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/によって実装された静的メソッドのセットを使用して、リクエストとレスポンスを簡単にテストできます。 request / MockMvcRequestBuilders.html [_MockMvcRequestBuilders_]および_https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/web/servlet/result/MockMvcResultMatchers.html [MockMvcResultMatchers] _クラス。
ここで、リクエスト本文で渡される有効および無効な_User_オブジェクトを使用して、_addUser()_メソッドをテストしましょう。
@Test
public void whenPostRequestToUsersAndValidUser_thenCorrectResponse() throws Exception {
    MediaType textPlainUtf8 = new MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8"));
    String user = "{\"name\": \"bob\", \"email\" : \"[email protected]\"}";
    mockMvc.perform(MockMvcRequestBuilders.post("/users")
      .content(user)
      .contentType(MediaType.APPLICATION_JSON_UTF8))
      .andExpect(MockMvcResultMatchers.status().isOk())
      .andExpect(MockMvcResultMatchers.content()
        .contentType(textPlainUtf8));
}

@Test
public void whenPostRequestToUsersAndInValidUser_thenCorrectResponse() throws Exception {
    String user = "{\"name\": \"\", \"email\" : \"[email protected]\"}";
    mockMvc.perform(MockMvcRequestBuilders.post("/users")
      .content(user)
      .contentType(MediaType.APPLICATION_JSON_UTF8))
      .andExpect(MockMvcResultMatchers.status().isBadRequest())
      .andExpect(MockMvcResultMatchers.jsonPath("$.name", Is.is("Name is mandatory")))
      .andExpect(MockMvcResultMatchers.content()
        .contentType(MediaType.APPLICATION_JSON_UTF8));
    }
}
さらに、https://www.getpostman.com/ [Postman]やhttps://docs.katalon.com/katalon-studio/などの無料のAPIライフサイクルテストアプリケーションを使用して、RESTコントローラーAPIをテストできます。 new / version-46.html [Katalon Studio]。

7. サンプルアプリケーションの実行

最後に、標準の_main()_メソッドを使用してサンプルプロジェクトを実行できます。
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner run(UserRepository userRepository) throws Exception {
        return (String[] args) -> {
            User user1 = new User("Bob", "[email protected]");
            User user2 = new User("Jenny", "[email protected]");
            userRepository.save(user1);
            userRepository.save(user2);
            userRepository.findAll().forEach(System.out::println);
        };
    }
}
予想どおり、コンソールにいくつかの_User_オブジェクトが出力されます。
有効な_User_オブジェクトを使用したhttp:// localhost:8080 / usersエンドポイントへのPOST要求は、_String_「User is valid」を返します。
同様に、_name_値と_email_値のない_User_オブジェクトを使用したPOST要求は、次の応答を返します。
{
  "name":"Name is mandatory",
  "email":"Email is mandatory"
}

8. 結論

このチュートリアルでは、* Spring Bootで検証を実行する基本を学習しました*。
いつものように、このチュートリアルに示されているすべての例は、https://github.com/eugenp/tutorials/tree/master/spring-boot [GitHub]で入手できます。