merge master

This commit is contained in:
John
2018-05-17 22:54:19 +08:00
11 changed files with 218 additions and 116 deletions

View File

@ -34,23 +34,29 @@ func (s *Server)bindHandlerByMap(m HandlerMap) error {
return nil
}
// 将方法名称按照设定的规则转换为URI并附加到指定的URI后面
func (s *Server)appendMethodNameToUriWithPattern(pattern string, name string) string {
// 将方法名称按照设定的规则合并到pattern中.
// 规则1pattern中的URI包含{method}关键字,则替换该关键字为方法名称
// 规则2如果不满足规则1那么直接将防发明附加到pattern中的URI后面
func (s *Server)mergeMethodNameToPattern(pattern string, name string) string {
// 方法名中间存在大写字母转换为小写URI地址以“-”号链接每个单词
method := ""
for i := 0; i < len(name); i++ {
if i > 0 && gutil.IsLetterUpper(name[i]) {
method += "-"
}
method += strings.ToLower(string(name[i]))
}
if strings.Index(pattern, "{method}") != -1 {
return strings.Replace(pattern, "{method}", method, -1)
}
// 检测域名后缀
array := strings.Split(pattern, "@")
// 分离URI(其实可能包含HTTP Method)
uri := array[0]
uri = strings.TrimRight(uri, "/") + "/"
// 方法名中间存在大写字母转换为小写URI地址以“-”号链接每个单词
for i := 0; i < len(name); i++ {
if i > 0 && gutil.IsLetterUpper(name[i]) {
uri += "-"
}
uri += strings.ToLower(string(name[i]))
}
// 加上指定域名后缀
if len(array) > 1 {
uri += "@" + array[1]
return uri + "@" + array[1]
}
return uri
}
@ -72,7 +78,7 @@ func (s *Server)BindObject(pattern string, obj interface{}) error {
t := v.Type()
for i := 0; i < v.NumMethod(); i++ {
name := t.Method(i).Name
key := s.appendMethodNameToUriWithPattern(pattern, name)
key := s.mergeMethodNameToPattern(pattern, name)
m[key] = &HandlerItem {
ctype : nil,
fname : "",
@ -100,7 +106,7 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, methods string
if !fval.IsValid() {
return errors.New("invalid method name:" + name)
}
key := s.appendMethodNameToUriWithPattern(pattern, name)
key := s.mergeMethodNameToPattern(pattern, name)
m[key] = &HandlerItem{
ctype : nil,
fname : "",
@ -152,7 +158,7 @@ func (s *Server)BindController(pattern string, c Controller) error {
if name == "Init" || name == "Shut" || name == "Exit" {
continue
}
key := s.appendMethodNameToUriWithPattern(pattern, name)
key := s.mergeMethodNameToPattern(pattern, name)
m[key] = &HandlerItem {
ctype : v.Elem().Type(),
fname : name,
@ -181,7 +187,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, methods strin
if !cval.MethodByName(name).IsValid() {
return errors.New("invalid method name:" + name)
}
key := s.appendMethodNameToUriWithPattern(pattern, name)
key := s.mergeMethodNameToPattern(pattern, name)
m[key] = &HandlerItem {
ctype : ctype,
fname : name,

View File

@ -61,8 +61,8 @@ func (sp *SPath) Search(name string) string {
if path == "" {
sp.mu.RLock()
for _, v := range sp.paths {
path = v + gfile.Separator + name
if gfile.Exists(path) {
path = gfile.RealPath(v + gfile.Separator + name)
if path != "" && gfile.Exists(path) {
break
}
}

View File

@ -137,9 +137,9 @@ func SetDefaultErrorMsgs(msgs map[string]string) {
}
// 判断必须字段
func checkRequired(value, rulekey, ruleval string, params map[string]string) bool {
func checkRequired(value, ruleKey, ruleVal string, params map[string]string) bool {
required := false
switch rulekey {
switch ruleKey {
// 必须字段
case "required":
required = true
@ -147,7 +147,7 @@ func checkRequired(value, rulekey, ruleval string, params map[string]string) boo
// 必须字段(当任意所给定字段值与所给值相等时)
case "required-if":
required = false
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
// 必须为偶数,才能是键值对匹配
if len(array)%2 == 0 {
for i := 0; i < len(array); {
@ -166,7 +166,7 @@ func checkRequired(value, rulekey, ruleval string, params map[string]string) boo
// 必须字段(当所给定字段值与所给值都不相等时)
case "required-unless":
required = true
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
// 必须为偶数,才能是键值对匹配
if len(array)%2 == 0 {
for i := 0; i < len(array); {
@ -185,7 +185,7 @@ func checkRequired(value, rulekey, ruleval string, params map[string]string) boo
// 必须字段(当所给定任意字段值不为空时)
case "required-with":
required = false
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
for i := 0; i < len(array); i++ {
if v, ok := params[array[i]]; ok {
if v != "" {
@ -198,7 +198,7 @@ func checkRequired(value, rulekey, ruleval string, params map[string]string) boo
// 必须字段(当所给定所有字段值都不为空时)
case "required-with-all":
required = true
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
for i := 0; i < len(array); i++ {
if v, ok := params[array[i]]; ok {
if v == "" {
@ -211,7 +211,7 @@ func checkRequired(value, rulekey, ruleval string, params map[string]string) boo
// 必须字段(当所给定任意字段值为空时)
case "required-without":
required = false
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
for i := 0; i < len(array); i++ {
if v, ok := params[array[i]]; ok {
if v == "" {
@ -224,7 +224,7 @@ func checkRequired(value, rulekey, ruleval string, params map[string]string) boo
// 必须字段(当所给定所有字段值都为空时)
case "required-without-all":
required = true
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
for i := 0; i < len(array); i++ {
if v, ok := params[array[i]]; ok {
if v != "" {
@ -242,12 +242,12 @@ func checkRequired(value, rulekey, ruleval string, params map[string]string) boo
}
// 对字段值长度进行检测
func checkLength(value, rulekey, ruleval string, cmsgs map[string]string) string {
func checkLength(value, ruleKey, ruleVal string, custonMsgs map[string]string) string {
msg := ""
switch rulekey {
switch ruleKey {
// 长度范围
case "length":
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
min := 0
max := 0
if len(array) > 0 {
@ -261,8 +261,8 @@ func checkLength(value, rulekey, ruleval string, cmsgs map[string]string) string
}
}
if len(value) < min || len(value) > max {
if v, ok := cmsgs[rulekey]; !ok {
msg = errorMsgMap.Get(rulekey)
if v, ok := custonMsgs[ruleKey]; !ok {
msg = errorMsgMap.Get(ruleKey)
} else {
msg = v
}
@ -273,44 +273,44 @@ func checkLength(value, rulekey, ruleval string, cmsgs map[string]string) string
// 最小长度
case "min-length":
if min, err := strconv.Atoi(ruleval); err == nil {
if min, err := strconv.Atoi(ruleVal); err == nil {
if len(value) < min {
if v, ok := cmsgs[rulekey]; !ok {
msg = errorMsgMap.Get(rulekey)
if v, ok := custonMsgs[ruleKey]; !ok {
msg = errorMsgMap.Get(ruleKey)
} else {
msg = v
}
msg = strings.Replace(msg, ":min", strconv.Itoa(min), -1)
}
} else {
msg = "校验参数[" + ruleval + "]应当为整数类型"
msg = "校验参数[" + ruleVal + "]应当为整数类型"
}
// 最大长度
case "max-length":
if max, err := strconv.Atoi(ruleval); err == nil {
if max, err := strconv.Atoi(ruleVal); err == nil {
if len(value) > max {
if v, ok := cmsgs[rulekey]; !ok {
msg = errorMsgMap.Get(rulekey)
if v, ok := custonMsgs[ruleKey]; !ok {
msg = errorMsgMap.Get(ruleKey)
} else {
msg = v
}
msg = strings.Replace(msg, ":max", strconv.Itoa(max), -1)
}
} else {
msg = "校验参数[" + ruleval + "]应当为整数类型"
msg = "校验参数[" + ruleVal + "]应当为整数类型"
}
}
return msg
}
// 对字段值大小进行检测
func checkSize(value, rulekey, ruleval string, cmsgs map[string]string) string {
func checkSize(value, ruleKey, ruleVal string, custonMsgs map[string]string) string {
msg := ""
switch rulekey {
switch ruleKey {
// 大小范围
case "between":
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
min := float64(0)
max := float64(0)
if len(array) > 0 {
@ -325,8 +325,8 @@ func checkSize(value, rulekey, ruleval string, cmsgs map[string]string) string {
}
if v, err := strconv.ParseFloat(value, 10); err == nil {
if v < min || v > max {
if v, ok := cmsgs[rulekey]; !ok {
msg = errorMsgMap.Get(rulekey)
if v, ok := custonMsgs[ruleKey]; !ok {
msg = errorMsgMap.Get(ruleKey)
} else {
msg = v
}
@ -339,12 +339,12 @@ func checkSize(value, rulekey, ruleval string, cmsgs map[string]string) string {
// 最小值
case "min":
if min, err := strconv.ParseFloat(ruleval, 10); err == nil {
if min, err := strconv.ParseFloat(ruleVal, 10); err == nil {
if v, err := strconv.ParseFloat(value, 10); err == nil {
if v < min {
msg, ok := cmsgs[rulekey]
msg, ok := custonMsgs[ruleKey]
if !ok {
msg = errorMsgMap.Get(rulekey)
msg = errorMsgMap.Get(ruleKey)
}
msg = strings.Replace(msg, ":min", strconv.FormatFloat(min, 'f', -1, 64), -1)
}
@ -352,17 +352,17 @@ func checkSize(value, rulekey, ruleval string, cmsgs map[string]string) string {
msg = "输入参数[" + value + "]应当为数字类型"
}
} else {
msg = "校验参数[" + ruleval + "]应当为数字类型"
msg = "校验参数[" + ruleVal + "]应当为数字类型"
}
// 最大值
case "max":
if max, err := strconv.ParseFloat(ruleval, 10); err == nil {
if max, err := strconv.ParseFloat(ruleVal, 10); err == nil {
if v, err := strconv.ParseFloat(value, 10); err == nil {
if v > max {
msg, ok := cmsgs[rulekey]
msg, ok := custonMsgs[ruleKey]
if !ok {
msg = errorMsgMap.Get(rulekey)
msg = errorMsgMap.Get(ruleKey)
}
msg = strings.Replace(msg, ":max", strconv.FormatFloat(max, 'f', -1, 64), -1)
}
@ -370,7 +370,7 @@ func checkSize(value, rulekey, ruleval string, cmsgs map[string]string) string {
msg = "输入参数[" + value + "]应当为数字类型"
}
} else {
msg = "校验参数[" + ruleval + "]应当为数字类型"
msg = "校验参数[" + ruleVal + "]应当为数字类型"
}
}
return msg
@ -378,27 +378,44 @@ func checkSize(value, rulekey, ruleval string, cmsgs map[string]string) string {
// 检测键值对参数Map注意返回参数是一个2维的关联数组第一维键名为参数键名第二维为带有错误的校验规则名称值为错误信息
func CheckMap(params map[string]interface{}, rules map[string]string, msgs...map[string]interface{}) map[string]map[string]string {
var value interface{}
// 自定义消息,非必须参数,因此这里需要做判断
cmsgs := make(map[string]interface{})
customMsgs := make(map[string]interface{})
if len(msgs) > 0 {
cmsgs = msgs[0]
customMsgs = msgs[0]
}
emsgs := make(map[string]map[string]string)
for key, value := range params {
if rule, ok := rules[key]; ok {
msg, _ := cmsgs[key]
if m := Check(value, rule, msg, params); m != nil {
if _, ok := emsgs[key]; !ok {
emsgs[key] = make(map[string]string)
errorMsgs := make(map[string]map[string]string)
// 以校验规则作为基础
for key, rule := range rules {
value = nil
if v, ok := params[key]; ok {
value = v
}
msg, _ := customMsgs[key]
if m := Check(value, rule, msg, params); m != nil {
// 如果值为nil并且不需要require*验证时,其他验证失效
if value == nil {
required := false;
for k, _ := range m {
if strings.Index(k, "required") != -1 {
required = true;
break
}
}
for k, v := range m {
emsgs[key][k] = v
if !required {
continue
}
}
if _, ok := errorMsgs[key]; !ok {
errorMsgs[key] = make(map[string]string)
}
for k, v := range m {
errorMsgs[key][k] = v
}
}
}
if len(emsgs) > 0 {
return emsgs
if len(errorMsgs) > 0 {
return errorMsgs
}
return nil
}
@ -413,20 +430,20 @@ func CheckObject(object interface{}, rules map[string]string, msgs...map[string]
// values参数为表单联合校验参数对于需要联合校验的规则有效required-*、same、different
func Check(val interface{}, rules string, msgs interface{}, params...map[string]interface{}) map[string]string {
// 内部会将参数全部转换为字符串类型进行校验
value := strings.TrimSpace(gconv.String(val))
kvmap := make(map[string]string)
errmsgs := make(map[string]string)
value := strings.TrimSpace(gconv.String(val))
data := make(map[string]string)
errorMsgs := make(map[string]string)
if len(params) > 0 {
for k, v := range params[0] {
kvmap[k] = gconv.String(v)
data[k] = gconv.String(v)
}
}
// 自定义错误消息处理
list := make([]string, 0)
cmsgs := make(map[string]string)
list := make([]string, 0)
custonMsgs := make(map[string]string)
switch value := msgs.(type) {
case map[string]string:
cmsgs = value
custonMsgs = value
case string:
list = strings.Split(value, "|")
}
@ -434,13 +451,13 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
for index := 0; index < len(items); {
item := items[index]
results := ruleRegex.FindStringSubmatch(item)
rulekey := strings.TrimSpace(results[1])
ruleval := strings.TrimSpace(results[2])
ruleKey := strings.TrimSpace(results[1])
ruleVal := strings.TrimSpace(results[2])
match := false
if len(list) > index {
cmsgs[rulekey] = strings.TrimSpace(list[index])
custonMsgs[ruleKey] = strings.TrimSpace(list[index])
}
switch rulekey {
switch ruleKey {
// 必须字段
case "required": fallthrough
case "required-if": fallthrough
@ -449,14 +466,14 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
case "required-with-all": fallthrough
case "required-without": fallthrough
case "required-without-all":
match = checkRequired(value, rulekey, ruleval, kvmap)
match = checkRequired(value, ruleKey, ruleVal, data)
// 长度范围
case "length": fallthrough
case "min-length": fallthrough
case "max-length":
if msg := checkLength(value, rulekey, ruleval, cmsgs); msg != "" {
errmsgs[rulekey] = msg
if msg := checkLength(value, ruleKey, ruleVal, custonMsgs); msg != "" {
errorMsgs[ruleKey] = msg
} else {
match = true
}
@ -465,8 +482,8 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
case "min": fallthrough
case "max": fallthrough
case "between":
if msg := checkSize(value, rulekey, ruleval, cmsgs); msg != "" {
errmsgs[rulekey] = msg
if msg := checkSize(value, ruleKey, ruleVal, custonMsgs); msg != "" {
errorMsgs[ruleKey] = msg
} else {
match = true
}
@ -477,11 +494,11 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
for i := index + 1; i < len(items); i++ {
// 判断下一个规则是否合法,不合法那么和当前正则规则进行整合
if !gregx.IsMatchString(gSINGLE_RULE_PATTERN, items[i]) {
ruleval += "|" + items[i]
ruleVal += "|" + items[i]
index++
}
}
match = gregx.IsMatchString(ruleval, value)
match = gregx.IsMatchString(ruleVal, value)
// 日期格式,
case "date":
@ -494,13 +511,13 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
// 日期格式,需要给定日期格式
case "date-format":
if _, err := gtime.StrToTime(value, ruleval); err == nil {
if _, err := gtime.StrToTime(value, ruleVal); err == nil {
match = true
}
// 两字段值应相同(非敏感字符判断,非类型判断)
case "same":
if v, ok := kvmap[ruleval]; ok {
if v, ok := data[ruleVal]; ok {
if strings.Compare(value, v) == 0 {
match = true
}
@ -509,7 +526,7 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
// 两字段值不应相同(非敏感字符判断,非类型判断)
case "different":
match = true
if v, ok := kvmap[ruleval]; ok {
if v, ok := data[ruleVal]; ok {
if strings.Compare(value, v) == 0 {
match = false
}
@ -517,7 +534,7 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
// 字段值应当在指定范围中
case "in":
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
for _, v := range array {
if strings.Compare(value, strings.TrimSpace(v)) == 0 {
match = true
@ -528,7 +545,7 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
// 字段值不应当在指定范围中
case "not-in":
match = true
array := strings.Split(ruleval, ",")
array := strings.Split(ruleVal, ",")
for _, v := range array {
if strings.Compare(value, strings.TrimSpace(v)) == 0 {
match = false
@ -656,25 +673,25 @@ func Check(val interface{}, rules string, msgs interface{}, params...map[string]
match = gregx.IsMatchString(`^([0-9A-Fa-f]{2}-){5}[0-9A-Fa-f]{2}$`, value)
default:
errmsgs[rulekey] = "Invalid rule name:" + rulekey
errorMsgs[ruleKey] = "Invalid rule name:" + ruleKey
}
// 错误消息整合
if !match {
// 不存在则使用默认的错误信息,
// 如果在校验过程中已经设置了错误信息,那么这里便不作处理
if _, ok := errmsgs[rulekey]; !ok {
if msg, ok := cmsgs[rulekey]; ok {
errmsgs[rulekey] = msg
if _, ok := errorMsgs[ruleKey]; !ok {
if msg, ok := custonMsgs[ruleKey]; ok {
errorMsgs[ruleKey] = msg
} else {
errmsgs[rulekey] = errorMsgMap.Get(rulekey)
errorMsgs[ruleKey] = errorMsgMap.Get(ruleKey)
}
}
}
index++
}
if len(errmsgs) > 0 {
return errmsgs
if len(errorMsgs) > 0 {
return errorMsgs
}
return nil
}

View File

@ -5,6 +5,7 @@
// You can obtain one at https://gitee.com/johng/gf.
// 单元测试
// go test *.go -bench=".*"
package gvalid_test
@ -224,4 +225,18 @@ func Test_CustomError2(t *testing.T) {
}
}
}
}
// 如果值为nil并且不需要require*验证时,其他验证失效
func Test_CheckMapWithNilAndNotRequiredField(t *testing.T) {
data := map[string]interface{} {
"id" : "1",
}
rules := map[string]string {
"id" : "required",
"name" : "length:4,16",
}
if m := gvalid.CheckMap(data, rules); m != nil {
t.Error(m)
}
}

View File

@ -0,0 +1,19 @@
package demo
import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/frame/gmvc"
)
type ControllerRule struct {
gmvc.Controller
}
func init() {
g.Server().BindController("/rule/{method}/:name", &ControllerRule{})
}
func (c *ControllerRule) Show() {
c.Response.Write(c.Request.Get("name"))
}

View File

@ -1,11 +1,11 @@
package main
import (
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g"
_ "gitee.com/johng/gf/geg/frame/mvc/controller/demo"
)
func main() {
ghttp.GetServer().SetPort(8199)
ghttp.GetServer().Run()
g.Server().SetPort(8199)
g.Server().Run()
}

View File

@ -0,0 +1,30 @@
package main
import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/frame/gmvc"
)
func init() {
g.View().SetPath(`D:\Workspace\Go\GOPATH\src\gitee.com\johng\gf\geg\os\gview`)
}
// 测试控制器注册模板热更新机制
type Controller struct {
gmvc.Controller
}
// 测试模板热更新机制
func (c *Controller) Test() {
b, _ := c.View.Parse("test.tpl")
c.Response.Write(b)
}
func main() {
s := g.Server()
s.BindController("/", &Controller{})
s.Run()
}

View File

@ -4,13 +4,13 @@ package main
import (
"fmt"
"time"
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/frame/gins"
)
func main() {
v := gins.View()
v.SetPath("/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/geg/os/gview")
v := g.View()
v.SetPath(`D:\Workspace\Go\GOPATH\src\gitee.com\johng\gf\geg\os\gview`)
gtime.SetInterval(time.Second, func() bool {
b, _ := v.Parse("test.tpl", nil)
fmt.Println(string(b))

View File

@ -1 +1 @@
test.tpl content
test.tpl content2

View File

@ -0,0 +1,17 @@
package main
import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
g.View().SetPath(`D:\Workspace\Go\GOPATH\src\gitee.com\johng\gf\geg\os\gview`)
b, _ := g.View().Parse("test.tpl", nil)
r.Response.Write(b)
})
s.Run()
}

View File

@ -1,20 +1,18 @@
package main
import "fmt"
const (
CREATE = 1 << iota
WRITE
REMOVE
RENAME
CHMOD
import (
"fmt"
"gitee.com/johng/gf/g/util/gvalid"
)
func main(){
fmt.Println(CREATE)
fmt.Println(WRITE)
fmt.Println(REMOVE)
fmt.Println(RENAME)
}
func main() {
data := map[string]interface{} {
"id" : "1",
}
rules := map[string]string {
"id" : "required",
"name" : "length:4,16",
}
m := gvalid.CheckMap(data, rules)
fmt.Println(m)
}