どのように春/春ブーツでパラメータのチェックを行いますか?あなたがここに知っておく必要があるすべて!

この記事では、元の著者である、最初の有名なアドレスのテキストで再現場合はオープンの公共の数字が白転載ため、お申し込みください。

ガイド-springboot:春ブートチュートリアル(一緒に暇な時間の保守、メンテナンス歓迎)初心者に適しただけでなく、経験豊富な開発者のアクセス。

データ検証の重要性は、その後、再びそれを確認HTTPツールの数によってブラウザバイパスへの直接ユーザーを避けるためにも、フロントエンドのデータ検証の場合には、我々はまだ、着信バックエンドデータを持って、言ったことはなかっただろうバックエンドのデータにいくつかの違法直接リクエスト。

プロジェクトの彼の実務経験と組み合わせるこの記事では、と言うことができる友人はあなたが学ぶことができます理解していない、あなたはすぐにプロジェクトをバックアップするために練習することができ、記事の内容は非常に実用的な記述します。

今私はどのように、特に春の番組プログラムによって、Javaプログラムのインスタンスのパラメータの優雅検証で実証します。

ビルド・インフラストラクチャ

その依存関係

通常のJavaプログラムの開発する場合は、次のようにこれに依存する必要がする必要があるかもしれません。

   <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.9.Final</version>
   </dependency>
   <dependency>
             <groupId>javax.el</groupId>
             <artifactId>javax.el-api</artifactId>
             <version>3.0.0</version>
     </dependency>
     <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.6</version>
     </dependency>

使用春のブートプログラムは、その後、ちょうどspring-boot-starter-web十分な、それの依存子は、私たちが必要なものを含めます。この依存性に加えて、以下のデモもそうその依存関係に追加することを忘れないでください、ロンボクを使用しています。

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

Entityクラス

以下のものを用い、エンティティ・クラスの一例です。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    @NotNull(message = "classId 不能为空")
    private String classId;

    @Size(max = 33)
    @NotNull(message = "name 不能为空")
    private String name;

    @Pattern(regexp = "((^Man$|^Woman$|^UGM$))", message = "sex 值不在可选范围")
    @NotNull(message = "sex 不能为空")
    private String sex;

    @Email(message = "email 格式不正确")
    @NotNull(message = "email 不能为空")
    private String email;

}

正規表現の説明:

- ^string : 匹配以 string 开头的字符串
- string$ :匹配以 string 结尾的字符串
- ^string$ :精确匹配 string 字符串
- ((^Man$|^Woman$|^UGM$)) : 值只能在 Man,Woman,UGM 这三个值中选择

ます。https:次のセクションから参照チェックノートの内容を示して//www.cnkirito.moe/spring-validation/、@感謝徐Jingfeng

JSR申し出は、注意事項をご確認ください

  • @Null 注釈付き要素がnullでなければなりません
  • @NotNull 注釈付きの要素はnullであってはなりません
  • @AssertTrue 注釈付きされている要素が真でなければなりません
  • @AssertFalse 注釈付きされている要素はfalseでなければなりません
  • @Min(value) 注釈付き要素は、値が指定された最小値よりも大きくなければならない数でなければなりません
  • @Max(value) 注釈付き要素は、指定されたに等しい最大値未満でなければならない数でなければなりません
  • @DecimalMin(value) 注釈付き要素は、値が指定された最小値よりも大きくなければならない数でなければなりません
  • @DecimalMax(value) 注釈付き要素は、指定されたに等しい最大値未満でなければならない数でなければなりません
  • @Size(max=, min=) 指定された範囲内に注釈されるべき要素のサイズ
  • @Digits (integer, fraction) 注釈付き要素は、その値が許容範囲内でなければならない数でなければなりません
  • @Past 注釈付き要素は、過去の日付でなければなりません
  • @Future 注釈付き要素は、将来の日付でなければなりません
  • @Pattern(regex=,flag=) 注釈付きされている要素は、指定された正規表現を満たす必要があります。

Hibernateバリは、検証のアノテーションを提供します

  • @NotBlank(message =) 認証文字列がnullでなく、長さが0より大きくなければなりません
  • @Email 注釈付き要素は、電子メールアドレスでなければなりません
  • @Length(min=,max=) 文字列のサイズが指定された範囲内でなければなりません
  • @NotEmpty 注釈付きの文字列はnullであってはなりません
  • @Range(min=,max=,message=) 要素は、適切な範囲で注釈を付けなければなりません

入力コントローラの検証

検証要求ボディ(requestBody)

コントローラ:

私たちは、追加のパラメータを確認する必要があり@Valid、検証が失敗した場合、それは投げ、コメントをMethodArgumentNotValidExceptionデフォルトでは、春は非常にHTTPステータス400(不正な要求)には、この変換されます。


@RestController
@RequestMapping("/api")
public class PersonController {

    @PostMapping("/person")
    public ResponseEntity<Person> getPerson(@RequestBody @Valid Person person) {
        return ResponseEntity.ok().body(person);
    }
}

exceptionHandlerの:

カスタム例外ハンドラは、私たちは例外、およびいくつかの簡単な処理をキャッチすることができます。場合は、理解していないコードを扱う以下の例外のために、あなたは記事を参照することができ、「いくつかの一般的な異常姿勢のSpringBoot治療を」

@ControllerAdvice(assignableTypes = {PersonController.class})
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<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 ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errors);
    }
}

テストを通じて検証:

私は発効は、もちろん、あなたはまた、ポストマンツールでこれを確認できることを確認しMockMvcコントローラーのシミュレーションにより、次のように要求します。

我々は、すべての状況の正確なパラメータを入力してみてください。

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class PersonControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void should_get_person_correctly() throws Exception {
        Person person = new Person();
        person.setName("SnailClimb");
        person.setSex("Man");
        person.setClassId("82938390");
        person.setEmail("[email protected]");

        mockMvc.perform(post("/api/person")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(objectMapper.writeValueAsString(person)))
                .andExpect(MockMvcResultMatchers.jsonPath("name").value("SnailClimb"))
                .andExpect(MockMvcResultMatchers.jsonPath("classId").value("82938390"))
                .andExpect(MockMvcResultMatchers.jsonPath("sex").value("Man"))
                .andExpect(MockMvcResultMatchers.jsonPath("email").value("[email protected]"));
    }
}

認証は、不正な状況が例外をスローし、正確に捉えることができるパラメータ。

 @Test
    public void should_check_person_value() throws Exception {
        Person person = new Person();
        person.setSex("Man22");
        person.setClassId("82938390");
        person.setEmail("SnailClimb");

        mockMvc.perform(post("/api/person")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(objectMapper.writeValueAsString(person)))
                .andExpect(MockMvcResultMatchers.jsonPath("sex").value("sex 值不在可选范围"))
                .andExpect(MockMvcResultMatchers.jsonPath("name").value("name 不能为空"))
                .andExpect(MockMvcResultMatchers.jsonPath("email").value("email 格式不正确"));
    }

次のように検証結果を使用して郵便配達は以下のとおりです。

ポストマン検証結果

パラメータの検証要求(パス変数とリクエストパラメータ)

コントローラ:

必ずクラスに追加することを忘れないようにする必要がありますValidatedノート、このパラメータは、メソッドのパラメータをチェックするために春を告げることができます。

@RestController
@RequestMapping("/api")
@Validated
public class PersonController {

    @GetMapping("/person/{id}")
    public ResponseEntity<Integer> getPersonByID(@Valid @PathVariable("id") @Max(value = 5,message = "超过 id 的范围了") Integer id) {
        return ResponseEntity.ok().body(id);
    }

    @PutMapping("/person")
    public ResponseEntity<String> getPersonByName(@Valid @RequestParam("name") @Size(max = 6,message = "超过 name 的范围了") String name) {
        return ResponseEntity.ok().body(name);
    }
}

exceptionHandlerの:

    @ExceptionHandler(ConstraintViolationException.class)
    ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
    }

テストを通じて検証:

  @Test
    public void should_check_param_value() throws Exception {

        mockMvc.perform(get("/api/person/6")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isBadRequest())
                .andExpect(content().string("getPersonByID.id: 超过 id 的范围了"));
    }

    @Test
    public void should_check_param_value2() throws Exception {

        mockMvc.perform(put("/api/person")
                .param("name","snailclimbsnailclimb")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isBadRequest())
                .andExpect(content().string("getPersonByName.name: 超过 name 的范围了"));
    }

認証方式のサービス

我々はまた、任意の入力春のコンポーネントは、レベルコントローラの入力を検証するのではなく、我々が使用できることを確認することができます@Validatedし、@Valid要件コメントのこの組み合わせを達成するために。

必ずクラスに追加することを忘れないようにする必要がありますValidatedノート、このパラメータは、メソッドのパラメータをチェックするために春を告げることができます。

@Service
@Validated
public class PersonService {

    public void validatePerson(@Valid Person person){
        // do something
    }
}

テストを通じて検証:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class PersonServiceTest {
    @Autowired
    private PersonService service;

    @Test(expected = ConstraintViolationException.class)
    public void should_throw_exception_when_person_is_not_valid() {
        Person person = new Person();
        person.setSex("Man22");
        person.setClassId("82938390");
        person.setEmail("SnailClimb");
        service.validatePerson(person);
    }

}

Validatorは、手動でプログラミングパラメータを検証します

私たちは、手動でいくつかのシーンをチェックし、検証結果を取得する必要があるかもしれません。

    @Test
    public void check_person_manually() {

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        Person person = new Person();
        person.setSex("Man22");
        person.setClassId("82938390");
        person.setEmail("SnailClimb");
        Set<ConstraintViolation<Person>> violations = validator.validate(person);
        //output:
        //email 格式不正确
        //name 不能为空
        //sex 值不在可选范围
        for (ConstraintViolation<Person> constraintViolation : violations) {
            System.out.println(constraintViolation.getMessage());
        }
    }

私たちの上にValidatorファクトリクラスを取得するためにValidatorあなたがすることもでき、もちろん、例を@Autowired直接注入する方法。しかし、非春のコンポーネントのクラスでは、この方法では、それが唯一のファクトリクラスによって得ることができますValidator

@Autowired
Validator validate

バリデータとカスタマイズ(実用)

チェックは注釈がニーズを満たすことができない来る場合は、実装上の注意をカスタマイズすることができます。

ケース:チェック特定のフィールド選択可能な範囲かどうか

例えば、我々は今、このような要望を持っている:人クラス1つの以上のフィールド領域のみフィールド領域ChinaChina-TaiwanChina-HongKong1で3。

最初のステップは、あなたはコメントを作成する必要があります。

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = RegionValidator.class)
@Documented
public @interface Region {

    String message() default "Region 值不在可选范围内";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

第二のステップは、あなたが実装する必要があるConstraintValidatorインターフェイスを、そしてオーバーライドするisValid方法を:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;

public class RegionValidator implements ConstraintValidator<Region, String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        HashSet<Object> regions = new HashSet<>();
        regions.add("China");
        regions.add("China-Taiwan");
        regions.add("China-HongKong");
        return regions.contains(value);
    }
}

今、あなたはこのコメントを使用することができます。

    @Region
    private String region;

ケースII:チェックの電話番号

私たちの電話番号を確認し、これは正規表現を介して行うことができ、正当なものであるに関連する正規表現がオンラインで見つけることができ、あなたも、特定の事業者の電話番号セクションに正規表現を検索することができます。

PhoneNumber.java

import javax.validation.Constraint;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Constraint(validatedBy = PhoneNumberValidator.class)
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface PhoneNumber {
    String message() default "Invalid phone number";
    Class[] groups() default {};
    Class[] payload() default {};
}

PhoneNumberValidator.java

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber,String> {

    @Override
    public boolean isValid(String phoneField, ConstraintValidatorContext context) {
        if (phoneField == null) {
            // can be null
            return true;
        }
        return phoneField.matches("^1(3[0-9]|4[57]|5[0-35-9]|8[0-9]|70)\\d{8}$") && phoneField.length() > 8 && phoneField.length() < 14;
    }
}

取得し、我々は今、この注釈付きを使用することができます。

@PhoneNumber(message = "phoneNumber 格式不正确")
@NotNull(message = "phoneNumber 不能为空")
private String phoneNumber;

使用検証グループ

単純なポイントは、オブジェクトの検証作業の異なる方法で異なるルールがあるということです、このプロジェクトの私の現在の経験を次の例は、(あまりを使用することであると述べた我々はそれがあるかもしれないと述べたグループを、確認するために使用する必要がありますいくつかのシナリオの下では、明確ではありませんコード自体はこのレベルが)たくさんの悩みを書くために、その後、理解するための多くの問題ですので。

二つのインターフェースを作成します。

public interface AddPersonGroup {
}
public interface DeletePersonGroup {
}

私たちは、グループを確認するためにこれを使用することができます

@NotNull(groups = DeletePersonGroup.class)
@Null(groups = AddPersonGroup.class)
private String group;
@Service
@Validated
public class PersonService {

    public void validatePerson(@Valid Person person) {
        // do something
    }

    @Validated(AddPersonGroup.class)
    public void validatePersonGroupForAdd(@Valid Person person) {
        // do something
    }

    @Validated(DeletePersonGroup.class)
    public void validatePersonGroupForDelete(@Valid Person person) {
        // do something
    }

}

テストを通じて検証:

  @Test(expected = ConstraintViolationException.class)
    public void should_check_person_with_groups() {
        Person person = new Person();
        person.setSex("Man22");
        person.setClassId("82938390");
        person.setEmail("SnailClimb");
        person.setGroup("group1");
        service.validatePersonGroupForAdd(person);
    }

    @Test(expected = ConstraintViolationException.class)
    public void should_check_person_with_groups2() {
        Person person = new Person();
        person.setSex("Man22");
        person.setClassId("82938390");
        person.setEmail("SnailClimb");
        service.validatePersonGroupForDelete(person);
    }

注意しなければならない。このように、検証グループを使用し、これはアンチパターンである、それは貧しいコードのロジックになります。

コードのアドレスします。https://github.com/Snailclimb/springboot-guide/tree/master/source-code/advanced/bean-validation-demo

@NotNullVS @Column(nullable = false)(重要)

JPA動作するデータを使用しているとき、私たちはしばしば遭遇する@Column(nullable = false)拘束のこのタイプを、それと@NotNullはどのような違いを生むのでしょうか?これは非常に重要であることを理解!

  • @NotNullJSR 303ビーン検証が承認され、それがデータベースの制約自体とは何の関係もありません。
  • @Column(nullable = false) :JPAは、空でないアプローチとして宣言されています。

結論は、後者は、データベーステーブルにテーブル制約を作成する場合を示すために使用される前者は、検証するために使用されることです。

ALL

  • []原理分析

参照

  • https://reflectoring.io/bean-validation-with-spring-boot/
  • https://www.cnkirito.moe/spring-validation//

推奨されるオープンソースプロジェクト

他のオープンソースプロジェクトの推薦:

  1. JavaGuide:Javaの学習[+]面接ガイドは、Javaプログラマの大半はコアな知識を習得する必要がカバーしています。
  2. ガイド-springboot:春ブートチュートリアル(一緒に暇な時間の保守、メンテナンス歓迎)初心者に適しただけでなく、経験豊富な開発者のアクセス。
  3. 進歩-プログラマー:私は技術スタッフが、いくつかの良い習慣を持つべきだと思います!
  4. -security-JWTスプリングガイド:ゼロから始めましょう!(検証機関を含む)春のセキュリティが強化されたJWTコードの後端部。

おすすめ

転載: www.cnblogs.com/javaguide/p/11832752.html