Early form of parameter verification

In the early days of Java, parameter verification stopped at the code level after obtaining parameters, like the following operations:

@PostMapping("/test")
public String test(@RequestBody TestRequest request) {
  if (StringUtils.isEmpty(request.getName())) {
      return "Name cannot be empty.";
  }
  if (request.getName().length() > 6) {
      return "Name length cannot exceed 6";
  }
  if (StringUtils.isEmpty(request.getPhone())) {
      return "The phone cannot be empty.";
  }
  if(! isPhone(request.getPhone())) {return "Incorrect phone number format";
  }

  return "SUCCESS";
}
/** * verify phone format */
private boolean isPhone(String phone) {
  return true;
}
Copy the code

As seen in the code, each verification rule needs to be implemented in the code, so even parameter verification will cost developers a lot of energy, and the development efficiency will be greatly reduced.

JSR – 303

A Specification has been released in Java 6: JSR-303. JSR stands for Java Specification Requests, also known as Bean Validation.

JSR 303 is a standard framework provided by Java for bean data validation. Hibernate Validator is a reference implementation of Bean Validation.

Jsr-303 Parameter verification remarks

Built-in annotations in Bean Validation

Hibernate Validator additional annotations

Use JSR303 specification for parameter verification

We will modify the above code that does not use JSR303

@Data
public class TestRequest {
  @NotEmpty(message = "Name cannot be empty.")
  @Length(min = 1, max = 6, message = "The name must be 1-6 in length.")
  private String name;

  @NotBlank(message = "Phone number cannot be empty.")
  @Pattern(regexp = "134-8 0 ^ \ \ d {7} $| ^ 13 [^ 4] \ \ d {8} $| ^ 14 [5-9] \ \ d {8} $| ^ 15 [^ 4] \ \ d {8} $| ^ 16 [6] \ \ d {8} $| ^ 17 [0 to 8] \ \ d {8} $| ^ 18 [\ \ d] {9} $| ^ 19 [8, 9] \ \ d {8 } $", message = "Incorrect phone number format")
  private String phone;

  @Email(message = "Mail format is incorrect")
  private String email;

  @NotNull(message = "Age cannot be empty.")
  @Max(value = 18,message = "No older than 18.")
  private Integer age;
}
Copy the code

Check the controller with @valid

@PostMapping("/test")
public String test(@RequestBody @Valid TestRequest request) {
    return "SUCCESS";
}
Copy the code

Modification effect

Difference between @Valid and @Validated

First take a look at the packages they belong to:

You can see that @Validated belongs to Spring and @Valid belongs to Javax.

  • @ Validated:org.springframework.validation.annotation.Validated
  • @ Valid:javax.validation.Valid

However, in actual basic use, there is no difference between the two. (Note that basic use is used; in other words, using @Valid and @Validated is equivalent.)

@Validated Verifies the controller

@PostMapping("/test")
public String test(@RequestBody @Validated TestRequest request) {
    return "SUCCESS";
}
Copy the code

You can get the same result by substituting the comment:

Two annotated source

  • @Valid
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE     })
@Retention(RUNTIME)
@Documented
public @interface Valid {
}
Copy the code
  • @Validated
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interfaceValidated { Class<? >[] value()default {};
}
Copy the code

“@”, “Validated”, “Validated”, “Validated”, “Validated”, “Validated”, “Validated”, “Validated”, “Validated”

The @ provides a grouping function. When verifying parameters, you can use different verification mechanisms based on different groups. When no grouping attribute is added, the default validates the ungrouped validation attribute.

@Validated Group verification

Write checksum group identifier:

public class ValidatedGroup {
  public interface  Add extends Default {}
  public interface  Delete extends Default {}
  public interface  Update extends Default {}
  public interface  Query extends Default {}
}
Copy the code

Test request class:

@Data
public class TestSaveRequest {

  @NotNull(groups = {ValidatedGroup.Update.class, ValidatedGroup.Delete.class}, message = "Id cannot be empty when updating or deleting")
  private Long id;

  @NotBlank(groups = {ValidatedGroup.Update.class}, message = "Name cannot be empty when updating")
  private String name;

  @NotNull(groups = {ValidatedGroup.Add.class}, message = "The balance cannot be empty when adding.")
  @Digits(integer = 10, fraction = 2)
  private BigDecimal balance;

  @NotBlank(groups = {ValidatedGroup.Add.class}, message = "Phone cannot be empty when adding")
  @Pattern(regexp = "134-8 0 ^ \ \ d {7} $| ^ 13 [^ 4] \ \ d {8} $| ^ 14 [5-9] \ \ d {8} $| ^ 15 [^ 4] \ \ d {8} $| ^ 16 [6] \ \ d {8} $| ^ 17 [0 to 8] \ \ d {8} $| ^ 18 [\ \ d] {9} $| ^ 19 [8, 9] \ \ d {8 } $", message = "Incorrect phone number format")
  private String phone;

  @NotBlank(groups = {ValidatedGroup.Add.class}, message = "Mail cannot be empty when new")
  @Email
  private String email;
}
Copy the code

Based on the type of test request we wrote, we can expect:

  • If the verification group is Add, the balance, phone, and Email request fields are verified
  • If the verification group is Update, the ID and name fields are verified

The tests are as follows:

@PostMapping("/testAdd")
public String testAdd(@RequestBody @Validated(value = ValidatedGroup.Add.class) TestSaveRequest request) {
    return "SUCCESS";
}

@PostMapping("/testUpdate")
public String testUpdate(@RequestBody @Validated(value = ValidatedGroup.Update.class) TestSaveRequest request) {
    return "SUCCESS";
}
Copy the code

TestAdd results:

TestUpdate results:

The results are exactly in line with expectations. @ validation A lot of additional development can be saved when grouping validation, especially when adding and updating.

A case where you need to pass a primary key and a case where you don’t need to pass a primary key, where you used to need an AddRequest and an UpdateRequest, now you just need one.

Nested check

What is nested verification? The code:

@Data
public class TestNestRequest {

  @NotNull(message = "Id cannot be empty")
  private Long id;

  @NotNull(message = "Nested object request data cannot be empty")
  private ItemRequest itemRequest;
}
Copy the code
@Data
public class ItemRequest {

  @NotEmpty(message = "Name cannot be empty")
  private String name;
}
Copy the code
@PostMapping("/testNest")
public String testNest(@RequestBody @Valid TestNestRequest request) {
  return "SUCCESS";
}
Copy the code

The test results are as follows:

Only the ID is checked, not the name attribute in the nested object.

If you need to validate properties in nested objects, you need to modify the TestNestRequest class.

The @valid annotation to the itemRequest attribute validates the attributes in the nested object

The transformation is as follows:

@Data
public class TestNestRequest {

  @NotNull(message = "Id cannot be empty")
  private Long id;

  @Valid
  @NotNull(message = "Nested object request data cannot be empty")
  private ItemRequest itemRequest;
}
Copy the code

Test results:

It is important to note that nested validation must be used@ValidAnnotation.

Follow wechat public account: IT elder brother

Java actual combat project video tutorial: you can get 200G, 27 sets of actual combat project video tutorial

Reply: Java learning route, you can get the latest and most complete a learning roadmap

Re: Java ebooks, get 13 must-read books for top programmers

Java foundation, Java Web, JavaEE all tutorials, including Spring Boot, etc

Reply: Resume template, you can get 100 beautiful resumes