代码拉取完成,页面将自动刷新
package httplibs
import (
"embed"
"gitee.com/captials-team/ubdframe/src/common"
"gitee.com/captials-team/ubdframe/src/common/utils"
v1log "gitee.com/captials-team/ubdframe/src/pkg/logs"
"github.com/gin-contrib/multitemplate"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/render"
"html/template"
"net/http"
"path/filepath"
"strings"
)
// DefaultViewHandlerConfig 默认配置
var DefaultViewHandlerConfig = ViewHandlerConfig{
ParamName: "name",
}
// ViewHandlerConfig viewHandler配置
type ViewHandlerConfig struct {
ViewFs embed.FS //模板渲染的viewFs
ViewDir string //模板渲染所在目录
FuncMaps []template.FuncMap //模板文件迁入的函数map
ParamName string //获取view渲染模板名称的参数名(如name)
ParamFunc func(r *http.Request) string //定制化获取view渲染模板名称的方法(不存在则默认方式获取)
OptionLayoutFlag string //布局文件前缀标志
}
// ViewHandler viewHandler
type ViewHandler struct {
ViewHandlerConfig
htmlRender render.HTMLRender
v1log.InvokeLog
}
func NewViewHandler(cnf ViewHandlerConfig) *ViewHandler {
h := &ViewHandler{
ViewHandlerConfig: cnf,
}
return h
}
func (h *ViewHandler) init() {
if h.ParamName == "" {
h.ParamName = "name"
}
if h.ViewDir != "" {
h.htmlRender = h.loadRenderFromDir(h.ViewDir, h.FuncMaps...)
} else {
h.htmlRender = h.loadRenderFromFs(h.ViewFs, h.FuncMaps...)
}
}
// InitiateRender 初始化渲染器
func (h *ViewHandler) InitiateRender() {
h.init()
}
func (h *ViewHandler) Render() render.HTMLRender {
return h.htmlRender
}
func (h *ViewHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var name string
if h.ParamFunc != nil {
name = h.ParamFunc(r)
} else {
name = r.Form.Get(h.ParamName)
}
instance := h.htmlRender.Instance(h.templateName(name), map[string]interface{}{
"Request": r,
})
if err := instance.Render(w); err != nil {
panic(err)
}
}
// GinRouter 推荐的ginRouter配置
func (h *ViewHandler) GinRouter(r *gin.Engine, prefix string) {
prefix = utils.KeepHasPrefix(prefix, "/")
r.GET(prefix, h.ViewForGin)
r.GET(prefix+"/:name", h.ViewForGin)
}
func (h *ViewHandler) GinRouterJump(r *gin.Engine, prefix string) {
h.GinRouter(r, prefix)
r.NoRoute(func(ctx *gin.Context) {
ctx.Redirect(http.StatusMovedPermanently, prefix)
})
}
func (h *ViewHandler) ViewForGin(ctx *gin.Context) {
var name string
defer func() {
if err := recover(); err != nil {
h.Error("view err %s", err)
if h.templateName(name) != "index.html" {
h.renderForGin(ctx, "index")
return
}
ctx.String(http.StatusNotFound, "")
return
}
}()
if h.ParamFunc != nil {
name = h.ParamFunc(ctx.Request)
} else {
name = ctx.Params.ByName(h.ParamName)
}
//h.Info("ViewForGin %s", name)
h.renderForGin(ctx, name)
}
func (h *ViewHandler) renderForGin(ctx *gin.Context, name string) {
ctx.Render(http.StatusOK, h.htmlRender.Instance(h.templateName(name), gin.H{
"Ctx": ctx,
"Request": ctx.Request,
}))
}
func (h *ViewHandler) templateName(name string) string {
if name == "" {
name = "index.html"
}
if !strings.HasSuffix(name, ".html") {
name = name + ".html"
}
return name
}
// loadRenderFromFs 使用FS做template
func (h *ViewHandler) loadRenderFromFs(embFs embed.FS, funcs ...template.FuncMap) multitemplate.Renderer {
r := multitemplate.NewRenderer()
templates := [][2]string{}
layouts := []string{}
layoutPrefix := h.LayoutFilePrefix()
//扫描分为模板文件和布局文件(l_开头的为布局文件)
err := utils.ScanEmbedFsDo(embFs, func(file string, path string) error {
if strings.HasPrefix(file, layoutPrefix) {
layouts = append(layouts, path)
//logger.Info("content:%s", bt)
} else {
layouts = append(layouts, path)
templates = append(templates, [2]string{file, path})
}
return nil
})
common.ErrPanic(err)
if err != nil {
h.Error("scan embed err: %s", err)
return r
}
//h.Info("templates %+v", templates)
for _, f := range templates {
file := f[0]
path := f[1]
tpl := template.New(file)
for _, v := range funcs {
tpl = tpl.Funcs(v)
}
tmpl := template.Must(tpl.ParseFS(embFs, append(layouts, path)...))
r.Add(file, tmpl)
//debug
//if file == "index.html" {
// tmpl.ExecuteTemplate(os.Stdout, file, map[string]string{
// "action": "xxx",
// })
//}
//h.Info("%s", path)
//h.Info("templateAdd %s,%+v,%s", file, layouts, path)
}
return r
}
// loadRenderFromDir 使用目录做template
func (h *ViewHandler) loadRenderFromDir(dir string, funcs ...template.FuncMap) multitemplate.Renderer {
r := multitemplate.NewRenderer()
templates := [][2]string{}
layouts := []string{}
layoutPrefix := h.LayoutFilePrefix()
//扫描分为模板文件和布局文件(l_开头的为布局文件)
err := utils.ScanDirFileDo(dir, func(file string, path string) error {
if strings.HasPrefix(file, layoutPrefix) {
layouts = append(layouts, path)
//logger.Info("content:%s", bt)
} else {
layouts = append(layouts, path)
templates = append(templates, [2]string{file, path})
}
return nil
})
common.ErrPanic(err)
if err != nil {
h.Error("scan dir files err: %s", err)
return r
}
//h.Info("templates %+v", templates)
for _, f := range templates {
file := f[0]
path := f[1]
tpl := template.New(file)
for _, v := range funcs {
tpl = tpl.Funcs(v)
}
tmpl := template.Must(tpl.ParseFiles(append(layouts, path)...))
r.Add(file, tmpl)
//debug
//if file == "index.html" {
// tmpl.ExecuteTemplate(os.Stdout, file, map[string]string{
// "action": "xxx",
// })
//}
//h.Info("%s", path)
//h.Info("templateAdd %s,%+v,%s", file, layouts, path)
}
return r
}
// LayoutFilePrefix 布局文件前缀
func (h *ViewHandler) LayoutFilePrefix() string {
if len(h.OptionLayoutFlag) > 0 {
return h.OptionLayoutFlag
}
return "l_"
}
// loadTemplates 直接使用目录
func (h *ViewHandler) loadTemplates(templatesDir string) multitemplate.Renderer {
r := multitemplate.NewRenderer()
layouts, err := filepath.Glob(templatesDir + "/layouts/*.html")
if err != nil {
panic(err.Error())
}
includes, err := filepath.Glob(templatesDir + "/includes/*.html")
if err != nil {
panic(err.Error())
}
// Generate our templates map from our layouts/ and includes/ directories
for _, include := range includes {
layoutCopy := make([]string, len(layouts))
copy(layoutCopy, layouts)
files := append(layoutCopy, include)
r.AddFromFiles(filepath.Base(include), files...)
}
return r
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。