3.2.13.2. 运行时验证
- 在 UI 中验证
-
连接到数据源的通用 UI 组件获取
BeanValidator
实例来检查字段的值。验证器是从可视化组件实现的Component.Validatable.validate()
方法调用的。如果验证不通过,会抛出CompositeValidationException
异常,这个异常实例中包含了一组违规信息的集合。可以移除标准的验证器,也可以使用不同的约束组初始化标准验证器:
@UiController("sample_NewScreen") @UiDescriptor("new-screen.xml") public class NewScreen extends Screen { @Inject private TextField<String> field1; @Inject private TextField<String> field2; @Subscribe protected void onInit(InitEvent event) { field1.getValidators().stream() .filter(BeanPropertyValidator.class::isInstance) .forEach(field1::removeValidator); (1) field2.getValidators().stream() .filter(BeanPropertyValidator.class::isInstance) .forEach(validator -> { ((BeanPropertyValidator) validator).setValidationGroups(new Class[] {UiComponentChecks.class}); (2) }); } }
1 从 UI 组件中完全删除 bean 验证。 2 这里,验证器将仅检查显式设置了 UiComponentChecks 组的约束,因为没有传递默认组。 默认情况下,
BeanValidator
具有Default
和UiComponentChecks
分组。如果实体属性带有
@NotNull
注解且没有定义约束组,则在元数据中这个属性会被标记为强制的(mandatory),并且通过数据源使用此属性的 UI 组件将具有required = true
属性。DateField和DatePicker组件使用
@Past
、@PastOrPresent
、@Future
、@FutureOrPresent
注解自动设置其rangeStart
和rangeEnd
属性,不过这里忽略了时间部分。如果约束包含
UiCrossFieldChecks
组并且所有属性级别的检查都通过了,编辑界面将在提交时做类级别约束的验证。可以在 XML 描述或界面控制器使用crossFieldValidate
属性关闭此验证:<window xmlns="http://schemas.haulmont.com/cuba/window.xsd" caption="msg://editorCaption" class="com.company.demo.web.task.TaskEdit" datasource="taskDs" crossFieldValidate="false"> <!-- ... --> </window>
public class TaskEdit extends StandardEditor<Task> { @Subscribe protected void onInit(InitEvent event) { setCrossFieldValidate(false); } }
- DataManager中的验证
-
DataManager 可以对保存的实体实例进行验证。以下参数会影响验证:
-
cuba.dataManagerBeanValidation 应用程序属性设置设置是否进行验证的全局默认值。
-
也可以覆盖上面的全局默认值,在 UI 界面保存数据的时候,可以在使用
DataManager.commit()
或者DataContext.PreCommitEvent
里为CommitContext
设置CommitContext.ValidationMode
-
也可以提供一个 验证组 的列表给
CommitContext
或者DataContext.PreCommitEvent
,这样可以只应用定义的约束的一部分。
-
- 中间件服务验证
-
如果服务接口中的方法带有
@Validated
注解,则中间件服务会对方法的参数和返回结果执行验证。例如:public interface TaskService { String NAME = "demo_TaskService"; @Validated @NotNull String completeTask(@Size(min = 5) String comment, @NotNull Task task); }
@Validated
注解可以指定约束组以使验证应用到某组约束上,如果没有指定任何组,默认使用以下约束组:-
Default
和ServiceParametersChecks
- 进行方法参数验证时 -
Default
和ServiceResultChecks
- 进行方法返回值验证时
在验证错误时会抛出
MethodParametersValidationException
和MethodResultValidationException
异常。如果要在服务中以编程的方式执行某些自定义验证,请使用
CustomValidationException
来通知客户端有关验证的错误信息,这样可以与标准 bean 验证错误信息保持相同的格式。此异常也可以跟 REST API 客户端有特定的关联。 -
- 在 REST API 中验证
-
对于创建和更新操作, 通常 REST API 会自动执行 bean 验证。验证错误会以如下方式返回给客户端:
-
MethodResultValidationException
和ValidationException
导致500 Server error
HTTP 状态 -
MethodParametersValidationException
、ConstraintViolationException
和CustomValidationException
导致400 Bad request
HTTP 状态 -
格式为
Content-Type: application/json
的响应体将包含一个对象列表,每个对象都包含属性message
、messageTemplate
、path
和invalidValue
属,例如:[ { "message": "Invalid email: aaa", "messageTemplate": "{msg://com.company.demo.entity/Customer.email.validationMsg}", "path": "email", "invalidValue": "aaa" } ]
-
path
- 表示被验证对象的无效属性在对象关系图中的路径。 -
messageTemplate
- 消息模板字符串,这个模板字符串是在message
注解属性中定义。 -
message
- 包含验证消息的实际值 。 -
invalidValue
- 属性值类型是String
、Date
、Number
、Enum
、UUID
中的其中之一时才返回。
-
-
- 以编程的方式进行验证
-
可以使用
BeanValidation
基础设施接口以编程的方式执行验证。该接口可在中间件和客户端层使用。它用于获取执行验证的javax.validation.Validator
实现。验证的结果是一组ConstraintViolation
对象。例如:@Inject private BeanValidation beanValidation; public void save(Foo foo) { Validator validator = beanValidation.getValidator(); Set<ConstraintViolation<Foo>> violations = validator.validate(foo); // ... }