使用验证建议可以很容易地验证 Micronaut 控制器传入的数据。
Micronaut 为具有 micronaut-validation 依赖项的 javax.validation 注解提供原生支持:
Gradle |
Maven |
implementation("io.micronaut:micronaut-validation")
|
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-validation</artifactId>
</dependency>
|
或者完全符合 micronaut-hibernate-validator 依赖的 JSR 380:
Gradle |
Maven |
implementation("io.micronaut.beanvalidation:micronaut-hibernate-validator")
|
<dependency>
<groupId>io.micronaut.beanvalidation</groupId>
<artifactId>micronaut-hibernate-validator</artifactId>
</dependency>
|
我们可以在类级别使用 javax.validation 注释和 Validated 注释来验证参数。
示例
Java |
Groovy |
Kotlin |
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"));
}
}
|
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
@Validated // (1)
@Controller("/email")
class EmailController {
@Get("/send")
HttpResponse send(@NotBlank String recipient, // (2)
@NotBlank String subject) { // (2)
HttpResponse.ok(msg: "OK")
}
}
|
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
@Validated // (1)
@Controller("/email")
open class EmailController {
@Get("/send")
open fun send(@NotBlank recipient: String, // (2)
@NotBlank subject: String): HttpResponse<*> { // (2)
return HttpResponse.ok(mapOf("msg" to "OK"))
}
}
|
使用 Validated 注释控制器
主题和收件人不能为空。
如果发生验证错误,则抛出 javax.validation.ConstraintViolationException。默认情况下,集成的 io.micronaut.validation.exception.ConstraintExceptionHandler 处理异常,导致如下测试所示的行为:
示例测试
Java |
Groovy |
Kotlin |
@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());
}
|
def "test parameter validation"() {
when:
client.toBlocking().exchange('/email/send?subject=Hi&recipient=')
then:
def e = thrown(HttpClientResponseException)
def response = e.response
response.status == HttpStatus.BAD_REQUEST
when:
response = client.toBlocking().exchange('/email/send?subject=Hi&recipient=me@micronaut.example')
then:
response.status == HttpStatus.OK
}
|
"test params are validated"() {
val e = shouldThrow<HttpClientResponseException> {
client.toBlocking().exchange<Any>("/email/send?subject=Hi&recipient=")
}
var response = e.response
response.status shouldBe HttpStatus.BAD_REQUEST
response = client.toBlocking().exchange<Any>("/email/send?subject=Hi&recipient=me@micronaut.example")
response.status shouldBe HttpStatus.OK
}
|
要使用您自己的 ExceptionHandler 来处理约束异常,请使用 @Replaces(ConstraintExceptionHandler.class) 对其进行注释
通常您可能希望使用 POJO 作为控制器方法参数。
Java |
Groovy |
Kotlin |
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;
}
}
|
import io.micronaut.core.annotation.Introspected
import javax.validation.constraints.NotBlank
@Introspected
class Email {
@NotBlank // (1)
String subject
@NotBlank // (1)
String recipient
}
|
import io.micronaut.core.annotation.Introspected
import javax.validation.constraints.NotBlank
@Introspected
open class Email {
@NotBlank // (1)
var subject: String? = null
@NotBlank // (1)
var recipient: String? = null
}
|
您可以在 POJO 中使用 javax.validation 注释。
使用 Validated 注释您的控制器,并使用 @Valid 注释绑定 POJO。
例子
Java |
Groovy |
Kotlin |
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"));
}
}
|
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
@Validated // (1)
@Controller("/email")
class EmailController {
@Post("/send")
HttpResponse send(@Body @Valid Email email) { // (2)
HttpResponse.ok(msg: "OK")
}
}
|
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
@Validated // (1)
@Controller("/email")
open class EmailController {
@Post("/send")
open fun send(@Body @Valid email: Email): HttpResponse<*> { // (2)
return HttpResponse.ok(mapOf("msg" to "OK"))
}
}
|
用 Validated 注释控制器
注释 POJO 以使用 @Valid 进行验证
POJO 的验证显示在以下测试中:
Java |
Groovy |
Kotlin |
@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());
}
|
def "invoking /email/send parse parameters in a POJO and validates"() {
when:
Email email = new Email(subject: 'Hi', recipient: '')
client.toBlocking().exchange(HttpRequest.POST('/email/send', email))
then:
def e = thrown(HttpClientResponseException)
def response = e.response
response.status == HttpStatus.BAD_REQUEST
when:
email = new Email(subject: 'Hi', recipient: 'me@micronaut.example')
response = client.toBlocking().exchange(HttpRequest.POST('/email/send', email))
then:
response.status == HttpStatus.OK
}
|
"test pojo validation" {
val e = shouldThrow<HttpClientResponseException> {
val email = Email()
email.subject = "Hi"
email.recipient = ""
client.toBlocking().exchange<Email, Any>(HttpRequest.POST("/email/send", email))
}
var response = e.response
response.status shouldBe HttpStatus.BAD_REQUEST
val email = Email()
email.subject = "Hi"
email.recipient = "me@micronaut.example"
response = client.toBlocking().exchange<Email, Any>(HttpRequest.POST("/email/send", email))
response.status shouldBe HttpStatus.OK
}
|
Bean 注入在 Hibernate Validator 配置的自定义约束中受支持。
验证组
您可以使用验证组使用验证组来强制约束的子集。
Java |
Groovy |
Kotlin |
import javax.validation.groups.Default;
public interface FinalValidation extends Default {} // (1)
|
import javax.validation.groups.Default
interface FinalValidation extends Default {} // (1)
|
import javax.validation.groups.Default
interface FinalValidation : Default {} // (1)
|
定义自定义验证组。这一个扩展了默认值,因此使用该组完成的任何验证都将包括默认组中的约束。
Java |
Groovy |
Kotlin |
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;
}
}
|
import io.micronaut.core.annotation.Introspected
import javax.validation.constraints.NotBlank
@Introspected
class Email {
@NotBlank // (1)
String subject
@NotBlank(groups = FinalValidation) // (2)
String recipient
}
|
import io.micronaut.core.annotation.Introspected
import javax.validation.constraints.NotBlank
@Introspected
open class Email {
@NotBlank // (1)
var subject: String? = null
@NotBlank(groups = [FinalValidation::class]) // (2)
var recipient: String? = null
}
|
使用默认验证组指定约束。只有在默认处于活动状态时才会强制执行此约束。
使用自定义 FinalValidation 验证组指定约束。只有在 FinalValidation 处于活动状态时才会强制执行此约束。
使用 Validated 注释您的控制器,指定将激活的验证组或让它默认为 Default。还要用@Valid 注释绑定的POJO。
示例
Java |
Groovy |
Kotlin |
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"));
}
}
|
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
@Validated // (1)
@Controller("/email")
class EmailController {
@Post("/createDraft")
HttpResponse createDraft(@Body @Valid Email email) { // (2)
HttpResponse.ok(msg: "OK")
}
@Post("/send")
@Validated(groups = [FinalValidation]) // (3)
HttpResponse send(@Body @Valid Email email) { // (4)
HttpResponse.ok(msg: "OK")
}
}
|
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
@Validated // (1)
@Controller("/email")
open class EmailController {
@Post("/createDraft")
open fun createDraft(@Body @Valid email: Email): HttpResponse<*> { // (2)
return HttpResponse.ok(mapOf("msg" to "OK"))
}
@Post("/send")
@Validated(groups = [FinalValidation::class]) // (3)
open fun send(@Body @Valid email: Email): HttpResponse<*> { // (4)
return HttpResponse.ok(mapOf("msg" to "OK"))
}
}
|
在不指定组的情况下使用 Validated 注释意味着默认组将处于活动状态。由于这是在类上定义的,因此它将适用于所有方法。
默认验证组中的约束将被强制执行,从类继承。效果是调用此方法时不会强制执行 email.recipient 上的 @NotBlank。
指定组意味着调用此方法时将强制执行这些验证组。请注意,FinalValidation 扩展了 Default,因此将强制执行来自两个组的约束。
Default 和 FinalValidation 验证组中的约束将被强制执行,因为 FinalValidation 扩展了 Default。效果是当调用此方法时,将强制执行电子邮件中的两个 @NotBlank 约束。
使用默认验证组的 POJO 验证显示在以下测试中:
Java |
Groovy |
Kotlin |
@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());
}
|
def "invoking /email/createDraft parse parameters in a POJO and validates using default validation groups"() {
when:
Email email = new Email(subject: '', recipient: '')
client.toBlocking().exchange(HttpRequest.POST('/email/createDraft', email))
then:
def e = thrown(HttpClientResponseException)
def response = e.response
response.status == HttpStatus.BAD_REQUEST
when:
email = new Email(subject: 'Hi', recipient: '')
response = client.toBlocking().exchange(HttpRequest.POST('/email/createDraft', email))
then:
response.status == HttpStatus.OK
}
|
"test pojo validation using default validation groups" {
val e = shouldThrow<HttpClientResponseException> {
val email = Email()
email.subject = ""
email.recipient = ""
client.toBlocking().exchange<Email, Any>(HttpRequest.POST("/email/createDraft", email))
}
var response = e.response
response.status shouldBe HttpStatus.BAD_REQUEST
val email = Email()
email.subject = "Hi"
email.recipient = ""
response = client.toBlocking().exchange<Email, Any>(HttpRequest.POST("/email/createDraft", email))
response.status shouldBe HttpStatus.OK
}
|
以下测试显示了使用自定义 FinalValidation 验证组对 POJO 的验证:
Java |
Groovy |
Kotlin |
@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());
}
|
def "invoking /email/send parse parameters in a POJO and validates using FinalValidation validation group"() {
when:
Email email = new Email(subject: 'Hi', recipient: '')
client.toBlocking().exchange(HttpRequest.POST('/email/send', email))
then:
def e = thrown(HttpClientResponseException)
def response = e.response
response.status == HttpStatus.BAD_REQUEST
when:
email = new Email(subject: 'Hi', recipient: 'me@micronaut.example')
response = client.toBlocking().exchange(HttpRequest.POST('/email/send', email))
then:
response.status == HttpStatus.OK
}
|
"test pojo validation using FinalValidation validation group" {
val e = shouldThrow<HttpClientResponseException> {
val email = Email()
email.subject = "Hi"
email.recipient = ""
client.toBlocking().exchange<Email, Any>(HttpRequest.POST("/email/send", email))
}
var response = e.response
response.status shouldBe HttpStatus.BAD_REQUEST
val email = Email()
email.subject = "Hi"
email.recipient = "me@micronaut.example"
response = client.toBlocking().exchange<Email, Any>(HttpRequest.POST("/email/send", email))
response.status shouldBe HttpStatus.OK
}
|
更多建议: