虽然辛苦,但我还是会选择那种滚烫的人生。
加油,各位!
5.9:这篇文章前前后后写了两天,最近也没有很频繁的更新。
为什么不去写springboot or cloud的文章:
感觉两者的文章数量已经过于饱和,现在完全可以享受到前人种树后人乘凉这种更好的状态,但是蒟蒻觉得国内的go社区还是有待完善,为了为go社区的发展尽一份绵薄之力,蒟蒻决定好好写一写go大大小小的文章,即使为了方便别人,也是为了加强记忆毕竟自己也蔡 。当然JAVA或者其中间件的也会写,可能是会面向更基础或者更有趣这两个极端。毕竟,写一些主流的文章没太大的意义。
5.8:这两天蒟蒻把电脑重装了一下,原因很简单。
1.开始不注意文件的放置位置,导致C盘爆满,只剩5G,跑idea够呛。
2.电脑名是中文名,很多中间件只能在阿里云上跑。比如rabbitmq,然而activemq可以正常运行。。VM的跑起来就更卡了。。阿里云8月就到期,所以应该做起自力更生的准备
得莫,现在已经
C盘39G真是舒服啊~
要好好爱惜空间了。
由于自己出路时间不长,前期没意识到文件管理的重要性,所以痛下决心折腾一下电脑。
重装的路对小白来说是坎坷的
C盘进行了格式化,我提前把idea,webstorm的数据存在D,其他编译器没保存,想着反正都没用多少。。
然后就是折腾各种语言的运行环境啊,各个中间件的运行环境。。
虽然自己这些都在最开始接触的时候做过不止一次了,遇到难一点的还是会卡很长时间,这个时候感觉自己心态很好,可能是习惯项目调BUG两小时起步的感觉了吧,做起来都很平静。
大半天左右把前后端运行环境都能跑起来我还是很欣慰的。阿里也很鼓励员工养成爱折腾的习惯。比如初玩linux都会有几次失败这样。
遇到问题切莫急躁,程序员大忌。
虽然这些方面做的很好,但是总体还是有损失的,,比如除了idea,webstorm之前的程序,其他ide都没保存。近期也没打算好高骛远,先学好JAVA。
毕竟在一些springcloud内容方面,比如集群的nacos,分布式交易seata啥的,三个nocos阿里云也运行不起来。。。这种工具问题很难解决(学生机太蔡了)。
然后就是把数据库换回了5X。。还是因为sc有些组件8的环境真的太难了。。。例如上面的三个nacos,,官方文档专门写了8x的注意事项,为了学习路线更平滑,我折腾回了5。顺便吐槽mysql真的是我最不想折腾的工具,8换回5也很艰辛。。8.20的BUG也巨多,经常上午好好的下午搞事情,redis的开箱即用真的太好了。。
5.9:
那么开始gin系列的学习。
熟悉一门不是很复杂的框架JAVA就算了 ,看官方文档无疑是个好方法,贴一下gin的文档,貌似有面向中国区的,所以直接可以访问,很友好。
gin
1h内差不多可以通读一遍。
如果看到这张图,能让你产生xcd的话,那么你已经入门了
所以对着官方文档来:
安装gin
go get -u github.com/gin-gonic/gin
引入
import "github.com/gin-gonic/gin"
接下来就直接在goland可以开一个project来写测试代码了
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
// 创建一个默认的路由引擎
r := gin.Default()
// GET:请求方式;/hello:请求的路径
// 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数
r.GET("/hello", func(c *gin.Context) {
// c.JSON:返回JSON格式的数据
c.JSON(200, gin.H{
"message": "Hello world!",
})
})
不出所料各位看到了Hello world的JSON数据。注释解释的差不多了,,接下来对比spring家的乱七八糟 的反射,你应该感叹gin多么友好。。有手就行,而且gin的crud真的是爽到爆。。。体验舒适度大概和人人开源的逆向工程差不多~
路由(Route)
路由方法有 GET, POST, PUT, PATCH, DELETE 和 OPTIONS,还有Any,可匹配以上任意类型的请求。
Any基本上可以囊括所有路由,但就像restful开发风格一样,很多就是coder前辈们约定俗成的规则,所以其他的也会用。
// 无参数
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Who are you?")
})
直接访问localhost:xxxx/可以看到输出了吧!
curl http://localhost:9999/
Who are you?
有时候我们需要动态的路由,如 /user/:name,通过调用不同的 url 来传入不同的 name。/user/:name/role, 代表可选。
一般来说,就是你随便起的变量名,前面加个:你就可以随心所欲的赋值访问:
http://localhost:9999/user/hhhhhh
Hello hhhhhh
获取Query参数
// 匹配users?name=xxx&role=xxx,role可选
r.GET("/users", func(c *gin.Context) {
name := c.Query("name")
role := c.DefaultQuery("role", "teacher")
c.String(http.StatusOK, "%s is a %s", name, role)
})
curl "http://localhost:9999/users?name=Tom&role=student"
Tom is a student
Query:url上你写的值,不写会为空而不是default值
DefaultQuery:默认访问这个值。
获取POST参数
// POST
r.POST("/form", func(c *gin.Context) {
username := c.PostForm("username")
password := c.DefaultPostForm("password", "000000") // 可设置默认值
c.JSON(http.StatusOK, gin.H{
"username": username,
"password": password,
})
})
curl http://localhost:9999/form -X POST -d 'username=qqqq&password=1234'
{"password":"1234","username":"qqqq"}
Query和POST混合参数
// GET 和 POST 混合
r.POST("/posts", func(c *gin.Context) {
id := c.Query("id")
page := c.DefaultQuery("page", "0")
username := c.PostForm("username")
password := c.DefaultPostForm("username", "000000") // 可设置默认值
c.JSON(http.StatusOK, gin.H{
"id": id,
"page": page,
"username": username,
"password": password,
})
})
Map参数(字典参数)
r.POST("/post", func(c *gin.Context) {
ids := c.QueryMap("ids")
names := c.PostFormMap("names")
c.JSON(http.StatusOK, gin.H{
"ids": ids,
"names": names,
})
})
重定向(Redirect)
r.GET("/redirect", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/index")
})
r.GET("/goindex", func(c *gin.Context) {
c.Request.URL.Path = "/"
r.HandleContext(c)
})
curl -i http://localhost:9999/redirect
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=utf-8
Location: /
Date: Thu, 08 Aug 2019 17:22:14 GMT
Content-Length: 36
<a href="/">Moved Permanently</a>.
$ curl "http://localhost:9999/goindex"
Who are you?
go的重定向貌似有两种,学j2ee的肯定都知道重定向和转发的区别,但是gin这边好像是都叫做重定向,只不过适应不同业务这样,蒟蒻自己的理解,没有过分深究,知道的大佬可以提醒一下。
分组路由(Grouping Routes)
如果有一组路由,前缀都是/api/v1开头,是否每个路由都需要加上/api/v1这个前缀呢?答案是不需要,分组路由可以解决这个问题。利用分组路由还可以更好地实现权限控制,例如将需要登录鉴权的路由放到同一分组中去,简化权限控制。
// group routes 分组路由
defaultHandler := func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"path": c.FullPath(),
})
}
// group: v1
v1 := r.Group("/v1")
{
v1.GET("/posts", defaultHandler)
v1.GET("/series", defaultHandler)
}
// group: v2
v2 := r.Group("/v2")
{
v2.GET("/posts", defaultHandler)
v2.GET("/series", defaultHandler)
}
上传文件
单个文件
r.POST("/upload1", func(c *gin.Context) {
file, _ := c.FormFile("file")
// c.SaveUploadedFile(file, dst)
c.String(http.StatusOK, "%s uploaded!", file.Filename)
})
多个文件
r.POST("/upload2", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["upload[]"]
for _, file := range files {
log.Println(file.Filename)
// c.SaveUploadedFile(file, dst)
}
c.String(http.StatusOK, "%d files uploaded!", len(files))
})
HTML模板(Template)
type student struct {
Name string
Age int8
}
r.LoadHTMLGlob("templates/*")
stu1 := &student{Name: "Geektutu", Age: 20}
stu2 := &student{Name: "Jack", Age: 22}
r.GET("/arr", func(c *gin.Context) {
c.HTML(http.StatusOK, "arr.tmpl", gin.H{
"title": "Gin",
"stuArr": [2]*student{stu1, stu2},
})
})
<!-- templates/arr.tmpl -->
<html>
<body>
<p>hello, {{.title}}</p>
{{range $index, $ele := .stuArr }}
<p>{{ $index }}: {{ $ele.Name }} is {{ $ele.Age }} years old</p>
{{ end }}
</body>
</html>
$ curl http://localhost:9999/arr
<html>
<body>
<p>hello, Gin</p>
<p>0: Geektutu is 20 years old</p>
<p>1: Jack is 22 years old</p>
</body>
</html>
Gin默认使用模板Go语言标准库的模板text/template和html/template,语法与标准库一致,支持各种复杂场景的渲染。
中间件
// 作用于全局
r.Use(gin.Logger())
r.Use(gin.Recovery())
// 作用于单个路由
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
// 作用于某个组
authorized := r.Group("/")
authorized.Use(AuthRequired())
{
authorized.POST("/login", loginEndpoint)
authorized.POST("/submit", submitEndpoint)
自定义中间件
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// 给Context实例设置一个值
c.Set("geektutu", "1111")
// 请求前
c.Next()
// 请求后
latency := time.Since(t)
log.Print(latency)
}
}
热加载调试 Hot Reload
Python 的 Flask框架,有 debug 模式,启动时传入 debug=True 就可以热加载(Hot Reload, Live Reload)了。即更改源码,保存后,自动触发更新,浏览器上刷新即可。免去了杀进程、重新启动之苦。
Gin 原生不支持,但有很多额外的库可以支持。例如
github.com/codegangsta/gin
github.com/pilu/fresh
go get -v -u github.com/pilu/fresh
安装好后,只需要将go run main.go命令换成fresh即可。每次更改源文件,代码将自动重新编译(Auto Compile)。
gin的入门就到这里了,下章讲讲gorm,也是超好用的go crud工具!