直接上我的一个web播放器的样例代码片段
主要是 LoadTemplate 方法
然后打包的时候需要用packr2工具:
#安装编译工具,用于打包html到二进制 go get -u github.com/gobuffalo/packr/v2/packr2 #build和go build一样,交叉编译的方式也是一样的 CGO_ENABLED=0 GOOS=linux GOARCH=arm packr2 build -o 115_player #简单点的 packr2 build -o 115_player
代码片段:
package web import ( "crypto/md5" "encoding/hex" "fmt" "github.com/gin-gonic/gin" "github.com/gobuffalo/packr/v2" "github.com/google/uuid" log "github.com/sirupsen/logrus" "html/template" "net" "net/http" "os" "runtime" "strings" "time" ) var MainConsole = make(chan os.Signal, 1) type webServer struct { Engine *gin.Engine } type Conf struct { User string Password string } var Webserver = &webServer{} type MSG map[string]interface{} func OK(data interface{}) MSG { return MSG{"data": data, "code": 0, "msg": "ok"} } func Failed(code int, msg string) MSG { return MSG{"data": nil, "code": code, "msg": msg} } func (s *webServer) Run(addr string) { gin.SetMode(gin.ReleaseMode) s.Engine = gin.New() // 自动加载模板 t := template.New("tmp") //func 函数映射 全局模板可用 t.Funcs(template.FuncMap{ "getYear": GetYear, "formatAsDate": FormatAsDate, "getConf": GetConf, "getDate": GetDate, "getavator": Getavator, "getServerInfo": GetServerInfo, "formatFileSize": FormatFileSize, }) //从二进制中加载模板(后缀必须.html) t, _ = s.LoadTemplate(t) s.Engine.SetHTMLTemplate(t) //静态资源 assets := packr.New("assets", "../template/assets") //s.Engine.Static("/assets", "./template/assets") s.Engine.StaticFS("/assets", assets) s.Engine.GET("/", func(c *gin.Context) { c.Redirect(302, "/index/login") }) //通用路由 s.Engine.Any("/m3u8/*action", s.AdminM3u8) // 用于代理m3u8的文件和ts文件的全局访问 s.Engine.Any("/admin/:action", AuthMiddleWare(), s.admin) s.Engine.Any("/index/:action", s.index) go func() { log.Infof("115 player webui 服务器已启动: %v", addr) err := s.Engine.Run(addr) if err != nil { log.Error(err) log.Infof("请检查端口是否被占用.") time.Sleep(time.Second * 5) os.Exit(1) } }() return } // loadTemplate loads templates by packr 将html 打包到二进制包 func (s *webServer) LoadTemplate(t *template.Template) (*template.Template, error) { box := packr.New("tmp", "../template/html") for _, file := range box.List() { if !strings.HasSuffix(file, ".html") { continue } h, err := box.FindString(file) if err != nil { return nil, err } //拼接方式,组装模板 admin/index.html 这种,方便调用 t, err = t.New(strings.Replace(file, "html/", "", 1)).Parse(h) if err != nil { return nil, err } } return t, nil } //格式化年月日 func FormatAsDate(t time.Time) string { year, month, day := t.Date() return fmt.Sprintf("%d%02d/%02d", year, month, day) } // 获取年份 func GetYear() string { t := time.Now() year, _, _ := t.Date() return fmt.Sprintf("%d", year) } // 获取当前年月日 func GetDate() string { t := time.Now() year, month, day := t.Date() return fmt.Sprintf("%d-%02d-%02d", year, month, day) } // 随机获取一个头像 func Getavator() string { Uuid := uuid.New().String() grav_url := "https://www.gravatar.com/avatar/" + Uuid return grav_url } type info struct { Root string Version string Hostname string Interfaces interface{} Goarch string Goos string //VirtualMemory *mem.VirtualMemoryStat Sys uint64 CpuInfoStat struct { Count int Percent []float64 } } func GetServerInfo() *info { root := runtime.GOROOT() // GO 路径 version := runtime.Version() //GO 版本信息 hostname, _ := os.Hostname() //获得PC名 interfaces, _ := net.Interfaces() //获得网卡信息 goarch := runtime.GOARCH //系统构架 386、amd64 goos := runtime.GOOS //系统版本 windows Info := &info{ Root: root, Version: version, Hostname: hostname, Interfaces: interfaces, Goarch: goarch, Goos: goos, } //v, _ := mem.VirtualMemory() //Info.VirtualMemory = v var ms runtime.MemStats runtime.ReadMemStats(&ms) Info.Sys = ms.Sys //Info.CpuInfoStat.Count, _ = cpu.Counts(true) //Info.CpuInfoStat.Percent, _ = cpu.Percent(0, true) return Info } // 字节的单位转换 保留两位小数 func FormatFileSize(fileSize uint64) (size string) { if fileSize < 1024 { //return strconv.FormatInt(fileSize, 10) + "B" return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1)) } else if fileSize < (1024 * 1024) { return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024)) } else if fileSize < (1024 * 1024 * 1024) { return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024)) } else if fileSize < (1024 * 1024 * 1024 * 1024) { return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024)) } else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) { return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024)) } else { //if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024) return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024)) } } // admin 控制器 登录验证 func AuthMiddleWare() gin.HandlerFunc { return func(c *gin.Context) { //conf := GetConf() user := "admin" password := "admin" str1 := user + password h := md5.New() h.Write([]byte(str1)) md51 := hex.EncodeToString(h.Sum(nil)) if cookie, err := c.Request.Cookie("userinfo"); err == nil { value := cookie.Value if value == md51 { c.Next() return } } c.HTML(http.StatusOK, "index/jump.html", gin.H{ "url": "/index/login", "timeout": "3", "code": 0, //1为success,0为error "msg": "请登录后再访问", }) //c.Redirect(http.StatusMovedPermanently, "/index/login") c.Abort() return } } func (s *webServer) admin(c *gin.Context) { action := c.Param("action") log.Debugf("webServer接收到cgi调用: %v", action) if f, ok := HttpuriAdmin[action]; ok { f(s, c) } else { c.JSON(200, Failed(404, "没有相关页面")) } } func (s *webServer) index(c *gin.Context) { action := c.Param("action") log.Debugf("webServer接收到cgi调用: %v", action) if f, ok := HttpuriIndex[action]; ok { f(s, c) } else { c.JSON(200, Failed(404, "没有相关页面")) } } // 获取当前配置文件信息 func GetConf() Conf { conf := Conf{User: "admin", Password: "admin"} return conf } func Error(c *gin.Context, msg string, timeout int, url string) { c.HTML(http.StatusOK, "index/jump.html", gin.H{ "url": url, "timeout": timeout, "code": 0, //1为success,0为error "msg": msg, }) c.Abort() return }