2025-06-04 22:01:47 +08:00
|
|
|
|
package mapstruct
|
|
|
|
|
|
|
|
|
|
import (
|
2025-06-04 22:59:12 +08:00
|
|
|
|
"fmt"
|
2025-06-04 22:01:47 +08:00
|
|
|
|
"reflect"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// HookFunc 定义字段转换钩子函数类型
|
|
|
|
|
type HookFunc func(reflect.Value, reflect.StructField) (any, error)
|
2025-06-04 22:01:47 +08:00
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// StringHookFunc 定义字符串到值的转换钩子函数类型
|
|
|
|
|
type StringHookFunc func(string, reflect.StructField) (any, error)
|
2025-06-04 22:01:47 +08:00
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// Options 包含所有转换选项
|
|
|
|
|
type Options struct {
|
|
|
|
|
TagName string // 使用的结构体标签名称
|
|
|
|
|
TypeHooks map[reflect.Type]HookFunc // 类型级别的钩子
|
|
|
|
|
StringTypeHooks map[reflect.Type]StringHookFunc // 字符串到类型的钩子
|
|
|
|
|
FieldHooks map[string]HookFunc // 字段级别的钩子
|
2025-06-04 22:01:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// Option 是配置选项的函数类型
|
2025-06-04 22:01:47 +08:00
|
|
|
|
type Option func(*Options)
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// WithTagName 设置结构体标签名称
|
2025-06-04 22:01:47 +08:00
|
|
|
|
func WithTagName(name string) Option {
|
|
|
|
|
return func(o *Options) {
|
|
|
|
|
o.TagName = name
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// WithTypeHook 添加类型级别的转换钩子
|
2025-06-04 22:01:47 +08:00
|
|
|
|
func WithTypeHook(typ reflect.Type, hook HookFunc) Option {
|
|
|
|
|
return func(o *Options) {
|
|
|
|
|
if o.TypeHooks == nil {
|
|
|
|
|
o.TypeHooks = make(map[reflect.Type]HookFunc)
|
|
|
|
|
}
|
|
|
|
|
o.TypeHooks[typ] = hook
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// WithStringTypeHook 添加字符串到类型的转换钩子
|
2025-06-04 22:01:47 +08:00
|
|
|
|
func WithStringTypeHook(typ reflect.Type, hook StringHookFunc) Option {
|
|
|
|
|
return func(o *Options) {
|
|
|
|
|
if o.StringTypeHooks == nil {
|
|
|
|
|
o.StringTypeHooks = make(map[reflect.Type]StringHookFunc)
|
|
|
|
|
}
|
|
|
|
|
o.StringTypeHooks[typ] = hook
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// WithFieldHook 添加字段级别的转换钩子
|
2025-06-04 22:01:47 +08:00
|
|
|
|
func WithFieldHook(fieldName string, hook HookFunc) Option {
|
|
|
|
|
return func(o *Options) {
|
|
|
|
|
if o.FieldHooks == nil {
|
|
|
|
|
o.FieldHooks = make(map[string]HookFunc)
|
|
|
|
|
}
|
|
|
|
|
o.FieldHooks[fieldName] = hook
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
//// WithStringFieldHook 添加字段级别的字符串转换钩子
|
|
|
|
|
//func WithStringFieldHook(fieldName string, hook StringHookFunc) Option {
|
|
|
|
|
// return func(o *Options) {
|
|
|
|
|
// if o.FieldHooks == nil {
|
|
|
|
|
// o.FieldHooks = make(map[string]HookFunc)
|
|
|
|
|
// }
|
|
|
|
|
// // 适配器:将StringHookFunc转换为HookFunc
|
|
|
|
|
// o.FieldHooks[fieldName] = func(v reflect.Value, f reflect.StructField) (any, error) {
|
|
|
|
|
// if v.Kind() != reflect.String {
|
|
|
|
|
// return nil, nil
|
|
|
|
|
// }
|
|
|
|
|
// return hook(v.String(), f)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//}
|
2025-06-04 22:01:47 +08:00
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// defaultOptions 返回默认配置选项
|
2025-06-04 22:01:47 +08:00
|
|
|
|
func defaultOptions() *Options {
|
|
|
|
|
opts := &Options{
|
2025-06-04 22:59:12 +08:00
|
|
|
|
TagName: "json", // 默认使用json标签
|
2025-06-04 22:01:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
// 注册默认的时间类型钩子
|
|
|
|
|
WithStringTypeHook(reflect.TypeOf(time.Time{}), func(value string, _ reflect.StructField) (any, error) {
|
|
|
|
|
// 尝试多种常见时间格式
|
|
|
|
|
formats := []string{
|
|
|
|
|
"2006-01-02 15:04:05", // 标准格式
|
|
|
|
|
"2006-01-02", // 仅日期
|
|
|
|
|
time.RFC3339, // ISO8601格式
|
|
|
|
|
"2006/01/02 15:04:05", // 斜杠分隔
|
|
|
|
|
"2006/01/02", // 斜杠分隔仅日期
|
|
|
|
|
"02-Jan-2006", // 英文月份缩写
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, layout := range formats {
|
|
|
|
|
if t, err := time.Parse(layout, value); err == nil {
|
|
|
|
|
return t, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-04 22:01:47 +08:00
|
|
|
|
|
2025-06-04 22:59:12 +08:00
|
|
|
|
return nil, fmt.Errorf("无法解析时间字符串: %s", value)
|
2025-06-04 22:01:47 +08:00
|
|
|
|
})(opts)
|
|
|
|
|
|
|
|
|
|
return opts
|
|
|
|
|
}
|