1.安装
通过go get命令安装gin框架:
go get -u github.com/ gin-gonic/gin
简单的使用
r := gin.Default() //建立一个gin的服务端
//匹配地址返回匿名函数json数据
r.GET("/hello", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
//启动服务,r.Run(":8090")指定端口
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
2.Gin网络请求与路由处理
在gin框架中,Engine被定义成为一个结构体,Engine代表gin框架的一个结构体定义,其中包含了路由组、中间件、页面渲染接口、框架配置设置等相关内容。默认的Engine可以通过gin.Default进行创建,或者使用gin.New()同样可以创建。两种方式如下所示:
engine1 = gin.Default()
engine2 = gin.New()
gin.Default()和gin.New()的区别在于gin.Default也使用gin.New()创建engine实例,但是会默认使用Logger{打印并输出日志}和Recovery{遇到panic中断了服务,则Recovery会恢复程序执行}中间件。
Handle处理GET请求
engine.Handle("GET", "/hello", func(context *gin.Context) {}
//获取请求接口
fmt.Println(context.FullPath())
可以通过context.Query和context.DefaultQuery获取GET请求携带的参数。
可以通过context.Writer.Write向请求发起端返回数据。
Handle处理POST请求
engine.Handle("POST", "/login", func(context *gin.Context) {}
POST请求是以form表单的方式提交数据的,可以通过context.PostForm获取表单中提交的数据字段。
其他类型的HTTP请求也可以通过Handle方法处理对应类型的请求。
engine.GET()处理GET请求
engine.GET("/hello", func(context *gin.Context) {}
username := context.Query("name")//获取请求参数
name := context.DefaultQuery("name", "")//获取参数
engine.POST()处理POST请求
engine.POST("/login", func(context *gin.Context) {}
password, exists := context.GetPostForm("pwd")
if exists {
fmt.Println(password)
}
context.GetPostForm获取表单数据:POST请求以表单的形式提交数据,除了可以使用context.PostForm获取表单数据意外,还可以使用context.GetPostForm来获取表单数据。
engine.DELETE()处理DELETE请求
engine.DELETE("/user/:id", DeleteHandle)
func DeleteHandle(context *gin.Context) {
userID := context.Param("id")
}
context.Param获取请求参数
3.请求参数绑定与多数据格式处理
表单实体绑定
以一个用户注册功能来进行讲解表单实体绑定操作。用户注册需要提交表单数据,假设注册时表单数据包含三项,分别为:username、phone和password。
type UserRegister struct {
Username string form:"username" binding:"required"
Phone string form:"phone" binding:"required"
Password string form:"password" binding:"required"
}
创建了UserRegister结构体用于接收表单数据,通过tag标签的方式设置每个字段对应的form表单中的属性名,通过binding属于设置属性是否是必须。
ShouldBindQuery
使用ShouldBindQuery可以实现Get方式的数据请求的绑定。具体实现如下:
var student Student
err := context.ShouldBindQuery(&student)
type Student struct {
Name string form:"name"
Classes string form:"classes"
}
ShouldBind
使用ShouldBind可以实现Post方式的提交数据的绑定工作。具体编程如下所示:
var _register Register
if err := context.ShouldBind(&_register); err != nil {
log.Fatal(err.Error())
return
}
type Register struct {
UserName string form:"name"
Phone string form:"phone"
Password string form:"pwd"
}
ShouldBind
当客户端使用Json格式进行数据提交时,可以采用ShouldBindJson对数据进行绑定并自动解析,如下所示:
var person Person
if err := context.BindJSON(&person); err != nil {
log.Fatal(err.Error())
return
}
type Person struct {
Name string form:"name"
Sex string form:"sex"
Age int form:"age"
}
4.多数据格式返回请求结果
[]byte
在之前的课程案例中,我们统一使用的请求返回数据格式为[]byte。通过context.Writer.Write方法写入[]byte数据
context.Writer.Write([]byte(fullPath))
如上段代码所示,使用context.Writer.Write向客户端写入返回数据。Writer是gin框架中封装的一个ResponseWriter接口类型
string
除了write方法以外,ResponseWriter自身还封装了WriteString方法返回数据。
和[]byte类型调用一样,可以通过Writer进行调用。详细编程示例如下所示:
context.Writer.WriteString('我是谁')
JSON
map类型
context.JSON(200, map[string]interface{}{
"code": 1,
"message": "OK",
"data": fullPath,
})
结构体类型
//通用请求返回结构体定义
type Response struct {
Code int64 `json:"code"`
Message string `json:"msg"`
Data interface{} `json:"data"`
}
resp := Response{Code: 1, Message: "Ok", Data: fullPath}
context.JSON(200, &resp)
HTML模板
除了JSON格式以外,gin框架还支持返回HTML格式的数据。可以直接渲染HTML页面。举例如下:
//设置html的目录
engine.LoadHTMLGlob("./html/*")
context.HTML(http.StatusOK, "index.html", gin.H{
"title": "Gin教程",
"fullpath": fullPath,
})
{{.title}}context.HTML来加载HTMl页面或者模板
加载静态资源文件
在上面的index.html的基础上,添加一张img进行展示。需要将img所在的目录进行静态资源路径设置才可能会生效,如下所示:
engine.Static("/img", "./img")
//app.Static("/img", "./img")
//设置html的目录
//app.LoadHTMLGlob("./static/html/*")
//{{.title}}context.HTML来加载HTMl页面或者模板
5.使用路由组分类处理请求
Group
gin框架中可以使用路由组来实现对路由的分类。
路由组是router.Group中的一个方法,用于对请求进行分组。如下案例所示:
userGroup := engine.Group("/user")
userGroup.GET("/register", registerHandle)
userGroup.GET("/login", loginHandle)
userGroup.GET("/info", infoHandle)
engine.Run(":9000")
6.middleware的编写与使用
Gin的中间件
在gin中,中间件称之为middleware,中间件的类型定义如下所示:
type HandlerFunc func(*Context)
HandlerFunc是一个函数类型,接收一个Context参数。用于编写程序处理函数并返回HandleFunc类型,作为中间件的定义。
中间件Use用法
在之前学习的课程中,均使用gin.Default创建了gin引擎engins变量,其中,就使用了中间件。如下图所示:
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
//Log中间件
func Logger() HandlerFunc {
return LoggerWithConfig(LoggerConfig{})
}
//Recovery中间件
func Recovery() HandlerFunc {
return RecoveryWithWriter(DefaultErrorWriter)
}
在Default函数中,engine调用Use方法设置了Logger中间件和Recovery中间件。Use函数接收一个可变参数,类型为HandlerFunc,恰为中间件的类型。Use方法定义如下:
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...)
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}
自定义中间件
根据上文的介绍,可以自己定义实现一个特殊需求的中间件,中间件的类型是函数,有两条标准:
func函数
返回值类型为HandlerFunc
定义一个名为RequestInfos的中间件,在该中间件中打印请求的path和method。具体代码实现如下所示:
func RequestInfos() gin.HandlerFunc {
return func(context *gin.Context) {
path := context.FullPath()
method := context.Request.Method
fmt.Println("请求Path:", path)
fmt.Println("请求Method:", method)
}
}
func main() {
engine := gin.Default()
engine.Use(RequestInfos())
engine.GET("/query", func(context *gin.Context) {
context.JSON(200, map[string]interface{}{
"code": 1,
"msg": context.FullPath(),
})
})
engine.Run(":9000")
}
context.Next函数
context.Next函数可以将中间件代码的执行顺序一分为二,Next函数调用之前的代码在请求处理之前之前,当程序执行到context.Next时,会中断向下执行,转而先去执行具体的业务逻辑,执行完业务逻辑处理函数之后,程序会再次回到context.Next处,继续执行中间件后续的代码。具体用法如下:
func main() {
engine := gin.Default()
engine.Use(RequestInfos())
engine.GET("/query", func(context *gin.Context) {
fmt.Println(" 中间件的使用方法 ")
context.JSON(404, map[string]interface{}{
"code": 1,
"msg": context.FullPath(),
})
})
engine.Run(":9000")
}
func RequestInfos() gin.HandlerFunc {
return func(context *gin.Context) {
path := context.FullPath()
method := context.Request.Method
fmt.Println("请求Path:", path)
fmt.Println("请求Method:", method)
context.Next()
fmt.Println(context.Writer.Status())
}
}
结果
请求Path: /query
请求Method: GET
中间件的使用方法
404
7. Gin框架中使用数据库
1.安装数据库
2.安装MySQL驱动
go get "github.com/go-sql-driver/mysql"
3.、创建数据库
mysql -uroot -p
create database ginsql;
4.gin_使用
a、引入mysql驱动程序:使用import将mysql驱动默认引入,具体语法如下:
import _ "github.com/go-sql-driver/mysql"
b、拼接链接字符:在程序中链接mysql,需要按照一定的规则进行用户名,密码等信息的组合。
connStr := "root:12345678@tcp(127.0.0.1:3306)/ginsql"
c、使用sql.Open创建数据库连接
db, err := sql.Open("mysql", connStr)
if err != nil {
log.Fatal(err.Error())
return
}
5.操作数据库
a、 创建数据库表
_, err = db.Exec("create table person(" +
"id int auto_increment primary key," +
"name varchar(12) not null," +
"age int default 1" +
");")
if err != nil {
log.Fatal(err.Error())
return
}
b、向数据库中插入数据
_, err = db.Exec("insert into person(name,age) "+
"values(?,?);", "Lily", 15)
if err != nil {
log.Fatal(err.Error())
return
} else {
fmt.Println("数据插入成功")
}
c、查询数据库记录
rows, err := db.Query("select id,name,age from person")
if err != nil {
log.Fatal(err.Error())
return
}
scan:
if rows.Next() {
//columns, err := rows.Columns()
//fmt.Println(columns)
person := new(Person)
err = rows.Scan(&person.Id, &person.Name, &person.Age)
if err != nil {
log.Fatal(err.Error())
return
}
fmt.Println(person.Id, person.Name, person.Age)
goto scan
}
8.项目开发介绍及初始化
创建项目
在gopath的src目录下,创建OnlineRestaurant目录,作为服务端项目。
mkdir CloudRestaurant
创建配置文件目录
mkdir config
config目录中,配置app.json配置文件:
{
"app_name": "qianfengmall",
"app_mode": "debug",
"app_host": "localhost",
"app_port": "8090"
}
并创建Config.go文件,用于解析项目配置信息。Config.go如下:
type Config struct {
AppName string json:"app_name"
AppMode string json:"app_mode"
AppHost string json:"app_host"
AppPort string json:"app_port"
}
var _cfg *Config = nil
func GetConfig() *Config {
return _cfg
}
func ParseConfig(path string) (*Config, error) {
file, err := os.Open(path)
if err != nil {
panic(err)
}
defer file.Close()
reader := bufio.NewReader(file)
decoder := json.NewDecoder(reader)
if err := decoder.Decode(&_cfg); err != nil {
return nil, err
}
return _cfg, nil
}
编写main.go
func main() {
//读取配置文件
cfg, err := toolbox.ParseConfig("./config/app.json")
if err != nil {
toolbox.Error(err.Error())
return
}
app := gin.Default()
app.Run(cfg.AppHost + ":" + cfg.AppPort)
}
编写Hell world
编写Controller:创建controller,并创建HelloController。
package controller
import "github.com/gin-gonic/gin"
type HelloController struct {
}
func (hello *HelloController) Router(engine *gin.Engine) {
engine.GET("/hello", hello.Hello)
}
func (hello *HelloController) Hello(context *gin.Context) {
context.JSON(200, map[string]interface{}{
"message": "hello world",
})
}
在main.go程序中添加路由设置
func registerRouter(router *gin.Engine) {
new(controller.HelloController).Router(router)
}
9.创建数据库和数据表
xorm介绍
在项目开发过程中,我们会使用一些成熟的框架来操作数据库。xorm就是一个比较流行的数据库操作orm框架。
xorm安装及mysql驱动
go get github.com/go-xorm/xorm
//安装mysql驱动:
go get github.com/go-sql-driver/mysql
连接数据库
create database cloudrestaurant;
创建完数据库并安装好xorm库以后,使用xorm进行连接数据库。具体的连接操作如下所示:
import (
"github.com/go-xorm/xorm"
_ "github.com/go-sql-driver/mysql"
)
database := cfg.Database
conn := database.User + ":" + database.Password + "@tcp(" + database.Host + ":" + database.Port + ")/" + database.DbName + "?charset=" + database.Charset
engine, err := xorm.NewEngine(database.Driver, conn)
if err != nil {
return nil, err
}
连接数据库有些参数需要自己指定,比如说驱动类型,登录数据库的用户名,密码,数据库名等。将这些变量配置在app.json配置文件中,如下所示:
{
...
"database": {
"driver": "mysql",
"user": "root",
"password": "12345678",
"host": "127.0.0.1",
"port": "3306",
"db_name": "cloudrestaurant",
"charset": "utf8mb4",
"show_sql": true
}
...
}
并在Config结构体中添加对dtabase的解析:
type Config struct {
AppName string json:"app_name"
AppMode string json:"app_mode"
AppHost string json:"app_host"
AppPort string json:"app_port"
Database DatabaseConfig json:"database"
Sms SmsConfig json:"sms"
}
type DatabaseConfig struct {
Driver string json:"driver"
User string json:"user"
Password string json:"password"
Host string json:"host"
Port string json:"port"
DbName string json:"db_name"
Charset string json:"charset"
ShowSql bool json:"show_sql"
}
创建SmsCode
要存储验证码,需要在数据库中创建表结构进行存储。我们可以创建SmsCode结构体,并通过tag设置数据库字段约束,具体的SmsCode定义如下:
package model
type SmsCode struct {
Id int64 xorm:"pk autoincr" json:"id"
Phone string xorm:"varchar(11)" json:"phone"
BizId string xorm:"varchar(30)" json:"biz_id"
Code string xorm:"varchar(4)" json:"code"
CreateTime int64 xorm:"bigint" json:"create_time"
}
通过tag的xorm设置字段数据类型以及约束。
- pk:表示主键
- autoinc:表示自增
- bigint:整形变量
- varchar:字符串类型
Sync2同步生成数据库表
可以调用engine.Sync2方法,将结构体类型同步映射到数据库中,生成数据库表。
err = engine.Sync2(new(model.SmsCode))
if err != nil {
return nil, err
}
将验证码数据保存到数据库中
在MemberService的SendCode方法,添加保存验证码到数据库的操作
func (msi *MemberServiceImpl) SendCode(phone string) string {
code := fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
...
dao := impl.NewMemberDao()
smsCode := model.SmsCode{Phone: phone, Code: code, BizId: response.BizId, CreateTime: time.Now().Unix()}
if result := dao.InsertCode(smsCode); result > 0 {
return code
}
return ""
}
10.服务器全局跨域请求处理设置
服务端设置跨域访问
可以在gin服务端,编写程序进行全局设置。通过中间件的方式设置全局跨域访问,用以返回Access-Control-Allow-Origin和浏览器进行匹配。
在服务端编写跨域访问中间件,详细内容如下:
func Cors() gin.HandlerFunc {
return func(context *gin.Context) {
method := context.Request.Method
origin := context.Request.Header.Get("Origin")
var headerKeys []string
for k, _ := range context.Request.Header {
headerKeys = append(headerKeys, k)
}
headerStr := strings.Join(headerKeys, ",")
if headerStr != "" {
headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
} else {
headerStr = "access-control-allow-origin, access-control-allow-headers"
}
if origin != "" {
context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
context.Header("Access-Control-Max-Age", "172800")
context.Header("Access-Control-Allow-Credentials", "false")
context.Set("content-type", "application/json") //// 设置返回格式是json
}
if method == "OPTIONS" {
context.JSON(http.StatusOK, "Options Request!")
}
//处理请求
context.Next()
}
}
其中的Access-Control-Allow-Origin的设置,表示允许进行跨域访问,*表示可以访问所有域。同时,通过Header方法进行了其他的设置。
最后context.Next()是中间件使用的标准用法,表示继续处理请求。
在main函数中,调用编写好的跨域访问。调用如下:
func main(){
...
app := gin.Default()
app.Use(Cors())
...
}
11.图形化验证码生成和验证
验证码库安装
go get -u github.com/mojocn/base64Captcha
通过自定义配置,可以选择不同的生成验证码的参数,并刷新验证码,同时还可以对验证码进行验证。
通过exmaple目录下的main.go程序可以看到生成验证码和验证验证码的逻辑,此处不再赘述。
项目集成验证码生成和Redis缓存
安装go-redis库
在项目中使用redis,需要安装go-redis库,可以在https://github.com/go-redis/redis中查看如何下载go-redis和配置。
增加Redis配置
在配置文件app.json中新增redis配置:
"redis_config": {
"addr": "127.0.0.1",
"port": "6379",
"password": "",
"db": 0
}
...
同时,新增RedisConfig结构体定义,如下所示:
type RedisConfig struct {
Addr string json:"addr"
Port string json:"port"
Db int json:"db"
}
Redis初始化操作
进行了redis配置以后,需要对redis进行初始化。可以封装redis初始化操作函数如下所示:
type RedisStore struct {
redisClient *redis.Client
}
var Redis *redis.Client
func InitRediStore() *RedisStore {
config := GetConfig().RedistConfig
Redis = redis.NewClient(&redis.Options{
Addr: config.Addr + ":" + config.Port,
Password: "",
DB: config.Db,
})
customeStore := &RedisStore{Redis}
base64Captcha.SetCustomStore(customeStore)
return customeStore
}
同时,为customeStore提供Set和Get两个方法,如下所示:
func (cs *RedisStore) Set(id string, value string) {
err := cs.redisClient.Set(id, value, time.Minute*10).Err()
if err != nil {
log.Println(err.Error())
}
}
func (cs *RedisStore) Get(id string, clear bool) string {
val, err := cs.redisClient.Get(id).Result()
if err != nil {
toolbox.Error(err.Error())
return ""
}
if clear {
err := cs.redisClient.Del(id).Err()
if err != nil {
toolbox.Error(err.Error())
return ""
}
}
return val
}
[https://bbs.csdn.net/topics/603464006?utm_source=1594742339](“我的Go+语言初体验” | 征文活动进行中......)