简介
本文接着上文(Golang GinWeb框架6-绑定请求字符串/URI/请求头/复选框/表单类型)继续探索GinWeb框架
静态文件服务
package main
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
"os"
)
func main() {
router := gin.Default()
cwd, _ := os.Getwd() //获取当前文件目录
log.Printf("当前项目路径:%s", cwd)
router.Static("/static", cwd) //提供静态文件服务器, 第一个参数为相对路径,第二个参数为根路径, 这个路径一般放置css,js,fonts等静态文件,前端html中采用/static/js/xxx或/static/css/xxx等相对路径的方式引用
router.StaticFS("/more_static", http.Dir("./")) //将本地文件树结构映射到前端, 通过浏览器可以访问本地文件系统, 模拟访问:
router.StaticFile("/logo.png", "./resources/logo.png") //StaticFile提供单静态单文件服务, 模拟访问:
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
返回文件数据
package main
import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.Use(cors.Default())
router.GET("/local/file", func(c *gin.Context) {
c.File("./main.go")
})
// A FileSystem implements access to a collection of named files.
// The elements in a file path are separated by slash ('/', U+002F)
// characters, regardless of host operating system convention.
// FileSystem接口, 要求实现文件的访问的方法, 提供文件访问服务根路径的HTTP处理器
var fs http.FileSystem = http.Dir("./") //将本地目录作为文件服务根路径
router.GET("/fs/file", func(c *gin.Context) {
c.FileFromFS("main.go", fs) //将文件服务系统下的文件数据返回
})
router.Run(":8080")
}
/*
模拟访问文件数据:
curl
模拟访问文件系统下的文件数据:
curl
*/
用文件读出器提供文件数据服务
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/someDataFromReader", func(c *gin.Context) {
response, err := http.Get("#34;)
if err != nil || response.StatusCode != http.StatusOK { //请求链接中的文件出现错误时, 直接返回服务不可用
c.Status(http.StatusServiceUnavailable)
return
}
reader := response.Body //用响应体内容构造一个文件读出器
defer reader.Close()
contentLength := response.ContentLength
contentType := response.Header.Get("Content-Type")
extraHeaders := map[string]string{
"Content-Disposition": `attachment; filename="gopher.png"`,
}
// DataFromReader writes the specified reader into the body stream and updates the HTTP code.
// func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) {}
// DataFromReader方法将指定的读出器reader中的内容, 写入http响应体流中, 并更新响应码, 响应头信息等
c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
})
router.Run(":8080")
}
/*
模拟访问:
curl
*/
HTML渲染
使用LoadHTMLGlob()方法或LoadHTMLFiles()方法
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
//LoadHTMLGlob方法以glob模式加载匹配的HTML文件, 并与HTML渲染器结合
router.LoadHTMLGlob("templates/*")
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
router.GET("/index", func(c *gin.Context) {
//HTML方法设置响应码, 模板文件名, 渲染替换模板中的值, 设置响应内容类型Content-Type "text/html"
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
})
})
router.Run(":8080")
}
/*
模拟测试:
curl
*/
增加模板文件, templates/index.tmpl
<html>
<h1>
{{ .title }}
</h1>
</html>
使用不同文件夹下的相同文件名的模板文件
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
})
})
router.GET("/users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
})
})
router.Run(":8080")
}
posts目录下添加模板文件, templates/posts/index.tmpl
{{ define "posts/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}
users目录下添加模板文件, templates/users/index.tmpl
{{ define "users/index.tmpl" }}
<html><h1>
{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}
自定义模板渲染器
你也可以使用你自定义的HTML模板渲染器, 需要自定义模板文件file1, file2等
package main
import (
"github.com/gin-gonic/gin"
"html/template"
"net/http"
)
func main() {
router := gin.Default()
//template.ParseFiles(文件1,文件2...)创建一个模板对象, 然后解析一组模板,使用文件名作为模板的名字
// Must方法将模板和错误进行包裹, 返回模板的内存地址 一般用于变量初始化,比如:var t = template.Must(template.New("name").Parse("html"))
html := template.Must(template.ParseFiles("file1", "file2"))
router.SetHTMLTemplate(html) //关联模板和HTML渲染器
router.GET("/index", func(c *gin.Context) {
//HTML方法设置响应码, 模板文件名, 渲染替换模板中的值, 设置响应内容类型Content-Type "text/html"
c.HTML(http.StatusOK, "file1", gin.H{
"title": "Main website",
})
})
router.Run(":8080")
}
自定义分隔符
你可以自定义分隔符, 模板中默认的分隔符是{{ }}, 我们也可以修改, 比如下面增加一对中括号
r := gin.Default()
r.Delims("{[{", "}]}")
r.LoadHTMLGlob("/path/to/templates")
自定义模板方法
详见 示例代码.
模板中与后端都定义好模板方法, 模板渲染时执行该方法, 类似过滤器方法, 比如时间格式化操作
package main
import (
"fmt"
"html/template"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func formatAsDate(t time.Time) string {
year, month, day := t.Date() //Date方法返回年,月,日
return fmt.Sprintf("%d%02d/%02d", year, month, day) //格式化时间
}
func main() {
router := gin.Default()
router.Delims("{[{", "}]}") //自定义模板中的左右分隔符
//SetFuncMap方法用给定的template.FuncMap设置到Gin引擎上, 后面模板渲染时会调用同名方法
//FuncMap是一个map,键名关联方法名, 键值关联方法, 每个方法必须返回一个值, 或者返回两个值,其中第二个是error类型
router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate,
})
router.LoadHTMLFiles("./testdata/template/raw.tmpl") //加载单个模板文件并与HTML渲染器关联
router.GET("/raw", func(c *gin.Context) {
c.HTML(http.StatusOK, "raw.tmpl", gin.H{
"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
})
})
router.Run(":8080")
}
/*
模拟测试:
curl
*/
定义模板文件: raw.tmpl
Date: {[{.now | formatAsDate}]}
时间格式化结果:
Date: 2017/07/01
多个模板
Gin默认只使用一个html.Template模板引擎, 也可以参考多模板渲染器使用类似Go1.6的块级模板 block template 功能.
模板相关详情请参考官方template包
参考文档
Gin官方仓库:
END已结束
欢迎大家留言, 订阅, 交流哦!
往期回顾
Golang GinWeb框架6-XML/JSON/YAML/ProtoBuf等渲染
Golang GinWeb框架5-绑定请求字符串/URI/请求头/复选框/表单类型
Golang GinWeb框架4-请求参数绑定和验证
Golang GinWeb框架3-自定义日志格式和输出方式/启禁日志颜色
Golang GinWeb框架2-文件上传/程序panic崩溃后自定义处理方式
Golang GinWeb框架-快速入门/参数解析
Golang与亚马逊对象存储服务AmazonS3快速入门
Golang+Vue实现Websocket全双工通信入门
GolangWeb编程之控制器方法HandlerFunc与中间件Middleware
Golang连接MySQL执行查询并解析-告别结构体
Golang的一种发布订阅模式实现
Golang 并发数据冲突检测器(Data Race Detector)与并发安全
Golang”驱动”MongoDB-快速入门(“快码加鞭”)