mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
Merge branch 'develop'
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
package gfile
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/os/gfpool"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -15,8 +16,8 @@ import (
|
||||
const (
|
||||
// 方法中涉及到读取的时候的缓冲大小
|
||||
gREAD_BUFFER = 1024
|
||||
// 方法中涉及到文件指针池的默认缓存时间(秒)
|
||||
gFILE_POOL_EXPIRE = 60
|
||||
// 方法中涉及到文件指针池的默认缓存时间(毫秒)
|
||||
gFILE_POOL_EXPIRE = 60000
|
||||
)
|
||||
|
||||
// (文本)读取文件内容
|
||||
@ -43,7 +44,7 @@ func putContents(path string, data []byte, flag int, perm int) error {
|
||||
}
|
||||
}
|
||||
// 创建/打开文件
|
||||
f, err := OpenWithFlagPerm(path, flag, perm)
|
||||
f, err := gfpool.Open(path, flag, os.FileMode(perm), gFILE_POOL_EXPIRE)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -82,11 +83,11 @@ func PutBinContentsAppend(path string, content []byte) error {
|
||||
}
|
||||
|
||||
// 获得文件内容下一个指定字节的位置
|
||||
func GetNextCharOffset(file *os.File, char byte, start int64) int64 {
|
||||
func GetNextCharOffset(reader io.ReaderAt, char byte, start int64) int64 {
|
||||
buffer := make([]byte, gREAD_BUFFER)
|
||||
offset := start
|
||||
for {
|
||||
if n, err := file.ReadAt(buffer, offset); n > 0 {
|
||||
if n, err := reader.ReadAt(buffer, offset); n > 0 {
|
||||
for i := 0; i < n; i++ {
|
||||
if buffer[i] == char {
|
||||
return int64(i) + offset
|
||||
@ -102,7 +103,7 @@ func GetNextCharOffset(file *os.File, char byte, start int64) int64 {
|
||||
|
||||
// 获得文件内容下一个指定字节的位置
|
||||
func GetNextCharOffsetByPath(path string, char byte, start int64) int64 {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
if f, err := gfpool.Open(path, os.O_RDONLY, gDEFAULT_PERM, gFILE_POOL_EXPIRE); err == nil {
|
||||
defer f.Close()
|
||||
return GetNextCharOffset(f, char, start)
|
||||
} else {
|
||||
@ -112,16 +113,16 @@ func GetNextCharOffsetByPath(path string, char byte, start int64) int64 {
|
||||
}
|
||||
|
||||
// 获得文件内容直到下一个指定字节的位置(返回值包含该位置字符内容)
|
||||
func GetBinContentsTilChar(file *os.File, char byte, start int64) ([]byte, int64) {
|
||||
if offset := GetNextCharOffset(file, char, start); offset != -1 {
|
||||
return GetBinContentsByTwoOffsets(file, start, offset + 1), offset
|
||||
func GetBinContentsTilChar(reader io.ReaderAt, char byte, start int64) ([]byte, int64) {
|
||||
if offset := GetNextCharOffset(reader, char, start); offset != -1 {
|
||||
return GetBinContentsByTwoOffsets(reader, start, offset + 1), offset
|
||||
}
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
// 获得文件内容直到下一个指定字节的位置(返回值包含该位置字符内容)
|
||||
func GetBinContentsTilCharByPath(path string, char byte, start int64) ([]byte, int64) {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
if f, err := gfpool.Open(path, os.O_RDONLY, gDEFAULT_PERM, gFILE_POOL_EXPIRE); err == nil {
|
||||
defer f.Close()
|
||||
return GetBinContentsTilChar(f, char, start)
|
||||
} else {
|
||||
@ -131,9 +132,9 @@ func GetBinContentsTilCharByPath(path string, char byte, start int64) ([]byte, i
|
||||
}
|
||||
|
||||
// 获得文件内容中两个offset之间的内容 [start, end)
|
||||
func GetBinContentsByTwoOffsets(file *os.File, start int64, end int64) []byte {
|
||||
func GetBinContentsByTwoOffsets(reader io.ReaderAt, start int64, end int64) []byte {
|
||||
buffer := make([]byte, end - start)
|
||||
if _, err := file.ReadAt(buffer, start); err != nil {
|
||||
if _, err := reader.ReadAt(buffer, start); err != nil {
|
||||
return nil
|
||||
}
|
||||
return buffer
|
||||
@ -141,7 +142,7 @@ func GetBinContentsByTwoOffsets(file *os.File, start int64, end int64) []byte {
|
||||
|
||||
// 获得文件内容中两个offset之间的内容 [start, end)
|
||||
func GetBinContentsByTwoOffsetsByPath(path string, start int64, end int64) []byte {
|
||||
if f, err := OpenWithFlagPerm(path, os.O_RDONLY, gDEFAULT_PERM); err == nil {
|
||||
if f, err := gfpool.Open(path, os.O_RDONLY, gDEFAULT_PERM, gFILE_POOL_EXPIRE); err == nil {
|
||||
defer f.Close()
|
||||
return GetBinContentsByTwoOffsets(f, start, end)
|
||||
} else {
|
||||
|
||||
@ -28,7 +28,7 @@ type Pool struct {
|
||||
|
||||
// 文件指针池指针
|
||||
type File struct {
|
||||
os.File // 底层文件指针
|
||||
*os.File // 底层文件指针
|
||||
mu sync.RWMutex // 互斥锁
|
||||
pool *Pool // 所属池
|
||||
poolid int // 所属池ID,如果池ID不同表示池已经重建,那么该文件指针也应当销毁,不能重新丢到原有的池中
|
||||
@ -81,8 +81,8 @@ func newFilePool(p *Pool, path string, flag int, perm os.FileMode, expire int) *
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &File{
|
||||
File : *file,
|
||||
return &File {
|
||||
File : file,
|
||||
pool : p,
|
||||
poolid : p.id.Val(),
|
||||
flag : flag,
|
||||
@ -108,7 +108,7 @@ func (p *Pool) File() (*File, error) {
|
||||
if file, err := os.OpenFile(f.path, f.flag, f.perm); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
f.File = *file
|
||||
f.File = file
|
||||
if stat, err = f.Stat(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -127,7 +127,9 @@ func (p *Pool) File() (*File, error) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
f.Seek(0, 0)
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if !p.inited.Set(true) {
|
||||
gfsnotify.Add(f.path, func(event *gfsnotify.Event) {
|
||||
|
||||
@ -5,17 +5,44 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func Benchmark_os_Open_Close(b *testing.B) {
|
||||
func Benchmark_os_Open_Close_ALLFlags(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
f, _ := os.OpenFile("/tmp/bench-test", os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0766)
|
||||
f, _ := os.OpenFile("/tmp/bench-test", os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_gfpool_Open_Close(b *testing.B) {
|
||||
func Benchmark_gfpool_Open_Close_ALLFlags(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
f, _ := Open("/tmp/bench-test", os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0766)
|
||||
f, _ := Open("/tmp/bench-test", os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_os_Open_Close_RDWR(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
f, _ := os.OpenFile("/tmp/bench-test", os.O_RDWR, 0666)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_gfpool_Open_Close_RDWR(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
f, _ := Open("/tmp/bench-test", os.O_RDWR, 0666)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_os_Open_Close_RDONLY(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
f, _ := os.OpenFile("/tmp/bench-test", os.O_RDONLY, 0666)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_gfpool_Open_Close_RDONLY(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
f, _ := Open("/tmp/bench-test", os.O_RDONLY, 0666)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
@ -191,35 +191,75 @@ func (w *Watcher) startWatchLoop() {
|
||||
|
||||
// 检索给定path的回调方法**列表**
|
||||
func (w *Watcher) getCallbacks(path string) *glist.List {
|
||||
for path != "/" {
|
||||
for {
|
||||
if l := w.callbacks.Get(path); l != nil {
|
||||
return l.(*glist.List)
|
||||
} else {
|
||||
path = fileDir(path)
|
||||
if p := fileDir(path); p != path {
|
||||
path = p
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获得真正监听的文件路径,判断规则:
|
||||
// 1、在 callbacks 中应当有回调注册函数(否则监听根本没意义);
|
||||
// 2、如果该path下不存在回调注册函数,则按照path长度从右往左递减,直到减到目录地址为止(不包含);
|
||||
// 3、如果仍旧无法匹配回调函数,那么忽略,否则使用查找到的新path覆盖掉event的path;
|
||||
func (w *Watcher) getWatchTruePath(path string) string {
|
||||
if w.getCallbacks(path) != nil {
|
||||
return path
|
||||
}
|
||||
dirPath := fileDir(path)
|
||||
for {
|
||||
path = path[0 : len(path) - 1]
|
||||
if path == dirPath {
|
||||
break
|
||||
}
|
||||
if w.getCallbacks(path) != nil {
|
||||
return path
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 事件循环
|
||||
func (w *Watcher) startEventLoop() {
|
||||
go func() {
|
||||
for {
|
||||
if v := w.events.Pop(); v != nil {
|
||||
event := v.(*Event)
|
||||
// 如果是删除操作,那么需要判断是否文件真正不存在了
|
||||
if event.IsRemove() {
|
||||
if fileExists(event.Path) {
|
||||
// 如果是文件删除事件,判断该文件是否存在,如果存在,那么将此事件认为“假删除”,
|
||||
// 并重新添加监控(底层fsnotify会自动删除掉监控,这里重新添加回去)
|
||||
w.watcher.Add(event.Path)
|
||||
// 修改事件操作为重命名(相当于重命名为自身名称,最终名称没变)
|
||||
event.Op = RENAME
|
||||
} else {
|
||||
// 如果是真实删除,那么递归删除监控信息
|
||||
w.Remove(event.Path)
|
||||
}
|
||||
if path := w.getWatchTruePath(event.Path); path == "" {
|
||||
continue
|
||||
} else {
|
||||
event.Path = path
|
||||
}
|
||||
switch {
|
||||
// 如果是删除操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假删除”
|
||||
case event.IsRemove():
|
||||
if fileExists(event.Path) {
|
||||
// 重新添加监控(底层fsnotify会自动删除掉监控,这里重新添加回去)
|
||||
// 注意这里调用的是底层fsnotify添加监控,只会产生回调事件,并不会使回调函数重复注册
|
||||
w.watcher.Add(event.Path)
|
||||
// 修改事件操作为重命名(相当于重命名为自身名称,最终名称没变)
|
||||
event.Op = RENAME
|
||||
} else {
|
||||
// 如果是真实删除,那么递归删除监控信息
|
||||
w.Remove(event.Path)
|
||||
}
|
||||
|
||||
// 如果是删除操作,那么需要判断是否文件真正不存在了,如果存在,那么将此事件认为“假命名”
|
||||
// (特别是某些编辑器在编辑文件时会先对文件RENAME再CHMOD)
|
||||
case event.IsRename():
|
||||
if fileExists(event.Path) {
|
||||
// 重新添加监控
|
||||
w.watcher.Add(event.Path)
|
||||
}
|
||||
}
|
||||
|
||||
callbacks := w.getCallbacks(event.Path)
|
||||
// 如果创建了新的目录,那么将这个目录递归添加到监控中
|
||||
if event.IsCreate() && fileIsDir(event.Path) {
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"gitee.com/johng/gf/g/container/gtype"
|
||||
"gitee.com/johng/gf/g/os/gfile"
|
||||
"gitee.com/johng/gf/g/os/gfpool"
|
||||
"gitee.com/johng/gf/g/os/gmlock"
|
||||
"gitee.com/johng/gf/g/os/gtime"
|
||||
"gitee.com/johng/gf/g/util/gregex"
|
||||
@ -38,6 +39,8 @@ type Logger struct {
|
||||
const (
|
||||
gDEFAULT_FILE_FORMAT = `{Y-m-d}.log`
|
||||
gDEFAULT_FILE_POOL_FLAGS = os.O_CREATE|os.O_WRONLY|os.O_APPEND
|
||||
gDEFAULT_FPOOL_PERM = os.FileMode(0666)
|
||||
gDEFAULT_FPOOL_EXPIRE = 60000
|
||||
)
|
||||
|
||||
var (
|
||||
@ -127,14 +130,14 @@ func (l *Logger) GetWriter() io.Writer {
|
||||
}
|
||||
|
||||
// 获取默认的文件IO
|
||||
func (l *Logger) getFilePointer() *os.File {
|
||||
func (l *Logger) getFilePointer() *gfpool.File {
|
||||
if path := l.path.Val(); path != "" {
|
||||
// 文件名称中使用"{}"包含的内容使用gtime格式化
|
||||
file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.file.Val(), func(s string) string {
|
||||
return gtime.Now().Format(strings.Trim(s, "{}"))
|
||||
})
|
||||
fpath := path + gfile.Separator + file
|
||||
if fp, err := gfile.OpenWithFlagPerm(fpath, gDEFAULT_FILE_POOL_FLAGS, 0666); err == nil {
|
||||
if fp, err := gfpool.Open(fpath, gDEFAULT_FILE_POOL_FLAGS, gDEFAULT_FPOOL_PERM, gDEFAULT_FPOOL_EXPIRE); err == nil {
|
||||
return fp
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
||||
20
geg/net/ghttp/server/download/download.go
Normal file
20
geg/net/ghttp/server/download/download.go
Normal file
@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g"
|
||||
"gitee.com/johng/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/download", func(r *ghttp.Request){
|
||||
r.Response.Header().Set("Content-Type", "text/html;charset=utf-8");
|
||||
r.Response.Header().Set("Content-type", "application/force-download");
|
||||
r.Response.Header().Set("Content-Type", "application/octet-stream");
|
||||
r.Response.Header().Set("Accept-Ranges", "bytes");
|
||||
r.Response.Header().Set("Content-Disposition", "attachment;filename=\"下载文件名称.txt\"");
|
||||
r.Response.ServeFile("text.txt")
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
1
geg/net/ghttp/server/download/text.txt
Normal file
1
geg/net/ghttp/server/download/text.txt
Normal file
@ -0,0 +1 @@
|
||||
下载文件内容。
|
||||
@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g"
|
||||
"gitee.com/johng/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request){
|
||||
content :=`{{if (get "name")}} {{get "name"}} {{else}} NoName {{end}}`
|
||||
r.Response.WriteTplContent(content, nil)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
11
geg/net/ghttp/server/template/tpl1/index.html
Normal file
11
geg/net/ghttp/server/template/tpl1/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{.title}}</title>
|
||||
</head>
|
||||
<body>
|
||||
<H1>姓名 : {{.name}}</H1>
|
||||
12
|
||||
</body>
|
||||
</html>
|
||||
23
geg/net/ghttp/server/template/tpl1/tpl1.go
Normal file
23
geg/net/ghttp/server/template/tpl1/tpl1.go
Normal file
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/frame/gmvc"
|
||||
"gitee.com/johng/gf/g/net/ghttp"
|
||||
)
|
||||
type ControllerIndex struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
func (c *ControllerIndex) Info() {
|
||||
c.View.Assign("title", "Go Frame 第一个网站")
|
||||
c.View.Assigns(map[string]interface{}{
|
||||
"name" : "很开心1",
|
||||
"score" : 100,
|
||||
})
|
||||
c.View.Display("index.html")
|
||||
}
|
||||
func main() {
|
||||
s := ghttp.GetServer()
|
||||
s.BindController("/", new(ControllerIndex))
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"gitee.com/johng/gf/third/github.com/fsnotify/fsnotify"
|
||||
"log"
|
||||
"gitee.com/johng/gf/g/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -13,7 +14,7 @@ func main() {
|
||||
}
|
||||
defer watch.Close()
|
||||
//添加要监控的对象,文件或文件夹
|
||||
err = watch.Add("/home/john/temp")
|
||||
err = watch.Add("D:\\Workspace\\Go\\GOPATH\\src\\gitee.com\\johng\\gf\\geg\\other\\test.go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -21,32 +22,12 @@ func main() {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case ev := <-watch.Events:
|
||||
//判断事件发生的类型,如下5种
|
||||
// Create 创建
|
||||
// Write 写入
|
||||
// Remove 删除
|
||||
// Rename 重命名
|
||||
// Chmod 修改权限
|
||||
if ev.Op&fsnotify.Create == fsnotify.Create {
|
||||
log.Println("创建文件 : ", ev.Name)
|
||||
}
|
||||
if ev.Op&fsnotify.Write == fsnotify.Write {
|
||||
log.Println("写入文件 : ", ev.Name)
|
||||
}
|
||||
if ev.Op&fsnotify.Remove == fsnotify.Remove {
|
||||
log.Println("删除文件 : ", ev.Name)
|
||||
}
|
||||
if ev.Op&fsnotify.Rename == fsnotify.Rename {
|
||||
log.Println("重命名文件 : ", ev.Name)
|
||||
}
|
||||
if ev.Op&fsnotify.Chmod == fsnotify.Chmod {
|
||||
log.Println("修改权限 : ", ev.Name)
|
||||
}
|
||||
case ev := <-watch.Events:
|
||||
glog.Println(ev)
|
||||
|
||||
case err := <-watch.Errors:
|
||||
log.Println("error : ", err)
|
||||
return
|
||||
case err := <-watch.Errors:
|
||||
log.Println("error : ", err)
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,29 +6,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// /home/john/temp 是一个目录,当然也可以指定文件
|
||||
path := "/home/john/temp"
|
||||
path := "D:\\Workspace\\Go\\GOPATH\\src\\gitee.com\\johng\\gf\\geg\\other\\test.go"
|
||||
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
if event.IsCreate() {
|
||||
glog.Println("创建文件 : ", event.Path)
|
||||
}
|
||||
if event.IsWrite() {
|
||||
glog.Println("写入文件 : ", event.Path)
|
||||
}
|
||||
if event.IsRemove() {
|
||||
glog.Println("删除文件 : ", event.Path)
|
||||
}
|
||||
if event.IsRename() {
|
||||
glog.Println("重命名文件 : ", event.Path)
|
||||
}
|
||||
if event.IsChmod() {
|
||||
glog.Println("修改权限 : ", event.Path)
|
||||
}
|
||||
glog.Println(event)
|
||||
})
|
||||
|
||||
// 移除对该path的监听
|
||||
gfsnotify.Remove(path)
|
||||
//gfsnotify.Remove(path)
|
||||
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
|
||||
19
geg/os/gfsnotify/gfsnotify_limit.go
Normal file
19
geg/os/gfsnotify/gfsnotify_limit.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/os/gfsnotify"
|
||||
"gitee.com/johng/gf/g/os/glog"
|
||||
)
|
||||
|
||||
// 对同一个文件多次Add是否超过系统inotify限制
|
||||
func main() {
|
||||
path := "/Users/john/temp/log"
|
||||
for i := 0; i < 9999999; i++ {
|
||||
_, err := gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
glog.Println(event)
|
||||
})
|
||||
if err != nil {
|
||||
glog.Fatalln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,15 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
"gitee.com/johng/gf/g/frame/gins"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for {
|
||||
stat, err := os.Stat("/home/john/temp/log")
|
||||
fmt.Println(err)
|
||||
fmt.Println(stat.Size())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
fmt.Print(gins.Config().GetFilePath())
|
||||
}
|
||||
25
geg/util/gvalid/gvalid_result.go
Normal file
25
geg/util/gvalid/gvalid_result.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gitee.com/johng/gf/g/util/gutil"
|
||||
"gitee.com/johng/gf/g/util/gvalid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type User struct {
|
||||
Name string `gvalid:"name @required|length:6,30#请输入用户名称|用户名称长度非法"`
|
||||
Pass1 string `gvalid:"password1@required|password3"`
|
||||
Pass2 string `gvalid:"password2@required|password3|same:password1#||两次密码不一致,请重新输入"`
|
||||
}
|
||||
|
||||
user := &User{
|
||||
Name : "john",
|
||||
Pass1: "Abc123!@#",
|
||||
Pass2: "123",
|
||||
}
|
||||
|
||||
err := gvalid.CheckStruct(user, nil)
|
||||
gutil.Dump(err)
|
||||
gutil.Dump(err.String())
|
||||
gutil.Dump(err.FirstString())
|
||||
}
|
||||
Reference in New Issue
Block a user