Merge branch 'develop' of https://github.com/holooooo/beego into develop
This commit is contained in:
commit
0c04798bbe
@ -33,8 +33,9 @@
|
|||||||
- Improve: Avoid ignoring mistakes that need attention [4548](https://github.com/beego/beego/pull/4548)
|
- 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: DeepSource [4560](https://github.com/beego/beego/pull/4560)
|
||||||
- Integration: Remove unnecessary function call [4577](https://github.com/beego/beego/pull/4577)
|
- 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/4579)
|
||||||
|
- Optimize AddAutoPrefix: only register one router in case-insensitive mode. [4582](https://github.com/beego/beego/pull/4582)
|
||||||
|
|
||||||
## Fix Sonar
|
## Fix Sonar
|
||||||
- [4473](https://github.com/beego/beego/pull/4473)
|
- [4473](https://github.com/beego/beego/pull/4473)
|
||||||
|
|||||||
@ -17,8 +17,12 @@ package web
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
context2 "context"
|
context2 "context"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
@ -239,6 +243,50 @@ func (c *Controller) HandlerFunc(fnname string) bool {
|
|||||||
// URLMapping register the internal Controller router.
|
// URLMapping register the internal Controller router.
|
||||||
func (c *Controller) URLMapping() {}
|
func (c *Controller) URLMapping() {}
|
||||||
|
|
||||||
|
func (c *Controller) Bind(obj interface{}) error {
|
||||||
|
ct, exist := c.Ctx.Request.Header["Content-Type"]
|
||||||
|
if !exist || len(ct) == 0 {
|
||||||
|
return c.BindJson(obj)
|
||||||
|
}
|
||||||
|
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
|
// Mapping the method to function
|
||||||
func (c *Controller) Mapping(method string, fn func()) {
|
func (c *Controller) Mapping(method string, fn func()) {
|
||||||
c.methodMapping[method] = fn
|
c.methodMapping[method] = fn
|
||||||
|
|||||||
@ -15,7 +15,10 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"math"
|
"math"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -180,3 +183,64 @@ func TestAdditionalViewPaths(t *testing.T) {
|
|||||||
ctrl.ViewPath = dir2
|
ctrl.ViewPath = dir2
|
||||||
ctrl.RenderString()
|
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 TestBindNoContentType(t *testing.T) {
|
||||||
|
var s struct {
|
||||||
|
Foo string `json:"foo"`
|
||||||
|
}
|
||||||
|
header := map[string][]string{}
|
||||||
|
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 := `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<root>
|
||||||
|
<foo>FOO</foo>
|
||||||
|
</root>`
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@ -68,14 +68,21 @@ var (
|
|||||||
"LOCK": true,
|
"LOCK": true,
|
||||||
"UNLOCK": true,
|
"UNLOCK": true,
|
||||||
}
|
}
|
||||||
// these beego.Controller's methods shouldn't reflect to AutoRouter
|
// these web.Controller's methods shouldn't reflect to AutoRouter
|
||||||
exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString",
|
exceptMethod = []string{"Abort", "CheckXSRFCookie", "CustomAbort", "DelSession",
|
||||||
"RenderBytes", "Redirect", "Abort", "StopRun", "UrlFor", "ServeJSON", "ServeJSONP",
|
"DestroySession", "Finish", "GetBool", "GetControllerAndAction",
|
||||||
"ServeYAML", "ServeXML", "Input", "ParseForm", "GetString", "GetStrings", "GetInt", "GetBool",
|
"GetFile", "GetFiles", "GetFloat", "GetInt", "GetInt16",
|
||||||
"GetFloat", "GetFile", "SaveToFile", "StartSession", "SetSession", "GetSession",
|
"GetInt32", "GetInt64", "GetInt8", "GetSecureCookie", "GetSession",
|
||||||
"DelSession", "SessionRegenerateID", "DestroySession", "IsAjax", "GetSecureCookie",
|
"GetString", "GetStrings", "GetUint16", "GetUint32", "GetUint64",
|
||||||
"SetSecureCookie", "XsrfToken", "CheckXsrfCookie", "XsrfFormHtml",
|
"GetUint8", "HandlerFunc", "Init", "Input",
|
||||||
"GetControllerAndAction", "ServeFormatted"}
|
"IsAjax", "Mapping", "ParseForm",
|
||||||
|
"Prepare", "Redirect", "Render", "RenderBytes",
|
||||||
|
"RenderString", "SaveToFile", "SaveToFileWithBuffer", "SaveToFileWithBuffer",
|
||||||
|
"ServeFormatted", "ServeJSON", "ServeJSONP", "ServeXML", "ServeYAML",
|
||||||
|
"SessionRegenerateID", "SetData", "SetSecureCookie", "SetSession", "StartSession",
|
||||||
|
"StopRun", "URLFor", "URLMapping", "XSRFFormHTML",
|
||||||
|
"XSRFToken",
|
||||||
|
}
|
||||||
|
|
||||||
urlPlaceholder = "{{placeholder}}"
|
urlPlaceholder = "{{placeholder}}"
|
||||||
// DefaultAccessLogFilter will skip the accesslog if return true
|
// DefaultAccessLogFilter will skip the accesslog if return true
|
||||||
@ -725,22 +732,32 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface)
|
|||||||
ct := reflect.Indirect(reflectVal).Type()
|
ct := reflect.Indirect(reflectVal).Type()
|
||||||
controllerName := strings.TrimSuffix(ct.Name(), "Controller")
|
controllerName := strings.TrimSuffix(ct.Name(), "Controller")
|
||||||
for i := 0; i < rt.NumMethod(); i++ {
|
for i := 0; i < rt.NumMethod(); i++ {
|
||||||
if !utils.InSlice(rt.Method(i).Name, exceptMethod) {
|
methodName := rt.Method(i).Name
|
||||||
pattern := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name), "*")
|
if !utils.InSlice(methodName, exceptMethod) {
|
||||||
patternInit := path.Join(prefix, controllerName, rt.Method(i).Name, "*")
|
p.addAutoPrefixMethod(prefix, controllerName, methodName, ct)
|
||||||
patternFix := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name))
|
}
|
||||||
patternFixInit := path.Join(prefix, controllerName, rt.Method(i).Name)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
route := p.createBeegoRouter(ct, pattern)
|
func (p *ControllerRegister) addAutoPrefixMethod(prefix, controllerName, methodName string, ctrl reflect.Type) {
|
||||||
route.methods = map[string]string{"*": rt.Method(i).Name}
|
pattern := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(methodName), "*")
|
||||||
|
patternInit := path.Join(prefix, controllerName, methodName, "*")
|
||||||
|
patternFix := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(methodName))
|
||||||
|
patternFixInit := path.Join(prefix, controllerName, methodName)
|
||||||
|
|
||||||
|
route := p.createBeegoRouter(ctrl, pattern)
|
||||||
|
route.methods = map[string]string{"*": methodName}
|
||||||
for m := range HTTPMETHOD {
|
for m := range HTTPMETHOD {
|
||||||
|
|
||||||
p.addToRouter(m, pattern, route)
|
p.addToRouter(m, pattern, route)
|
||||||
|
|
||||||
|
// only case sensitive, we add three more routes
|
||||||
|
if p.cfg.RouterCaseSensitive {
|
||||||
p.addToRouter(m, patternInit, route)
|
p.addToRouter(m, patternInit, route)
|
||||||
p.addToRouter(m, patternFix, route)
|
p.addToRouter(m, patternFix, route)
|
||||||
p.addToRouter(m, patternFixInit, route)
|
p.addToRouter(m, patternFixInit, route)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertFilter Add a FilterFunc with pattern rule and action constant.
|
// InsertFilter Add a FilterFunc with pattern rule and action constant.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user