Validation
本指南涵盖如何使用 Hibernate Validator/Bean Validation:
-
验证您的 REST 接口的输入/输出;
-
验证您的业务服务方法的参数和返回值。
结构
本指南中创建的应用程序非常简单。 用户在网页上填写表格。
网页将表单内容以 JSON 格式 (使用 Ajax) 发送到 BookResource
. BookResource
验证用户输入并返回 JSON 格式 结果 。
成果
我们建议您按照下面章节指示,一步一步创建应用程序。 但是你也可以直接跳到已完成的例子。
克隆 Git 仓库: git clone https://github.com/quarkusio/quarkus-quickstarts.git
, 或下载 压缩包
代码在 validation-quickstart
目录。
创建 Maven 项目
首先,我们需要一个新项目。 通过以下命令创建一个新项目:
mvn io.quarkus:quarkus-maven-plugin:1.3.1.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=validation-quickstart \
-DclassName="org.acme.validation.BookResource" \
-Dpath="/books" \
-Dextensions="resteasy-jsonb, hibernate-validator"
cd validation-quickstart
此命令生成一个 Maven 项目结构并导入 RESTEasy/JAX-RS, JSON-B 和 Hibernate Validator/Bean Validation extensions。
访问 Validator
编辑 org.acme.validation.BookResource
类,注入 Validator
对象如下:
@Inject
Validator validator;
Validator
允许检查对特定对象的约束。
约束
在本应用程序中,我们将测试一个基本对象,但我们支持复杂约束,并且可以验证对象图。
创建 org.acme.validation.Book
类,内容如下:
package org.acme.validation;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Min;
public class Book {
@NotBlank(message="Title may not be blank")
public String title;
@NotBlank(message="Author may not be blank")
public String author;
@Min(message="Author has been very lazy", value=1)
public double pages;
}
约束添加到字段中,当对象被验证时将检查字段值。 getter 和 setter方法也用于JSON映射。
JSON 映射和验证
回到 BookResource
类。
增加以下方法:
@Path("/manual-validation")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Result tryMeManualValidation(Book book) {
Set<ConstraintViolation<Book>> violations = validator.validate(book);
if (violations.isEmpty()) {
return new Result("Book is valid! It was validated by manual validation.");
} else {
return new Result(violations);
}
}
它现在还编译不过, 缺少 Result
,但我们过会就添加它。
方法参数 (book
) 是自动从 JSON 创建的。
该方法使用 Validator
来检查 payload。
它会返回违背约束的集合。
如果此 set 为空,意味着对象是有效的。
如果出现错误,消息会被拼接起来发回浏览器。
现在我们创建 Result
内部类:
public static class Result {
Result(String message) {
this.success = true;
this.message = message;
}
Result(Set<? extends ConstraintViolation<?>> violations) {
this.success = false;
this.message = violations.stream()
.map(cv -> cv.getMessage())
.collect(Collectors.joining(", "));
}
private String message;
private boolean success;
public String getMessage() {
return message;
}
public boolean isSuccess() {
return success;
}
}
该类非常简单,仅包含 2 个字段和相关的 getters 和 setters。 因为我们指明会产生 JSON ,所以会自动映射成 JSON 。
REST 接口验证
当手动使用 Validator
时,可能对某些高级用途有用,
如果您只想验证参数或返回值或您的 REST 接口,
你可以直接给它注入约束 (@NotNull
, @Digits
…)
或使用 @Valid
(它将把验证传输到 bean 中)。
让我们创建一个验证请求中提供的 Book
的终点:
@Path("/end-point-method-validation")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Result tryMeEndPointMethodValidation(@Valid Book book) {
return new Result("Book is valid! It was validated by end point method validation.");
}
正如你可以看到的那样,我们不必再手动验证所提供的 Book
,因为它是自动验证的。
If a validation error is triggered, a violation report is generated and serialized as JSON as our end point produces a JSON output. It can be extracted and manipulated to display a proper error message.
Service 方法验证
在接口级别声明验证规则可能并非易事,因为它可能重复某些业务验证。
最好的选项是用您的约束注解您的业务 service 方法(或我们这的 @Valid
):
package org.acme.validation;
import javax.enterprise.context.ApplicationScoped;
import javax.validation.Valid;
@ApplicationScoped
public class BookService {
public void validateBook(@Valid Book book) {
// your business logic here
}
}
在 rest 接口调用 service 方法会自动验证 Book
:
@Inject BookService bookService;
@Path("/service-method-validation")
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Result tryMeServiceMethodValidation(Book book) {
try {
bookService.validateBook(book);
return new Result("Book is valid! It was validated by service method validation.");
} catch (ConstraintViolationException e) {
return new Result(e.getConstraintViolations());
}
}
注意,如果您想要将验证错误推送到前端, 您必须 catch 异常并推送您自己的信息 ,因为他们不会自动被推送到 JSON 输出。
请记住,您通常不想向公众透露您服务的内部信息 - 尤其不想透露违背约束对象中的有效值。
前端
现在让我们添加简单的网页来与我们的 BookResource
交互。
Quarkus 自动为 META-INF/resources
目录中包含的静态资源服务。
用 index.html 文件替换 src/main/resources/META-INF/resources
目录中的 index.html
文件。
运行应用程序
现在,让我们看看应用。 运行它:
./mvnw compile quarkus:dev
然后打开您的浏览器访问 http://localhost:8080/ :
-
输入 book 详细信息(有效或无效)
-
点击 Try me… 按钮来检查您的数据是否有效,使用我们上面介绍的方法之一。
像往常一样,应用程序可以使用 ./mvnw cound package
进行打包并用 -runner.jar
文件执行。
您也可以使用 ./mvnw package -Pnative
来构建 native 可执行文件。
进一步
Hibernate Validator extension 和 CDI
Hibernate Validator extension 与 CDI 密切结合。
配置 ValidatorFactory
有时,您可能需要配置 ValidatorFactory
的行为,例如使用特定的 ParameterNameProvider
。
ValidatorFactory
是由 Quarkus 本身实例化的。
您可以容易地调整为用在配置中注入的 beans 来替代它。
如果您在应用程序中创建了以下类型的 bean,它将被自动注入 ValidatorFactory
配置:
-
javax.validation.ClockProvider
-
javax.validation.ConstraintValidator
-
javax.validation.ConstraintValidatorFactory
-
javax.validation.MessageInterpolator
-
javax.validation.ParameterNameProvider
-
javax.validation.TraversableResolver
-
org.hibernate.validator.spi.properties.GetterPropertySelectionStrategy
-
org.hibernate.validator.spi.scripting.ScriptEvaluatorFactory
You don’t have to wire anything.
显然,对于列出的每一种类型,你只能声明一个 bean。 应宣布这些 bean 为 |
作为 beans 的约束验证器
可以声明您的约束验证器为 CDI bean:
@ApplicationScoped
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> {
@Inject
MyService service;
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return service.validate(value);
}
}
初始化给定类型的约束验证器时, Quarkus 将检查这种类型的 bean 是否可用,如果可用将使用它而不是实例化一个。
因此,正如我们的例子所显示的那样,您可以在约束验证器 bean 中充分使用注入。
除了非常特殊的情况外,建议将上述 bean 声明为 |
验证和本地化
默认情况下,将使用构建系统语言返回约束违背消息。
您可以通过 application.properties
中添加以下配置来调整:
# The default locale to use
quarkus.default-locale=fr-FR
如果您正在使用 RESTEasy, 在 JAX-RS 接口上, Hibernate Validator 将自动从 HTTP 头 Accept-Language
推断最合适的语言,
已支持的 locale 已经在 application.properties
指定。
# The list of all the supported locales
quarkus.locales=en-US,es-ES,fr-FR