add resource feature support for gview

This commit is contained in:
John
2019-08-16 00:29:14 +08:00
parent 9162fde14a
commit ab381dacfe
25 changed files with 252 additions and 101 deletions

View File

@ -1,18 +1,26 @@
package main
import (
_ "github.com/gogf/gf/.example/net/ghttp/server/resource/testdata"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/os/gres"
_ "github.com/gogf/gf/os/gres/testdata"
)
func main() {
gres.Dump()
v := g.View()
v.SetResource(gres.Default())
v.SetPath("/template/layout1")
s := g.Server()
s.SetIndexFolder(true)
s.SetResource(gres.Default())
s.SetServerRoot("/root")
s.BindHandler("/template", func(r *ghttp.Request) {
r.Response.WriteTpl("layout.html")
})
s.SetPort(8199)
s.Run()
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
package main
import (
"fmt"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/os/gres"
_ "github.com/gogf/gf/os/gres/testdata"
)
func main() {
gres.Dump()
v := g.View()
v.SetResource(gres.Default())
v.SetPath("/template/layout1")
s, err := v.Parse("layout.html")
fmt.Println(err)
fmt.Println(s)
}

View File

@ -0,0 +1,22 @@
package main
import (
"fmt"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/os/gres"
_ "github.com/gogf/gf/os/gres/testdata"
)
func main() {
gres.Dump()
v := g.View()
v.SetResource(gres.Default())
v.SetPath("/template/layout2")
s, err := v.Parse("layout.html", g.Map{
"mainTpl": "main/main1.html",
})
fmt.Println(err)
fmt.Println(s)
}

View File

@ -36,12 +36,12 @@ func (r *Response) WriteTplContent(content string, params ...gview.Params) error
// 解析模板文件,并返回模板内容
func (r *Response) ParseTpl(tpl string, params ...gview.Params) (string, error) {
return gins.View().Parse(tpl, r.buildInVars(params...))
return r.Server.config.View.Parse(tpl, r.buildInVars(params...))
}
// 解析并返回模板内容
func (r *Response) ParseTplContent(content string, params ...gview.Params) (string, error) {
return gins.View().ParseContent(content, r.buildInVars(params...))
return r.Server.config.View.ParseContent(content, r.buildInVars(params...))
}
// 内置变量/对象

View File

@ -13,6 +13,8 @@ import (
"strconv"
"time"
"github.com/gogf/gf/os/gview"
"github.com/gogf/gf/os/gres"
"github.com/gogf/gf/os/gfile"
@ -50,6 +52,7 @@ type ServerConfig struct {
TLSConfig tls.Config // HTTPS证书配置
KeepAlive bool // 是否开启长连接
ServerAgent string // Server Agent
View *gview.View // 模板引擎对象
Resource *gres.Resource // 资源文件对象
Rewrites map[string]string // URI Rewrite重写配置
IndexFiles []string // Static: 默认访问的文件列表
@ -87,6 +90,7 @@ var defaultServerConfig = ServerConfig{
IdleTimeout: 60 * time.Second,
MaxHeaderBytes: 1024,
KeepAlive: true,
View: gview.Instance(),
IndexFiles: []string{"index.html", "index.htm"},
IndexFolder: false,
ServerAgent: "gf http server",
@ -311,6 +315,15 @@ func (s *Server) SetKeepAlive(enabled bool) {
s.config.KeepAlive = enabled
}
// 设置模板引擎对象
func (s *Server) SetView(view *gview.View) {
if s.Status() == SERVER_STATUS_RUNNING {
glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR)
return
}
s.config.View = view
}
// 获取WebServer名称
func (s *Server) GetName() string {
return s.name

View File

@ -57,6 +57,11 @@ func GetWithIndex(path string, indexFiles []string) *File {
return defaultResource.GetWithIndex(path, indexFiles)
}
// GetContent directly returns the content of <path> in default resource object.
func GetContent(path string) []byte {
return defaultResource.GetContent(path)
}
// Contains checks whether the <path> exists in the default resource object.
func Contains(path string) bool {
return defaultResource.Contains(path)

View File

@ -32,17 +32,17 @@ func (f *File) Open() (io.ReadCloser, error) {
}
// Content returns the content of the file.
func (f *File) Content() ([]byte, error) {
func (f *File) Content() []byte {
reader, err := f.Open()
if err != nil {
return nil, err
return nil
}
defer reader.Close()
buffer := bytes.NewBuffer(nil)
if _, err := io.Copy(buffer, reader); err != nil {
return nil, err
return nil
}
return buffer.Bytes(), nil
return buffer.Bytes()
}
// FileInfo returns an os.FileInfo for the FileHeader.

View File

@ -57,11 +57,7 @@ func (f *File) Seek(offset int64, whence int) (int64, error) {
func (f *File) getReader() (*bytes.Reader, error) {
if f.reader == nil {
content, err := f.Content()
if err != nil {
return nil, err
}
f.reader = bytes.NewReader(content)
f.reader = bytes.NewReader(f.Content())
}
return f.reader, nil
}

View File

@ -76,11 +76,6 @@ func (r *Resource) Get(path string) *File {
return nil
}
// Contains checks whether the <path> exists in current resource object.
func (r *Resource) Contains(path string) bool {
return r.Get(path) != nil
}
// GetWithIndex searches file with <path>, if the file is directory
// it then does index files searching under this directory.
//
@ -105,6 +100,20 @@ func (r *Resource) GetWithIndex(path string, indexFiles []string) *File {
return nil
}
// GetContent directly returns the content of <path>.
func (r *Resource) GetContent(path string) []byte {
file := r.Get(path)
if file != nil {
return file.Content()
}
return nil
}
// Contains checks whether the <path> exists in current resource object.
func (r *Resource) Contains(path string) bool {
return r.Get(path) != nil
}
// Scan returns the files under the given path, the parameter <path> should be a folder type.
//
// The pattern parameter <pattern> supports multiple file name patterns,

View File

@ -0,0 +1,3 @@
{{define "container"}}
<h1>CONTAINER</h1>
{{end}}

View File

@ -0,0 +1,3 @@
{{define "footer"}}
<h1>FOOTER</h1>
{{end}}

View File

@ -0,0 +1,3 @@
{{define "header"}}
<h1>HEADER</h1>
{{end}}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>GoFrame Layout</title>
{{template "header"}}
</head>
<body>
<div class="container">
{{template "container"}}
</div>
<div class="footer">
{{template "footer"}}
</div>
</body>
</html>

View File

@ -0,0 +1 @@
<h1>FOOTER</h1>

View File

@ -0,0 +1 @@
<h1>HEADER</h1>

View File

@ -0,0 +1,3 @@
{{include "header.html" .}}
{{include .mainTpl .}}
{{include "footer.html" .}}

View File

@ -0,0 +1 @@
<h1>MAIN1</h1>

View File

@ -0,0 +1 @@
<h1>MAIN2</h1>

File diff suppressed because one or more lines are too long

View File

@ -60,6 +60,9 @@ func New(path string, cache bool) *SPath {
// 创建/获取一个单例的搜索对象, root必须为目录的绝对路径
func Get(root string, cache bool) *SPath {
if root == "" {
root = "/"
}
return pathsMap.GetOrSetFuncLock(root, func() interface{} {
return New(root, cache)
}).(*SPath)

View File

@ -8,11 +8,12 @@
package gview
import (
"bytes"
"errors"
"fmt"
"sync"
"github.com/gogf/gf/os/gres"
"github.com/gogf/gf"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/internal/cmdenv"
@ -27,6 +28,7 @@ type View struct {
paths *garray.StringArray // Searching path array.
data map[string]interface{} // Global template variables.
funcMap map[string]interface{} // Global template function map.
resource *gres.Resource // Resource management object.
delimiters []string // Customized template delimiters.
}
@ -120,43 +122,51 @@ func New(path ...string) *View {
return view
}
// SetResource sets the resource management object for current view.
func (view *View) SetResource(resource *gres.Resource) {
view.resource = resource
view.paths.Clear()
view.paths.Append("/")
}
// SetPath sets the template directory path for template file search.
// The parameter <path> can be absolute or relative path, but absolute path is suggested.
func (view *View) SetPath(path string) error {
// Absolute path.
realPath := gfile.RealPath(path)
if realPath == "" {
// Relative path.
view.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
isDir := false
realPath := ""
if view.resource != nil {
if file := view.resource.Get(path); file != nil {
realPath = path
isDir = file.FileInfo().IsDir()
}
} else {
// Absolute path.
realPath = gfile.RealPath(path)
if realPath == "" {
// Relative path.
view.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
}
}
}
})
})
}
if realPath != "" {
isDir = gfile.IsDir(realPath)
}
}
// Path not exist.
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if view.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gview] SetPath failed: cannot find directory \"%s\" in following paths:", path))
view.paths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
}
})
} else {
buffer.WriteString(fmt.Sprintf(`[gview] SetPath failed: path "%s" does not exist`, path))
}
err := errors.New(buffer.String())
err := errors.New(fmt.Sprintf(`[gview] SetPath failed: path "%s" does not exist`, path))
if errorPrint() {
glog.Error(err)
}
return err
}
// Should be a directory.
if !gfile.IsDir(realPath) {
if !isDir {
err := errors.New(fmt.Sprintf(`[gview] SetPath failed: path "%s" should be directory type`, path))
if errorPrint() {
glog.Error(err)
@ -175,40 +185,41 @@ func (view *View) SetPath(path string) error {
// AddPath adds a absolute or relative path to the search paths.
func (view *View) AddPath(path string) error {
// Absolute path.
realPath := gfile.RealPath(path)
if realPath == "" {
// Relative path.
view.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
isDir := false
realPath := ""
if view.resource != nil {
if file := view.resource.Get(path); file != nil {
realPath = path
isDir = file.FileInfo().IsDir()
}
} else {
// Absolute path.
realPath = gfile.RealPath(path)
if realPath == "" {
// Relative path.
view.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ := gspath.Search(v, path); path != "" {
realPath = path
break
}
}
}
})
})
}
if realPath != "" {
isDir = gfile.IsDir(realPath)
}
}
// Path not exist.
if realPath == "" {
buffer := bytes.NewBuffer(nil)
if view.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gview] AddPath failed: cannot find directory \"%s\" in following paths:", path))
view.paths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
}
})
} else {
buffer.WriteString(fmt.Sprintf(`[gview] AddPath failed: path "%s" does not exist`, path))
}
err := errors.New(buffer.String())
err := errors.New(fmt.Sprintf(`[gview] AddPath failed: path "%s" does not exist`, path))
if errorPrint() {
glog.Error(err)
}
return err
}
// realPath should be type of folder.
if !gfile.IsDir(realPath) {
if !isDir {
err := errors.New(fmt.Sprintf(`[gview] AddPath failed: path "%s" should be directory type`, path))
if errorPrint() {
glog.Error(err)

View File

@ -79,6 +79,7 @@ func (view *View) funcInclude(file string, data ...map[string]interface{}) strin
if len(data) > 0 {
m = data[0]
}
// It will search the file internally.
content, err := view.Parse(file, m)
if err != nil {
return err.Error()

View File

@ -10,11 +10,15 @@ import (
"bytes"
"errors"
"fmt"
"strings"
"text/template"
"github.com/gogf/gf/os/gfcache"
"github.com/gogf/gf/os/gres"
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/encoding/ghash"
"github.com/gogf/gf/os/gfcache"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/os/gfsnotify"
"github.com/gogf/gf/os/glog"
@ -41,12 +45,27 @@ var (
// if the template files under <path> changes (recursively).
func (view *View) getTemplate(path string, pattern string) (tpl *template.Template, err error) {
r := templates.GetOrSetFuncLock(path, func() interface{} {
files := ([]string)(nil)
files, err = gfile.ScanDir(path, pattern, true)
tpl = template.New(path).Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
if view.resource != nil {
tempFiles := view.resource.Scan(path, pattern, true)
if len(tempFiles) > 0 {
var err error
for _, v := range tempFiles {
if v.FileInfo().IsDir() {
continue
}
_, err = tpl.New(v.FileInfo().Name()).Parse(string(v.Content()))
if err != nil {
glog.Error(err)
}
}
return tpl
}
}
files, err := gfile.ScanDir(path, pattern, true)
if err != nil {
return nil
}
tpl = template.New(path).Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
if tpl, err = tpl.ParseFiles(files...); err != nil {
return nil
}
@ -64,18 +83,40 @@ func (view *View) getTemplate(path string, pattern string) (tpl *template.Templa
// searchFile returns the found absolute path for <file>, and its template folder path.
func (view *View) searchFile(file string) (path string, folder string, err error) {
view.paths.RLockFunc(func(array []string) {
for _, v := range array {
if path, _ = gspath.Search(v, file); path != "" {
folder = v
break
separator := gfile.Separator
if view.resource != nil {
separator = "/"
view.paths.RLockFunc(func(array []string) {
f := (*gres.File)(nil)
for _, v := range array {
v = strings.TrimRight(v, separator)
if f = view.resource.Get(v + separator + file); f != nil {
path = f.Name()
folder = gfile.Dir(path)
break
}
if f = view.resource.Get(v + separator + "template" + separator + file); f != nil {
path = f.Name()
folder = gfile.Dir(path)
break
}
}
if path, _ = gspath.Search(v+gfile.Separator+"template", file); path != "" {
folder = v + gfile.Separator + "template"
break
})
} else {
view.paths.RLockFunc(func(array []string) {
for _, v := range array {
v = strings.TrimRight(v, separator)
if path, _ = gspath.Search(v, file); path != "" {
folder = v
break
}
if path, _ = gspath.Search(v+separator+"template", file); path != "" {
folder = v + separator + "template"
break
}
}
}
})
})
}
if path == "" {
buffer := bytes.NewBuffer(nil)
if view.paths.Len() > 0 {
@ -83,9 +124,13 @@ func (view *View) searchFile(file string) (path string, folder string, err error
view.paths.RLockFunc(func(array []string) {
index := 1
for _, v := range array {
v = strings.TrimRight(v, "/")
if v == "" {
v = "/"
}
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v))
index++
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v+gfile.Separator+"template"))
buffer.WriteString(fmt.Sprintf("\n%d. %s", index, strings.TrimRight(v, "/")+separator+"template"))
index++
}
})
@ -116,7 +161,12 @@ func (view *View) Parse(file string, params ...Params) (parsed string, err error
}
// Using memory lock to ensure concurrent safety for template parsing.
gmlock.LockFunc("gview-parsing:"+folder, func() {
tpl, err = tpl.Parse(gfcache.GetContents(path))
if view.resource != nil {
tpl, err = tpl.Parse(string(view.resource.GetContent(path)))
} else {
tpl, err = tpl.Parse(gfcache.GetContents(path))
}
})
if err != nil {
return "", err