首页 > 其他分享 >Gin的结构

Gin的结构

时间:2024-02-10 19:55:50浏览次数:29  
标签:http admin ctx html gin go Gin 结构

Gin的基本使用

首先用go mod建立一个项目,比如就叫ginnote吧。

go mod init ginnote

然后获取一下gin包,即便是已经装了gin包,也要获取,因为要配置go.mod文件。

go get github.com/gin-gonic/gin

除此以外,还需要另一项工具,可以提供热加载,也就是可以一边写一边加载网页,每次保存项目都会自动重新编译运行。

go get github.com/pilu/fresh

执行完之后,文件夹里会多一个tmp文件夹,这就表示成功了。

然后新建一个main.go,用这样一段代码就可以生成一个网页。

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/", func(ctx *gin.Context) {
		ctx.String(http.StatusOK, "Hello World!") //http.StatusOK就等于200。
	})
	r.Run() //默认端口是8000。括号里可以指定端口号,接收字符串类型,比如":4000"。注意":"不能省略!
}

在终端中输入下面这行即可开启热加载,Ctrl+C退出。

go run github.com/pilu/fresh

Gin的目录结构

假如,现在有这么一个项目:

  • 网页主要分为三部分,包含default,admin,api。
  • 每部分各有自己的首页,default包含了普通人能看到的页面,admin有一些高级权限,api包含一些功能。
  • 项目里包含了静态资源,css,js,image。

那么整个项目的目录大概是这样的。

project
│
└───controllers
│   │
│   └───admin
│   │   │   articleController.go
│   │   │   indexController.go
│   │   │   userController.go
│   │
│   └───api
│   │   │   apiController.go
│   │   
│   └───defaults
│       │   defaultController.go
│   
└───routers
│   │   adminRouters.go
│   │   apiRouters.go
│   │   defaultRouters.go
│
└───static
│   │
│   └───css
│   │   │   base.css
│   │
│   └───image
│   │   │   pm.jpg
│   │   
│   └───js
│       │   base.js
│
└───templates
│   │
│   └───admin
│   │   │   index.html
│   │   │   news.html
│   │
│   └───default
│   │   │   index.html
│   │   │   news.html
│   │   │   user.html
│   │   
│   └───public
│       │   page_header.html
│
└───tmp
│   │   runner-build.exe
│   │   runner-build.exe~
│   
│   go.mod
│   go.sum
│   main.go
│

很吓人对吧,但是别急。
从下往上看,go.mod,go.sum都是自动生成的,不用管,main.go是我们自己写的。tmp文件夹和里面的exe都是前面go get github.com/pilu/fresh自动生成的。
templates文件夹里面存放的是html文件,也就是模板,page_header.html代表被继承的父模板。
static存放静态资源,包括css,js和图片。
重点就在于最上面这两个文件夹。
routers中的.go文件是路由组,包含了那一部分网页的全部路由。并且只包含路由的路径,而不包括具体实现方法。所有的实现方法都写在controllers下的文件中。

这里以controllers/admin中的文件举例,比如这个indexController.go。

package admin

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type IndexController struct {
}

func (con IndexController) Index(ctx *gin.Context) {
	ctx.String(http.StatusOK, "首页--")
}

在之前的Gin的基本使用里给的例子中,是直接把逻辑写在了匿名函数里作为参数,而这里是直接把函数抽离出来,以便后续维护。如果在测试过程中出现了什么bug,那么就找到对应的函数进行修改即可。这里的函数并不是独立的,而是作为结构体IndexController的方法而存在,这是为了继承,并且可以将函数分类,增强代码的可读性。

再看articleController.go中的内容。

package admin

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type ArticleController struct {
}

func (con ArticleController) Index(ctx *gin.Context) {
	ctx.String(http.StatusOK, "文章列表--")
}

func (con ArticleController) Add(ctx *gin.Context) {
	ctx.String(http.StatusOK, "增加文章--")
}

func (con ArticleController) Edit(ctx *gin.Context) {
	ctx.String(http.StatusOK, "修改文章--")
}

这里定义了名为ArticleController的结构体及其相关方法,这表明这些方法都是和Article相关的。

定义好这些方法以后,就可以在routers/adminRouters.go中调用了。

package routers

import (
	"ginpro2/controllers/admin"
	"net/http"

	"github.com/gin-gonic/gin"
)

func AdminRoutersInit(r *gin.Engine) {
	adminRouters := r.Group("/admin")
	{
		adminRouters.GET("/", func(ctx *gin.Context) {
			ctx.String(http.StatusOK, "后台首页")
		})
		adminRouters.GET("/user", admin.UserController{}.Index) //先实例化结构体,再调用方法。
		adminRouters.GET("/user/add", admin.UserController{}.Add)
		adminRouters.GET("/user/edit", admin.UserController{}.Edit)
		adminRouters.GET("/article", admin.ArticleController{}.Index)
		adminRouters.GET("/article/add", admin.ArticleController{}.Add)
		adminRouters.GET("/article/edit", admin.ArticleController{}.Edit)
	}
}

这里就是一个路由组,把"/admin"路径下的所有路由集合在一起,虽然很多方法命重名了,但它们都是不同结构体的方法,所以也是不同的功能。要注意的是,路由组自身也是一个函数,它要在main.go中被调用,就像这样:

package main

import (
	"ginnote/routers"
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/", func(ctx *gin.Context) {
		ctx.String(http.StatusOK, "Hello World!") //http.StatusOK就等于200。
	})
	routers.AdminRoutersInit(r) //调用路由组。
	r.Run(":4000")              //默认端口是8000。括号里可以指定端口号,接收字符串类型,比如":4000"。注意":"不能省略!
}

于是就形成了这样一种关系:main.go调用路由组,路由组adminRouters.go包含了路由路径并调用了方法,在controllers/admin中实现了具体的方法。

渲染模板和静态资源

我们决定在default部分渲染一个html网页。
在defaultController.go中写好渲染模板的方法。这里要注意的是,package后面不能直接写default,因为default是go中的关键词,所以写成了defaults,或者写个别的包名也行。

package defaults

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type DefaultController struct {
}

type Article struct {
	Title   string `json:"title"`
	Content string `json:"content"`
}

func (con DefaultController) Index(ctx *gin.Context) {
	ctx.HTML(http.StatusOK, "default/index.html", gin.H{  //这里的路径是"default/index.html"
		"title": "首页",
		"msg":   "我是msg",
		"score": 89,
		"hobby": []string{"吃饭", "睡觉", "写代码"},
		"newsList": []interface{}{
			Article{
				Title:   "新闻标题1",
				Content: "新闻内容1",
			},
			Article{
				Title:   "新闻标题2",
				Content: "新闻内容2",
			},
		},
		"testSlice": []string{},
		"news": Article{
			Title:   "新闻标题3",
			Content: "新闻内容3",
		},
		"date": 1629423555,
	})
}

func (con DefaultController) News(ctx *gin.Context) {
	ctx.String(http.StatusOK, "新闻")
}

在defaultRouters.go中调用方法。

package routers

import (
	"ginnote/controllers/defaults"

	"github.com/gin-gonic/gin"
)

func DefaultRoutersInit(r *gin.Engine) {
	defaultRouters := r.Group("/")
	{
		defaultRouters.GET("/", defaults.DefaultController{}.Index)
		defaultRouters.GET("/news", defaults.DefaultController{}.News)
	}
}

除此之外,我们还要在main.go中加载模板。

package main

import (
	"ginnote/routers"
	"html/template"
	"time"

	"github.com/gin-gonic/gin"
)

func UnixToTime(timestamp int) string {
	t := time.Unix(int64(timestamp), 0)
	return t.Format("2006-01-02 15:04:05")
}

func main() {
	r := gin.Default()

	//自定义模板函数
	r.SetFuncMap(template.FuncMap{
		"UnixToTime": UnixToTime,
	})

	//加载模板
	r.LoadHTMLGlob("templates/**/*")
	//这里括号里参数的意思就是加载目录"templates/xxx/"下的所有模板。
	//如果换成"templates/*"就变成的加载目录"templates/"下的所有模板。

	//配置静态web服务,第一个参数表示路由,第二个参数表示映射的目录。
	r.Static("/static", "./static")

	routers.AdminRoutersInit(r) //调用路由组
	routers.DefaultRoutersInit(r)
	routers.ApiRoutersInit(r)
	r.Run() //默认端口是8000。括号里可以指定端口号,接收字符串类型,比如":4000"。注意":"不能省略!
}

上面代码中多了一些奇奇怪怪的东西,现在大可以忽略或者照抄。其中routers.ApiRoutersInit(r)中的定义与之前的routers.AdminRoutersInit(r)类似,不再赘述。

在templates/default中新建一个index.html,在里面随便写点什么。

{{define "default/index.html"}}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="/static/css/base.css">
</head>
<body>

    {{template "public/page_header.html" .}}
    <h2>index</h2>
    <h2>{{.title}}</h2>
    <!-- 定义变量 -->
    {{$t := .title}}
    <hr>
    <h4>
        {{$t}}
    </h4>
    <!-- 条件判断 -->
    {{if ge .score 60}}
    <p>及格</p>
    {{else}}
    <p>不及格</p>
    {{end}}

    {{if gt .score 90}}
    <p>优秀</p>
    {{else if gt .score 80}}
    <p>良好</p>
    {{else if gt .score 60}}
    <p>及格</p>
    {{else}}
    <p>不及格</p>
    {{end}}

    <!-- 循环遍历数据 -->
    <ul>
        {{range $key,$value := .hobby}}
        <li>{{$key}}-----{{$value}}</li>
        {{end}}
    </ul>

    <ul>
        {{range $key,$value := .newsList}}
        <li>{{$key}}-----{{$value.Title}}----{{$value.Content}}</li>
        {{end}}
    </ul>
    <hr>
    <ul>
        {{range $key,$value := .hobby}}
        <li>{{$key}}-----{{$value}}</li>
        {{else}}
        <li>切片没有数据</li>
        {{end}}
    </ul>
    <!-- 解构结构体 -->
    <hr>
    <p>
        {{with.news}}
        {{.Title}}
        {{.Content}}
        {{end}}
    </p>
    <hr>
    {{len .title}}
    <hr>
    {{.date}}
    <hr>
    {{UnixToTime .date}}
    <img src="/static/image/pm.jpg" alt="">
</body>
</html>
{{end}}

这里开头写一句{{define "default/index.html"}}意思是在调用这个模板时要用的路径。


这还没完,我们还希望引入一些静态资源。可以看到,我们在html中已经写了一行导入外部css,,但这样直接导入会失败。所以所以前面的mian.go中已经加了一行代码r.Static("/static", "./static")。第二个参数"./static"表示我们引入了相对于main.go文件的"./static"目录下的资源,并把他的路由链接设定为"/static"。(这里我在写博客的时候,我这里搞了好一会儿一直都是即便故意不配置也能加载css和图片。后来发现是浏览器的缓存原因。)

总结

至此,Gin的大致结构就是这样,主要就包含这么几个部分。

  • 用于启动的main.go
  • 用于存放模板的templates
  • 用于存放静态资源的static
  • 用于集合路由的路由组routers
  • 用于实现方法逻辑的controllers

最后这篇文章里还有一些没有解释的地方,以后再解释。

标签:http,admin,ctx,html,gin,go,Gin,结构
From: https://www.cnblogs.com/luviichann/p/18013008

相关文章

  • 【Java 并发】【十】【JUC数据结构】【十】PriorityBlockingQueue 原理
    1 前言这节我们继续看看另一个队列 PriorityBlockingQueue,优先级的哈。2 PriorityBlockingQueue介绍PriorityBlockingQueue是带优先级的无界阻塞队列,每次出队都返回优先级最高或者最低的元素。其内部是使用平衡二叉树堆实现的,所以直接遍历队列元素不保证有序。默认使......
  • 【Java 并发】【十】【JUC数据结构】【九】ConcurrentLinkedQueue 原理
    1 前言JDK中提供了一系列场景的并发安全队列。总的来说,按照实现方式的不同可分为阻塞队列和非阻塞队列,前者使用锁实现,而后者则使用CAS非阻塞算法实现。这节我们来看看 ConcurrentLinkedQueue。2 ConcurrentLinkedQueue介绍ConcurrentLinkedQueue是线程安全的无界非阻......
  • BeginCTF 2024(自由赛道)MISC
    realcheckin题目:从catf1y的笔记本中发现了这个神秘的代码MJSWO2LOPNLUKTCDJ5GWKX3UN5PUEM2HNFXEGVCGL4ZDAMRUL5EDAUDFL5MU6VK7O5UUYMK7GEYWWZK7NE3X2===你能帮助我找到最后的flag吗?我的解答:base32解码begin{WELCOMe_to_B3GinCTF_2024_H0Pe_YOU_wiL1_11ke_i7}下一站上岸......
  • maven--插件的管理(pluginManagement)
     原文网址:​​maven--插件的管理(pluginManagement)_IT利刃出鞘的博客-CSDN博客​​简介说明本文介绍maven如何使用pluginManagement来管理插件(build标签中的plugins标签)。概述Maven使用 dependencyManagement对依赖进行管理,见:​​这里​​,与之类似地,Maven中还提供了一个......
  • MySQL表结构及数据对比工具:MySQL Utilities
    简介MySQLUtilities是一组基于python语言编写的python库的命令行实用工具集,依赖于python2.6。该工具提供了MySQL数据库运维工程中常用的一些工具,诸如克隆、复制、比较、差异、导出、导入、安装、配置、索引、磁盘查看等等。Linux下安装yuminstallmysql-utilities.noarch......
  • 听说有 Hugging Face 陪伴的春节,是这样的…
    辞旧迎新春节到,家家户户好热闹。HuggingFace中国团队成员祝各位社区成员们新春快乐,万事如意!过去的一年我们持续看到AI技术的腾飞和发展,以及诸多机构为开源AI作出巨大的贡献。非常感谢将模型、数据集和应用Demo发布在HuggingFace上的团队,新的一年,我们也会持续发掘和介......
  • gal game 杂谈——《GINKA》
    galgame杂谈——《GINKA》剧情梳理Ps:女主分为小学阶段和高中阶段,这里称小学阶段为小时候的女主,高中阶段为大女主,分离出来爱的为GINKA(长相是小时候的女主)。1.乘船回忆女主及关键信息这里流了一个伏笔,写男主在船上晕过去。和后面剧情有关。回忆起女主,小学时俩人约定在夏日......
  • 结构体
    题目描述给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。输入格式第一行为n(0<n<20),表示班里的学生数目;接下来的n行,每行为每个学生的名字和他的成绩,中间用单个空格隔开。名字只包含字母且长度不超过20,成绩为一个不大......
  • 数据结构——第1章 绪论
    目录1.1数据结构的研究内容1.2基本概念和术语1.2.1数据、··元素、··项和··对象1.2.2数据结构1.2.3数据类型和抽象数据类型1.3抽象数据类型的表示与实现1.4算法和算法分析1.4.1算法的定义与特性1.4.2算法的时间复杂度1.4.3算法的空间复杂度1.5小结1.1数据结构的......
  • 微信小程序(二) | 了解页面结构与组件
    ......