03 . Go框架之Gin框架從入門到熟悉(Cookie和Session,數據庫操作)


Cookie是什么

HTTP是無狀態協議,服務器不能記錄瀏覽器的訪問狀態,也就是說服務器不能區分兩次請求是否由同一個客戶端發出

Cookie就是解決HTTP協議無狀態的方案之一,中文是小甜餅的意思

Cookie實際上就是服務器保存在瀏覽器上的一段信息。瀏覽器有了Cookie之后,每次向服務器發送請求時都會同時將該信息發送給服務器,服務器收到請求后,就可以根據該信息處理請求

Cookie由服務器創建,並發送給瀏覽器,最終由瀏覽器保存

Cookie的用途

保持用戶登錄狀態

Cookie的缺點
/*
		不安全,明文
		增加帶寬消耗
		可以被禁用
		Cookie有上限
*/
Cookie的使用

測試服務器發送cookie給客戶端,客戶端請求時攜帶cookie

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func main() {
	// 1.創建路由
	// 默認使用了2個中間件Logger(), Recovery()
	r := gin.Default()

	// 服務端要給客戶端
	r.GET("cookie", func(c *gin.Context) {
		// 獲取客戶端是否攜帶cookie
		cookie,err := c.Cookie("key_cookie")
		if err != nil {
			cookie = "NotSet"
			// 給客戶端設置cookie
			// maxAge int, 單位 s
			// path cookie  所在目錄
			// domain string  域名
			// secure  是否只能通過https訪問
			// httponly bool  是否允許別人通過js獲取自己的cookie
			c.SetCookie("key_cookie","value_cookie",60,"/","localhost",false,true)
		}
		fmt.Printf("cookie的值是: %s\n",cookie)
	})
	r.Run()
}

模擬實現權限驗證中間件

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func AuthMiddleWare() gin.HandlerFunc {
	return func(c *gin.Context) {
		if cookie, err := c.Cookie("abc"); err == nil {
			if cookie == "123" {
				c.Next()
				return
			}
		}
		// 返回錯誤
		c.JSON(http.StatusUnauthorized,gin.H{"error":"err"})
		c.Abort()
		return
	}
}

func main() {
	// 1.創建路由
	// 默認使用了2個中間件Logger(), Recovery()
	r := gin.Default()
	r.GET("/login", func(c *gin.Context) {
		c.SetCookie("abc","123",60,"/","localhost",false,true)
		c.String(200,"Login success!")
	})

	r.GET("/home",AuthMiddleWare(), func(c *gin.Context) {
		c.JSON(200,gin.H{"data":"home"})
	})
	r.Run()
}

Session

Session是什么

Session可以彌補Cookie的不足, Session必須依賴於Cookie才能使用, 生成一個SessionID放在Cookie里傳到客戶端就可以.

Session中間件開發

設計一個通用的Session服務, 支持內存存儲和redis存儲

Session模塊設計

/*
		本質上k-v系統,通過key進行增刪改查.
		Session可以存儲在內存或者redis(2個版本)
*/

Session接口設計

/*
		Set()
		Get()
		Del()
		Save()  session存儲, redis的實現延遲加載
*/

SessionMgr接口設計

/*
		Init()  初始化,加載redis地址
		CreateSession()  創建一個新的session
		GetSession()   通過SessionID獲取對應的Session對象
*/

MemorySession設計

/*
		定義MemorySession對象 (字段:  SessionID, 存kv的map,讀寫鎖)
		構造函數,為了獲取對象
		Set()
		Get()
		Del()
		Save()
*/

MemorySessionMgr設計

/*
		定義MemorySessionMgr對象(字段: 存放所有session的map, 讀寫鎖)
		構造函數
		Init()
		CreateSession()
		GetSession()
*/

RedisSession設計

/*
		定義RedisSession對象(字段: sessionID,存kv的map, 讀寫鎖, redis連接池, 記錄內存中map是否被修改的標記)
		
		構造函數
		
		Set(): 將session存到內存中的map
		Get(): 取數據,實現延遲加載
		Del()
		Save():  將session存到redis
*/

RedisSessionMgr設計

/*
		定義RedisSessionMgr對象(字段: redis地址,redis密碼, 連接池,讀寫鎖, 大map)
		構造函數
		Init()
		CreateeSession()
		GetSession()
*/

session.go


數據庫操作

sql
CREATE TABLE `book` (
  `id` int(50) NOT NULL AUTO_INCREMENT,
  `title` varchar(50) DEFAULT NULL,
  `price` int(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
結構
 tree 
.
├── book
├── db
│   └── db.go
├── go.mod
├── go.sum
├── main.go
├── model
│   └── book.go
└── templates
    ├── book_list.html
    └── new_book.html
db

db.go

// 查詢單條數據示例
package db

import (
	"database_test1/model"
	"fmt"
	_ "github.com/go-sql-driver/mysql" // init()
	"github.com/jmoiron/sqlx"
)

// Go連接MySQL示例

var db *sqlx.DB // 是一個連接池對象

func InitDB() (err error) {
	// 數據庫信息
	// 用戶名:密碼@tcp(ip:端口)/數據庫的名字
	dsn := "test:ZHOUjian.22@tcp(121.36.43.223:3306)/book?charset=utf8"

	// 連接數據庫
	db, err = sqlx.Connect("mysql", dsn)
	if err != nil {
		return
	}
	db.SetMaxOpenConns(10) // 設置數據庫連接池的最大連接數
	db.SetMaxIdleConns(5)  // 設置最大空閑連接數
	return
}


func QueryAllBook() (bookList []*model.Book,err error)  {
	sqlStr := "select id,title,price from book"
	err = db.Select(&bookList,sqlStr)
	if err != nil {
		fmt.Println("查詢失敗")
		return
	}
	return
}

func InsertBook(title string,price int64) (err error)  {
	sqlStr := "insert into book(title,price) values(?,?)"
	_, err = db.Exec(sqlStr,title,price)
	if err != nil {
		fmt.Println("插入失敗")
		return
	}
	return
}

func DeleteBook(id int64) (err error)  {
	sqlStr := "delete from book where id =?"
	_,err = db.Exec(sqlStr,id)
	if err != nil {
		fmt.Println("刪除失敗")
		return
	}
	return
}
model

book.go

package model

type Book struct {
	ID string `db:"id"`
	Title string  `db:"title"`
	Price int64 `db:"price"`
}
template

book_list.html

{{ define "book_list.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>書籍列表</title>
</head>
<body>
    <div><a href="/book/new">添加新書</a></div>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>title</th>
                <th>price</th>
                <th>操作</th>
            </tr>
        </thead>

        <tbody>
            {{ range .data}}
                <tr>
                    <td>{{ .ID }}</td>
                    <td>{{ .Title }}</td>
                    <td>{{ .Price }}</td>
                    <td><a href="/book/delete?id={{ .ID }}">刪除</a></td>
                </tr>
            {{  end }}

        </tbody>

    </table>

</body>
</html>
{{ end }}

new_book.html

{{ define "new_book.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加圖書信息</title>
</head>
<body>
    <form action="/book/new" method="POST">

        <div>
            <label>書名:
                <input type="text" name="title">
            </label>
        </div>

        <div>
            <label>價格:
                <input type="number" name="price">
            </label>
        </div>

        <div>
            <input type="submit" value="點我">
        </div>

    </form>

</body>
</html>
{{ end }}
Main.go
package main

import (
	"database_test1/db"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main()  {
	// 初始化數據庫
	err := db.InitDB()
	if err != nil {
		panic(err)
	}

	r := gin.Default()
	r.LoadHTMLGlob("./templates/*")
	// 查詢所有圖書
	r.GET("/book/list",bookListHandler)
	r.Run()
}

func bookListHandler(c *gin.Context)  {
	bookList ,err := db.QueryAllBook()
	if err != nil {
		c.JSON(http.StatusOK,gin.H{
			"code":1,
			"msg":err,
		})
		return
	}

	// 返回數據
	c.HTML(http.StatusOK,"book_list.html",gin.H{
		"code":200,
		"data":bookList,
	})
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM