merge master

This commit is contained in:
John
2019-07-09 11:11:49 +08:00
14 changed files with 625 additions and 91 deletions

226
README.MD
View File

@ -40,6 +40,7 @@ golang version >= 1.10
# Quick Start
## Hello World
```go
package main
@ -56,8 +57,231 @@ func main() {
s.Run()
}
```
## Rich Router
```go
package main
[View More..](https://goframe.org/start/index)
import (
"github.com/gogf/gf/g/net/ghttp"
"github.com/gogf/gf/g"
)
func main() {
s := g.Server()
s.BindHandler("/{class}-{course}/:name/*act", func(r *ghttp.Request) {
r.Response.Writeln(r.Get("class"))
r.Response.Writeln(r.Get("course"))
r.Response.Writeln(r.Get("name"))
r.Response.Writeln(r.Get("act"))
})
s.SetPort(8199)
s.Run()
}
```
## Group Routers
```go
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
)
type Object struct {}
func (o *Object) Show(r *ghttp.Request) {
r.Response.Writeln("Object Show")
}
func (o *Object) Delete(r *ghttp.Request) {
r.Response.Writeln("Object 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)
group := s.Group("/api")
group.ALL ("*", HookHandler, ghttp.HOOK_BEFORE_SERVE)
group.ALL ("/handler", Handler)
group.ALL ("/obj", obj)
group.GET ("/obj/showit", obj, "Show")
group.REST("/obj/rest", obj)
s.SetPort(8199)
s.Run()
}
```
or
```go
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/showit", obj, "Show"},
{"REST", "/obj/rest", obj},
})
s.SetPort(8199)
s.Run()
}
```
## Multi ports & domains
```go
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
)
func Hello1(r *ghttp.Request) {
r.Response.Write("127.0.0.1: Hello1!")
}
func Hello2(r *ghttp.Request) {
r.Response.Write("localhost: Hello2!")
}
func main() {
s := g.Server()
s.Domain("127.0.0.1").BindHandler("/", Hello1)
s.Domain("localhost").BindHandler("/", Hello2)
s.SetPort(8100, 8200, 8300)
s.Run()
}
```
## Template Engine
```go
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/template", func(r *ghttp.Request) {
r.Response.WriteTpl("index.tpl", g.Map{
"id": 123,
"name": "john",
})
})
s.SetPort(8199)
s.Run()
}
```
## File Uploading
```go
func Upload(r *ghttp.Request) {
if f, h, e := r.FormFile("upload-file"); e == nil {
defer f.Close()
name := gfile.Basename(h.Filename)
buffer := make([]byte, h.Size)
f.Read(buffer)
gfile.PutBinContents("/tmp/" + name, buffer)
r.Response.Write(name + " uploaded successly")
} else {
r.Response.Write(e.Error())
}
}
```
## ORM Operations
### 1. Retrieving instance
```go
db := g.DB()
db := g.DB("user-center")
```
### 2. Chaining Operations
`Where + string`
```go
// SELECT * FROM user WHERE uid>1 LIMIT 0,10
r, err := db.Table("user").Where("uid > ?", 1).Limit(0, 10).Select()
// SELECT uid,name FROM user WHERE uid>1 LIMIT 0,10
r, err := db.Table("user").Fileds("uid,name").Where("uid > ?", 1).Limit(0, 10).Select()
// SELECT * FROM user WHERE uid=1
r, err := db.Table("user").Where("u.uid=1",).One()
r, err := db.Table("user").Where("u.uid", 1).One()
r, err := db.Table("user").Where("u.uid=?", 1).One()
// SELECT * FROM user WHERE (uid=1) AND (name='john')
r, err := db.Table("user").Where("uid", 1).Where("name", "john").One()
r, err := db.Table("user").Where("uid=?", 1).And("name=?", "john").One()
// SELECT * FROM user WHERE (uid=1) OR (name='john')
r, err := db.Table("user").Where("uid=?", 1).Or("name=?", "john").One()
```
`Where + map`
```go
// SELECT * FROM user WHERE uid=1 AND name='john'
r, err := db.Table("user").Where(g.Map{"uid" : 1, "name" : "john"}).One()
// SELECT * FROM user WHERE uid=1 AND age>18
r, err := db.Table("user").Where(g.Map{"uid" : 1, "age>" : 18}).One()
```
`Where + struct/*struct`
```go
type User struct {
Id int `json:"uid"`
UserName string `gconv:"name"`
}
// SELECT * FROM user WHERE uid =1 AND name='john'
r, err := db.Table("user").Where(User{ Id : 1, UserName : "john"}).One()
// SELECT * FROM user WHERE uid =1
r, err := db.Table("user").Where(&User{ Id : 1}).One()
```
### 3. Update & Delete
```go
// UPDATE user SET name='john guo' WHERE name='john'
r, err := db.Table("user").Data(gdb.Map{"name" : "john guo"}).Where("name=?", "john").Update()
r, err := db.Table("user").Data("name='john guo'").Where("name=?", "john").Update()
// UPDATE user SET status=1 ORDER BY login_time asc LIMIT 10
r, err := db.Table("user").Data("status", 1).OrderBy("login_time asc").Limit(10).Update
// DELETE FROM user WHERE uid=10
r, err := db.Table("user").Where("uid=?", 10).Delete()
// DELETE FROM user ORDER BY login_time asc LIMIT 10
r, err := db.Table("user").OrderBy("login_time asc").Limit(10).Delete()
```
### 4. Insert & Replace & Save
```go
r, err := db.Table("user").Data(g.Map{"name": "john"}).Insert()
r, err := db.Table("user").Data(g.Map{"uid": 10000, "name": "john"}).Replace()
r, err := db.Table("user").Data(g.Map{"uid": 10001, "name": "john"}).Save()
```
### 5. Transaction
```go
if tx, err := db.Begin(); err == nil {
r, err := tx.Save("user", g.Map{
"uid" : 1,
"name" : "john",
})
tx.Commit()
}
```
### 6. Error Handling
```go
func GetOrderInfo(id int) (order *Order, err error) {
err = g.DB().Table("order").Where("id", id).Struct(&order)
if err != nil && err == sql.ErrNoRows {
err = nil
}
return
}
```
[More Features...](https://goframe.org/start/index)
# License

View File

@ -58,33 +58,6 @@ func (v *Var) Interface() interface{} {
return v.Val()
}
// Time converts and returns <v> as time.Time.
// The parameter <format> specifies the format of the time string using gtime,
// eg: Y-m-d H:i:s.
func (v *Var) Time(format ...string) time.Time {
return gconv.Time(v.Val(), format...)
}
// Duration converts and returns <v> as time.Duration.
// If value of <v> is string, then it uses time.ParseDuration for conversion.
func (v *Var) Duration() time.Duration {
return gconv.Duration(v.Val())
}
// GTime converts and returns <v> as *gtime.Time.
// The parameter <format> specifies the format of the time string using gtime,
// eg: Y-m-d H:i:s.
func (v *Var) GTime(format ...string) *gtime.Time {
return gconv.GTime(v.Val(), format...)
}
// Struct maps value of <v> to <objPointer>.
// The parameter <objPointer> should be a pointer to a struct instance.
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
return gconv.Struct(v.Val(), pointer, mapping...)
}
// IsNil checks whether <v> is nil.
func (v *Var) IsNil() bool {
return v.Val() == nil
@ -184,3 +157,57 @@ func (v *Var) Strings() []string {
func (v *Var) Interfaces() []interface{} {
return gconv.Interfaces(v.Val())
}
// Time converts and returns <v> as time.Time.
// The parameter <format> specifies the format of the time string using gtime,
// eg: Y-m-d H:i:s.
func (v *Var) Time(format ...string) time.Time {
return gconv.Time(v.Val(), format...)
}
// Duration converts and returns <v> as time.Duration.
// If value of <v> is string, then it uses time.ParseDuration for conversion.
func (v *Var) Duration() time.Duration {
return gconv.Duration(v.Val())
}
// GTime converts and returns <v> as *gtime.Time.
// The parameter <format> specifies the format of the time string using gtime,
// eg: Y-m-d H:i:s.
func (v *Var) GTime(format ...string) *gtime.Time {
return gconv.GTime(v.Val(), format...)
}
// Map converts <v> to map[string]interface{}.
func (v *Var) Map(tags ...string) map[string]interface{} {
return gconv.Map(v.Val(), tags...)
}
// MapDeep converts <v> to map[string]interface{} recursively.
func (v *Var) MapDeep(tags ...string) map[string]interface{} {
return gconv.MapDeep(v.Val(), tags...)
}
// Struct maps value of <v> to <pointer>.
// The parameter <pointer> should be a pointer to a struct instance.
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
return gconv.Struct(v.Val(), pointer, mapping...)
}
// Struct maps value of <v> to <pointer> recursively.
// The parameter <pointer> should be a pointer to a struct instance.
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
func (v *Var) StructDeep(pointer interface{}, mapping ...map[string]string) error {
return gconv.StructDeep(v.Val(), pointer, mapping...)
}
// Structs converts <v> to given struct slice.
func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.Structs(v.Val(), pointer, mapping...)
}
// StructsDeep converts <v> to given struct slice recursively.
func (v *Var) StructsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.StructsDeep(v.Val(), pointer, mapping...)
}

View File

@ -673,6 +673,21 @@ func TestModel_Where(t *testing.T) {
gtest.Assert(err, nil)
gtest.Assert(result["id"].Int(), 3)
})
// slice
gtest.Case(t, func() {
result, err := db.Table("user").Where("id=? AND nickname=?", g.Slice{3, "T3"}...).One()
if err != nil {
gtest.Fatal(err)
}
gtest.Assert(result["id"].Int(), 3)
})
gtest.Case(t, func() {
result, err := db.Table("user").Where("passport like ? and nickname like ?", g.Slice{"t3", "T3"}...).One()
if err != nil {
gtest.Fatal(err)
}
gtest.Assert(result["id"].Int(), 3)
})
// map
gtest.Case(t, func() {
result, err := db.Table("user").Where(g.Map{"id": 3, "nickname": "T3"}).One()

View File

@ -22,10 +22,7 @@ func Encode(src []byte) []byte {
func Decode(dst []byte) ([]byte, error) {
src := make([]byte, base64.StdEncoding.DecodedLen(len(dst)))
n, err := base64.StdEncoding.Decode(src, dst)
if err != nil {
return nil, err
}
return src[:n], nil
return src[:n], err
}
// EncodeString encodes bytes with BASE64 algorithm.

View File

@ -266,11 +266,32 @@ func (j *Json) GetToVar(pattern string, pointer interface{}) error {
return nil
}
// GetToStruct gets the value by specified <pattern>,
// and converts it to specified object <objPointer>.
// The <objPointer> should be the pointer to an object.
func (j *Json) GetToStruct(pattern string, pointer interface{}) error {
return gconv.Struct(j.Get(pattern), pointer)
// GetStruct gets the value by specified <pattern>,
// and converts it to specified object <pointer>.
// The <pointer> should be the pointer to an object.
func (j *Json) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
return gconv.Struct(j.Get(pattern), pointer, mapping...)
}
// GetStructDeep does GetStruct recursively.
func (j *Json) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
return gconv.StructDeep(j.Get(pattern), pointer, mapping...)
}
// GetStructs converts any slice to given struct slice.
func (j *Json) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
return gconv.Structs(j.Get(pattern), pointer, mapping...)
}
// GetStructsDeep converts any slice to given struct slice recursively.
func (j *Json) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
return gconv.StructsDeep(j.Get(pattern), pointer, mapping...)
}
// GetToStruct is alias of GetStruct.
// Deprecated.
func (j *Json) GetToStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
return j.GetStruct(pattern, pointer, mapping...)
}
// ToMap converts current Json object to map[string]interface{}.
@ -290,7 +311,7 @@ func (j *Json) ToArray() []interface{} {
}
// ToStruct converts current Json object to specified object.
// The <objPointer> should be a pointer type.
// The <pointer> should be a pointer type.
func (j *Json) ToStruct(pointer interface{}) error {
j.mu.RLock()
defer j.mu.RUnlock()

View File

@ -145,11 +145,32 @@ func (p *Parser) GetToVar(pattern string, pointer interface{}) error {
return p.json.GetToVar(pattern, pointer)
}
// GetToStruct gets the value by specified <pattern>,
// GetStruct gets the value by specified <pattern>,
// and converts it to specified object <pointer>.
// The <pointer> should be the pointer to a struct.
func (p *Parser) GetToStruct(pattern string, pointer interface{}) error {
return p.json.GetToStruct(pattern, pointer)
// The <pointer> should be the pointer to an object.
func (p *Parser) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
return p.json.GetStruct(pattern, pointer, mapping...)
}
// GetStructDeep does GetStruct recursively.
func (p *Parser) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
return p.json.GetStructDeep(pattern, pointer, mapping...)
}
// GetStructs converts any slice to given struct slice.
func (p *Parser) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
return p.json.GetStructs(pattern, pointer, mapping...)
}
// GetStructsDeep converts any slice to given struct slice recursively.
func (p *Parser) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
return p.json.GetStructsDeep(pattern, pointer, mapping...)
}
// GetToStruct is alias of GetStruct.
// Deprecated.
func (p *Parser) GetToStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
return p.json.GetStruct(pattern, pointer, mapping...)
}
// Set sets value with specified <pattern>.

View File

@ -154,5 +154,5 @@ func (r *Request) GetPostToStruct(pointer interface{}, mapping ...map[string]str
for k, v := range r.GetPostMap() {
params[k] = v
}
return gconv.Struct(params, pointer, tagMap)
return gconv.StructDeep(params, pointer, tagMap)
}

View File

@ -489,14 +489,41 @@ func (c *Config) GetGTime(pattern string, format ...string) *gtime.Time {
return nil
}
func (c *Config) GetToStruct(pattern string, pointer interface{}, def ...interface{}) error {
func (c *Config) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
if j := c.getJson(); j != nil {
return j.GetToStruct(pattern, pointer)
return j.GetStruct(pattern, pointer, mapping...)
}
return errors.New("config file not found")
}
// Deprecated. See Clear.
func (c *Config) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
if j := c.getJson(); j != nil {
return j.GetStructDeep(pattern, pointer, mapping...)
}
return errors.New("config file not found")
}
func (c *Config) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
if j := c.getJson(); j != nil {
return j.GetStructs(pattern, pointer, mapping...)
}
return errors.New("config file not found")
}
func (c *Config) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
if j := c.getJson(); j != nil {
return j.GetStructsDeep(pattern, pointer, mapping...)
}
return errors.New("config file not found")
}
// Deprecated.
func (c *Config) GetToStruct(pattern string, pointer interface{}) error {
return c.GetStruct(pattern, pointer)
}
// Reload is alias of Clear.
// Deprecated.
func (c *Config) Reload() {
c.jsons.Clear()
}

View File

@ -11,11 +11,8 @@ import (
"bytes"
"errors"
"fmt"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/text/gregex"
"github.com/gogf/gf/g/text/gstr"
"github.com/gogf/gf/g/util/gconv"
"io"
"io/ioutil"
"os"
"os/exec"
"os/user"
@ -24,6 +21,11 @@ import (
"sort"
"strings"
"time"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/text/gregex"
"github.com/gogf/gf/g/text/gstr"
"github.com/gogf/gf/g/util/gconv"
)
const (
@ -142,29 +144,109 @@ func Rename(src string, dst string) error {
return Move(src, dst)
}
// Copy file from <src> to <dst>.
// Copy file/directory from <src> to <dst>.
//
// @TODO directory copy support.
// If <src> is file, it calls CopyFile to implements copy feature,
// or else it calls CopyDir.
func Copy(src string, dst string) error {
srcFile, err := Open(src)
if IsFile(src) {
return CopyFile(src, dst)
}
return CopyDir(src, dst)
}
// CopyFile copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file. The file mode will be copied from the source and
// the copied data is synced/flushed to stable storage.
// Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
func CopyFile(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return
}
defer func() {
if e := in.Close(); e != nil {
err = e
}
}()
out, err := os.Create(dst)
if err != nil {
return
}
defer func() {
if e := out.Close(); e != nil {
err = e
}
}()
_, err = io.Copy(out, in)
if err != nil {
return
}
err = out.Sync()
if err != nil {
return
}
si, err := os.Stat(src)
if err != nil {
return
}
err = os.Chmod(dst, si.Mode())
if err != nil {
return
}
return
}
// CopyDir recursively copies a directory tree, attempting to preserve permissions.
// Source directory must exist, destination directory must *not* exist.
// Symlinks are ignored and skipped.
func CopyDir(src string, dst string) (err error) {
src = filepath.Clean(src)
dst = filepath.Clean(dst)
si, err := os.Stat(src)
if err != nil {
return err
}
defer srcFile.Close()
dstFile, err := Create(dst)
if err != nil {
return err
if !si.IsDir() {
return fmt.Errorf("source is not a directory")
}
defer dstFile.Close()
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return err
_, err = os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
return
}
err = dstFile.Sync()
if err != nil {
return err
if err == nil {
return fmt.Errorf("destination already exists")
}
return nil
err = os.MkdirAll(dst, si.Mode())
if err != nil {
return
}
entries, err := ioutil.ReadDir(src)
if err != nil {
return
}
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
if entry.IsDir() {
err = CopyDir(srcPath, dstPath)
if err != nil {
return
}
} else {
// Skip symlinks.
if entry.Mode()&os.ModeSymlink != 0 {
continue
}
err = CopyFile(srcPath, dstPath)
if err != nil {
return
}
}
}
return
}
// DirNames returns sub-file names of given directory <path>.

View File

@ -1,12 +1,13 @@
package gfile_test
import (
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/test/gtest"
"os"
"path/filepath"
"strings"
"testing"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/test/gtest"
)
func TestIsDir(t *testing.T) {
@ -677,3 +678,71 @@ func TestMainPkgPath(t *testing.T) {
gtest.Assert(reads, "")
})
}
func TestCopyFile(t *testing.T) {
gtest.Case(t, func() {
var (
paths string = "/testfile_copyfile1.txt"
topath string = "/testfile_copyfile2.txt"
)
createTestFile(paths, "")
defer delTestFiles(paths)
gtest.Assert(gfile.CopyFile(testpath()+paths, testpath()+topath), nil)
defer delTestFiles(topath)
gtest.Assert(gfile.IsFile(testpath()+topath), true)
gtest.AssertNE(gfile.CopyFile("", ""), nil)
})
}
func TestCopyDir(t *testing.T) {
gtest.Case(t, func() {
var (
dirpath1 string = "/testcopydir1"
dirpath2 string = "/testcopydir2"
)
havelist1 := []string{
"t1.txt",
"t2.txt",
}
createDir(dirpath1)
for _, v := range havelist1 {
createTestFile(dirpath1+"/"+v, "")
}
defer delTestFiles(dirpath1)
yfolder := testpath() + dirpath1
tofolder := testpath() + dirpath2
if gfile.IsDir(tofolder) {
gtest.Assert(gfile.Remove(tofolder), nil)
gtest.Assert(gfile.Remove(""), nil)
}
gtest.Assert(gfile.CopyDir(yfolder, tofolder), nil)
defer delTestFiles(tofolder)
// 检查复制后的旧文件夹是否真实存在
gtest.Assert(gfile.IsDir(yfolder), true)
// 检查复制后的旧文件夹中的文件是否真实存在
for _, v := range havelist1 {
gtest.Assert(gfile.IsFile(yfolder+"/"+v), true)
}
// 检查复制后的新文件夹是否真实存在
gtest.Assert(gfile.IsDir(tofolder), true)
// 检查复制后的新文件夹中的文件是否真实存在
for _, v := range havelist1 {
gtest.Assert(gfile.IsFile(tofolder+"/"+v), true)
}
gtest.Assert(gfile.Remove(tofolder), nil)
gtest.Assert(gfile.Remove(""), nil)
})
}

View File

@ -7,8 +7,6 @@
package gfsnotify
import (
"fmt"
"github.com/gogf/gf/g/container/glist"
)
@ -23,7 +21,7 @@ func (w *Watcher) startWatchLoop() {
// 监听事件
case ev := <-w.watcher.Events:
fmt.Println("ev:", ev.String())
//fmt.Println("ev:", ev.String())
w.cache.SetIfNotExist(ev.String(), func() interface{} {
w.events.Push(&Event{
event: ev,

View File

@ -14,6 +14,46 @@ import (
"github.com/gogf/gf/g/text/gstr"
)
// SliceInt is alias of Ints.
func SliceInt(i interface{}) []int {
return Ints(i)
}
// SliceStr is alias of Strings.
func SliceStr(i interface{}) []string {
return Strings(i)
}
// SliceAny is alias of Interfaces.
func SliceAny(i interface{}) []interface{} {
return Interfaces(i)
}
// SliceFloat is alias of Floats.
func SliceFloat(i interface{}) []float64 {
return Floats(i)
}
// SliceMap is alias of Maps.
func SliceMap(i interface{}) []map[string]interface{} {
return Maps(i)
}
// SliceMapDeep is alias of MapsDeep.
func SliceMapDeep(i interface{}) []map[string]interface{} {
return MapsDeep(i)
}
// SliceStruct is alias of Structs.
func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
return Structs(params, pointer, mapping...)
}
// SliceStructDeep is alias of StructsDeep.
func SliceStructDeep(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
return StructsDeep(params, pointer, mapping...)
}
// Ints converts <i> to []int.
func Ints(i interface{}) []int {
if i == nil {
@ -350,6 +390,26 @@ func Maps(i interface{}) []map[string]interface{} {
}
}
// MapsDeep converts <i> to []map[string]interface{} recursively.
func MapsDeep(i interface{}) []map[string]interface{} {
if i == nil {
return nil
}
if r, ok := i.([]map[string]interface{}); ok {
return r
} else {
array := Interfaces(i)
if len(array) == 0 {
return nil
}
list := make([]map[string]interface{}, len(array))
for k, v := range array {
list[k] = MapDeep(v)
}
return list
}
}
// Structs converts any slice to given struct slice.
func Structs(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
return doStructs(params, pointer, false, mapping...)

View File

@ -1,27 +1,19 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/util/gvalid"
"encoding/base64"
"fmt"
"github.com/gogf/gf/g/encoding/gbase64"
)
func main() {
type Pass struct {
Pass1 string `valid:"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致"`
Pass2 string `valid:"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致"`
}
type User struct {
Id int
Name string `valid:"name@required#请输入您的姓名"`
Pass Pass
}
user := &User{
Name: "john",
Pass: Pass{
Pass1: "1",
Pass2: "2",
},
}
err := gvalid.CheckStruct(user, nil)
g.Dump(err.Maps())
data := "HwHsGhXMaGc==="
datab, err := gbase64.Decode([]byte(data))
fmt.Println(err)
fmt.Println(datab)
fmt.Println(string(datab))
s, e := base64.StdEncoding.DecodeString(data)
fmt.Println(e)
fmt.Println(string(s))
}

3
go.mod
View File

@ -1 +1,2 @@
module github.com/gogf/gf
module github.com/gogf/gf