# Gin渲染
参考博客:[Gin框架介绍及使用](https://www.liwenzhou.com/posts/Go/gin/)
## HTML渲染
我们首先定义一个存放模板文件的`templates`文件夹,然后在其内部按照业务分别定义一个`posts`文件夹和一个`users`文件夹。 `posts/index.html`文件的内容如下:
```html
{{define "posts/index.html"}}
posts/index
{{.title}}
{{end}}
```
`users/index.html`文件的内容如下:
```html
{{define "users/index.html"}}
users/index
{{.title}}
{{end}}
```
Gin框架中使用`LoadHTMLGlob()`或者`LoadHTMLFiles()`方法进行HTML模板渲染。
```go
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/**/*")
//r.LoadHTMLFiles("templates/posts/index.html", "templates/users/index.html")
r.GET("/posts/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.html", gin.H{
"title": "posts/index",
})
})
r.GET("users/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.html", gin.H{
"title": "users/index",
})
})
r.Run(":8080")
```
## 自定义模板函数
定义一个不转义相应内容的`safe`模板函数如下:
```go
func main() {
router := gin.Default()
router.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML{
return template.HTML(str)
},
})
router.LoadHTMLFiles("./index.tmpl")
router.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.tmpl", "李文周的博客")
})
router.Run(":8080")
}
```
在`index.tmpl`中使用定义好的`safe`模板函数:
```html
修改模板引擎的标识符
{{ . | safe }}
```
## 静态文件处理
当我们渲染的HTML文件中引用了静态文件时,我们只需要按照以下方式在渲染页面前调用`gin.Static`方法即可。
```go
func main() {
r := gin.Default()
r.Static("/static", "./static")
r.LoadHTMLGlob("templates/**/*")
// ...
r.Run(":8080")
}
```
## 使用模板继承
Gin框架默认都是使用单模板,如果需要使用`block template`功能,可以通过`"github.com/gin-contrib/multitemplate"`库实现,具体示例如下:
首先,假设我们项目目录下的templates文件夹下有以下模板文件,其中`home.tmpl`和`index.tmpl`继承了`base.tmpl`:
```bash
templates
├── includes
│ ├── home.tmpl
│ └── index.tmpl
├── layouts
│ └── base.tmpl
└── scripts.tmpl
```
然后我们定义一个`loadTemplates`函数如下:
```go
func loadTemplates(templatesDir string) multitemplate.Renderer {
r := multitemplate.NewRenderer()
layouts, err := filepath.Glob(templatesDir + "/layouts/*.tmpl")
if err != nil {
panic(err.Error())
}
includes, err := filepath.Glob(templatesDir + "/includes/*.tmpl")
if err != nil {
panic(err.Error())
}
// 为layouts/和includes/目录生成 templates map
for _, include := range includes {
layoutCopy := make([]string, len(layouts))
copy(layoutCopy, layouts)
files := append(layoutCopy, include)
r.AddFromFiles(filepath.Base(include), files...)
}
return r
}
```
我们在`main`函数中
```go
func indexFunc(c *gin.Context){
c.HTML(http.StatusOK, "index.tmpl", nil)
}
func homeFunc(c *gin.Context){
c.HTML(http.StatusOK, "home.tmpl", nil)
}
func main(){
r := gin.Default()
r.HTMLRender = loadTemplates("./templates")
r.GET("/index", indexFunc)
r.GET("/home", homeFunc)
r.Run()
}
```
## 补充文件路径处理
关于模板文件和静态文件的路径,我们需要根据公司/项目的要求进行设置。可以使用下面的函数获取当前执行程序的路径。
```go
func getCurrentPath() string {
if ex, err := os.Executable(); err == nil {
return filepath.Dir(ex)
}
return "./"
}
```
## 返回Json
```go
func main() {
r := gin.Default()
// 方法1:使用map
r.GET("/json01", func(c *gin.Context) {
data := gin.H{ // gin.H is a shortcut for map[string]any
"name": "tom",
"age": 26,
"gender": "male",
}
c.JSON(http.StatusOK, data)
})
// 方法2:使用struct,使用tag来定制json字段的名称。
r.GET("/json02", func(c *gin.Context) {
var person struct {
Name string `json:"name"` // 这里一定要是可导出的,否则json获取不到数据。如果想要指定json字段的名称,可以使用Tag。
Age int `json:"age"`
Gender string `json:"gender"`
}
person.Name = "Jane"
person.Age = 24
person.Gender = "female"
c.JSON(http.StatusOK, person) // 传入结构体类型的数据
})
r.Run(":9003")
}
```
---
> 作者: [Hollis](https://www.xuexiqu.cn/)
> URL: https://www.xuexiqu.cn/golang/gin/gin_rendering/