From 8b92ed65049fcac384ae80c0eaa706481c347f41 Mon Sep 17 00:00:00 2001 From: byene0923 Date: Fri, 16 Apr 2021 22:12:06 +0800 Subject: [PATCH] Proposal:Add Bind() method for web.Controller --- CHANGELOG.md | 4 +-- server/web/controller.go | 52 +++++++++++++++++++++++++++++++++++ server/web/controller_test.go | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9417ee6..59efffc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,8 +33,8 @@ - Improve: Avoid ignoring mistakes that need attention [4548](https://github.com/beego/beego/pull/4548) - Integration: DeepSource [4560](https://github.com/beego/beego/pull/4560) - Integration: Remove unnecessary function call [4577](https://github.com/beego/beego/pull/4577) - - +- Feature issue #4402 finish router get example. [4416](https://github.com/beego/beego/pull/4416) +- Proposal: Add Bind() method for web.Controller [4491](https://github.com/beego/beego/issues/4491) ## Fix Sonar - [4473](https://github.com/beego/beego/pull/4473) diff --git a/server/web/controller.go b/server/web/controller.go index 32378829..eb8b9c68 100644 --- a/server/web/controller.go +++ b/server/web/controller.go @@ -17,8 +17,12 @@ package web import ( "bytes" context2 "context" + "encoding/json" + "encoding/xml" "errors" "fmt" + "github.com/gogo/protobuf/proto" + "gopkg.in/yaml.v2" "html/template" "io" "mime/multipart" @@ -147,6 +151,12 @@ type ControllerInterface interface { CheckXSRFCookie() bool HandlerFunc(fn string) bool URLMapping() + Bind(obj interface{}) error + BindJson(obj interface{}) error + BindXML(obj interface{}) error + BindForm(obj interface{}) error + BindProtobuf(obj interface{}) error + BindYAML(obj interface{}) error } // Init generates default values of controller operations. @@ -239,6 +249,48 @@ func (c *Controller) HandlerFunc(fnname string) bool { // URLMapping register the internal Controller router. func (c *Controller) URLMapping() {} +func (c *Controller) Bind(obj interface{}) error { + ct := c.Ctx.Request.Header["Content-Type"] + i, l := 0, len(ct[0]) + for ; i < l && ct[0][i] != ';'; i++ { + } + switch ct[0][0:i] { + case "application/json": + return c.BindJson(obj) + case "application/xml", "text/xml": + return c.BindXML(obj) + case "application/x-www-form-urlencoded": + return c.BindForm(obj) + case "application/x-protobuf": + return c.BindProtobuf(obj) + case "application/x-yaml": + return c.BindYAML(obj) + default: + return errors.New("Unsupported Content-Type:" + ct[0]) + } +} + +func (c *Controller) BindYAML(obj interface{}) error { + return yaml.Unmarshal(c.Ctx.Input.RequestBody, obj) +} + +func (c *Controller) BindForm(obj interface{}) error { + return c.ParseForm(obj) +} + +func (c *Controller) BindJson(obj interface{}) error { + return json.Unmarshal(c.Ctx.Input.RequestBody, obj) +} + +func (c *Controller) BindProtobuf(obj interface{}) error { + return proto.Unmarshal(c.Ctx.Input.RequestBody, obj.(proto.Message)) +} + +func (c *Controller) BindXML(obj interface{}) error { + return xml.Unmarshal(c.Ctx.Input.RequestBody, obj) +} + + // Mapping the method to function func (c *Controller) Mapping(method string, fn func()) { c.methodMapping[method] = fn diff --git a/server/web/controller_test.go b/server/web/controller_test.go index 4f8b6d1c..f3f5f321 100644 --- a/server/web/controller_test.go +++ b/server/web/controller_test.go @@ -15,7 +15,10 @@ package web import ( + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "math" + "net/http" "os" "path/filepath" "strconv" @@ -180,3 +183,50 @@ func TestAdditionalViewPaths(t *testing.T) { ctrl.ViewPath = dir2 ctrl.RenderString() } + +func TestBindJson(t *testing.T) { + var s struct { + Foo string `json:"foo"` + } + header := map[string][]string{"Content-Type": {"application/json"}} + request := &http.Request{Header: header} + input := &context.BeegoInput{RequestBody: []byte(`{"foo": "FOO"}`)} + ctx := &context.Context{Request: request, Input: input} + ctrlr := Controller{Ctx: ctx} + err := ctrlr.Bind(&s) + require.NoError(t, err) + assert.Equal(t, "FOO", s.Foo) +} + +func TestBindXML(t *testing.T) { + + var s struct { + Foo string `xml:"foo"` + } + xmlBody := ` + + FOO +` + header := map[string][]string{"Content-Type": {"text/xml"}} + request := &http.Request{Header: header} + input := &context.BeegoInput{RequestBody: []byte(xmlBody)} + ctx := &context.Context{Request: request, Input: input} + ctrlr := Controller{Ctx: ctx} + err := ctrlr.Bind(&s) + require.NoError(t, err) + assert.Equal(t, "FOO", s.Foo) +} + +func TestBindYAML(t *testing.T) { + var s struct { + Foo string `yaml:"foo"` + } + header := map[string][]string{"Content-Type": {"application/x-yaml"}} + request := &http.Request{Header: header} + input := &context.BeegoInput{RequestBody: []byte("foo: FOO")} + ctx := &context.Context{Request: request, Input: input} + ctrlr := Controller{Ctx: ctx} + err := ctrlr.Bind(&s) + require.NoError(t, err) + assert.Equal(t, "FOO", s.Foo) +} \ No newline at end of file