如何创建自定义验证规则?

wen PHP项目 67

本文目录导读:

如何创建自定义验证规则?

  1. 前端验证(JavaScript)
  2. 后端验证
  3. 数据库级验证(PostgreSQL)
  4. 完整示例:前端+后端组合验证

前端验证(JavaScript)

使用原生HTML5验证

<input type="text" 
       pattern="[A-Za-z]+" 
       title="只允许英文字母"
       required>

自定义JS验证函数

function validateCustom(value) {
    // 自定义规则:必须以"ABC"开头
    const regex = /^ABC/;
    if (!regex.test(value)) {
        return { valid: false, message: '必须以ABC开头' };
    }
    return { valid: true };
}
// 使用示例
const input = document.getElementById('myInput');
input.addEventListener('blur', function() {
    const result = validateCustom(this.value);
    if (!result.valid) {
        showError(result.message);
    }
});

使用验证库(如Yup)

import * as yup from 'yup';
const customSchema = yup.string()
    .required('必填')
    .test('is-valid-length', '长度必须在5-10之间', function(value) {
        return value.length >= 5 && value.length <= 10;
    })
    .test('no-special-char', '不能包含特殊字符', function(value) {
        return /^[a-zA-Z0-9]+$/.test(value);
    });
// 使用
async function validateForm(data) {
    try {
        await customSchema.validate(data.username);
        return { valid: true };
    } catch (error) {
        return { valid: false, message: error.message };
    }
}

后端验证

Python (Flask + WTForms)

from wtforms import Form, StringField, validators
from wtforms.validators import ValidationError
class CustomForm(Form):
    username = StringField('用户名', [
        validators.DataRequired(),
        validators.Length(min=3, max=20)
    ])
    def validate_username(form, field):
        # 自定义验证:禁止包含admin
        if 'admin' in field.data.lower():
            raise ValidationError('用户名不能包含admin')
        # 自定义验证:必须是邮箱格式但排除特定域名
        if not '@' in field.data:
            raise ValidationError('请输入有效的邮箱')
        if field.data.endswith('@example.com'):
            raise ValidationError('不接受example.com邮箱')
# 使用示例
@app.route('/register', methods=['POST'])
def register():
    form = CustomForm(request.form)
    if form.validate():
        return "表单有效"
    return str(form.errors)

Java (Spring Boot + Hibernate Validator)

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.Payload;
// 1. 定义注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface ValidPhone {
    String message() default "手机号格式不正确";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
// 2. 实现验证逻辑
public class PhoneValidator implements ConstraintValidator<ValidPhone, String> {
    @Override
    public void initialize(ValidPhone constraintAnnotation) {}
    @Override
    public boolean isValid(String phone, ConstraintValidatorContext context) {
        if (phone == null) return false;
        // 自定义验证:11位数字且以1开头
        return phone.matches("^1[3-9]\\d{9}$");
    }
}
// 3. 在实体中使用
public class User {
    @ValidPhone
    private String phone;
    @Pattern(regexp = "^[a-zA-Z0-9]{5,20}$", message = "用户名必须5-20位字母数字")
    private String username;
}

数据库级验证(PostgreSQL)

-- 创建自定义域
CREATE DOMAIN positive_integer AS INTEGER 
    CHECK (VALUE > 0);
-- 或使用检查约束
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE,
    age INTEGER CHECK (age >= 0 AND age <= 150),
    status VARCHAR(20) CHECK (status IN ('active', 'inactive', 'banned'))
);

完整示例:前端+后端组合验证

前端 (Vue 3 + VeeValidate)

// 自定义验证规则
import { defineRule } from 'vee-validate';
defineRule('strong_password', (value, [min]) => {
    if (!value || !value.length) {
        return '密码是必填项';
    }
    // 检查长度
    if (value.length < min) {
        return `密码长度不能小于${min}位`;
    }
    // 检查包含大写字母
    if (!/[A-Z]/.test(value)) {
        return '密码必须包含大写字母';
    }
    // 检查包含数字
    if (!/[0-9]/.test(value)) {
        return '密码必须包含数字';
    }
    return true;
});
// 在组件中使用
<template>
  <input v-model="password" name="password" 
         :rules="'strong_password:8'" />
</template>

后端 (Node.js + Express-validator)

const { body, validationResult } = require('express-validator');
// 自定义验证器
const customValidators = {
    isStrongPassword: (value) => {
        if (!value || value.length < 8) {
            throw new Error('密码长度至少8位');
        }
        if (!/[A-Z]/.test(value)) {
            throw new Error('密码必须包含大写字母');
        }
        if (!/[0-9]/.test(value)) {
            throw new Error('密码必须包含数字');
        }
        return true;
    },
    isNotBannedUser: async (value) => {
        const bannedUsers = ['spam1', 'spam2'];
        if (bannedUsers.includes(value.toLowerCase())) {
            throw new Error('该用户名已被禁用');
        }
        return true;
    }
};
// 路由中使用
app.post('/register', [
    body('username')
        .isLength({ min: 3, max: 20 })
        .custom(customValidators.isNotBannedUser),
    body('password')
        .custom(customValidators.isStrongPassword)
], (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
    }
    // 处理注册逻辑
});
  1. 前端验证:提升用户体验,但不可靠(可绕过)
  2. 后端验证:必须的,数据安全的第一道防线
  3. 数据库验证:最终保障,防止错误数据入库
  4. 统一规则:前后端验证规则保持一致
  5. 错误信息:提供清晰、友好的错误提示

选择哪种方式取决于你的技术栈和需求,通常建议前端+后端双重验证来确保数据安全。

抱歉,评论功能暂时关闭!