diff --git a/TODO b/TODO index ad6504006..1e81851e8 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,3 @@ -1. gconv完善针对不同类型的判断,例如:尽量减少sprintf("%v", xxx)来执行string类型的转换; -2. gdb Where方法参数的改进,研究是否可以将string参数类型修改为interfaceP{; -3. 增加对于数据表Model的封装; -4. ghttp.Server请求执行中增加服务退出的方法,不再执行后续操作; -5. ghttp.Response对象完善并改进数据返回方法(Write/WriteString); \ No newline at end of file +1. gdb Where方法参数的改进,研究是否可以将string参数类型修改为interfaceP{; +2. 增加对于数据表Model的封装; +3. ghttp.Server请求执行中增加服务退出的方法,不再执行后续操作; \ No newline at end of file diff --git a/g/encoding/gbinary/gbinary.go b/g/encoding/gbinary/gbinary.go index d3389ac5a..42013644d 100644 --- a/g/encoding/gbinary/gbinary.go +++ b/g/encoding/gbinary/gbinary.go @@ -8,33 +8,43 @@ package gbinary import ( + "fmt" + "math" "bytes" "encoding/binary" - "math" ) // 二进制位(0|1) type Bit int8 // 针对基本类型进行二进制打包,支持的基本数据类型包括:int/8/16/32/64、uint/8/16/32/64、float32/64、bool、string、[]byte -func Encode(vs ...interface{}) ([]byte, error) { +// 其他未知类型使用 fmt.Sprintf("%v", value) 转换为字符串之后处理 +func Encode(vs ...interface{}) []byte { buf := new(bytes.Buffer) for i := 0; i < len(vs); i++ { - var err error = nil - switch vs[i].(type) { - case int: buf.Write(EncodeInt(vs[i].(int))) - case uint: buf.Write(EncodeUint(vs[i].(uint))) - case bool: buf.Write(EncodeBool(vs[i].(bool))) - case string: buf.Write(EncodeString(vs[i].(string))) - case []byte: buf.Write(vs[i].([]byte)) + switch value := vs[i].(type) { + case int: buf.Write(EncodeInt(value)) + case int8: buf.Write(EncodeInt8(value)) + case int16: buf.Write(EncodeInt16(value)) + case int32: buf.Write(EncodeInt32(value)) + case int64: buf.Write(EncodeInt64(value)) + case uint: buf.Write(EncodeUint(value)) + case uint8: buf.Write(EncodeUint8(value)) + case uint16: buf.Write(EncodeUint16(value)) + case uint32: buf.Write(EncodeUint32(value)) + case uint64: buf.Write(EncodeUint64(value)) + case bool: buf.Write(EncodeBool(value)) + case string: buf.Write(EncodeString(value)) + case []byte: buf.Write(value) + case float32: buf.Write(EncodeFloat32(value)) + case float64: buf.Write(EncodeFloat64(value)) default: - err = binary.Write(buf, binary.LittleEndian, vs[i]) - } - if err != nil { - return nil, err + if err := binary.Write(buf, binary.LittleEndian, value); err != nil { + buf.Write(EncodeString(fmt.Sprintf("%v", value))) + } } } - return buf.Bytes(), nil + return buf.Bytes() } // 整形二进制解包,注意第二个及其后参数为字长确定的整形变量的指针地址,以便确定解析的[]byte长度, diff --git a/g/net/ghttp/http_request.go b/g/net/ghttp/http_request.go index f09812c93..dfb4da72a 100644 --- a/g/net/ghttp/http_request.go +++ b/g/net/ghttp/http_request.go @@ -29,7 +29,7 @@ type Request struct { // 创建一个Request对象 func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request { - return &Request{ + request := &Request{ parsedGet : gtype.NewBool(), parsedPost : gtype.NewBool(), values : make(map[string][]string), @@ -40,6 +40,10 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request { ResponseWriter : w, }, } + // 会话处理 + request.Cookie = GetCookie(request) + request.Session = GetSession(request) + return request } diff --git a/g/net/ghttp/http_response.go b/g/net/ghttp/http_response.go index 5b4c61fdc..d3046a273 100644 --- a/g/net/ghttp/http_response.go +++ b/g/net/ghttp/http_response.go @@ -10,6 +10,8 @@ package ghttp import ( "sync" "net/http" + "gitee.com/johng/gf/g/util/gconv" + "gitee.com/johng/gf/g/encoding/gparser" ) // 服务端请求返回对象 @@ -19,39 +21,52 @@ type Response struct { buffer []byte // 每个请求的返回数据缓冲区 } -// 返回的固定JSON数据结构 -//type ResponseJson struct { -// Result int `json:"result"` // 标识消息状态 -// Message string `json:"message"` // 消息使用string存储 -// Data []byte `json:"data"` // 二进制数据(不管什么数据结构) -//} - -// 返回信息(byte) -func (r *Response) Write(content []byte) { +// 返回信息,任何变量自动转换为bytes +func (r *Response) Write(content interface{}) { r.bufmu.Lock() - defer r.bufmu.Unlock() - r.buffer = append(r.buffer, content...) + r.buffer = append(r.buffer, gconv.Bytes(content)...) + r.bufmu.Unlock() } -// 返回信息(string) -func (r *Response) WriteString(content string) { - r.bufmu.Lock() - defer r.bufmu.Unlock() - r.buffer = append(r.buffer, content...) +// 返回JSON +func (r *Response) WriteJson(content interface{}) error { + if b, err := gparser.VarToJson(content); err != nil { + return err + } else { + r.Header().Set("Content-Type", "application/json") + r.Write(b) + } + return nil } -// 返回固定格式的json -//func (r *Response) WriteJson(result int, message string, data []byte) error { -// r.Header().Set("Content-Type", "application/json") -// r.bufmu.Lock() -// defer r.bufmu.Unlock() -// if jsonstr, err := gjson.Encode(ResponseJson{ result, message, data }); err != nil { -// return err -// } else { -// r.buffer = append(r.buffer, jsonstr...) -// } -// return nil -//} +// 返回XML +func (r *Response) WriteXml(content interface{}, rootTag...string) error { + if b, err := gparser.VarToXml(content, rootTag...); err != nil { + return err + } else { + r.Header().Set("Content-Type", "application/xml") + r.Write(b) + } + return nil +} + +// 返回HTTP Code状态码 +func (r *Response) WriteStatus(code int, content...string) { + r.Header().Set("Content-Type", "text/plain; charset=utf-8") + r.Header().Set("X-Content-Type-Options", "nosniff") + if len(content) > 0 { + r.Write(content[0]) + } else { + r.Write(http.StatusText(code)) + } + r.WriteHeader(code) +} + +// 返回location标识,引导客户端跳转 +func (r *Response) RedirectTo(location string) { + r.Header().Set("Location", location) + r.WriteHeader(http.StatusFound) +} // 获取当前缓冲区中的数据 func (r *Response) Buffer() []byte { @@ -60,19 +75,26 @@ func (r *Response) Buffer() []byte { return r.buffer } +// 手动设置缓冲区内容 +func (r *Response) SetBuffer(buffer []byte) { + r.bufmu.Lock() + r.buffer = buffer + r.bufmu.Unlock() +} + // 清空缓冲区内容 func (r *Response) ClearBuffer() { r.bufmu.Lock() - defer r.bufmu.Unlock() r.buffer = make([]byte, 0) + r.bufmu.Unlock() } // 输出缓冲区数据到客户端 func (r *Response) OutputBuffer() { r.bufmu.Lock() - defer r.bufmu.Unlock() if len(r.buffer) > 0 { r.ResponseWriter.Write(r.buffer) r.buffer = make([]byte, 0) } + r.bufmu.Unlock() } diff --git a/g/net/ghttp/http_server_handler.go b/g/net/ghttp/http_server_handler.go index e156f01fb..0dcbc4fc7 100644 --- a/g/net/ghttp/http_server_handler.go +++ b/g/net/ghttp/http_server_handler.go @@ -30,22 +30,33 @@ func (s *Server)defaultHttpHandle(w http.ResponseWriter, r *http.Request) { // 其次,如果没有对应的自定义处理接口配置,那么走默认的域名处理接口配置; // 最后,如果以上都没有找到处理接口,那么进行文件处理; func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) { + // 创建请求处理对象 request := newRequest(s, r, w) + // 事件 - BeforeServe + s.callHookHandler(request, "BeforeServe") if h := s.getHandler(request); h != nil { s.callHandler(h, request) } else { - s.serveFile(w, r) + s.serveFile(request) } + // 事件 - AfterServe + s.callHookHandler(request, "AfterServe") + // 事件 - BeforeOutput + s.callHookHandler(request, "BeforeOutput") + // 输出Cookie + request.Cookie.Output() + // 输出缓冲区 + request.Response.OutputBuffer() + // 事件 - AfterOutput + s.callHookHandler(request, "AfterOutput") + // 将Request对象指针丢到队列中异步处理 + s.closeQueue.PushBack(request) } // 初始化控制器 func (s *Server)callHandler(h *HandlerItem, r *Request) { - // 会话处理 - r.Cookie = GetCookie(r) - r.Session = GetSession(r) - // 请求处理 - s.callHookHandler(r, "BeforeServe") + if h.faddr == nil { // 新建一个控制器对象处理请求 c := reflect.New(h.ctype) @@ -55,23 +66,11 @@ func (s *Server)callHandler(h *HandlerItem, r *Request) { } else { h.faddr(r) } - s.callHookHandler(r, "AfterServe") - s.callHookHandler(r, "BeforeOutput") - - // 输出Cookie - r.Cookie.Output() - // 输出缓冲区 - r.Response.OutputBuffer() - - s.callHookHandler(r, "AfterOutput") - - // 将Request对象指针丢到队列中异步处理 - s.closeQueue.PushBack(r) } // 处理静态文件请求 -func (s *Server)serveFile(w http.ResponseWriter, r *http.Request) { +func (s *Server)serveFile(r *Request) { uri := r.URL.String() if s.config.ServerRoot != "" { // 获取文件的绝对路径 @@ -79,17 +78,17 @@ func (s *Server)serveFile(w http.ResponseWriter, r *http.Request) { path = path + uri path = gfile.RealPath(path) if path != "" { - s.doServeFile(w, r, path) + s.doServeFile(r, path) } else { - s.NotFound(w, r) + r.Response.WriteStatus(http.StatusNotFound) } } else { - s.NotFound(w, r) + r.Response.WriteStatus(http.StatusNotFound) } } // http server静态文件处理 -func (s *Server)doServeFile(w http.ResponseWriter, r *http.Request, path string) { +func (s *Server)doServeFile(r *Request, path string) { f, err := os.Open(path) if err != nil { return @@ -101,53 +100,41 @@ func (s *Server)doServeFile(w http.ResponseWriter, r *http.Request, path string) fpath := path + "/" + file if gfile.Exists(fpath) { f.Close() - s.doServeFile(w, r, fpath) + s.doServeFile(r, fpath) return } } } if s.config.IndexFolder { - s.listDir(w, f) + s.listDir(r, f) } else { - s.ResponseStatus(w, http.StatusForbidden) + r.Response.WriteStatus(http.StatusForbidden) } } else { - http.ServeContent(w, r, info.Name(), info.ModTime(), f) + // 读取文件内容返回 + http.ServeContent(r.Response.ResponseWriter, &r.Request, info.Name(), info.ModTime(), f) } f.Close() } // 目录列表 -func (s *Server)listDir(w http.ResponseWriter, f http.File) { +func (s *Server)listDir(r *Request, f http.File) { dirs, err := f.Readdir(-1) if err != nil { - http.Error(w, "Error reading directory", http.StatusInternalServerError) + r.Response.WriteStatus(http.StatusInternalServerError, "Error reading directory") return } sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() }) - w.Header().Set("Content-Type", "text/html; charset=utf-8") - fmt.Fprintf(w, "
\n")
+ r.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
+ r.Response.Write("\n")
for _, d := range dirs {
name := d.Name()
if d.IsDir() {
name += "/"
}
u := url.URL{Path: name}
- fmt.Fprintf(w, "%s\n", u.String(), ghtml.SpecialChars(name))
+ r.Response.Write(fmt.Sprintf("%s\n", u.String(), ghtml.SpecialChars(name)))
}
- fmt.Fprintf(w, "\n")
+ r.Response.Write("\n")
}
-
-// 返回http状态码,并使用默认配置的字符串返回信息
-func (s *Server)ResponseStatus(w http.ResponseWriter, code int) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.Header().Set("X-Content-Type-Options", "nosniff")
- w.WriteHeader(code)
- w.Write([]byte(http.StatusText(code)))
-}
-
-// 404
-func (s *Server)NotFound(w http.ResponseWriter, r *http.Request) {
- http.NotFound(w, r)
-}
\ No newline at end of file
diff --git a/g/util/gconv/gconv.go b/g/util/gconv/gconv.go
index bfa110122..e181127a0 100644
--- a/g/util/gconv/gconv.go
+++ b/g/util/gconv/gconv.go
@@ -5,13 +5,12 @@
// You can obtain one at https://gitee.com/johng/gf.
// 类型转换.
-// 如果给定的interface{}参数不是指定转换的输出类型,那么会进行强制转换,效率会比较低,
-// 建议已知类型的转换自行调用相关方法来单独处理。
+// 内部使用了bytes作为底层转换类型,效率很高。
package gconv
import (
"fmt"
- "strconv"
+ "gitee.com/johng/gf/g/encoding/gbinary"
)
func Bytes(i interface{}) []byte {
@@ -21,10 +20,11 @@ func Bytes(i interface{}) []byte {
if r, ok := i.([]byte); ok {
return r
} else {
- return []byte(String(i))
+ return gbinary.Encode(i)
}
}
+// 基础的字符串类型转换
func String(i interface{}) string {
if i == nil {
return ""
@@ -32,7 +32,7 @@ func String(i interface{}) string {
if r, ok := i.(string); ok {
return r
} else {
- return fmt.Sprintf("%v", i)
+ return string(Bytes(i))
}
}
@@ -73,19 +73,97 @@ func Int(i interface{}) int {
if v, ok := i.(int); ok {
return v
}
- v, _ := strconv.Atoi(String(i))
- return v
+ return gbinary.DecodeToInt(Bytes(i))
}
-func Uint (i interface{}) uint {
+func Int8(i interface{}) int8 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(int8); ok {
+ return v
+ }
+ return gbinary.DecodeToInt8(Bytes(i))
+}
+
+func Int16(i interface{}) int16 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(int16); ok {
+ return v
+ }
+ return gbinary.DecodeToInt16(Bytes(i))
+}
+
+func Int32(i interface{}) int32 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(int32); ok {
+ return v
+ }
+ return gbinary.DecodeToInt32(Bytes(i))
+}
+
+func Int64(i interface{}) int64 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(int64); ok {
+ return v
+ }
+ return gbinary.DecodeToInt64(Bytes(i))
+}
+
+func Uint(i interface{}) uint {
if i == nil {
return 0
}
if v, ok := i.(uint); ok {
return v
}
- v, _ := strconv.ParseUint(String(i), 10, 8)
- return uint(v)
+ return gbinary.DecodeToUint(Bytes(i))
+}
+
+func Uint8(i interface{}) uint8 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(uint8); ok {
+ return v
+ }
+ return gbinary.DecodeToUint8(Bytes(i))
+}
+
+func Uint16(i interface{}) uint16 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(uint16); ok {
+ return v
+ }
+ return gbinary.DecodeToUint16(Bytes(i))
+}
+
+func Uint32(i interface{}) uint32 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(uint32); ok {
+ return v
+ }
+ return gbinary.DecodeToUint32(Bytes(i))
+}
+
+func Uint64(i interface{}) uint64 {
+ if i == nil {
+ return 0
+ }
+ if v, ok := i.(uint64); ok {
+ return v
+ }
+ return gbinary.DecodeToUint64(Bytes(i))
}
func Float32 (i interface{}) float32 {
@@ -95,8 +173,7 @@ func Float32 (i interface{}) float32 {
if v, ok := i.(float32); ok {
return v
}
- v, _ := strconv.ParseFloat(String(i), 8)
- return float32(v)
+ return gbinary.DecodeToFloat32(Bytes(i))
}
func Float64 (i interface{}) float64 {
@@ -106,6 +183,5 @@ func Float64 (i interface{}) float64 {
if v, ok := i.(float64); ok {
return v
}
- v, _ := strconv.ParseFloat(String(i), 8)
- return v
+ return gbinary.DecodeToFloat64(Bytes(i))
}
diff --git a/geg/net/ghttp/hello.go b/geg/net/ghttp/hello.go
index 5cb869e97..fc77cffbd 100644
--- a/geg/net/ghttp/hello.go
+++ b/geg/net/ghttp/hello.go
@@ -1,24 +1,28 @@
package main
-import "gitee.com/johng/gf/g/net/ghttp"
+import (
+ "gitee.com/johng/gf/g/net/ghttp"
+)
func main() {
ghttp.GetServer().BindHandler("get:/h", func(r *ghttp.Request) {
- r.Response.WriteString("hello world")
+ //r.Response.RedirectTo("http://www.baidu.com/")
+ r.Response.Write("hello world")
+ //r.Response.WriteStatus(302)
})
ghttp.GetServer().BindHandler("/:name/*any", func(r *ghttp.Request) {
- r.Response.WriteString("any")
- r.Response.WriteString(r.GetQueryString("name"))
- r.Response.WriteString(r.GetQueryString("any"))
+ r.Response.Write("any")
+ r.Response.Write(r.GetQueryString("name"))
+ r.Response.Write(r.GetQueryString("any"))
})
//ghttp.GetServer().BindHandler("/:name/action", func(r *ghttp.Request) {
// r.Response.WriteString(r.GetQueryString("name"))
//})
ghttp.GetServer().BindHandler("/:name/:action/:aaa", func(r *ghttp.Request) {
- r.Response.WriteString("name")
- r.Response.WriteString(r.GetQueryString("name"))
- r.Response.WriteString(r.GetQueryString("action"))
+ r.Response.Write("name")
+ r.Response.Write(r.GetQueryString("name"))
+ r.Response.Write(r.GetQueryString("action"))
})
ghttp.GetServer().SetPort(10000)
ghttp.GetServer().Run()
diff --git a/geg/other/test.go b/geg/other/test.go
index b3c16412b..233ca467f 100644
--- a/geg/other/test.go
+++ b/geg/other/test.go
@@ -4,6 +4,14 @@ import (
"fmt"
)
+type T struct{
+ name string
+}
func main() {
- fmt.Println(make(map[string]interface{}) == nil)
+ var i interface{} = T{"john"}
+ switch v := i.(type) {
+ case T:
+ default:
+ fmt.Println(v)
+ }
}
\ No newline at end of file