mirror of
https://github.com/gogf/gf.git
synced 2025-04-04 10:32:46 +08:00
feat(net/ghttp): add Request.GetMetaTag
to retrieve specific meta tag value (#4185)
This commit is contained in:
parent
bcda48bf82
commit
f8331bad6e
6
.github/workflows/ci-main.sh
vendored
6
.github/workflows/ci-main.sh
vendored
@ -3,7 +3,7 @@
|
||||
coverage=$1
|
||||
|
||||
# update code of submodules
|
||||
make subup
|
||||
git clone https://github.com/gogf/examples
|
||||
|
||||
# find all path that contains go.mod.
|
||||
for file in `find . -name go.mod`; do
|
||||
@ -22,14 +22,14 @@ for file in `find . -name go.mod`; do
|
||||
fi
|
||||
|
||||
# Check if it's a contrib directory or examples directory
|
||||
if [[ $dirpath =~ "/contrib/" ]] || [ "examples" = $(basename $dirpath) ]; then
|
||||
if [[ $dirpath =~ "/contrib/" ]] || [[ $dirpath =~ "/examples/" ]]; then
|
||||
# Check if go version meets the requirement
|
||||
if ! go version | grep -qE "go${LATEST_GO_VERSION}"; then
|
||||
echo "ignore path $dirpath as go version is not ${LATEST_GO_VERSION}: $(go version)"
|
||||
continue 1
|
||||
fi
|
||||
# If it's examples directory, only build without tests
|
||||
if [ "examples" = $(basename $dirpath) ]; then
|
||||
if [[ $dirpath =~ "/examples/" ]]; then
|
||||
echo "the examples directory only needs to be built, not unit tests and coverage tests."
|
||||
cd $dirpath
|
||||
go mod tidy
|
||||
|
2
examples
2
examples
@ -1 +1 @@
|
||||
Subproject commit c454db2549ac7ecce844b687c1e610461818830d
|
||||
Subproject commit bf0ab5ac16fbf654fc424baf45e96e541a037cb3
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gview"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
@ -40,7 +41,7 @@ type Request struct {
|
||||
// =================================================================================================================
|
||||
|
||||
handlers []*HandlerItemParsed // All matched handlers containing handler, hook and middleware for this request.
|
||||
serveHandler *HandlerItemParsed // Real handler serving for this request, not hook or middleware.
|
||||
serveHandler *HandlerItemParsed // Real business handler serving for this request, not hook or middleware handler.
|
||||
handlerResponse interface{} // Handler response object for Request/Response handler.
|
||||
hasHookHandler bool // A bool marking whether there's hook handler in the handlers for performance purpose.
|
||||
hasServeHandler bool // A bool marking whether there's serving handler in the handlers for performance purpose.
|
||||
@ -288,3 +289,25 @@ func (r *Request) GetHandlerResponse() interface{} {
|
||||
func (r *Request) GetServeHandler() *HandlerItemParsed {
|
||||
return r.serveHandler
|
||||
}
|
||||
|
||||
// GetMetaTag retrieves and returns the metadata value associated with the given key from the request struct.
|
||||
// The meta value is from struct tags from g.Meta/gmeta.Meta type.
|
||||
// For example:
|
||||
//
|
||||
// type GetMetaTagReq struct {
|
||||
// g.Meta `path:"/test" method:"post" summary:"meta_tag" tags:"meta"`
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// r.GetMetaTag("summary") // returns "meta_tag"
|
||||
// r.GetMetaTag("method") // returns "post"
|
||||
func (r *Request) GetMetaTag(key string) string {
|
||||
if r.serveHandler == nil || r.serveHandler.Handler == nil {
|
||||
return ""
|
||||
}
|
||||
metaValue := gmeta.Get(r.serveHandler.Handler.Info.Type.In(1), key)
|
||||
if metaValue != nil {
|
||||
return metaValue.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ package ghttp_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
@ -861,3 +862,43 @@ func Test_Params_GetRequestMapStrVar(t *testing.T) {
|
||||
t.Assert(client.GetContent(ctx, "/GetRequestMapStrVar", "id=1"), 1)
|
||||
})
|
||||
}
|
||||
|
||||
type GetMetaTagReq struct {
|
||||
g.Meta `path:"/test" method:"post" summary:"meta_tag" tags:"meta"`
|
||||
Name string
|
||||
}
|
||||
type GetMetaTagRes struct{}
|
||||
|
||||
type GetMetaTagSt struct{}
|
||||
|
||||
func (r GetMetaTagSt) PostTest(ctx context.Context, req *GetMetaTagReq) (*GetMetaTagRes, error) {
|
||||
return &GetMetaTagRes{}, nil
|
||||
}
|
||||
|
||||
func TestRequest_GetMetaTag(t *testing.T) {
|
||||
s := g.Server(guid.S())
|
||||
s.Use(func(r *ghttp.Request) {
|
||||
r.Response.Writef(
|
||||
"summary:%s,method:%s",
|
||||
r.GetMetaTag("summary"), r.GetMetaTag("method"),
|
||||
)
|
||||
})
|
||||
s.Group("/", func(grp *ghttp.RouterGroup) {
|
||||
grp.Bind(GetMetaTagSt{})
|
||||
})
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
client := g.Client()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
|
||||
t.Assert(client.PostContent(ctx, "/test", "name=john"), "summary:meta_tag,method:post")
|
||||
})
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ type Field struct {
|
||||
type FieldsInput struct {
|
||||
// Pointer should be type of struct/*struct.
|
||||
// TODO this attribute name is not suitable, which would make confuse.
|
||||
Pointer interface{}
|
||||
Pointer any
|
||||
|
||||
// RecursiveOption specifies the way retrieving the fields recursively if the attribute
|
||||
// is an embedded struct. It is RecursiveOptionNone in default.
|
||||
@ -47,7 +47,7 @@ type FieldsInput struct {
|
||||
type FieldMapInput struct {
|
||||
// Pointer should be type of struct/*struct.
|
||||
// TODO this attribute name is not suitable, which would make confuse.
|
||||
Pointer interface{}
|
||||
Pointer any
|
||||
|
||||
// PriorityTagArray specifies the priority tag array for retrieving from high to low.
|
||||
// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
|
||||
@ -123,6 +123,7 @@ func Fields(in FieldsInput) ([]Field, error) {
|
||||
}
|
||||
}
|
||||
continue
|
||||
default:
|
||||
}
|
||||
}
|
||||
continue
|
||||
@ -194,6 +195,7 @@ func FieldMap(in FieldMapInput) (map[string]Field, error) {
|
||||
mapField[k] = tempV
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
mapField[field.Name()] = tempField
|
||||
@ -205,7 +207,19 @@ func FieldMap(in FieldMapInput) (map[string]Field, error) {
|
||||
|
||||
// StructType retrieves and returns the struct Type of specified struct/*struct.
|
||||
// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
|
||||
func StructType(object interface{}) (*Type, error) {
|
||||
func StructType(object any) (*Type, error) {
|
||||
// if already reflect.Type
|
||||
if reflectType, ok := object.(reflect.Type); ok {
|
||||
for reflectType.Kind() == reflect.Ptr {
|
||||
reflectType = reflectType.Elem()
|
||||
}
|
||||
if reflectType.Kind() == reflect.Struct {
|
||||
return &Type{
|
||||
Type: reflectType,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
reflectValue reflect.Value
|
||||
reflectKind reflect.Kind
|
||||
|
@ -8,6 +8,8 @@
|
||||
package gmeta
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/os/gstructs"
|
||||
)
|
||||
@ -15,19 +17,20 @@ import (
|
||||
// Meta is used as an embedded attribute for struct to enabled metadata feature.
|
||||
type Meta struct{}
|
||||
|
||||
const (
|
||||
metaAttributeName = "Meta" // metaAttributeName is the attribute name of metadata in struct.
|
||||
metaTypeName = "gmeta.Meta" // metaTypeName is for type string comparison.
|
||||
)
|
||||
// metaAttributeName is the attribute name of metadata in struct.
|
||||
const metaAttributeName = "Meta"
|
||||
|
||||
// metaType holds the reflection. Type of Meta, used for efficient type comparison.
|
||||
var metaType = reflect.TypeOf(Meta{})
|
||||
|
||||
// Data retrieves and returns all metadata from `object`.
|
||||
func Data(object interface{}) map[string]string {
|
||||
func Data(object any) map[string]string {
|
||||
reflectType, err := gstructs.StructType(object)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if field, ok := reflectType.FieldByName(metaAttributeName); ok {
|
||||
if field.Type.String() == metaTypeName {
|
||||
if field.Type == metaType {
|
||||
return gstructs.ParseTag(string(field.Tag))
|
||||
}
|
||||
}
|
||||
@ -35,7 +38,7 @@ func Data(object interface{}) map[string]string {
|
||||
}
|
||||
|
||||
// Get retrieves and returns specified metadata by `key` from `object`.
|
||||
func Get(object interface{}, key string) *gvar.Var {
|
||||
func Get(object any, key string) *gvar.Var {
|
||||
v, ok := Data(object)[key]
|
||||
if !ok {
|
||||
return nil
|
||||
|
Loading…
x
Reference in New Issue
Block a user