ValidatorExtension
ValidatorExtension 在 models.json 中声明式 DSL 约束(required、min、max、regex、enum)之上增加程序化校验规则。当规则依赖于另一条记录(唯一性、外键存在性)、当前用户(组织作用域检查)或外部状态时,请使用 Validator。
概念
Validator 是字段级校验扩展,通过 getValidatorKey() 返回的 namespace:validator-name 唯一键被注册和解析。validate(ValidationContext) 接收待校验的字段值(context.value())、字段码(context.fieldCode())以及同一记录的其它字段(context.recordData()),返回 ValidationResult —— 或 success(),或一组聚合后的字段错误。返回错误时会在 UI 上呈现字段级错误 toast(平台会把 field 映射到表单控件错误,绝不会显示泛化的 "Bad parameter" toast —— 见红线 §2.2)。
DSL 约束与 ValidatorExtension 是叠加关系;两者必须都通过。
接口签名
package com.auraboot.framework.plugin.extension;
import org.pf4j.ExtensionPoint;
public interface ValidatorExtension extends ExtensionPoint {
String getValidatorKey();
ValidationResult validate(ValidationContext context);
// 默认方法:supports(validatorKey) / getOrder() / isFailFast()
}ValidationResult API(ValidationResult 与 ValidationContext 均为 ValidatorExtension 的内部 record):
ValidationResult.success();
ValidationResult.error("A lead with this email already exists");
ValidationResult.error("email", "A lead with this email already exists");
ValidationResult.errors(List.of(
new ValidationError("email", "Already exists"),
new ValidationError("phone", "Invalid format")
));error(field, message) 中的 field 参数必须是合法的 model field code;平台会将其映射到表单控件。对于跨字段错误,使用合成 field code,如 _form,或用 error(message) 省略字段。
实现示例
校验 lead 邮箱字段的格式与依赖关系(字段级,纯读取):
package com.acme.crm.validator;
import com.auraboot.framework.plugin.extension.ValidatorExtension;
import org.pf4j.Extension;
import java.util.Map;
@Extension
public class LeadEmailValidator implements ValidatorExtension {
@Override
public String getValidatorKey() { return "crm:lead-email"; }
@Override
public ValidationResult validate(ValidationContext ctx) {
Object value = ctx.value();
if (value == null || ((String) value).isBlank()) {
return ValidationResult.success(); // DSL `required` 已处理缺失情况
}
String email = (String) value;
if (!email.contains("@")) {
return ValidationResult.error(ctx.fieldCode(),
"$i18n:crm.lead.email.invalid");
}
// 同一记录的其它字段可从 recordData 读取做跨字段校验
Map<String, Object> record = ctx.recordData();
// ...
return ValidationResult.success();
}
}注意 $i18n: 前缀 —— 在错误中暴露原始英文文本违反红线 §3。
ValidationContext record 还提供 tenantId()、namespace()、validatorKey()、validatorParams()、settings() 等元数据访问器。
注册
只需 @Extension。共享同一 validatorKey 的多个 validator 会按 getOrder() 升序执行;isFailFast() 默认 false,即收集所有错误后在单个响应中返回,使用户一次看到所有问题。
常见陷阱
- 返回缺少
field的泛化错误。 会呈现为横幅 toast 而非表单控件错误 —— 违反红线 §2.2。如确属跨字段,使用_form,或用error(message)重载。 - 无条件执行昂贵校验。 请先以廉价检查短路(如值为空时直接
success())。 - 将校验与变更混在一起。 Validator 必须是纯读取操作。变更属于
CommandHandlerExtension(其CommandContext提供DataAccessor做数据访问)。
相关
- CommandHandlerExtension ——
CommandHandlerExtension.execute负责变更,ValidatorExtension.validate负责纯检查 - Models DSL —— 声明式 DSL 约束
- Commands pipeline —— 命令管道