项目场景:
要对数个数据库表中的数据进行加密/解密,需针对每个数据表建立结构体,针对不同的结构体写不同的解密方法,此过程十分繁琐,但必不可少。
解决方案:
通过使用反射,对结构体进行动态的获取属性,修改属性等操作可大大减少代码量。
package decode
import (
"DecodeService/util"
"fmt"
"reflect"
"strconv"
"strings"
)
const tag = "json"
func DeCommon(o interface{}) {
// 获取类型
t := reflect.TypeOf(o)
// 因为传入的是指针所以需要这步
t = t.Elem()
// 获取值
v := reflect.ValueOf(o)
// 因为传入的是指针所以需要这步
v = v.Elem()
// 可以获取所有属性
// 获取结构体字段个数:t.NumField()
for i := 0; i < t.NumField(); i++ {
// 取每个不为空的字段
if !v.Field(i).IsZero() {
f := t.Field(i)
tag := f.Tag.Get(tag)
fv := v.Field(i).String()
if strings.HasPrefix(tag, "enc") && fv != "0" {
fmt.Println("- decode - ", fv)
var plaintext string
plaintext = util.DecodeEDE3WithKey(fv)
tagName := "de" + tag[3:]
setValue(o, tagName, plaintext)
}
}
}
}
// 可以运行
func setValue(o interface{}, tagName, plaintext string) {
v := reflect.ValueOf(o)
v = v.Elem()
t := reflect.TypeOf(o)
t = t.Elem()
var f reflect.Value
for i := 0; i < t.NumField(); i++ {
if t.Field(i).Tag.Get("json") == tagName {
f = v.Field(i)
}
}
if !f.IsValid() {
fmt.Println("ERROR : Not find field that tag is ", tagName)
}
if f.Kind() == reflect.String {
f.SetString(plaintext)
}
if f.Kind() == reflect.Int {
i, err := strconv.Atoi(plaintext)
if err != nil {
fmt.Println(err)
}
f.SetInt(int64(i))
}
}