跳到主要内容

6.15 数据校验

使用验证通知(Validation Advice),使用 Micronaut 控制器可以很容易地验证传入数据。

Micronaut 为带有 micronaut-validation 依赖项的 javax.validation 注解提供本机支持:

implementation("io.micronaut:micronaut-validation")

或者完全符合 JSR380 的 micronaut-hibernate-validator 依赖:

implementation("io.micronaut.beanvalidation:micronaut-hibernate-validator")

我们可以在类级别使用 javax.validation 注解和 Validated 注解来验证参数。

示例

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.validation.Validated;

import javax.validation.constraints.NotBlank;
import java.util.Collections;

@Validated // (1)
@Controller("/email")
public class EmailController {

@Get("/send")
public HttpResponse send(@NotBlank String recipient, // (2)
@NotBlank String subject) { // (2)
return HttpResponse.ok(Collections.singletonMap("msg", "OK"));
}
}
  1. Validated 注解控制器
  2. subjectrecipient 不能为空

如果发生验证错误,将引发 javax.validation.ConstraintViolationException。默认情况下,集成的 io.micronauth.validation.exception.ConstraintException 处理程序会处理异常,导致如下测试所示的行为:

示例测试

@Test
public void testParametersAreValidated() {
HttpClientResponseException e = Assertions.assertThrows(HttpClientResponseException.class, () ->
client.toBlocking().exchange("/email/send?subject=Hi&recipient="));
HttpResponse<?> response = e.getResponse();

assertEquals(HttpStatus.BAD_REQUEST, response.getStatus());

response = client.toBlocking().exchange("/email/send?subject=Hi&recipient=me@micronaut.example");

assertEquals(HttpStatus.OK, response.getStatus());
}

要使用自己的 ExceptionHandler 来处理约束异常,请使用 @Replaces(ConstraintExceptionHandler.class) 对其进行注解。

通常,你可能希望使用 POJO 作为控制器方法参数。

import io.micronaut.core.annotation.Introspected;

import javax.validation.constraints.NotBlank;

@Introspected
public class Email {

@NotBlank // (1)
String subject;

@NotBlank // (1)
String recipient;

public String getSubject() {
return subject;
}

public void setSubject(String subject) {
this.subject = subject;
}

public String getRecipient() {
return recipient;
}

public void setRecipient(String recipient) {
this.recipient = recipient;
}
}
  1. 你可以在 POJO 中使用 javax.validation 注解。

Validated 注解你的控制器,用 @Valid 注解绑定 POJO。

示例

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.validation.Validated;

import javax.validation.Valid;
import java.util.Collections;

@Validated // (1)
@Controller("/email")
public class EmailController {

@Post("/send")
public HttpResponse send(@Body @Valid Email email) { // (2)
return HttpResponse.ok(Collections.singletonMap("msg", "OK"));
}
}
  1. Validated 对控制器进行注解
  2. 注解 POJO 以使用 @Valid 进行验证

POJO 的验证如以下测试所示:

@Test
public void testPojoValidation() {
HttpClientResponseException e = assertThrows(HttpClientResponseException.class, () -> {
Email email = new Email();
email.subject = "Hi";
email.recipient = "";
client.toBlocking().exchange(HttpRequest.POST("/email/send", email));
});
HttpResponse<?> response = e.getResponse();

assertEquals(HttpStatus.BAD_REQUEST, response.getStatus());

Email email = new Email();
email.subject = "Hi";
email.recipient = "me@micronaut.example";
response = client.toBlocking().exchange(HttpRequest.POST("/email/send", email));

assertEquals(HttpStatus.OK, response.getStatus());
}
注解

使用 Hibernate Validator 配置在自定义约束中支持 Bean 注入。

6.15.1 验证组

你可以使用 Validated 上的 groups 来使用验证组,用于强制执行约束的子集。Bean 验证规范中提供了更多信息。

import io.micronaut.core.annotation.Introspected;

import javax.validation.constraints.NotBlank;

@Introspected
public class Email {

@NotBlank // (1)
String subject;

@NotBlank(groups = FinalValidation.class) // (2)
String recipient;

public String getSubject() {
return subject;
}

public void setSubject(String subject) {
this.subject = subject;
}

public String getRecipient() {
return recipient;
}

public void setRecipient(String recipient) {
this.recipient = recipient;
}
}
  1. 使用默认验证组指定约束。只有当 Default 处于活动状态时,才会强制执行此约束。
  2. 使用自定义 FinalValidation 验证组指定约束。只有当 FinalValidation 处于活动状态时,才会强制执行此约束。

Validated 注解控制器,指定将处于活动状态的验证组或使其默认为 Default。同时用 @Valid 注解绑定 POJO。

示例

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.validation.Validated;

import javax.validation.Valid;
import java.util.Collections;

@Validated // (1)
@Controller("/email")
public class EmailController {

@Post("/createDraft")
public HttpResponse createDraft(@Body @Valid Email email) { // (2)
return HttpResponse.ok(Collections.singletonMap("msg", "OK"));
}

@Post("/send")
@Validated(groups = FinalValidation.class) // (3)
public HttpResponse send(@Body @Valid Email email) { // (4)
return HttpResponse.ok(Collections.singletonMap("msg", "OK"));
}
}
  1. 使用 Validated 进行注解而不指定组意味着 Default 组将处于活动状态。由于这是在类上定义的,因此它将应用于所有方法。
  2. Default 验证组中的约束将被强制执行,继承自类。其效果是,当调用此方法时,将不会强制执行 email.recipient 上的 @NotBlank
  3. 指定 groups 意味着在调用此方法时将强制执行这些验证组。请注意,FinalValidation 继承 Default,因此将强制执行来自两个组的约束。
  4. 由于 FinalValidation 继承 Default,因此将强制执行 DefaultFinalValidat 验证组中的约束。其效果是,当调用此方法时, email 中的两个 @NotBlank 约束都将被强制执行。

以下测试显示了使用默认验证组对 POJO 的验证:

@Test
public void testPojoValidation_defaultGroup() {
HttpClientResponseException e = assertThrows(HttpClientResponseException.class, () -> {
Email email = new Email();
email.subject = "";
email.recipient = "";
client.toBlocking().exchange(HttpRequest.POST("/email/createDraft", email));
});
HttpResponse<?> response = e.getResponse();

assertEquals(HttpStatus.BAD_REQUEST, response.getStatus());

Email email = new Email();
email.subject = "Hi";
email.recipient = "";
response = client.toBlocking().exchange(HttpRequest.POST("/email/createDraft", email));

assertEquals(HttpStatus.OK, response.getStatus());
}

使用自定义 FinalValidation 验证组对 POJO 进行验证,如以下测试所示:

@Test
public void testPojoValidation_finalValidationGroup() {
HttpClientResponseException e = assertThrows(HttpClientResponseException.class, () -> {
Email email = new Email();
email.subject = "Hi";
email.recipient = "";
client.toBlocking().exchange(HttpRequest.POST("/email/send", email));
});
HttpResponse<?> response = e.getResponse();

assertEquals(HttpStatus.BAD_REQUEST, response.getStatus());

Email email = new Email();
email.subject = "Hi";
email.recipient = "me@micronaut.example";
response = client.toBlocking().exchange(HttpRequest.POST("/email/send", email));

assertEquals(HttpStatus.OK, response.getStatus());
}

英文链接