您的位置:首页 > 数据库

03 . Go框架之Gin框架从入门到熟悉(Cookie和Session,数据库操作)

2020-10-31 17:22 1026 查看

Cookie

Cookie是什么

HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出

Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思

Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求

Cookie由服务器创建,并发送给浏览器,最终由浏览器保存

Cookie的用途

保持用户登录状态

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

测试服务器发送cookie给客户端,客户端请求时携带cookie

package mainimport ("fmt""github.com/gin-gonic/gin")func main() {// 1.创建路由// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()// 服务端要给客户端r.GET("cookie", func(c *gin.Context) {// 获取客户端是否携带cookiecookie,err := c.Cookie("key_cookie")if err != nil {cookie = "NotSet"// 给客户端设置cookie// maxAge int, 单位 s// path cookie  所在目录// domain string  域名// secure  是否只能通过https访问// httponly bool  是否允许别人通过js获取自己的cookiec.SetCookie("key_cookie","value_cookie",60,"/","localhost",false,true)}fmt.Printf("cookie的值是: %s\n",cookie)})r.Run()}

模拟实现权限验证中间件

package mainimport ("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()  创建一个新的sessionGetSession()   通过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存到内存中的mapGet(): 取数据,实现延迟加载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 dbimport ("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 modeltype 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 mainimport ("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,})}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: