热门搜索:和平精英 原神 街篮2 

您的位置:首页 > > 教程攻略 > ai资讯 >从 PHP 到 AI + Golang,程序员自救转型手记(四十三):前后端数据验证

从 PHP 到 AI + Golang,程序员自救转型手记(四十三):前后端数据验证

来源:互联网 更新时间:2026-08-03 07:45

这是一个系列 Blog,作者将以一个 PHP 全栈工程师的身份,利用 AI 工具(claude code、codex、deepseek、豆包等):从零开始学习 golang 语言,并最终完成 ai-go-admin(github | gitee)开源项目的制作,全程记录分享。

从 PHP 到 AI + Golang,程序员自救转型手记(四十三):前后端数据验证

上一期聊了前端表格组件,这一期轮到数据验证上场。前后端各自该验什么、怎么验,整理清楚了,能省不少返工的麻烦。

前后端数据验证

服务端数据验证

服务端的数据验证,主流方案有三种,各有各的适用场景,直接看。

方案一

模型层写 binding tag,控制器层用 ginShouldBindJSON,绑定 JSON 数据的同时就把验证给办了。基控制器的 CreateUpdate 方法默认已经调用了 ShouldBindJSON,所以模型里写对验证规则就能自动生效。示例:

Username string `gorm:"comment:用户名;type:varchar(64);not null" binding:"required"`

required 表示必填,完整可用规则可以参考 go-playground/validator 文档,或者 gin 模型绑定和验证章节。注意,go-playground/validator 已随 gin 框架内置,直接拿来用就行。

方案二

模型定义里写 validate tag,这是 go-playground/validator 原生的写法,规则和 binding 一致。比如:

Username string `gorm:"comment:用户名;type:varchar(64)" validate:"required"`

但和方案一不同的是,验证需要手动触发——在服务层或控制器层重写 CreateUpdate 等方法,调用 validate.Struct 来完成。示例:

type User struct {
    FirstName string `validate:"required"`
    Age       uint8  `validate:"gte=0,lte=130"`
    Email     string `validate:"required,email"`
}

validate := validator.New()

user := &User{
    Age:   135,
    Email: "Badger.Smith@gmail.com",
}

err := validate.Struct(user)

方案三

增加 DTO,在 DTO 里定义 binding / validate tag,然后重写控制器或服务层的方法。比如 AdminUpdateRequest 就是一个自定义 DTO,不理解的全局搜索一下就能找到参考。

何时在控制器效验,何时在服务层效验?

这是一个很实际的问题,分清楚能让代码结构更清晰。

服务层

:负责那些依赖数据库、父子关系、唯一性、字段联动的校验。比如检查某个名称是否重复、上级 ID 不能是自身,这些逻辑一定放在服务层。

控制器层

:只校验字段自身的独立规则,比如必填、长度、有效值范围,不依赖数据库,也不跨字段判断。像 titlenametype 的必填,放控制器层就足够了。

举个例子:AdminRule 表

——titlenametype 的必填校验放在控制器层;name 的重复性检查、pid 不能是自己的判断,放在服务层。仓储层呢?不做任何校验,只靠数据库本身的 not null、唯一索引等机制兜底。

前端数据验证

前端的数据验证,核心是表单验证。我们准备了一个工具包 src/utils/validate.ts,里面定义了各种验证规则,最重要的是一直导出的验证规则构建器 buildValidatorRule 函数——它能很方便地生成 el-form 表单的常用验证规则。

element plus 的表单验证基于 async-validator。

具体用法参考下面的代码片段:



<script setup lang="ts">
import { regularPassword, buildValidatorRule } from '/@/utils/validate'
import type { FormItemRule } from 'element-plus'

const rules: Partial> = reactive({
    username: [buildValidatorRule({ name: 'required', title: '用户名' }), buildValidatorRule({ name: 'account' })],
    nickname: [buildValidatorRule({ name: 'required', title: '昵称' })],
    email: [buildValidatorRule({ name: 'email', message: '邮箱错误' })],
    mobile: [buildValidatorRule({ name: 'mobile', message: '手机号错误' })],
    password: [
        {
            validator: (rule: any, val: string, callback: Function) => {
                if (props.manager.form.operate == 'create') {
                    if (!val) {
                        return callback(new Error('密码必填'))
                    }
                } else {
                    if (!val) {
                        return callback()
                    }
                }
                if (!regularPassword(val)) {
                    return callback(new Error('密码需要 6-32 位,禁止使用特殊符号'))
                }
                return callback()
            },
            trigger: 'blur',
        },
    ],
})
</script>

注意密码字段的验证逻辑:创建时必填,编辑时非必填;但只要有值,就必须符合 6-32 位且无特殊符号的规则。这种条件判断在业务中很常见,直接用 validator 函数处理最灵活。

热门手游

手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc