mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
improve Map converting feature for gconv; improve package gproc for local shell searching; improve JSON/XML response for ghttp.Response
This commit is contained in:
22
.example/net/ghttp/server/router/group/basic.go
Normal file
22
.example/net/ghttp/server/router/group/basic.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
group := s.Group("/api")
|
||||
group.ALL("/all", func(r *ghttp.Request) {
|
||||
r.Response.Write("all")
|
||||
})
|
||||
group.GET("/get", func(r *ghttp.Request) {
|
||||
r.Response.Write("get")
|
||||
})
|
||||
group.POST("/post", func(r *ghttp.Request) {
|
||||
r.Response.Write("post")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
38
.example/net/ghttp/server/router/group/batch.go
Normal file
38
.example/net/ghttp/server/router/group/batch.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type Object struct{}
|
||||
|
||||
func (o *Object) Show(r *ghttp.Request) {
|
||||
r.Response.Writeln("Show")
|
||||
}
|
||||
|
||||
func (o *Object) Delete(r *ghttp.Request) {
|
||||
r.Response.Writeln("REST Delete")
|
||||
}
|
||||
|
||||
func Handler(r *ghttp.Request) {
|
||||
r.Response.Writeln("Handler")
|
||||
}
|
||||
|
||||
func HookHandler(r *ghttp.Request) {
|
||||
r.Response.Writeln("HOOK Handler")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
obj := new(Object)
|
||||
s.Group("/api").Bind([]ghttp.GroupItem{
|
||||
{"ALL", "*", HookHandler, ghttp.HOOK_BEFORE_SERVE},
|
||||
{"ALL", "/handler", Handler},
|
||||
{"ALL", "/obj", obj},
|
||||
{"GET", "/obj/show", obj, "Show"},
|
||||
{"REST", "/obj/rest", obj},
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func MiddlewareAuth(r *ghttp.Request) {
|
||||
@ -24,39 +23,37 @@ func MiddlewareCORS(r *ghttp.Request) {
|
||||
|
||||
func MiddlewareLog(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
glog.Println(r.Response.Status, r.URL.Path)
|
||||
g.Log().Println(r.Response.Status, r.URL.Path)
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareLog)
|
||||
})
|
||||
s.Use(MiddlewareLog)
|
||||
s.Group("/api.v2", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(MiddlewareAuth, MiddlewareCORS)
|
||||
g.GET("/test", func(r *ghttp.Request) {
|
||||
group.GET("/test", func(r *ghttp.Request) {
|
||||
r.Response.Write("test")
|
||||
})
|
||||
g.Group("/order", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/list", func(r *ghttp.Request) {
|
||||
group.Group("/order", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/list", func(r *ghttp.Request) {
|
||||
r.Response.Write("list")
|
||||
})
|
||||
g.PUT("/update", func(r *ghttp.Request) {
|
||||
group.PUT("/update", func(r *ghttp.Request) {
|
||||
r.Response.Write("update")
|
||||
})
|
||||
})
|
||||
g.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
g.GET("/info", func(r *ghttp.Request) {
|
||||
group.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/info", func(r *ghttp.Request) {
|
||||
r.Response.Write("info")
|
||||
})
|
||||
g.POST("/edit", func(r *ghttp.Request) {
|
||||
group.POST("/edit", func(r *ghttp.Request) {
|
||||
r.Response.Write("edit")
|
||||
})
|
||||
g.DELETE("/drop", func(r *ghttp.Request) {
|
||||
group.DELETE("/drop", func(r *ghttp.Request) {
|
||||
r.Response.Write("drop")
|
||||
})
|
||||
})
|
||||
g.Group("/hook", func(group *ghttp.RouterGroup) {
|
||||
group.Group("/hook", func(group *ghttp.RouterGroup) {
|
||||
group.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook any")
|
||||
})
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
package main
|
||||
|
||||
import "github.com/gogf/gf/net/ghttp"
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s := g.Server()
|
||||
s.BindHandler("/user/:name", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Router.Uri)
|
||||
})
|
||||
|
||||
@ -1,17 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/test", func(r *ghttp.Request) {
|
||||
fmt.Println(r.GetBody())
|
||||
r.Response.Write(r.GetBody())
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
type Ids struct {
|
||||
Id int `c:"id"`
|
||||
Uid int `c:"uid"`
|
||||
}
|
||||
type Base struct {
|
||||
Ids
|
||||
CreateTime string `c:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base
|
||||
Passport string `c:"passport"`
|
||||
Password string `c:"password"`
|
||||
Nickname string `c:"nickname"`
|
||||
}
|
||||
user := new(User)
|
||||
user.Id = 1
|
||||
user.Uid = 100
|
||||
user.Nickname = "John"
|
||||
user.Passport = "johng"
|
||||
user.Password = "123456"
|
||||
user.CreateTime = "2019"
|
||||
g.Dump(gconv.Map(user))
|
||||
g.Dump(gconv.MapDeep(user))
|
||||
}
|
||||
|
||||
@ -7,18 +7,18 @@ import (
|
||||
|
||||
func main() {
|
||||
type Ids struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Id int `c:"id"`
|
||||
Uid int `c:"uid"`
|
||||
}
|
||||
type Base struct {
|
||||
Ids
|
||||
CreateTime string `json:"create_time"`
|
||||
CreateTime string `c:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base
|
||||
Passport string `json:"passport"`
|
||||
Password string `json:"password"`
|
||||
Nickname string `json:"nickname"`
|
||||
Passport string `c:"passport"`
|
||||
Password string `c:"password"`
|
||||
Nickname string `c:"nickname"`
|
||||
}
|
||||
user := new(User)
|
||||
user.Id = 1
|
||||
@ -27,5 +27,6 @@ func main() {
|
||||
user.Passport = "johng"
|
||||
user.Password = "123456"
|
||||
user.CreateTime = "2019"
|
||||
g.Dump(gconv.Map(user))
|
||||
g.Dump(gconv.MapDeep(user))
|
||||
}
|
||||
|
||||
@ -103,6 +103,14 @@ func (r *Response) WriteflnExit(format string, params ...interface{}) {
|
||||
|
||||
// WriteJson writes <content> to the response with JSON format.
|
||||
func (r *Response) WriteJson(content interface{}) error {
|
||||
// If given string/[]byte, response it directly to client.
|
||||
switch content.(type) {
|
||||
case string, []byte:
|
||||
r.Header().Set("Content-Type", "application/json")
|
||||
r.Write(content)
|
||||
return nil
|
||||
}
|
||||
// Else use json.Marshal function to encode the parameter.
|
||||
if b, err := json.Marshal(content); err != nil {
|
||||
return err
|
||||
} else {
|
||||
@ -127,6 +135,14 @@ func (r *Response) WriteJsonExit(content interface{}) error {
|
||||
//
|
||||
// Note that there should be a "callback" parameter in the request for JSONP format.
|
||||
func (r *Response) WriteJsonP(content interface{}) error {
|
||||
// If given string/[]byte, response it directly to client.
|
||||
switch content.(type) {
|
||||
case string, []byte:
|
||||
r.Header().Set("Content-Type", "application/json")
|
||||
r.Write(content)
|
||||
return nil
|
||||
}
|
||||
// Else use json.Marshal function to encode the parameter.
|
||||
if b, err := json.Marshal(content); err != nil {
|
||||
return err
|
||||
} else {
|
||||
@ -159,6 +175,14 @@ func (r *Response) WriteJsonPExit(content interface{}) error {
|
||||
|
||||
// WriteXml writes <content> to the response with XML format.
|
||||
func (r *Response) WriteXml(content interface{}, rootTag ...string) error {
|
||||
// If given string/[]byte, response it directly to client.
|
||||
switch content.(type) {
|
||||
case string, []byte:
|
||||
r.Header().Set("Content-Type", "application/xml")
|
||||
r.Write(content)
|
||||
return nil
|
||||
}
|
||||
// Else use gparser.VarToXml function to encode the parameter.
|
||||
if b, err := gparser.VarToXml(content, rootTag...); err != nil {
|
||||
return err
|
||||
} else {
|
||||
|
||||
@ -41,3 +41,9 @@ func (s *Server) BindMiddlewareDefault(handlers ...HandlerFunc) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Use is alias of BindMiddlewareDefault.
|
||||
// See BindMiddlewareDefault.
|
||||
func (s *Server) Use(handlers ...HandlerFunc) {
|
||||
s.BindMiddlewareDefault(handlers...)
|
||||
}
|
||||
|
||||
@ -155,6 +155,14 @@ func getShell() string {
|
||||
case "windows":
|
||||
return SearchBinary("cmd.exe")
|
||||
default:
|
||||
// Check the default binary storage path.
|
||||
if gfile.Exists("/bin/bash") {
|
||||
return "/bin/bash"
|
||||
}
|
||||
if gfile.Exists("/bin/sh") {
|
||||
return "/bin/sh"
|
||||
}
|
||||
// Else search the env PATH.
|
||||
path := SearchBinary("bash")
|
||||
if path == "" {
|
||||
path = SearchBinary("sh")
|
||||
|
||||
@ -26,6 +26,19 @@ type apiMapStrAny interface {
|
||||
// If <value> is a struct/*struct object, the second parameter <tags> specifies the most priority
|
||||
// tags that will be detected, otherwise it detects the tags in order of: gconv, json, and then the field name.
|
||||
func Map(value interface{}, tags ...string) map[string]interface{} {
|
||||
return doMapConvert(value, false, tags...)
|
||||
}
|
||||
|
||||
// MapDeep does Map function recursively, which means if the attribute of <value>
|
||||
// is also a struct/*struct, calls Map function on this attribute converting it to
|
||||
// a map[string]interface{} type variable.
|
||||
// Also see Map.
|
||||
func MapDeep(value interface{}, tags ...string) map[string]interface{} {
|
||||
return doMapConvert(value, true, tags...)
|
||||
}
|
||||
|
||||
// doMapConvert implements the map converting.
|
||||
func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]interface{} {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
@ -121,14 +134,18 @@ func Map(value interface{}, tags ...string) map[string]interface{} {
|
||||
default:
|
||||
tagArray = append(tags, structTagPriority...)
|
||||
}
|
||||
var rtField reflect.StructField
|
||||
var rvField reflect.Value
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
rtField = rt.Field(i)
|
||||
rvField = rv.Field(i)
|
||||
// Only convert the public attributes.
|
||||
fieldName := rt.Field(i).Name
|
||||
fieldName := rtField.Name
|
||||
if !utilstr.IsLetterUpper(fieldName[0]) {
|
||||
continue
|
||||
}
|
||||
name = ""
|
||||
fieldTag := rt.Field(i).Tag
|
||||
fieldTag := rtField.Tag
|
||||
for _, tag := range tagArray {
|
||||
if name = fieldTag.Get(tag); name != "" {
|
||||
break
|
||||
@ -146,7 +163,7 @@ func Map(value interface{}, tags ...string) map[string]interface{} {
|
||||
if len(array) > 1 {
|
||||
switch strings.TrimSpace(array[1]) {
|
||||
case "omitempty":
|
||||
if empty.IsEmpty(rv.Field(i).Interface()) {
|
||||
if empty.IsEmpty(rvField.Interface()) {
|
||||
continue
|
||||
} else {
|
||||
name = strings.TrimSpace(array[0])
|
||||
@ -156,7 +173,30 @@ func Map(value interface{}, tags ...string) map[string]interface{} {
|
||||
}
|
||||
}
|
||||
}
|
||||
m[name] = rv.Field(i).Interface()
|
||||
switch rvField.Kind() {
|
||||
case reflect.Ptr:
|
||||
if rvField.Elem().Kind() == reflect.Struct {
|
||||
if recursive {
|
||||
for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) {
|
||||
m[k] = v
|
||||
}
|
||||
} else {
|
||||
m[name] = doMapConvert(rvField.Interface(), recursive, tags...)
|
||||
}
|
||||
} else {
|
||||
m[name] = rvField.Interface()
|
||||
}
|
||||
case reflect.Struct:
|
||||
if recursive {
|
||||
for k, v := range doMapConvert(rvField.Interface(), recursive, tags...) {
|
||||
m[k] = v
|
||||
}
|
||||
} else {
|
||||
m[name] = doMapConvert(rvField.Interface(), recursive, tags...)
|
||||
}
|
||||
default:
|
||||
m[name] = rvField.Interface()
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
@ -166,30 +206,6 @@ func Map(value interface{}, tags ...string) map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
// MapDeep does Map function recursively, which means if the attribute of <value>
|
||||
// is also a struct/*struct, calls Map function on this attribute converting it to
|
||||
// a map[string]interface{} type variable.
|
||||
// Also see Map.
|
||||
func MapDeep(value interface{}, tags ...string) map[string]interface{} {
|
||||
data := Map(value, tags...)
|
||||
for key, value := range data {
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Struct:
|
||||
delete(data, key)
|
||||
for k, v := range MapDeep(value, tags...) {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrStr converts <value> to map[string]string.
|
||||
// Note that there might be data copy for this map type converting.
|
||||
func MapStrStr(value interface{}, tags ...string) map[string]string {
|
||||
|
||||
@ -113,6 +113,44 @@ func Test_Map_StructWithJsonTag(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Map_StructWithCTag(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Uid int
|
||||
Name string
|
||||
SiteUrl string `c:"-"`
|
||||
NickName string `c:"nickname, omitempty"`
|
||||
Pass1 string `c:"password1"`
|
||||
Pass2 string `c:"password2"`
|
||||
}
|
||||
user1 := User{
|
||||
Uid: 100,
|
||||
Name: "john",
|
||||
SiteUrl: "https://goframe.org",
|
||||
Pass1: "123",
|
||||
Pass2: "456",
|
||||
}
|
||||
user2 := &user1
|
||||
map1 := gconv.Map(user1)
|
||||
map2 := gconv.Map(user2)
|
||||
gtest.Assert(map1["Uid"], 100)
|
||||
gtest.Assert(map1["Name"], "john")
|
||||
gtest.Assert(map1["SiteUrl"], nil)
|
||||
gtest.Assert(map1["NickName"], nil)
|
||||
gtest.Assert(map1["nickname"], nil)
|
||||
gtest.Assert(map1["password1"], "123")
|
||||
gtest.Assert(map1["password2"], "456")
|
||||
|
||||
gtest.Assert(map2["Uid"], 100)
|
||||
gtest.Assert(map2["Name"], "john")
|
||||
gtest.Assert(map2["SiteUrl"], nil)
|
||||
gtest.Assert(map2["NickName"], nil)
|
||||
gtest.Assert(map2["nickname"], nil)
|
||||
gtest.Assert(map2["password1"], "123")
|
||||
gtest.Assert(map2["password2"], "456")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Map_PrivateAttribute(t *testing.T) {
|
||||
type User struct {
|
||||
Id int
|
||||
@ -126,18 +164,18 @@ func Test_Map_PrivateAttribute(t *testing.T) {
|
||||
|
||||
func Test_Map_StructInherit(t *testing.T) {
|
||||
type Ids struct {
|
||||
Id int `json:"id"`
|
||||
Uid int `json:"uid"`
|
||||
Id int `c:"id"`
|
||||
Uid int `c:"uid"`
|
||||
}
|
||||
type Base struct {
|
||||
Ids
|
||||
CreateTime string `json:"create_time"`
|
||||
CreateTime string `c:"create_time"`
|
||||
}
|
||||
type User struct {
|
||||
Base
|
||||
Passport string `json:"passport"`
|
||||
Password string `json:"password"`
|
||||
Nickname string `json:"nickname"`
|
||||
Passport string `c:"passport"`
|
||||
Password string `c:"password"`
|
||||
Nickname string `c:"nickname"`
|
||||
}
|
||||
gtest.Case(t, func() {
|
||||
user := new(User)
|
||||
|
||||
Reference in New Issue
Block a user