validator注册自定义类型的验证器

This commit is contained in:
xh
2025-12-05 23:50:01 +08:00
parent ea0d138e88
commit 387bc074bc
11 changed files with 239 additions and 166 deletions
@@ -38,14 +38,12 @@ type {{{ toUpperCamelCase .EntityName }}}AddReq struct {
//{{{ toUpperCamelCase .EntityName }}}EditReq {{{ .FunctionName }}}编辑参数
type {{{ toUpperCamelCase .EntityName }}}EditReq struct {
{{{ toUpperCamelCase .EntityName }}}Primarykey
{{{ toUpperCamelCase .EntityName }}}AddReq
{{{- range .Columns }}}
{{{- if .IsEdit }}}
{{{- if .IsPk }}}
// {{{ toUpperCamelCase .GoField }}} {{{ .GoType }}} // {{{ .ColumnComment }}}
{{{ toUpperCamelCase .GoField }}} {{{ .GoType }}} // {{{ .ColumnComment }}}
{{{- else }}}
// {{{ toUpperCamelCase .GoField }}} {{{goWithAddEditType .GoType }}} // {{{ .ColumnComment }}}
{{{ toUpperCamelCase .GoField }}} {{{goWithAddEditType .GoType }}} // {{{ .ColumnComment }}}
{{{- end }}}
{{{- end }}}
{{{- end }}}
@@ -65,7 +65,7 @@ func (service {{{ toCamelCase .EntityName }}}Service) GetModel(listReq schema.{{
return dbModel
}
// 获取更新map
func (service {{{ toCamelCase .EntityName }}}Service) GetUpdateMap(listReq schema.{{{ toUpperCamelCase .EntityName }}}EditReq) map[string]interface{} {
func (service {{{ toCamelCase .EntityName }}}Service) GetUpdateMap(editReq schema.{{{ toUpperCamelCase .EntityName }}}EditReq) map[string]interface{} {
updateMap := make(map[string]interface{})
{{{- range .Columns }}}
{{{- if .IsEdit }}}
+27
View File
@@ -20,6 +20,33 @@ type NullTime struct {
// Format string
}
// func DecodeNulLTime(value any) (any, error) {
// switch v := value.(type) {
// case string:
// if v == "" {
// return NullTime{
// Val: nil,
// Exist: true,
// }, nil
// }
// tt, e := time.ParseInLocation(TimeFormat, v, time.Local)
// if e != nil {
// return NullTime{}, e
// }
// return NullTime{
// Val: &tt,
// Exist: true,
// }, nil
// case time.Time:
// return NullTime{
// Val: &v,
// Exist: true,
// }, nil
// default:
// return NullTime{}, errors.New("时间格式错误")
// }
// }
func (i *NullTime) UnmarshalText(text []byte) error {
return i.Scan(string(text))
}
+59 -42
View File
@@ -3439,39 +3439,7 @@ const docTemplate = `{
}
}
},
"/api/ws": {
"get": {
"tags": [
"公共接口"
],
"summary": "websocket连接",
"parameters": [
{
"type": "string",
"description": "token",
"name": "token",
"in": "header",
"required": true
},
{
"type": "string",
"description": "用户ID",
"name": "uid",
"in": "query",
"required": true
},
{
"type": "string",
"description": "房间ID",
"name": "room",
"in": "query",
"required": true
}
],
"responses": {}
}
},
"/swagger/doc.json": {
"/api/swagger/doc.json": {
"get": {
"tags": [
"公共接口"
@@ -3480,6 +3448,55 @@ const docTemplate = `{
"responses": {}
}
},
"/api/ws": {
"get": {
"tags": [
"公共接口"
],
"summary": "ws通用接口",
"parameters": [
{
"type": "string",
"default": "\"websocket\"",
"description": "请求协议升级",
"name": "Upgrade",
"in": "header",
"required": true
},
{
"type": "string",
"default": "\"Upgrade\"",
"description": "升级连接类型",
"name": "Connection",
"in": "header",
"required": true
},
{
"type": "string",
"description": "WebSocket握手密钥",
"name": "Sec-WebSocket-Key",
"in": "header",
"required": true
},
{
"type": "string",
"default": "\"13\"",
"description": "WebSocket协议版本",
"name": "Sec-WebSocket-Version",
"in": "header",
"required": true
}
],
"responses": {
"101": {
"description": "协议切换成功",
"schema": {
"type": "string"
}
}
}
}
},
"/system/admin/ListByDeptId/{deptId}": {
"get": {
"description": "获取部门的用户",
@@ -3511,25 +3528,25 @@ const docTemplate = `{
"core.NullInt": {
"type": "object",
"properties": {
"exist": {
"description": "是否有值",
"type": "boolean"
},
"val": {
"description": "整数或者null",
"type": "integer",
"format": "int64"
},
"valid": {
"description": "是否有值",
"type": "boolean"
}
}
},
"core.NullTime": {
"type": "object",
"properties": {
"exist": {
"type": "boolean"
},
"val": {
"type": "string"
},
"valid": {
"type": "boolean"
}
}
},
@@ -3925,7 +3942,7 @@ const docTemplate = `{
"type": "string"
},
"createTime": {
"description": "Sort core.NullFloat // 排序",
"description": "创建时间",
"type": "string"
},
"id": {
@@ -3945,7 +3962,7 @@ const docTemplate = `{
},
"version": {
"description": "版本",
"type": "integer"
"type": "number"
}
}
}
+59 -42
View File
@@ -3430,39 +3430,7 @@
}
}
},
"/api/ws": {
"get": {
"tags": [
"公共接口"
],
"summary": "websocket连接",
"parameters": [
{
"type": "string",
"description": "token",
"name": "token",
"in": "header",
"required": true
},
{
"type": "string",
"description": "用户ID",
"name": "uid",
"in": "query",
"required": true
},
{
"type": "string",
"description": "房间ID",
"name": "room",
"in": "query",
"required": true
}
],
"responses": {}
}
},
"/swagger/doc.json": {
"/api/swagger/doc.json": {
"get": {
"tags": [
"公共接口"
@@ -3471,6 +3439,55 @@
"responses": {}
}
},
"/api/ws": {
"get": {
"tags": [
"公共接口"
],
"summary": "ws通用接口",
"parameters": [
{
"type": "string",
"default": "\"websocket\"",
"description": "请求协议升级",
"name": "Upgrade",
"in": "header",
"required": true
},
{
"type": "string",
"default": "\"Upgrade\"",
"description": "升级连接类型",
"name": "Connection",
"in": "header",
"required": true
},
{
"type": "string",
"description": "WebSocket握手密钥",
"name": "Sec-WebSocket-Key",
"in": "header",
"required": true
},
{
"type": "string",
"default": "\"13\"",
"description": "WebSocket协议版本",
"name": "Sec-WebSocket-Version",
"in": "header",
"required": true
}
],
"responses": {
"101": {
"description": "协议切换成功",
"schema": {
"type": "string"
}
}
}
}
},
"/system/admin/ListByDeptId/{deptId}": {
"get": {
"description": "获取部门的用户",
@@ -3502,25 +3519,25 @@
"core.NullInt": {
"type": "object",
"properties": {
"exist": {
"description": "是否有值",
"type": "boolean"
},
"val": {
"description": "整数或者null",
"type": "integer",
"format": "int64"
},
"valid": {
"description": "是否有值",
"type": "boolean"
}
}
},
"core.NullTime": {
"type": "object",
"properties": {
"exist": {
"type": "boolean"
},
"val": {
"type": "string"
},
"valid": {
"type": "boolean"
}
}
},
@@ -3916,7 +3933,7 @@
"type": "string"
},
"createTime": {
"description": "Sort core.NullFloat // 排序",
"description": "创建时间",
"type": "string"
},
"id": {
@@ -3936,7 +3953,7 @@
},
"version": {
"description": "版本",
"type": "integer"
"type": "number"
}
}
}
+42 -30
View File
@@ -2,20 +2,20 @@ basePath: /
definitions:
core.NullInt:
properties:
exist:
description: 是否有值
type: boolean
val:
description: 整数或者null
format: int64
type: integer
valid:
description: 是否有值
type: boolean
type: object
core.NullTime:
properties:
exist:
type: boolean
val:
type: string
valid:
type: boolean
type: object
flowSchema.FlowApplyResp:
properties:
@@ -278,7 +278,7 @@ definitions:
description: 协议内容
type: string
createTime:
description: Sort core.NullFloat // 排序
description: 创建时间
type: string
id:
type: string
@@ -293,7 +293,7 @@ definitions:
type: string
version:
description: 版本
type: integer
type: number
type: object
externalDocs:
description: OpenAPI
@@ -2454,34 +2454,46 @@ paths:
summary: 用户协议列表-所有
tags:
- user_protocol-用户协议
/api/ws:
get:
parameters:
- description: token
in: header
name: token
required: true
type: string
- description: 用户ID
in: query
name: uid
required: true
type: string
- description: 房间ID
in: query
name: room
required: true
type: string
responses: {}
summary: websocket连接
tags:
- 公共接口
/swagger/doc.json:
/api/swagger/doc.json:
get:
responses: {}
summary: swagger文档数据
tags:
- 公共接口
/api/ws:
get:
parameters:
- default: '"websocket"'
description: 请求协议升级
in: header
name: Upgrade
required: true
type: string
- default: '"Upgrade"'
description: 升级连接类型
in: header
name: Connection
required: true
type: string
- description: WebSocket握手密钥
in: header
name: Sec-WebSocket-Key
required: true
type: string
- default: '"13"'
description: WebSocket协议版本
in: header
name: Sec-WebSocket-Version
required: true
type: string
responses:
"101":
description: 协议切换成功
schema:
type: string
summary: ws通用接口
tags:
- 公共接口
/system/admin/ListByDeptId/{deptId}:
get:
description: 获取部门的用户
+1 -1
View File
@@ -30,7 +30,7 @@ require (
github.com/gorilla/websocket v1.5.3
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20251113013923-bd30b77d5468
github.com/mitchellh/mapstructure v1.5.0
github.com/redis/go-redis/v9 v9.16.0
github.com/redis/go-redis/v9 v9.17.2
github.com/robfig/cron/v3 v3.0.1
github.com/wneessen/go-mail v0.7.2
go.uber.org/ratelimit v0.3.1
+2 -2
View File
@@ -134,8 +134,8 @@ github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY=
github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c=
github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4=
github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI=
github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+20 -1
View File
@@ -1,9 +1,11 @@
package main
import (
"database/sql/driver"
"fmt"
"log"
"net/http"
"reflect"
"strconv"
"time"
"x_admin/config"
@@ -16,6 +18,8 @@ import (
// _ "x_admin/docs"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
// // go:embed public/static
@@ -23,6 +27,7 @@ import (
// initRouter 初始化router
func initRouter() *gin.Engine {
// 初始化gin
gin.SetMode(config.AppConfig.GinMode)
r := gin.New()
@@ -70,6 +75,15 @@ func initServer(router *gin.Engine) *http.Server {
}
}
// ValidateValuer 将 NullInt等类型 转换为底层值(int64 或 nil)
func ValidateValuer(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(driver.Valuer); ok {
val, _ := valuer.Value()
return val // 返回 int64 或 nil
}
return nil
}
// @description x_admin是一个完整的后台管理系统
// @termsOfService http://x.adtk.cn
@@ -84,6 +98,11 @@ func initServer(router *gin.Engine) *http.Server {
// @externalDocs.description OpenAPI
// @externalDocs.url https://swagger.io/resources/open-api/
func main() {
// 注册自定义类型的验证器
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterCustomTypeFunc(ValidateValuer, core.NullString{}, core.NullInt{}, core.NullFloat{}, core.NullTime{})
}
// 刷新日志缓冲
defer core.Logger.Sync()
// 程序结束前关闭数据库连接
@@ -98,7 +117,7 @@ func main() {
fmt.Println("格式化文档注释:", "swag fmt")
fmt.Println("生成文档:", "swag init")
// fmt.Printf("文档: http://localhost:%v/swagger/index.html", config.AppConfig.Port)
fmt.Printf("文档: http://localhost:%v/api/static/api/index.html", config.AppConfig.Port)
fmt.Printf("文档: http://localhost:%v/api/static/api/index.html\n", config.AppConfig.Port)
// 初始化server
s := initServer(router)
+6 -1
View File
@@ -30,7 +30,7 @@ func apiList(api *gin.RouterGroup, rootRouter *gin.Engine) {
// @Summary swagger文档数据
// @Tags 公共接口
// @Router /swagger/doc.json [get]
// @Router /api/swagger/doc.json [get]
func swaggerJson(api *gin.RouterGroup) {
api.GET("/swagger/doc.json", func(c *gin.Context) {
// 获取域名和端口号
@@ -44,6 +44,11 @@ func swaggerJson(api *gin.RouterGroup) {
})
}
// @Summary ws通用接口
// @schemes ws
// @Tags 公共接口
// @Success 101 {string} string "协议切换成功"
// @Router /api/ws [get]
func wsHandler(api *gin.RouterGroup) {
api.GET("/ws", middleware.LoginAuth(), controller.WsHandler)
}
+20 -42
View File
@@ -1,6 +1,7 @@
package util
import (
"errors"
"time"
"x_admin/core"
)
@@ -22,47 +23,24 @@ func (t nullTimeUtil) DecodeTime(value any) (any, error) {
return tt, e
}
// EncodeTime 时间编码
func (t nullTimeUtil) EncodeTime(value any) any {
var str = ""
switch v := value.(type) {
case map[string]interface{}:
val := v["Time"]
switch tt := val.(type) {
case *string:
ttt, _ := t.Parse(*tt)
str = ttt.String()
case *time.Time:
if tt != nil {
ttt, _ := t.Parse(*tt)
str = ttt.String()
} else {
str = ""
}
}
}
return str
}
// ToUnix 时间戳转时间戳
func (t nullTimeUtil) ToUnix(date any) int64 {
switch v := date.(type) {
case string:
if v == "" {
return 0
}
tt, e := time.Parse(t.TimeFormat, v)
if e != nil {
return 0
}
return time.Time(tt).Unix()
case time.Time:
return v.Unix()
default:
return 0
}
}
// func (t nullTimeUtil) ToUnix(date any) int64 {
// switch v := date.(type) {
// case string:
// if v == "" {
// return 0
// }
// tt, e := time.Parse(t.TimeFormat, v)
// if e != nil {
// return 0
// }
// return time.Time(tt).Unix()
// case time.Time:
// return v.Unix()
// default:
// return 0
// }
// }
// Parse 时间戳转时间
func (t nullTimeUtil) Parse(value interface{}) (core.NullTime, error) {
@@ -76,7 +54,7 @@ func (t nullTimeUtil) Parse(value interface{}) (core.NullTime, error) {
case core.NullTime:
return v, nil
default:
return t.Null(), nil
return t.Null(), errors.New("时间格式错误")
}
}
@@ -104,7 +82,7 @@ func (t nullTimeUtil) ParseString(date string) (core.NullTime, error) {
func (t nullTimeUtil) Null() core.NullTime {
return core.NullTime{
Val: nil,
Exist: true,
Exist: false,
}
}