1. 写在最前面
笔者在去年 coding 的时候,有用到两个比较好用的库,在此记录下,以便后面再次使用,同时也方便那些有这方面需求的参考。
-
golang map to structure 的库 — https://github.com/mitchellh/mapstructure
-
golang json 校验库 — https://github.com/go-playground/validator
2. mapstructure
2.1 用途
map[string]interface{}
encoding/jsonmap[string]interface{}mapstructure
2.2 例子
坑
package main
import (
"fmt"
"github.com/mitchellh/mapstructure"
)
type School struct {
name string
}
type Person struct {
Name string
Address string
Phones []string
XInfo string `json:"x-info"`
School School
}
func DecodesExample() {
m := map[string]interface{}{
"name": "xiyan",
"address": "earth",
"x-info": "not-parse",
"phones": []string{"12345678", "87654321"}, // object type
"school": School{name: "xy"}, // nested structure
}
var p Person
err := mapstructure.Decode(m, &p)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%#v", p)
}
func main() {
DecodesExample()
}
输出:
mapToStruct $>go run main.go
main.Person{Name:"xiyan", Address:"earth", Phones:[]string{"12345678", "87654321"}, XInfo:"", School:main.School{name:"xy"}}
2.3 坑说明
map[stirng]interface{}
-
3. validator
3.1 用途
在 web 应用中经常会遇到数据验证问题,比较常用的的是包 validator。其原理是将验证规则写在 struct 对应字段 tag 里,然后再通过反射获取 struct 的 tag,实现数据验证。
3.2 例子
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
func BasicExample() {
type Person struct {
Name string `json:"name" validate:"required"`
Age int64 `json:"age" validate:"required"`
}
p := Person{
Name: "",
Age: 18,
}
v := validator.New()
err := v.Struct(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p)
}
func FieldExample() {
type Person struct {
// 注意:required与nameValidator 之间只能有 「,」 不能有空格
Name string `json:"name" validate:"required,nameValidator"`
Age int64 `json:"age" validate:"required"`
}
nameValidator := func(f validator.FieldLevel) bool {
return f.Field().String() != "xiyan"
}
v := validator.New()
v.RegisterValidation("nameValidator", nameValidator)
p := Person{
Name: "xiyan",
Age: 19,
}
err := v.Struct(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p)
}
func SturctLevelExample() {
type Person struct {
Name string `json:"name" validate:"required"`
Age int64 `json:"age" validate:"required"`
}
structValidator := func(f validator.StructLevel) {
p := f.Current().Interface().(Person)
if p.Name == "xiyan" {
f.ReportError(p.Name, "Name", "name", "name", "")
}
if p.Age > 80 {
f.ReportError(p.Age, "Age", "age", "age", "")
}
}
v := validator.New()
v.RegisterStructValidation(structValidator, Person{})
p := Person{
Name: "xiyan",
Age: 81,
}
err := v.Struct(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p)
}
func main() {
// FieldExample()
SturctLevelExample()
}
上述的例子包括三部分:
- 直接在 sturcture 定义的 tag 部分定义校验规则 — BasicExample
- 针对 structure 的 Field 字段定义特定函数做校验 — FieldExample
- 针对 structure 的整体做特定函数的校验 — SturctLevelExample
SturctLevelExample
注:办法总比问题多,这里在暴露错误的使用上,笔者用了个 dirty 的处理方法,将错误的字段通过 tag 字段暴露,然后再从上层的 error 字段将 Tag 取出。
3.3 坑说明
具体例子
func SturctLevelExample() {
type Person struct {
Name string `json:"name" validate:"required"`
Age int64 `json:"age" validate:"required"`
}
structValidator := func(f validator.StructLevel) {
p := f.Current().Interface().(Person)
if p.Name == "xiyan" {
f.ReportError(p.Name, "Name", "name", "name should not equal xiyan", "")
}
if p.Age > 80 {
f.ReportError(p.Age, "Age", "age", "age should not greater than 80", "")
}
}
v := validator.New()
v.RegisterStructValidation(structValidator, Person{})
p := Person{
Name: "xiyan",
Age: 81,
}
err := v.Struct(p)
if err != nil {
for _, e := range err.(validator.ValidationErrors) {
fmt.Println(e.Tag())
}
return
}
fmt.Println(p)
}
func main() {
SturctLevelExample()
}
输出:
validator $> go run main.go
name should not equal xiyan
age should not greater than 80
4. 碎碎念
今天是个好日子,希望加班的人都能早点下班哦。
- 希望你可以明白,长大对你而言,是可以做更多想做的事,而不是被迫做更多不想做的事。
- 我希望你可以活得开心,做你喜欢做的事,累的时候喝酒吹吹风,过你想要的生活。
- 喜欢就争取,得到就珍惜,错过就忘记。
人生快乐法则之一,就是吃东西的时候就考虑东西好不好吃。