GOLANG Web請求引數驗證

怪咖_OOP發表於2018-07-17

基於golang web專案實際開發中在controller層對客戶端請求引數進行驗證,這樣導致controller層程式碼冗餘度非常高,影響開發效率。程式碼示例:

    feedback := &mysql_model.OfbankFeedback{}
	err := json.Unmarshal(body, feedback)
	feedback.FStatus=1
	feedback.CreateTime=time.Now()
	if err != nil {
		resp := apiservice.GenerateResponse(0, "請求引數有誤", "")
		rw.Write([]byte(resp))
		return
	}
	if feedback.Phone=="" {
		resp := apiservice.GenerateResponse(0, "引數phone不能為空", "")
		rw.Write([]byte(resp))
		return
	}
	if feedback.Contacts=="" {
		resp := apiservice.GenerateResponse(0, "引數contacts不能為空", "")
		rw.Write([]byte(resp))
		return
	}
	if feedback.FType==0 {
		resp := apiservice.GenerateResponse(0, "引數fType不能為空", "")
		rw.Write([]byte(resp))
		return
	}
	if feedback.Img==""&&feedback.Content=="" {
		resp := apiservice.GenerateResponse(0, "引數img或content不能同時為空", "")
		rw.Write([]byte(resp))
		return
	}
複製程式碼

程式碼冗餘度高?影響開發效率?如何解決?

目前有很多web框架(beego、faygo等)支援結構體引數驗證;為了解決專案管理上的問題引入一個框架且框架中引數驗證規則擴充套件性不是很好,個人感覺不是很優雅;於是自己寫了一個結構體引數驗證工具(struct_util.go)

程式碼示例:
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: yangzhao
 * Date: 2018-07-17
 * Time: 11:08
 */
package utils

import (
	"reflect"
	"errors"
	"strings"
	"strconv"
)
//自定義驗證規則
const (
	NOT_EMPTY = "NotEmpty" //字串不能為空
	INT_MAX = "int-max" //int最大值
	INT_MIN = "int-min" //int最小值
	TYPE = "type" //型別
	STR_MAX_LENGTH = "str-max-len" //字串最大長度
	STR_MIN_LENGTH = "str-min-len" //字串最小長度
	STR_LENGTH = "str-len" //字串長度
	RANGE = "range" //元素必須在合適的範圍內 例:1-100
)
//對外暴露結構體驗證函式
func StructValidate(bean interface{}) error {
	fields := reflect.ValueOf(bean).Elem()
	for i := 0; i < fields.NumField(); i++ {
		field := fields.Type().Field(i)
		valid := field.Tag.Get("valid")
		if valid == "" {
			continue
		}
		value := fields.FieldByName(field.Name)
		err := fieldValidate(field.Name, valid, value)
		if err != nil {
			return err
		}
	}
	return nil
}
//屬性驗證
func fieldValidate(fieldName, valid string, value reflect.Value) error {
	valids := strings.Split(valid, " ")
	for _, valid := range valids {

		if strings.Index(valid, TYPE) != -1 {
			v := value.Type().Name()
			split := strings.Split(valid, "=")
			t := split[1]
			if v != t {
				return errors.New(fieldName + " type must is " + t)
			}
		}

		if strings.Index(valid, NOT_EMPTY) != -1 {
			str := value.String()
			if str == "" {
				return errors.New(fieldName + " value not empty")
			}
		}
		if strings.Index(valid, INT_MIN) != -1 {
			v := value.Int()
			split := strings.Split(valid, "=")
			rule, err := strconv.Atoi(split[1])
			if err != nil {
				return errors.New(fieldName + ":驗證規則有誤")
			}
			if int(v) < rule {
				return errors.New(fieldName + " value must >= " + strconv.Itoa(rule))
			}
		}

		if strings.Index(valid, INT_MAX) != -1 {
			v := value.Int()
			split := strings.Split(valid, "=")
			rule, err := strconv.Atoi(split[1])
			if err != nil {
				return errors.New(fieldName + ":驗證規則有誤")
			}
			if int(v) > rule {

				return errors.New(fieldName + " value must <= " + strconv.Itoa(rule))
			}
		}
		//字串特殊處理
		if value.Type().Name() == "string" {
			if strings.Index(valid, STR_LENGTH) != -1 {
				v := value.String()
				split := strings.Split(valid, "=")
				lenStr := split[1]
				length, err := strconv.Atoi(lenStr)
				if err != nil {
					return errors.New(fieldName + " " + STR_LENGTH + " rule is error")
				}
				if len(v) != length {
					return errors.New(fieldName + " str length  must be " + lenStr)
				}
			}
			if strings.Index(valid, STR_MAX_LENGTH) != -1 {
				v := value.String()
				split := strings.Split(valid, "=")
				lenStr := split[1]
				length, err := strconv.Atoi(lenStr)
				if err != nil {
					return errors.New(fieldName + " " + STR_LENGTH + " rule is error")
				}
				if len(v) > length {
					return errors.New(fieldName + " str length  <= " + lenStr)
				}
			}

			if strings.Index(valid, STR_MIN_LENGTH) != -1 {
				v := value.String()
				split := strings.Split(valid, "=")
				lenStr := split[1]
				length, err := strconv.Atoi(lenStr)
				if err != nil {
					return errors.New(fieldName + " " + STR_LENGTH + " rule is error")
				}
				if len(v) < length {
					return errors.New(fieldName + " str length  >= " + lenStr)
				}
			}
		}
	}
	return nil
}
複製程式碼
demo示例:

image.png

以上屬於原創文章,轉載請註明作者@怪咖 QQ:208275451

相關文章