1. 为什么我们需要字段校验规则清单?
在开发任何涉及用户输入或数据交互的系统时,字段校验都是保证数据质量和系统稳定性的第一道防线。我见过太多因为前端校验不严谨导致数据库崩溃的案例——比如一个简单的年龄字段,如果只在前端用HTML5的number类型限制,攻击者完全可以绕过前端直接调用API接口提交"年龄=一百万岁"这样的荒谬数据。
字段校验的核心价值在于:
- 数据完整性:确保必填字段不被遗漏
- 业务合规性:比如金额不能为负数,身份证号必须符合规则
- 系统安全性:防止SQL注入、XSS等攻击
- 用户体验:即时反馈比提交后报错更友好
2. 基础校验类型详解
2.1 必填校验(Required)
这是最基本的校验类型,但实际应用中远比if(!value) throw error复杂。以用户注册表单为例:
// 错误示范 - 仅检查空字符串 function validateRequired(value) { return value !== ''; } // 正确做法 - 考虑各种边界情况 function validateRequired(value) { return ( value !== undefined && value !== null && (typeof value !== 'string' || value.trim() !== '') && (!Array.isArray(value) || value.length > 0) ); }常见坑点:
- 数字0会被误判为空值
- 空格字符串通过校验
- 空数组未被正确处理
- 多选框至少选一项的场景
2.2 范围校验(Range)
范围校验通常用于数字、日期等可比较类型:
// 日期范围校验示例 function validateDateRange(date, minDate, maxDate) { const timestamp = new Date(date).getTime(); return ( timestamp >= new Date(minDate).getTime() && timestamp <= new Date(maxDate).getTime() ); }特殊场景处理:
- 开区间 vs 闭区间(是否包含边界值)
- 时区处理(建议统一转为UTC时间比较)
- 浮点数精度问题(金额比较建议使用decimal.js)
3. 高级校验类型实现
3.1 唯一性校验(Unique)
唯一校验需要与数据库交互,实现时要注意:
// Spring Boot JPA实现示例 @Column(unique = true) private String username; // 自定义唯一校验逻辑 public void checkUniqueEmail(String email) { if (userRepository.existsByEmail(email)) { throw new BusinessException("邮箱已被注册"); } }性能优化技巧:
- 对高频查询字段添加数据库唯一索引
- 使用Redis做缓存层校验
- 批量导入时先collect+groupBy内存去重
3.2 组合唯一校验(Composite Unique)
当唯一性需要多个字段组合确定时:
-- MySQL联合唯一索引 ALTER TABLE orders ADD CONSTRAINT uk_order_item UNIQUE (user_id, product_id, date);实际案例: 电商系统中,同一个用户对同一商品每天只能提交一次评价,就需要(user_id, product_id, date)的组合唯一约束。
4. 正则表达式实战指南
4.1 常用正则模式
| 校验目标 | 正则表达式 | 说明 |
|---|---|---|
| 手机号 | ^1[3-9]\d{9}$ | 中国大陆手机号 |
| 邮箱 | ^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ | 兼容大多数常见格式 |
| 身份证号 | `^[1-9]\d{5}(18 | 19 |
4.2 正则优化技巧
预编译正则:对于高频使用的正则,提前编译提升性能
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");避免灾难性回溯:
- 慎用嵌套量词
(a+)+ - 用具体字符类
\d替代通配符.
- 慎用嵌套量词
可读性维护:
// 使用命名捕获组(ES2018+) const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; const { groups: { year, month, day } } = dateRegex.exec('2023-05-15');
5. 校验规则组合策略
5.1 校验顺序优化
合理的校验顺序可以提升性能和用户体验:
- 先做本地可验证的规则(必填、格式)
- 再做需要服务端交互的规则(唯一性)
- 最后执行耗时的业务规则校验
5.2 多语言错误消息
// 错误码映射方案 const errorMessages = { 'required': { 'zh-CN': '${field}不能为空', 'en-US': '${field} is required' }, 'email': { 'zh-CN': '邮箱格式不正确', 'en-US': 'Invalid email format' } }; function getMessage(rule, field, lang = 'zh-CN') { return errorMessages[rule][lang] .replace('${field}', field); }6. 校验表设计模板
6.1 基础字段校验表
| 字段名 | 类型 | 必填 | 范围 | 格式 | 唯一性 | 关联字段 |
|---|---|---|---|---|---|---|
| 用户名 | string | 是 | 2-20字符 | 中文/字母 | 全局唯一 | - |
| 手机号 | string | 是 | 11位数字 | 1开头 | 全局唯一 | 国家区号 |
| 密码 | string | 是 | 8-32位 | 大小写+数字 | - | 密码强度(前端) |
6.2 状态流转校验
对于订单状态等需要校验状态机的场景:
# 状态流转规则示例 ALLOWED_TRANSITIONS = { 'CREATED': ['PAID', 'CANCELLED'], 'PAID': ['SHIPPED', 'REFUNDING'], 'SHIPPED': ['COMPLETED', 'RETURNING'] } def validate_transition(current, next): if next not in ALLOWED_TRANSITIONS.get(current, []): raise InvalidStateError(f"Cannot change from {current} to {next}")7. 前端与后端校验协同
7.1 分层校验策略
| 层级 | 校验重点 | 实现方式 |
|---|---|---|
| 前端 | 即时反馈、基础格式 | JS/TS、表单库校验 |
| API网关 | 参数完整性、基础类型 | JSON Schema、参数过滤器 |
| 服务端 | 业务规则、数据一致性 | 领域模型校验、数据库约束 |
| 数据库 | 最终一致性保障 | 唯一索引、外键、CHECK约束 |
7.2 校验逻辑复用方案
推荐使用JSON Schema实现前后端统一校验:
// 用户注册Schema示例 { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["username", "password", "email"], "properties": { "username": { "type": "string", "minLength": 2, "maxLength": 20, "pattern": "^[a-zA-Z\u4e00-\u9fa5]+$" }, "password": { "type": "string", "minLength": 8, "maxLength": 32, "pattern": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$" } } }8. 性能优化与异常处理
8.1 批量校验优化
当处理CSV导入等批量操作时:
// 使用Hibernate Validator进行批量校验 Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Set<ConstraintViolation<User>> violations = new HashSet<>(); for (User user : users) { violations.addAll(validator.validate(user)); if (violations.size() > 50) break; // 达到阈值提前终止 }8.2 优雅的错误收集
// 前端错误收集示例 const errors = {}; function validateField(field, value) { const fieldErrors = []; if (rules.required && !value) { fieldErrors.push('必填字段'); } if (rules.pattern && !new RegExp(rules.pattern).test(value)) { fieldErrors.push('格式不符'); } if (fieldErrors.length) { errors[field] = fieldErrors; } } // 最终返回结构化错误 { "username": ["必填字段", "至少2个字符"], "email": ["邮箱格式不正确"] }9. 现代校验库推荐
9.1 前端校验库对比
| 库名 | 特点 | 适用场景 |
|---|---|---|
| Yup | 声明式Schema,TypeScript友好 | React/Vue表单 |
| Joi | 功能强大,浏览器/Node通用 | 全栈应用 |
| VeeValidate | Vue专用,模板集成友好 | Vue 2/3项目 |
| Zod | 类型安全优先 | TypeScript重度项目 |
9.2 后端校验框架
Spring Boot示例:
@Data public class UserDTO { @NotBlank(message = "用户名不能为空") @Size(min = 2, max = 20, message = "用户名2-20个字符") private String username; @Email(message = "邮箱格式不正确") private String email; @AssertTrue(message = "必须接受协议") private boolean agreed; }Django示例:
from django.core.validators import RegexValidator phone_validator = RegexValidator( regex=r'^1[3-9]\d{9}$', message="手机号格式不正确" ) class User(models.Model): phone = models.CharField( max_length=11, validators=[phone_validator], unique=True )10. 复杂业务规则校验
10.1 跨字段依赖校验
// 密码与确认密码匹配校验 function validatePasswordMatch(data) { if (data.password !== data.confirmPassword) { return { isValid: false, errors: { confirmPassword: '两次输入密码不一致' } }; } return { isValid: true }; }10.2 条件必填逻辑
// 当支付方式为银行转账时,账号信息必填 public class PaymentRequest { @NotNull private PaymentType type; @NotBlank(groups = BankTransfer.class) private String accountNumber; @Valid private BankInfo bankInfo; public interface BankTransfer {} @AssertTrue(message = "银行转账需要完整账号信息") private boolean isValidBankTransfer() { return type != PaymentType.BANK_TRANSFER || (accountNumber != null && bankInfo != null); } }11. 测试策略
11.1 单元测试覆盖
// Jest测试示例 describe('validateEmail', () => { test('接受标准邮箱', () => { expect(validateEmail('test@example.com')).toBeTruthy(); }); test('拒绝无@符号的字符串', () => { expect(validateEmail('invalid-email')).toBeFalsy(); }); });11.2 边界值测试
// JUnit参数化测试 @ParameterizedTest @ValueSource(strings = {"", " ", "a", "a@b", "a@b.c"}) void testEmailBoundary(String email) { assertFalse(validator.validateEmail(email)); }12. 安全注意事项
重要:所有前端校验都只能提升用户体验,必须同时在服务端做完全相同的校验
SQL注入防护:
- 永远不要用字符串拼接构造SQL
- 使用预编译语句或ORM框架
XSS防护:
// 转义HTML输出 function escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); }正则DoS防护:
- 避免使用用户输入作为正则表达式
- 对复杂正则设置超时机制
13. 移动端特殊处理
13.1 小程序表单校验
// 微信小程序示例 Page({ formSubmit(e) { const { value } = e.detail; if (!value.username) { wx.showToast({ title: '用户名必填', icon: 'none' }); return; } // 调用云函数进行服务端校验 wx.cloud.callFunction({ name: 'validateForm', data: value }); } });13.2 输入法兼容问题
常见问题:
- 中文输入法下触发过早校验
- 全角/半角字符差异
- 移动键盘特殊符号处理
解决方案:
// 延迟校验触发 let composing = false; input.addEventListener('compositionstart', () => composing = true); input.addEventListener('compositionend', () => { composing = false; validate(); });14. 国际化(i18n)支持
14.1 多语言错误消息
// 基于i18n的校验错误配置 const messages = { en: { validation: { required: '{field} is required', email: 'Invalid email format' } }, zh: { validation: { required: '{field}不能为空', email: '邮箱格式不正确' } } }; function getMessage(rule, field, locale) { return messages[locale].validation[rule] .replace('{field}', field); }14.2 本地化格式校验
// Java本地化手机号校验 public boolean validatePhoneNumber(String number, Locale locale) { if (locale.getCountry().equals("CN")) { return number.matches("^1[3-9]\\d{9}$"); } else if (locale.getCountry().equals("US")) { return number.matches("^\\+1\\d{10}$"); } // 其他地区规则... }15. 可视化配置方案
15.1 低代码校验配置
// 可视化编辑器生成的校验配置 { "fields": [ { "name": "username", "label": "用户名", "type": "string", "rules": [ { "type": "required", "message": "用户名必填" }, { "type": "minLength", "value": 2 }, { "type": "maxLength", "value": 20 } ] } ] }15.2 动态规则加载
// 从服务端获取校验规则 async function loadValidationRules(formId) { const response = await fetch(`/api/validation-rules/${formId}`); return response.json(); } // 初始化动态表单 const rules = await loadValidationRules('user-registration'); const validator = new Validator(rules);16. 历史数据迁移校验
16.1 脏数据处理策略
-- 找出不符合新规则的历史数据 SELECT * FROM users WHERE LENGTH(username) < 2 OR LENGTH(username) > 20;16.2 渐进式校验迁移
- 先添加数据库约束
NOT NULL - 部署新校验逻辑到服务端
- 最后更新前端校验规则
- 对历史数据分批清洗
17. 微服务场景下的分布式校验
17.1 唯一性校验挑战
在分布式系统中,需要额外考虑:
// 使用Redis分布式锁保证唯一性校验原子性 public boolean checkUniqueWithLock(String key, String value) { String lockKey = "lock:" + key + ":" + value; try { // 尝试获取分布式锁 boolean locked = redisTemplate.opsForValue() .setIfAbsent(lockKey, "1", Duration.ofSeconds(5)); if (!locked) throw new BusyException("操作太频繁"); return !repository.existsByField(key, value); } finally { redisTemplate.delete(lockKey); } }17.2 最终一致性方案
对于允许短暂重复的场景:
- 先快速通过内存校验
- 异步队列处理最终一致性检查
- 发现冲突后触发补偿机制
18. 校验规则版本管理
18.1 规则变更策略
非破坏性变更:
- 放宽校验条件(如长度上限增加)
- 添加可选字段校验
破坏性变更:
- 收紧校验条件
- 修改必填字段
- 需要配合数据迁移和版本通知
18.2 版本化校验配置
# 校验规则版本控制示例 version: 1.2.0 effective_date: 2023-06-01 fields: username: min_length: 2 max_length: 20 email: format: standard required: true19. 机器学习辅助校验
19.1 异常输入检测
使用简单ML模型识别可疑输入:
# 使用TF-IDF检测异常输入示例 from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.ensemble import IsolationForest # 训练异常检测模型 vectorizer = TfidfVectorizer() X = vectorizer.fit_transform(normal_samples) clf = IsolationForest().fit(X) # 检测异常输入 def is_abnormal(input): vec = vectorizer.transform([input]) return clf.predict(vec)[0] == -119.2 智能纠错建议
// 邮箱纠错示例 function suggestEmailCorrection(email) { const commonTypos = { 'gamil.com': 'gmail.com', 'hotnail.com': 'hotmail.com' }; for (const [wrong, correct] of Object.entries(commonTypos)) { if (email.endsWith(wrong)) { return email.replace(wrong, correct); } } return null; }20. 无障碍(A11Y)校验考量
20.1 错误提示的可访问性
<!-- 正确的错误提示方式 --> <div class="form-group"> <label for="email">邮箱</label> <input id="email" type="email" aria-describedby="email-error"> <div id="email-error" class="error-message" role="alert"> 请输入有效的邮箱地址 </div> </div>20.2 校验时机选择
- 即时校验:适合简单格式校验(用
input事件) - 失焦校验:适合复杂校验(用
blur事件) - 提交校验:最终保障(用
submit事件)
21. 性能监控与调优
21.1 校验耗时统计
// 前端性能监控 function withValidationMetrics(fn) { return function(...args) { const start = performance.now(); const result = fn(...args); const duration = performance.now() - start; metrics.track('validation_time', { field: args[0], duration: duration }); return result; }; } const validateEmail = withValidationMetrics(email => { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); });21.2 高频校验优化
对于自动完成等高频触发场景:
// 防抖校验实现 const debouncedValidate = _.debounce(validate, 300); input.addEventListener('input', () => { debouncedValidate(input.value); });22. 领域特定校验模式
22.1 电商领域示例
商品库存校验:
public void validateInventory(OrderItem item) { Product product = productRepository.findById(item.getProductId()); if (product.getStock() < item.getQuantity()) { throw new InventoryException("库存不足"); } if (product.getStatus() != ProductStatus.ON_SALE) { throw new BusinessException("商品已下架"); } }22.2 金融领域示例
金额校验:
from decimal import Decimal, getcontext getcontext().prec = 6 def validate_amount(amount): if not isinstance(amount, Decimal): amount = Decimal(str(amount)) if amount <= Decimal('0'): raise ValueError("金额必须大于0") if amount.as_tuple().exponent < -2: raise ValueError("最多支持两位小数")23. 校验规则文档化
23.1 Swagger集成示例
@Schema(description = "用户注册参数") public class RegisterDTO { @Schema(description = "用户名", required = true, minLength = 2, maxLength = 20) @NotBlank @Size(min = 2, max = 20) private String username; @Schema(description = "邮箱", format = "email") @Email private String email; }23.2 校验规则导出
// 将校验规则导出为Markdown文档 function generateValidationDocs(rules) { let md = `# 字段校验规则\n\n`; Object.entries(rules).forEach(([field, rule]) => { md += `## ${field}\n`; md += `- 类型: ${rule.type}\n`; if (rule.required) md += `- 必填: 是\n`; if (rule.minLength) md += `- 最小长度: ${rule.minLength}\n`; if (rule.pattern) md += `- 正则: \`${rule.pattern}\`\n`; md += '\n'; }); return md; }24. 校验规则测试数据生成
24.1 合法测试数据
// 根据校验规则生成合法测试数据 function generateValidData(rules) { const data = {}; Object.entries(rules).forEach(([field, rule]) => { if (rule.type === 'string') { data[field] = generateString(rule); } else if (rule.type === 'number') { data[field] = generateNumber(rule); } }); return data; } function generateString(rule) { const length = rule.minLength || 5; let result = ''; // 生成逻辑... return result; }24.2 边界测试数据
// JUnit 5参数化测试数据 static Stream<Arguments> invalidUsernames() { return Stream.of( Arguments.of(""), // 空字符串 Arguments.of(" "), // 空格 Arguments.of("a"), // 太短 Arguments.of("very_long_username_exceeding_limit") // 太长 ); } @ParameterizedTest @MethodSource("invalidUsernames") void testInvalidUsernames(String username) { assertFalse(validator.validateUsername(username)); }25. 校验规则的自动化重构
25.1 重复规则提取
// 提取公共邮箱校验规则 const commonRules = { email: { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '邮箱格式不正确' } }; // 在多个表单中复用 const loginRules = { email: commonRules.email, password: { required: true } };25.2 规则版本迁移工具
# 规则升级脚本示例 def migrate_validation_rules_v1_to_v2(old_rules): new_rules = {} for field, rule in old_rules.items(): new_rule = { 'type': rule['field_type'], 'constraints': [] } if rule.get('required'): new_rule['constraints'].append({ 'type': 'required' }) # 其他规则转换逻辑... new_rules[field] = new_rule return new_rules26. 校验规则的动态调整
26.1 基于上下文的规则
// 根据用户类型动态调整校验规则 function getValidationRules(userType) { const baseRules = { username: { required: true, minLength: 2 } }; if (userType === 'admin') { return { ...baseRules, email: { required: true, pattern: /@company\.com$/ } }; } return baseRules; }26.2 运行时规则修改
// 动态更新校验规则 public class DynamicValidator { private Map<String, Predicate<String>> rules = new ConcurrentHashMap<>(); public void addRule(String field, Predicate<String> rule) { rules.put(field, rule); } public boolean validate(String field, String value) { return rules.getOrDefault(field, v -> true).test(value); } }27. 校验规则可视化调试
27.1 规则调试面板
<div class="validator-debugger"> <h3>校验规则测试</h3> <select id="rule-selector"> <option value="email">邮箱校验</option> <option value="phone">手机号校验</option> </select> <input id="test-input" type="text"> <button id="test-button">测试</button> <div id="test-result"></div> </div> <script> document.getElementById('test-button').addEventListener('click', () => { const rule = document.getElementById('rule-selector').value; const value = document.getElementById('test-input').value; const isValid = validators[rule](value); document.getElementById('test-result').textContent = isValid ? '✓ 验证通过' : '✗ 验证失败'; }); </script>27.2 正则表达式可视化
使用工具如regexper.com生成正则表达式图解,帮助团队理解复杂规则:
^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$对应可视化图形可以清晰展示邮箱校验的各个组成部分。
28. 校验规则的AB测试
28.1 不同严格度的规则对比
// 定义不同严格级别的校验规则 const validationVariants = { relaxed: { password: { minLength: 6 } }, standard: { password: { minLength: 8, requireSpecialChar: true } }, strict: { password: { minLength: 12, requireSpecialChar: true, requireMixedCase: true } } }; // 根据用户分组应用不同规则 function getVariantRules(userId) { const variant = getUserVariant(userId); // AB测试分组逻辑 return validationVariants[variant]; }28.2 校验规则效果分析
通过埋点收集数据:
| 指标 | 宽松版 | 标准版 | 严格版 |
|---|---|---|---|
| 注册转化率 | 85% | 78% | 65% |
| 首次登录成功率 | 92% | 95% | 98% |
| 客服投诉率 | 12% | 8% | 3% |
根据业务目标选择最佳平衡点。
29. 校验规则的知识管理
29.1 规则决策记录
为每个重要校验规则创建ADR(Architecture Decision Record):
# 密码强度校验规则决策 ## 状态 已通过 ## 背景 现有系统密码规则仅为6位任意字符,安全评估显示需要增强 ## 决策 采用以下密码规则: - 最小长度8位 - 必须包含字母和数字 - 可选包含特殊字符 ## 后果 - 安全性提升,预计减少30%的暴力破解风险 - 注册转化率可能下降5-8% - 需要更新所有客户端提示文案29.2 规则变更通知
建立校验规则变更的沟通机制:
- 修改前:在团队频道公告+文档标注"即将变更"
- 修改后:更新接口版本号,维护旧版本至少一个迭代周期
- 提供自动检测工具帮助调用方升级
30. 新兴技术对校验的影响
30.1 无密码登录的校验变化
传统校验:
{ username: { required: true }, password: { required: true, minLength: 8 } }无密码登录校验:
{ email: { required: true, format: 'email' }, magicLink: { expiresIn: '15m' } }30.2 生物识别校验
// iOS Face ID校验示例 let context = LAContext() var error: NSError? if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "验证以继续") { success, error in DispatchQueue.main.async { if success { // 校验通过 } else { // 处理错误 } } } }31. 校验规则的自动化测试
31.1 规则覆盖度检测
# 使用突变测试验证校验规则有效性 def test_validation_mutations(validator): # 原始合法数据 valid_data = {"email": "test@example.com"} assert validator.validate(valid_data) # 生成突变数据 mutations = [ {"email": "invalid-email"}, # 移除@符号 {"email": "test@example"}, # 移除顶级域名 {"email": ""}, # 空字符串 {"email": "a@b.c" * 100} # 超长字符串 ] # 验证所有突变都应被捕获 for mutation in mutations: assert not validator.validate(mutation)31.2 规则性能基准
@BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MICROSECONDS) public class EmailValidatorBenchmark { private static final String[] TEST_EMAILS = { "valid@example.com", "invalid.email@", "another.valid@test.org" }; @Benchmark public void benchmarkEmailValidation(Blackhole bh) { for (String email : TEST_EMAILS) { bh.consume(EmailValidator.validate(email)); } } }32. 校验规则的错误分类
32.1 错误严重等级
| 等级 | 类型 | 示例 | 处理方式 |
|---|---|---|---|
| 1 | 安全风险 | SQL注入特征 | 阻断请求并记录安全日志 |
| 2 | 业务规则违反 | 订单金额为负 | 拒绝并返回明确错误 |
| 3 | 格式问题 | 邮箱缺少@符号 | 提示用户修正 |
| 4 | 建议性提示 | 密码强度较弱 | 警告但允许继续 |
32.2 错误处理策略
function handleValidationErrors(errors) { const securityErrors = errors.filter(e => e.level === 1); if (securityErrors.length) { securityAlert(securityErrors); throw new BlockedRequestError('安全风险'); } // 其他错误处理逻辑... }33. 校验规则的元数据管理
33.1 规则属性标注
# 校验规则的元数据描述 fields: email: label: 电子邮箱 rules: - type: required message: 邮箱不能为空 severity: error since: v1.0 owner: auth-team - type: pattern value: ^\S+@\S+\.\S+$ message: 邮箱格式不正确 severity: error33.2 规则依赖分析
graph TD A[用户注册表单] -->|依赖| B(邮箱格式校验) A -->|依赖| C(密码强度校验) B -->|使用| D[正则表达式库] C -->|使用| E[密码策略服务]34. 校验规则的质量评估
34.1 规则有效性指标
- 拦截率:无效请求中被正确拦截的比例
- 误报率:有效请求被错误拦截的比例
- 处理耗时:平均每个校验规则的执行时间
- 维护成本:修改规则所需的平均时间
34.2 规则健康度检查
def check_rule_health(validator): report = { 'redundant_rules': [], 'conflicting_rules': [], 'performance_issues': [] } # 检查冗余规则 for rule1, rule2 in combinations(validator.rules, 2): if rule1.implies(rule2): report['redundant_rules'].append(f"{rule1} 使 {rule2} 冗余") # 性能检测 for rule in validator.rules: if rule.avg_time > 100ms: report['performance_issues'].append(rule.name) return report35. 校验规则的可扩展设计
35.1 插件式校验架构
// 校验规则插件接口 public interface ValidationPlugin { boolean supports(String fieldType); ValidationResult validate(String fieldName, Object value); } // 实现示例 @Component public class EmailValidationPlugin implements ValidationPlugin { @Override public boolean supports(String fieldType) { return "email".equals(fieldType); } @Override public ValidationResult validate(String fieldName, Object value) { // 具体校验逻辑... } }35.2 自定义规则DSL
// 自定义校验规则语言示例 const ruleEngine = new RuleEngine({ rules: { isAdult: { validate: value => value >=