golangの下でどのようにdjangoをまねてserializerを実現して、とても適用します!

21980 ワード

serializer用golangの実装方法
返されたmodelに対してdjangoのtoRepresentation()操作(update,pop,picked)は現在json符号化方式のみに対して行われており、他の方式はserializerにフォローして以下のように実現される.
package serializer

import (
	"encoding/json"
	"github.com/fwhezfwhez/errorx"
)

// A block type aims to mapper the origin struct to a map[string]interface{}
// For Instance:
//   struct{
// 		Name string
//		Age int
//   }{
//		Name: "fwhezfwhez",
//		Age: 9,
//    }
// The Block of the struct would be a map[string]interface{} {"name":"ft","age":9}
//
type Block map[string]interface{}
func (b *Block) Update(key string, value interface{})*Block{
	(*b)[key] = value
	return b
}

func (b *Block) Pop(key string)*Block{
	delete(*b, key)
	return b
}

type SerializerI interface{
	Serialize(dest interface{},f func(b Block)(func(b Block)Block,[]string))([]byte,error)
}

// a json serializer realization
type JsonSerializer struct{
}

func (s JsonSerializer) Serialize(dest interface{},f func(b Block)(func(b Block)Block,[]string))([]byte,error){
	//1. transfer the struct to a map
	var m = make(Block,0)
	buf, er :=json.Marshal(dest)
	if er!=nil {
		return nil, errorx.New(er)
	}
	er = json.Unmarshal(buf,&m)
	if er!=nil {
		return nil, errorx.New(er)
	}

	//2. handle picked fields into the map
	blockHandler,picked :=f(m)
	//2.1 get filtered fields , get all fields if picked is nil or len=0
	var filtPicked Block
	if picked ==nil || len(picked) ==0{
		filtPicked = m
	}else{
		filtPicked = make(Block,0)
		for _,v :=range picked{
			vm,ok := m[v]
			if !ok {
				continue
			}
			filtPicked[v] = vm
		}
	}

	//2.2 change fields with the updated and popped staff
	buf, er = json.Marshal(blockHandler(filtPicked))
	if er != nil {
		return nil, errorx.Wrap(er)
	}

	return buf, nil
}

使用方法go get github.com/fwhezfwhez/go-serializer
package main

import (
	"encoding/json"
	"fmt"
	"github.com/fwhezfwhez/go-serializer"
	"time"
)

type User struct {
	serializer.SerializerI
	Name      string    `json:"name"`
	Age       int       `json:"age"`
	Salary    float64   `json:"salary"`
	CreatedAt time.Time `json:"created_at"`
}

func (u User) ToRepresentation(f func(serializer.Block) (func(b serializer.Block) serializer.Block, []string)) ([]byte, error) {
	return u.Serialize(u, f)
}

func main() {
	u := User{
		SerializerI: serializer.JsonSerializer{},
		Name:      "ft2",
		Age:       9,
		Salary:    1000,
		CreatedAt: time.Now(),
	}

	buf, er := u.ToRepresentation(func(m serializer.Block) (func(b serializer.Block) serializer.Block, []string) {
		// abandon the 'Salary' field,use 'pick:= []string(nil)' to stand for all picked
		pick := []string{"age", "created", "name"}
		handler := func(b serializer.Block) serializer.Block {
			// update
			b.Update("question", "why?")
			b.Update("location", "china")
			// pop
			b.Pop("location")
			// rewrite
			b.Update("created_at", u.CreatedAt.Format("2006-01-02 15:04:05"))
			return b
		}
		return handler, pick
	})
	if er != nil {
		fmt.Println(er.Error())
		return
	}
	// the result of buf is a json []byte
	fmt.Println(string(buf))
	// if you want a further operator to the json map,get it by:
	var m map[string]interface{}
	json.Unmarshal(buf, &m)
	fmt.Println(m)
}


result:
{"age":9,"created_at":"2018-10-15 09:55:24","name":"ft2","question":"why?"}
map[age:9 created_at:2018-10-15 09:55:24 name:ft2 question:why?]