JeecgBoot表单验证:自定义校验规则+异步验证实现

JeecgBoot表单验证:自定义校验规则+异步验证实现

【免费下载链接】JeecgBoot 🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~ 【免费下载链接】JeecgBoot 项目地址: https://gitcode.com/jeecgboot/JeecgBoot

在企业级应用开发中,表单验证是确保数据完整性和准确性的关键环节。JeecgBoot作为一款强大的低代码开发平台,提供了丰富而灵活的表单验证机制,本文将深入探讨其自定义校验规则和异步验证的实现方式。

表单验证体系概述

JeecgBoot基于Ant Design Vue和SpringBoot构建了完整的表单验证体系,支持:

  • 基础验证:必填项、格式验证、长度限制等
  • 自定义验证规则:业务逻辑验证、复杂条件判断
  • 异步验证:服务端数据校验、实时查重验证
  • 组合验证:多规则组合、条件触发验证

基础验证规则实现

内置验证器

JeecgBoot提供了丰富的内置验证规则,位于 src/utils/helper/validator.ts

// 邮箱验证
email(required) {
  return [{
    required: required ? required : false,
    validator: async (_rule, value) => {
      if (required == true && !value) {
        return Promise.reject('请输入邮箱!');
      }
      if (value && !new RegExp(
        /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
      ).test(value)) {
        return Promise.reject('请输入正确邮箱格式!');
      }
      return Promise.resolve();
    },
    trigger: 'change',
  }];
}

// 手机号验证  
phone(required) {
  return [{
    required: required,
    validator: async (_, value) => {
      if (required && !value) {
        return Promise.reject('请输入手机号码!');
      }
      if (!/^1[3456789]\d{9}$/.test(value)) {
        return Promise.reject('手机号码格式有误');
      }
      return Promise.resolve();
    },
    trigger: 'change',
  }];
}

密码强度验证

rules: [{
  required: true,
  message: '请输入登录密码',
}, {
  pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
  message: '密码由8位数字、大小写字母和特殊符号组成!',
}]

自定义校验规则开发

1. 时间范围验证

实现开始时间和结束时间的关联验证:

startTime(endTime, required) {
  return [{
    required: required ? required : false,
    validator: (_, value) => {
      if (required && !value) {
        return Promise.reject('请选择开始时间');
      }
      if (endTime && value && dateUtil(endTime).isBefore(value)) {
        return Promise.reject('开始时间需小于结束时间');
      }
      return Promise.resolve();
    },
    trigger: 'change',
  }];
}

endTime(startTime, required) {
  return [{
    required: required ? required : false,
    validator: (_, value) => {
      if (required && !value) {
        return Promise.reject('请选择结束时间');
      }
      if (startTime && value && dateUtil(value).isBefore(startTime)) {
        return Promise.reject('结束时间需大于开始时间');
      }
      return Promise.resolve();
    },
    trigger: 'change',
  }];
}

2. 密码确认验证

confirmPassword(values, required) {
  return [{
    required: required ? required : false,
    validator: (_, value) => {
      if (!value) {
        return Promise.reject('密码不能为空');
      }
      if (value !== values.password) {
        return Promise.reject('两次输入的密码不一致!');
      }
      return Promise.resolve();
    },
  }];
}

3. Cron表达式验证器

实现复杂的Cron表达式格式验证:

const cronRule: ValidatorRule = {
  validator({}, value) {
    if (!value) return Promise.resolve();
    
    const values: string[] = value.split(' ').filter((item) => !!item);
    if (values.length > 7) {
      return Promise.reject('Cron表达式最多7项!');
    }
    
    // 年份验证
    if (values.length === 7) {
      const year = values[6];
      if (year !== '*' && year !== '?') {
        let yearValues: string[] = [];
        if (year.indexOf('-') >= 0) {
          yearValues = year.split('-');
        } else if (year.indexOf('/')) {
          yearValues = year.split('/');
        } else {
          yearValues = [year];
        }
        
        const checkYear = yearValues.some((item) => isNaN(Number(item)));
        if (checkYear) {
          return Promise.reject('Cron表达式参数[年]错误:' + year);
        }
      }
    }
    
    // 表达式解析验证
    try {
      const iter = CronParser.parseExpression(val);
      iter.next();
      return Promise.resolve();
    } catch (e) {
      return Promise.reject('Cron表达式错误:' + e);
    }
  },
};

异步验证实现

1. 重复数据校验

JeecgBoot提供了强大的异步重复校验机制:

// 前端验证规则
duplicateCheckRule(tableName, fieldName, model, schema, required?) {
  return [{
    validator: (_, value) => {
      if (!value && required) {
        return Promise.reject(`请输入${schema.label}`);
      }
      return new Promise<void>((resolve, reject) => {
        duplicateCheck({
          tableName,
          fieldName,
          fieldVal: value,
          dataId: model.id,
        })
          .then((res) => {
            res.success ? resolve() : reject(res.message || '校验失败');
          })
          .catch((err) => {
            reject(err.message || '验证失败');
          });
      });
    },
  }];
}

// 后端校验接口
@RestController
@RequestMapping("/sys/duplicate")
@Tag(name="重复校验")
public class DuplicateCheckController {

    @RequestMapping(value = "/check", method = RequestMethod.GET)
    @Operation(summary="重复校验接口")
    public Result<String> doDuplicateCheck(DuplicateCheckVo duplicateCheckVo) {
        if(StringUtils.isEmpty(duplicateCheckVo.getFieldVal())){
            return Result.error("数据为空,不作处理!");
        }
        
        if (sysDictService.duplicateCheckData(duplicateCheckVo)) {
            return Result.ok("该值可用!");
        } else {
            return Result.error("该值不可用,系统中已存在!");
        }
    }
}

2. 防抖异步验证

为避免频繁请求,实现防抖机制的异步验证:

const timer = {};
export const duplicateCheckDelay = (params) => {
  return new Promise((resove, rejected) => {
    let key = `${params.tableName}_${params.fieldName}`;
    clearTimeout(timer[key]);
    
    timer[key] = setTimeout(() => {
      defHttp
        .get({ url: Api.duplicateCheck, params }, { isTransformResponse: false })
        .then((res: any) => {
          resove(res as any);
        })
        .catch((error) => {
          rejected(error);
        });
      delete timer[key];
    }, 500); // 500ms防抖延迟
  });
};

实战应用示例

用户表单验证配置

export const formSchema: FormSchema[] = [
  {
    label: '用户账号',
    field: 'username',
    component: 'Input',
    required: true,
    dynamicRules: ({ model, schema }) => 
      rules.duplicateCheckRule('sys_user', 'username', model, schema, true),
  },
  {
    label: '登录密码',
    field: 'password',
    component: 'StrengthMeter',
    rules: [{
      required: true,
      message: '请输入登录密码',
    }, {
      pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,./]).{8,}$/,
      message: '密码由8位数字、大小写字母和特殊符号组成!',
    }],
  },
  {
    label: '邮箱',
    field: 'email',
    component: 'Input',
    required: true,
    dynamicRules: ({ model, schema }) => {
      return [
        { ...rules.duplicateCheckRule('sys_user', 'email', model, schema, true)[0], trigger: 'blur' },
        { ...rules.rule('email', false)[0], trigger: 'blur' },
      ];
    },
  },
  {
    label: '手机号码',
    field: 'phone',
    component: 'Input',
    required: true,
    dynamicRules: ({ model, schema }) => {
      return [
        { ...rules.duplicateCheckRule('sys_user', 'phone', model, schema, true)[0], trigger: 'blur' },
        { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误', trigger: 'blur' },
      ];
    },
  }
];

验证流程示意图

mermaid

高级验证技巧

1. 动态验证规则

根据表单状态动态调整验证规则:

dynamicDisabled: ({ values }) => {
  return !!values.id; // 编辑时禁用某些字段
},
dynamicRules: ({ model, schema }) => {
  if (model.userType === 'admin') {
    return [/* 管理员特殊规则 */];
  }
  return rules.duplicateCheckRule('sys_user', 'username', model, schema, true);
}

2. 多规则组合验证

dynamicRules: ({ model, schema }) => {
  return [
    { required: true, message: '字段不能为空' },
    { min: 6, message: '最少6个字符' },
    { ...rules.duplicateCheckRule('table', 'field', model, schema, true)[0] },
    { validator: customValidator }
  ];
}

3. 跨字段验证

{
  label: '结束时间',
  field: 'endTime',
  component: 'DatePicker',
  dynamicRules: ({ model }) => [
    { required: true, message: '请选择结束时间' },
    {
      validator: (_, value) => {
        if (model.startTime && value && value < model.startTime) {
          return Promise.reject('结束时间必须大于开始时间');
        }
        return Promise.resolve();
      }
    }
  ]
}

性能优化建议

  1. 防抖处理:对频繁触发的验证添加防抖机制
  2. 缓存结果:对重复的验证请求进行缓存
  3. 分批验证:将验证逻辑分批执行,避免阻塞UI
  4. 懒加载验证器:按需加载复杂的验证逻辑

常见问题解决方案

问题1:异步验证Promise挂起

解决方案:使用防抖机制和超时处理

const validateWithTimeout = (validator, timeout = 3000) => {
  return Promise.race([
    validator(),
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('验证超时')), timeout)
    )
  ]);
};

问题2:验证规则冲突

解决方案:明确规则优先级,使用 trigger 控制触发时机

rules: [
  { required: true, message: '必填项', trigger: 'blur' },
  { validator: asyncValidator, trigger: 'change' }
]

问题3:国际化支持

解决方案:使用JeecgBoot内置的国际化机制

validator: (_, value) => {
  const { t } = useI18n();
  if (!value) {
    return Promise.reject(t('validation.required'));
  }
  return Promise.resolve();
}

总结

JeecgBoot的表单验证体系提供了从基础到高级的完整解决方案:

  • 基础验证:内置丰富的验证规则
  • 自定义验证:支持复杂的业务逻辑验证
  • 异步验证:完整的服务端校验机制
  • 性能优化:防抖、缓存等优化措施
  • 错误处理:完善的错误提示和恢复机制

通过合理运用这些验证技术,可以构建出既用户友好又数据安全的企业级表单系统,显著提升应用的数据质量和用户体验。

【免费下载链接】JeecgBoot 🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~ 【免费下载链接】JeecgBoot 项目地址: https://gitcode.com/jeecgboot/JeecgBoot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值