当前位置: 首页 > news >正文

做网站的问题怎么建立网上销售平台

做网站的问题,怎么建立网上销售平台,江苏省建设主管部门网站,调用wordpress编辑器Gin框架入门实战系列教程之Gin环境搭建 Gin程序的热加载 Gin路由 GET POST PUT DELETE 主讲教师#xff1a;#xff08;大地#xff09; 在线文档见网盘下载#xff1a; 百度网盘 请输入提取码 提取码#xff1a;abcd 一、Gin介绍 Gin 是一个 Go (Golang) 编写的轻量级…Gin框架入门实战系列教程之Gin环境搭建 Gin程序的热加载 Gin路由 GET POST PUT DELETE 主讲教师大地 在线文档见网盘下载 百度网盘 请输入提取码 提取码abcd 一、Gin介绍 Gin 是一个 Go (Golang) 编写的轻量级http web 框架运行速度非常快如果你是性能和高效的追求者我们推荐你使用Gin框架。 Gin最擅长的就是Api接口的高并发如果项目的规模不大业务相对简单这个时候我们也推荐您使用Gin。 当某个接口的性能遭到较大挑战的时候这个还是可以考虑使用Gin重写接口。 Gin也是一个流行的golang Web框架Github Strat量已经超过了50k。 Gin的官网Gin Web Framework Gin Github地址GitHub - gin-gonic/gin: Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin. 二、Gin环境搭建 要安装 Gin 软件包需要先安装 Go 并设置 Go 工作区。 1.下载并安装 gin $ go get -u github.com/gin-gonic/gin 2.将 gin 引入到代码中 import github.com/gin-gonic/gin 3.可选如果使用诸如 http.StatusOK 之类的常量则需要引入 net/http 包 import net/http 4、新建Main.go配置路由 package mainimport (github.com/gin-gonic/gin )func main() {// 创建一个默认的路由引擎r : gin.Default()// 配置路由r.GET(/, func(c *gin.Context) { c.JSON(200, gin.H{ // c.JSON返回JSON格式的数据message: Hello world!,})})// 启动HTTP服务默认在0.0.0.0:8080启动服务r.Run() }5、运行你的项目 $ go run main.go 6、要改变默认启动的端口 r.Run(:9000)如果go get失败请参考 Golang Beego中没法下载第三方包解决办法 三、golang程序的热加载 所谓热加载就是当我们对代码进行修改时程序能够自动重新加载并执行这在我们开发中是非常便利的可以快速进行代码测试省去了每次手动重新编译 beego中我们可以使用官方给我们提供的bee工具来热加载项目但是gin中并没有官方提供的热加载工具这个时候我们要实现热加载就可以借助第三方的工具。 工具1推荐GitHub - gravityblast/fresh: Build and (re)start go web apps after saving/creating/deleting source files. go get github.com/pilu/fresh D:\gin_demofresh 工具2GitHub - codegangsta/gin: Live reload utility for Go web servers go get -u github.com/codegangsta/gin D:\gin_demogin run main.go 四、Gin框架中的路由 4.1、路由概述 路由Routing是由一个 URI或者叫路径和一个特定的 HTTP 方法GET、POST 等组成的涉及到应用如何响应客户端对某个网站节点的访问。 RESTful API是目前比较成熟的一套互联网应用程序的API设计理论所以我们设计我们的路由的时候建议参考RESTful API指南。 在RESTful架构中每个网址代表一种资源不同的请求方式表示执行不同的操作 GETSELECT 从服务器取出资源一项或多项 POSTCREATE 在服务器新建一个资源 PUTUPDATE 在服务器更新资源客户端提供改变后的完整资源 DELETEDELETE 从服务器删除资源 4.2、简单的路由配置 简单的路由配置(可以通过postman测试) 当用GET请求访问一个网址的时候做什么事情 r.GET(网址, func(c *gin.Context) { c.String(200, Get)}) 当用POST访问一个网址的时候做什么事情 r.POST(网址, func(c *gin.Context) { c.String(200, POST) }) 当用PUT访问一个网址的时候执行的操作 r.PUT(网址, func(c *gin.Context) {c.String(200, PUT) }) 当用DELETE访问一个网址的时候执行的操作 r.DELETE(网址, func(c *gin.Context) { c.String(200, DELETE) }) 路由里面获取Get传值 域名/news?aid20 r.GET(/news, func(c *gin.Context) {aid : c.Query(aid)c.String(200, aid%s, aid) }) 动态路由 域名/user/20 r.GET(/user/:uid, func(c *gin.Context) {uid : c.Param(uid)c.String(200, userID%s, uid) }) 4.3、 c.String( c.JSON() c.JSONP() c.XML() c.HTML() 返回一个字符串 r.GET(/news, func(c *gin.Context) {aid : c.Query(aid)c.String(200, aid%s, aid) }) 返回一个JSON数据 func main() {r : gin.Default()// gin.H 是map[string]interface{}的缩写r.GET(/someJSON, func(c *gin.Context) {// 方式一自己拼接JSONc.JSON(http.StatusOK, gin.H{message: Hello world!})})r.GET(/moreJSON, func(c *gin.Context) {// 方法二使用结构体var msg struct {Name string json:userMessage stringAge int}msg.Name IT营学院msg.Message Hello world!msg.Age 18c.JSON(http.StatusOK, msg)})r.Run(:8080) }JSOPN func main() {r : gin.Default()r.GET(/JSONP, func(c *gin.Context) {data : map[string]interface{}{foo: bar,}// /JSONP?callbackx// 将输出x({\foo\:\bar\})c.JSONP(http.StatusOK, data)})// 监听并在 0.0.0.0:8080 上启动服务r.Run(:8080) }返回XML数据 func main() {r : gin.Default()// gin.H 是map[string]interface{}的缩写r.GET(/someXML, func(c *gin.Context) {// 方式一自己拼接JSONc.XML(http.StatusOK, gin.H{message: Hello world!})})r.GET(/moreXML, func(c *gin.Context) {// 方法二使用结构体type MessageRecord struct {Name stringMessage stringAge int}var msg MessageRecordmsg.Name IT营学院msg.Message Hello world!msg.Age 18c.XML(http.StatusOK, msg)})r.Run(:8080) }渲染模板 router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, default/index.html, map[string]interface{}{title: 前台首页 }) }) 五、Gin HTML模板渲染 5.1、全部模板放在一个目录里面的配置方法 1、我们首先在项目根目录新建templates文件夹然后在文件夹中新建index.html !DOCTYPE html html langen headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title /head bodyh1这是一个html模板/h1h3{{.title}}/h3 /body /html2、Gin框架中使用c.HTML可以渲染模板渲染模板前需要使用LoadHTMLGlob()或者LoadHTMLFiles()方法加载模板。 router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, default/index.html, map[string]interface{}{title: 前台首页 }) }) router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, index.html, gin.H{title: Main website,}) }) package mainimport (net/httpgithub.com/gin-gonic/gin )func main() {router : gin.Default()router.LoadHTMLGlob(templates/*)//router.LoadHTMLFiles(templates/template1.html, templates/template2.html)router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, index.html, gin.H{title: Main website,})})router.Run(:8080) }5.2、模板放在不同目录里面的配置方法 Gin框架中如果不同目录下面有同名模板的话我们需要使用下面方法加载模板 注意定义模板的时候需要通过define定义名称 templates/admin/index.html !-- 相当于给模板定义一个名字 define end 成对出现-- {{ define admin/index.html }}!DOCTYPE htmlhtml langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title/headbodyh1后台模板/h1h3{{.title}}/h3/body/html {{ end }} templates/default/index.html !-- 相当于给模板定义一个名字 define end 成对出现-- {{ define default/index.html }}!DOCTYPE htmlhtml langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title/headbodyh1前台模板/h1h3{{.title}}/h3/body/html {{end}}业务逻辑 package mainimport (net/httpgithub.com/gin-gonic/gin )func main() {router : gin.Default()router.LoadHTMLGlob(templates/**/*) router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, default/index.html, gin.H{title: 前台首页,})})router.GET(/admin, func(c *gin.Context) {c.HTML(http.StatusOK, admin/index.html, gin.H{title: 后台首页,})})router.Run(:8080) }注意如果模板在多级目录里面的话需要这样配置r.LoadHTMLGlob(“templates///*”) /**表示目录 5.3、gin模板基本语法 1、{{.}} 输出数据 模板语法都包含在{{和}}中间其中{{.}}中的点表示当前对象。 当我们传入一个结构体对象时我们可以根据.来访问结构体的对应字段。例如 业务逻辑 package mainimport (net/httpgithub.com/gin-gonic/gin )type UserInfo struct {Name stringGender stringAge int }func main() {router : gin.Default()router.LoadHTMLGlob(templates/**/*)user : UserInfo{Name: 张三,Gender: 男,Age: 18,}router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, default/index.html, map[string]interface{}{title: 前台首页,user: user,})})router.Run(:8080) } 模板 !-- 相当于给模板定义一个名字 define end 成对出现-- {{ define default/index.html }} !DOCTYPE html html langen headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title /head bodyh1前台模板/h1h3{{.title}}/h3h4{{.user.Name}}/h4h4{{.user.Age}}/h4 /body /html {{end}}2、注释 {{/* a comment */}} 注释执行时会忽略。可以多行。注释不能嵌套并且必须紧贴分界符始止。 3、变量 我们还可以在模板中声明变量用来保存传入模板的数据或其他语句生成的结果。具体语法如下 h4{{$obj : .title}}/h4h4{{$obj}}/h4 4、移除空格 有时候我们在使用模板语法的时候会不可避免的引入一下空格或者换行符这样模板最终渲染出来的内容可能就和我们想的不一样这个时候可以使用{{-语法去除模板内容左侧的所有空白符号 使用-}}去除模板内容右侧的所有空白符号。 例如 {{- .Name -}} 注意-要紧挨{{和}}同时与模板值之间需要使用空格分隔。 5、比较函数 布尔函数会将任何类型的零值视为假其余视为真。 下面是定义为函数的二元比较运算的集合 eq 如果arg1 arg2则返回真 ne 如果arg1 ! arg2则返回真 lt 如果arg1 arg2则返回真 le 如果arg1 arg2则返回真 gt 如果arg1 arg2则返回真 ge 如果arg1 arg2则返回真 6、条件判断 Go模板语法中的条件判断有以下几种: {{if pipeline}} T1 {{end}}{{if pipeline}} T1 {{else}} T0 {{end}}{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}{{if gt .score 60}} 及格 {{else}} 不及格 {{end}}{{if gt .score 90}} 优秀 {{else if gt .score 60}} 及格 {{else}} 不及格 {{end}} 6、range Go的模板语法中使用range关键字进行遍历有以下两种写法其中pipeline的值必须是数组、切片、字典或者通道。 {{range $key,$value : .obj}} {{$value}} {{end}} 如果pipeline的值其长度为0不会有任何输出 {{range $key,$value : .obj}} {{$value}} {{else}} pipeline的值其长度为0 {{end}} 如果pipeline的值其长度为0则会执行T0。 router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, default/index.html, map[string]interface{}{ hobby: []string{吃饭, 睡觉, 写代码},}) }) {{range $key,$value : .hobby}}p{{$value}}/p {{end}} 7、With user : UserInfo{Name: 张三,Gender: 男,Age: 18,}router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, default/index.html, map[string]interface{}{user: user,})}) 以前要输出数据 h4{{.user.Name}}/h4h4{{.user.Gender}}/h4h4{{.user.Age}}/h4 现在要输出数据 {{with .user}}h4姓名{{.Name}}/h4h4性别{{.user.Gender}}/h4h4年龄{{.Age}}/h4{{end}} 简单理解相当于var ..user 8、预定义函数 了解 执行模板时函数从两个函数字典中查找首先是模板函数字典然后是全局函数字典。一般不在模板内定义函数而是使用Funcs方法添加函数到模板里。 预定义的全局函数如下 and 函数返回它的第一个empty参数或者最后一个参数 就是说and x y等价于if x then y else x所有参数都会执行 or 返回第一个非empty参数或者最后一个参数 亦即or x y等价于if x then x else y所有参数都会执行 not 返回它的单个参数的布尔值的否定 len 返回它的参数的整数类型长度 index 执行结果为第一个参数以剩下的参数为索引/键指向的值 如index x 1 2 3返回x[1][2][3]的值每个被索引的主体必须是数组、切片或者字典。 print 即fmt.Sprint printf 即fmt.Sprintf println 即fmt.Sprintln html 返回与其参数的文本表示形式等效的转义HTML。 这个函数在html/template中不可用。 urlquery 以适合嵌入到网址查询中的形式返回其参数的文本表示的转义值。 这个函数在html/template中不可用。 js 返回与其参数的文本表示形式等效的转义JavaScript。 call 执行结果是调用第一个参数的返回值该参数必须是函数类型其余参数作为调用该函数的参数 如call .X.Y 1 2等价于go语言里的dot.X.Y(1, 2) 其中Y是函数类型的字段或者字典的值或者其他类似情况 call的第一个参数的执行结果必须是函数类型的值和预定义函数如print明显不同 该函数类型值必须有1到2个返回值如果有2个则后一个必须是error接口类型 如果有2个返回值的方法返回的error非nil模板执行会中断并返回给调用模板执行者该错误 {{len .title}}{{index .hobby 2}} 9、自定义模板函数 router.SetFuncMap(template.FuncMap{formatDate: formatAsDate, }) package mainimport (fmthtml/templatenet/httptimegithub.com/gin-gonic/gin )func formatAsDate(t time.Time) string {year, month, day : t.Date()return fmt.Sprintf(%d/%02d/%02d, year, month, day) } func main() {router : gin.Default()//注册全局模板函数 注意顺序注册模板函数需要在加载模板上面router.SetFuncMap(template.FuncMap{formatDate: formatAsDate,})//加载模板router.LoadHTMLGlob(templates/**/*) router.GET(/, func(c *gin.Context) {c.HTML(http.StatusOK, default/index.html, map[string]interface{}{title: 前台首页, now: time.Now(),})})router.Run(:8080) }模板里面的用法 {{.now | formatDate}} 或者 {{formatDate .now }}5.4、嵌套template 1、新建templates/deafult/page_header.html {{ define “default/page_header.html” }} h1这是一个头部/h1 {{end}} 2、外部引入 注意 1、引入的名字为page_header.html中定义的名字 2、引入的时候注意最后的点. {{template “default/page_header.html” .}} !-- 相当于给模板定义一个名字 define end 成对出现– {{ define “default/index.html” }} !DOCTYPE html html lang“en” head meta charset“UTF-8” meta http-equiv“X-UA-Compatible” content“IEedge” meta name“viewport” content“widthdevice-width, initial-scale1.0” titleDocument/title /head body {{template “default/page_header.html” .}} /body /html {{end}} 六、静态文件服务 当我们渲染的HTML文件中引用了静态文件时,我们需要配置静态web服务 r.Static(/static, “./static”) 前面的/static表示路由 后面的./static表示路径 func main() { r : gin.Default() r.Static(/static, “./static”) r.LoadHTMLGlob(“templates/**/*”) // … r.Run(:8080) } link rel“stylesheet” href/static/css/base.css / 七、路由详解 路由Routing是由一个 URI或者叫路径和一个特定的 HTTP 方法GET、POST 等组成的涉及到应用如何响应客户端对某个网站节点的访问。 前面章节我们给大家介绍了路由基础以及路由配置这里我们详细给大家讲讲路由传值、路由返回值 7.1、GET POST 以及获取Get Post传值 7.1.1、Get请求传值 GET /user?uid20page1 router.GET(/user, func(c *gin.Context) { uid : c.Query(“uid”) page : c.DefaultQuery(“page”, “0”) c.String(200, “uid%v page%v”, uid, page) }) 7.1.2、动态路由传值 域名/user/20 r.GET(/user/:uid, func(c *gin.Context) { uid : c.Param(“uid”) c.String(200, “userID%s”, uid) }) 7.1.3、Post请求传值 获取form表单数据 定义一个add_user.html的页面 {{ define “default/add_user.html” }} !DOCTYPE html html lang“en” head meta charset“UTF-8” meta http-equiv“X-UA-Compatible” content“IEedge” meta name“viewport” content“widthdevice-width, initial-scale1.0” titleDocument/title /head body form action/doAddUser method“post” 用户名input typetext nameusername /密码: input typepassword namepassword /input typesubmit value提交 /form /body /html {{end}} 通过c.PostForm 接收表单传过来的数据 router.GET(/addUser, func(c *gin.Context) { c.HTML(200, “default/add_user.html”, gin.H{}) }) router.POST(/doAddUser, func(c *gin.Context) { username : c.PostForm(“username”) password : c.PostForm(“password”) age : c.DefaultPostForm(“age”, “20”) c.JSON(200, gin.H{usernmae: username,password: password,age: age,}) }) 7.1.4、获取GET POST传递的数据绑定到结构体 为了能够更方便的获取请求相关参数提高开发效率我们可以基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中QueryString、form表单、JSON、XML等参数到结构体中。 下面的示例代码演示了.ShouldBind()强大的功能它能够基于请求自动提取JSON、form表单和QueryString类型的数据并把值绑定到指定的结构体对象。 //注意首字母大写 type Userinfo struct { Username string form:username json:user Password string form:password json:password } Get传值绑定到结构体 /?usernamezhangsanpassword123456 router.GET(/, func(c *gin.Context) { var userinfo Userinfo if err : c.ShouldBind(userinfo); err nil { c.JSON(http.StatusOK, userinfo) } else { c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()}) } }) 返回数据 {“user”:“zhangsan”,“password”:“123456”} Post传值绑定到结构体 router.POST(/doLogin, func(c *gin.Context) { var userinfo Userinfo if err : c.ShouldBind(userinfo); err nil { c.JSON(http.StatusOK, userinfo) } else { c.JSON(http.StatusBadRequest, gin.H{“error”: err.Error()}) } }) 返回数据 {“user”:“zhangsan”,“password”:“123456”} 7.1.5、获取Post Xml数据 在 API 的开发中我们经常会用到 JSON 或 XML 来作为数据交互的格式这个时候我们可以在gin中使用c.GetRawData()获取数据。 ?xml version“1.0” encoding“UTF-8”? article content type“string”我是张三/content title type“string”张三/title /article type Article struct { Title string xml:title Content string xml:content } router.POST(/xml, func(c *gin.Context) { b, _ : c.GetRawData() // 从c.Request.Body读取请求数据 article : Article{}if err : xml.Unmarshal(b, article); err nil {c.JSON(http.StatusOK, article)} else {c.JSON(http.StatusBadRequest, err.Error())} }) 7.2、简单的路由组 func main() { router : gin.Default() // 简单的路由组: v1 v1 : router.Group(/v1) {v1.POST(/login, loginEndpoint)v1.POST(/submit, submitEndpoint)v1.POST(/read, readEndpoint) }// 简单的路由组: v2 v2 : router.Group(/v2) {v2.POST(/login, loginEndpoint)v2.POST(/submit, submitEndpoint)v2.POST(/read, readEndpoint) }router.Run(:8080) } 7.3、Gin路由文件 分组 8.2.1、新建routes文件夹routes文件下面新建adminRoutes.go、apiRoutes.go、defaultRoutes.go 1、新建adminRoutes.go package routes import ( “net/http” github.com/gin-gonic/gin ) func AdminRoutesInit(router *gin.Engine) { adminRouter : router.Group(/admin) { adminRouter.GET(/user, func(c *gin.Context) { c.String(http.StatusOK, “用户”) }) adminRouter.GET(/news, func(c *gin.Context) { c.String(http.StatusOK, “news”) }) } } 2、新建apiRoutes.go package routes import ( “net/http” github.com/gin-gonic/gin ) func ApiRoutesInit(router *gin.Engine) { apiRoute : router.Group(/api) { apiRoute.GET(/user, func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ “username”: “张三”, “age”: 20, }) }) apiRoute.GET(/news, func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ “title”: “这是新闻”, }) }) } } 3、新建defaultRoutes.go package routes import ( “github.com/gin-gonic/gin” ) func DefaultRoutesInit(router *gin.Engine) { defaultRoute : router.Group(/) { defaultRoute.GET(/, func(c *gin.Context) { c.String(200, “首页”) }) } } 8.2.2 、配置main.go package main import ( “gin_demo/routes” github.com/gin-gonic/gin ) //注意首字母大写 type Userinfo struct { Username string form:username json:user Password string form:password json:password } func main() { r : gin.Default() routes.AdminRoutesInit® routes.ApiRoutesInit® routes.DefaultRoutesInit® r.Run(:8080) } 访问 /api/user /admin/user测试 八、Gin中自定义控制器 9.1、控制器分组 当我们的项目比较大的时候有必要对我们的控制器进行分组 新建controller/admin/NewsController.go package admin import ( “net/http” github.com/gin-gonic/gin ) type NewsController struct { } func (c NewsController) Index(ctx *gin.Context) { ctx.String(http.StatusOK, “新闻首页”) } 新建controller/admin/UserController.go package admin import ( “net/http” github.com/gin-gonic/gin ) type UserController struct { } func (c UserController) Index(ctx *gin.Context) { ctx.String(http.StatusOK, “这是用户首页”) } func (c UserController) Add(ctx *gin.Context) { ctx.String(http.StatusOK, “增加用户”) } … 配置对应的路由 --adminRoutes.go 其他路由的配置方法类似 package routes import ( “gin_demo/controller/admin” “net/http” github.com/gin-gonic/gin ) func AdminRoutesInit(router *gin.Engine) { adminRouter : router.Group(/admin) { adminRouter.GET(/user, admin.UserController{}.Index) adminRouter.GET(/user/add, admin.UserController{}.Add) adminRouter.GET(/news, admin.NewsController{}.Add) } } 9.2、控制器的继承 1、新建controller/admin/BaseController.go package admin import ( “net/http” github.com/gin-gonic/gin ) type BaseController struct { } func (c BaseController) Success(ctx *gin.Context) { ctx.String(http.StatusOK, “成功”) } func (c BaseController) Error(ctx *gin.Context) { ctx.String(http.StatusOK, “失败”) } 2、NewsController 继承BaseController 继承后就可以调用控制器里面的公共方法了 package admin import ( “github.com/gin-gonic/gin” ) type NewsController struct { BaseController } func (c NewsController) Index(ctx *gin.Context) { c.Success(ctx) } 九、Gin中间件 Gin框架允许开发者在处理请求的过程中加入用户自己的钩子Hook函数。这个钩子函数就叫中间件中间件适合处理一些公共的业务逻辑比如登录认证、权限校验、数据分页、记录日志、耗时统计等。 通俗的讲中间件就是匹配路由前和匹配路由完成后执行的一系列操作 8.1、路由中间件 8.1.1、初识中间件 Gin中的中间件必须是一个gin.HandlerFunc类型配置路由的时候可以传递多个func回调函数最后一个func回调函数前面触发的方法都可以称为中间件。 package main import ( “fmt” github.com/gin-gonic/gin ) func initMiddleware(ctx *gin.Context) { fmt.Println(“我是一个中间件”) } func main() { r : gin.Default() r.GET(/, initMiddleware, func(ctx *gin.Context) { ctx.String(200, “首页–中间件演示”) }) r.GET(/news, initMiddleware, func(ctx *gin.Context) { ctx.String(200, “新闻页面–中间件演示”) }) r.Run(:8080) } 8.1.2、ctx.Next()调用该请求的剩余处理程序 中间件里面加上ctx.Next()可以让我们在路由匹配完成后执行一些操作。 比如我们统计一个请求的执行时间。 package main import ( “fmt” “time” github.com/gin-gonic/gin ) func initMiddleware(ctx *gin.Context) { fmt.Println(“1-执行中中间件”) start : time.Now().UnixNano() // 调用该请求的剩余处理程序 ctx.Next() fmt.Println(“3-程序执行完成 计算时间”) // 计算耗时 Go语言中的Since()函数保留时间值并用于评估与实际时间的差异 end : time.Now().UnixNano() fmt.Println(end - start) } func main() { r : gin.Default() r.GET(/, initMiddleware, func(ctx *gin.Context) { fmt.Println(“2-执行首页返回数据”) ctx.String(200, “首页–中间件演示”) }) r.GET(/news, initMiddleware, func(ctx *gin.Context) { ctx.String(200, “新闻页面–中间件演示”) }) r.Run(:8080) } 8.1.3、一个路由配置多个中间件的执行顺序 func initMiddlewareOne(ctx *gin.Context) { fmt.Println(“initMiddlewareOne–1-执行中中间件”) // 调用该请求的剩余处理程序 ctx.Next()fmt.Println(initMiddlewareOne--2-执行中中间件) } func initMiddlewareTwo(ctx *gin.Context) { fmt.Println(“initMiddlewareTwo–1-执行中中间件”) // 调用该请求的剩余处理程序 ctx.Next()fmt.Println(initMiddlewareTwo--2-执行中中间件) } func main() { r : gin.Default() r.GET(/, initMiddlewareOne, initMiddlewareTwo, func(ctx *gin.Context) { fmt.Println(“执行路由里面的程序”) ctx.String(200, “首页–中间件演示”) }) r.Run(:8080) } 控制台内容 initMiddlewareOne–1-执行中中间件 initMiddlewareTwo–1-执行中中间件 执行路由里面的程序 initMiddlewareTwo–2-执行中中间件 initMiddlewareOne–2-执行中中间件 8.1.4、 c.Abort()–了解 Abort是终止的意思 c.Abort() 表示终止调用该请求的剩余处理程序 package main import ( “fmt” github.com/gin-gonic/gin ) func initMiddlewareOne(ctx *gin.Context) { fmt.Println(“initMiddlewareOne–1-执行中中间件”) // 调用该请求的剩余处理程序 ctx.Next()fmt.Println(initMiddlewareOne--2-执行中中间件) } func initMiddlewareTwo(ctx *gin.Context) { fmt.Println(“initMiddlewareTwo–1-执行中中间件”) // 终止调用该请求的剩余处理程序 ctx.Abort()fmt.Println(initMiddlewareTwo--2-执行中中间件) } func main() { r : gin.Default() r.GET(/, initMiddlewareOne, initMiddlewareTwo, func(ctx *gin.Context) { fmt.Println(“执行路由里面的程序”) ctx.String(200, “首页–中间件演示”) }) r.Run(:8080) } initMiddlewareOne–1-执行中间件 initMiddlewareTwo–1-执行中间件 initMiddlewareTwo–2-执行中间件 initMiddlewareOne–2-执行中间件 8.2、全局中间件 package main import ( “fmt” “github.com/gin-gonic/gin” ) func initMiddleware(ctx *gin.Context) { fmt.Println(“全局中间件 通过 r.Use配置”) // 调用该请求的剩余处理程序 ctx.Next() } func main() { r : gin.Default() r.Use(initMiddleware) r.GET(/, func(ctx *gin.Context) { ctx.String(200, “首页–中间件演示”) }) r.GET(/news, func(ctx *gin.Context) { ctx.String(200, “新闻页面–中间件演示”) }) r.Run(:8080) } 8.3、在路由分组中配置中间件 1、为路由组注册中间件有以下两种写法。 写法1 shopGroup : r.Group(/shop, StatCost()) { shopGroup.GET(/index, func(c *gin.Context) {…}) … } 写法2 shopGroup : r.Group(/shop) shopGroup.Use(StatCost()) { shopGroup.GET(/index, func(c *gin.Context) {…}) … } 2、分组路由AdminRoutes.go中配置中间件 package routes import ( “fmt” “gin_demo/controller/admin” “net/http” github.com/gin-gonic/gin ) func initMiddleware(ctx *gin.Context) { fmt.Println(“路由分组中间件”) // 调用该请求的剩余处理程序 ctx.Next() } func AdminRoutesInit(router *gin.Engine) { adminRouter : router.Group(/admin, initMiddleware) { adminRouter.GET(/user, admin.UserController{}.Index) adminRouter.GET(/user/add, admin.UserController{}.Add) adminRouter.GET(/news, func(c *gin.Context) { c.String(http.StatusOK, “news”) }) } } 8.4、中间件和对应控制器之间共享数据 设置值 ctx.Set(“username”, “张三”) 获取值 username, _ : ctx.Get(“username”) 中间件设置值 func InitAdminMiddleware(ctx *gin.Context) { fmt.Println(“路由分组中间件”) // 可以通过ctx.Set在请求上下文中设置值后续的处理函数能够取到该值 ctx.Set(“username”, “张三”) // 调用该请求的剩余处理程序 ctx.Next() } 控制器获取值 func (c UserController) Index(ctx *gin.Context) { username, _ : ctx.Get(“username”) fmt.Println(username) ctx.String(http.StatusOK, “这是用户首页 111”) } 8.5、中间件注意事项 gin默认中间件 gin.Default()默认使用了Logger和Recovery中间件其中 •Logger中间件将日志写入gin.DefaultWriter即使配置了GIN_MODErelease。 •Recovery中间件会recover任何panic。如果有panic的话会写入500响应码。 如果不想使用上面两个默认的中间件可以使用gin.New()新建一个没有任何默认中间件的路由。 gin中间件中使用goroutine 当在中间件或handler中启动新的goroutine时不能使用原始的上下文c *gin.Context必须使用其只读副本c.Copy() 十、Gin中自定义Model 10.1、关于Model 如果我们的应用非常简单的话我们可以在Controller 里面处理常见的业务逻辑。但是如果我们有一个功能想在多个控制器、或者多个模板里面复用的话那么我们就可以把公共的功能单独抽取出来作为一个模块Model。 Model 是逐步抽象的过程一般我们会在 Model 里面封装一些公共的方法让不同Controller 使用也可以在Model中实现和数据库打交道 10.2、Model里面封装公共的方法 1、新建models/ tools.go package models import ( “crypto/md5” “fmt” “time” github.com/astaxie/beego ) //时间戳间戳转换成日期 func UnixToDate(timestamp int) string { t : time.Unix(int64(timestamp), 0)return t.Format(2006-01-02 15:04:05) } //日期转换成时间戳 2020-05-02 15:04:05 func DateToUnix(str string) int64 { template : “2006-01-02 15:04:05” t, err : time.ParseInLocation(template, str, time.Local) if err ! nil { beego.Info(err) return 0 } return t.Unix() } func GetUnix() int64 { return time.Now().Unix() } func GetDate() string { template : “2006-01-02 15:04:05” return time.Now().Format(template) } func GetDay() string { template : “20060102” return time.Now().Format(template) } func Md5(str string) string { data : []byte(str) return fmt.Sprintf(%x\n, md5.Sum(data)) } func Hello(in string) (out string) { out in “world” return } 10.3、控制器中调用Model package controllers import ( “gin_demo/models” ) day : models.GetDay() 10.4、调用Model注册全局模板函数 models/tools.go //时间戳间戳转换成日期 func UnixToDate(timestamp int64) string { t : time.Unix(timestamp, 0)return t.Format(2006-01-02 15:04:05) } main.go //注册全局模板函数 注意顺序注册模板函数需要在加载模板上面 r : gin.Default() r.SetFuncMap(template.FuncMap{ “unixToDate”: models.UnixToDate, }) 控制器 func (c UserController) Add(ctx *gin.Context) { ctx.HTML(http.StatusOK, “admin/user/add.html”, gin.H{ “now”: models.GetUnix(), }) } 模板 h2{{.now | unixToDate}}/h2 10.5、Golang Md5加密 打开golang包对应的网站https://pkg.go.dev/搜索md5 方法一 data : []byte(“123456”) has : md5.Sum(data) md5str : fmt.Sprintf(%x, has) fmt.Println(md5str) 方法二 h : md5.New() io.WriteString(h, “123456”) fmt.Printf(%x\n, h.Sum(nil)) 十一、Gin文件上传 注意需要在上传文件的form表单上面需要加入enctype“multipart/form-data” 11.1、单文件上传 单文件 | Gin Web Framework 官方示例 func main() { router : gin.Default() // 为 multipart forms 设置较低的内存限制 (默认是 32 MiB) router.MaxMultipartMemory 8 20 // 8 MiB router.POST(/upload, func(c *gin.Context) { // 单文件 file, _ : c.FormFile(“file”) log.Println(file.Filename) // 上传文件至指定目录c.SaveUploadedFile(file, dst)c.String(http.StatusOK, fmt.Sprintf(%s uploaded!, file.Filename)) }) router.Run(:8080) } 项目中实现文件上传 1、定义模板 需要在上传文件的form表单上面需要加入enctype“multipart/form-data” !-- 相当于给模板定义一个名字 define end 成对出现– {{ define “admin/user/add.html” }} !DOCTYPE html html lang“en” head meta charset“UTF-8” meta http-equiv“X-UA-Compatible” content“IEedge” meta name“viewport” content“widthdevice-width, initial-scale1.0” titleDocument/title /head body form action/admin/user/doAdd method“post” enctype“multipart/form-data” 用户名 input type“text” name“username” placeholder“用户名” br br 头 像input type“file” name“face”br br input type“submit” value“提交” /form /body /html {{ end }} 2、定义业务逻辑 func (c UserController) DoAdd(ctx *gin.Context) { username : ctx.PostForm(“username”) file, err : ctx.FormFile(“face”) if err ! nil {ctx.JSON(http.StatusInternalServerError, gin.H{message: err.Error(),})return } // 上传文件到指定的目录 dst : path.Join(./static/upload, file.Filename) fmt.Println(dst) ctx.SaveUploadedFile(file, dst) ctx.JSON(http.StatusOK, gin.H{message: fmt.Sprintf(%s uploaded!, file.Filename),username: username, }) } 11.2、多文件上传–不同名字的多个文件 1、定义模板 需要在上传文件的form表单上面需要加入enctype“multipart/form-data” !-- 相当于给模板定义一个名字 define end 成对出现– {{ define “admin/user/add.html” }} !DOCTYPE html html lang“en” head meta charset“UTF-8” meta http-equiv“X-UA-Compatible” content“IEedge” meta name“viewport” content“widthdevice-width, initial-scale1.0” titleDocument/title /head body form action/admin/user/doAdd method“post” enctype“multipart/form-data” 用户名 input type“text” name“username” placeholder“用户名” br br 头 像1input type“file” name“face1”br br 头 像2input type“file” name“face2”br br input type“submit” value“提交” /form /body /html {{ end }} 2、定义业务逻辑 func (c UserController) DoAdd(ctx *gin.Context) { username : ctx.PostForm(“username”) face1, err1 : ctx.FormFile(“face1”) face2, err2 : ctx.FormFile(“face2”) // 上传文件到指定的目录 if err1 nil { dst1 : path.Join(./static/upload, face1.Filename) ctx.SaveUploadedFile(face1, dst1) } if err2 nil { dst2 : path.Join(./static/upload, face2.Filename) ctx.SaveUploadedFile(face2, dst2) } ctx.JSON(http.StatusOK, gin.H{message: 文件上传成功,username: username, }) // ctx.String(200, username) } 11.3、多文件上传–相同名字的多个文件 参考多文件 | Gin Web Framework 1、定义模板 需要在上传文件的form表单上面需要加入enctype“multipart/form-data” !-- 相当于给模板定义一个名字 define end 成对出现– {{ define “admin/user/add.html” }} !DOCTYPE html html lang“en” head meta charset“UTF-8” meta http-equiv“X-UA-Compatible” content“IEedge” meta name“viewport” content“widthdevice-width, initial-scale1.0” titleDocument/title /head body form action/admin/user/doAdd method“post” enctype“multipart/form-data” 用户名 input type“text” name“username” placeholder“用户名” br br 头 像1input type“file” name“face[]”br br 头 像2input type“file” name“face[]”br br input type“submit” value“提交” /form /body /html {{ end }} 2、定义业务逻辑 func (c UserController) DoAdd(ctx *gin.Context) { username : ctx.PostForm(“username”) // Multipart form form, _ : ctx.MultipartForm() files : form.File[face[]]// var dst; for _, file : range files {// 上传文件至指定目录dst : path.Join(./static/upload, file.Filename)ctx.SaveUploadedFile(file, dst) }ctx.JSON(http.StatusOK, gin.H{message: 文件上传成功,username: username, }) } 10.4、文件上传 按照日期存储 1、定义模板 需要在上传文件的form表单上面需要加入enctype“multipart/form-data” !-- 相当于给模板定义一个名字 define end 成对出现– {{ define “admin/user/add.html” }} !DOCTYPE html html lang“en” head meta charset“UTF-8” meta http-equiv“X-UA-Compatible” content“IEedge” meta name“viewport” content“widthdevice-width, initial-scale1.0” titleDocument/title /head body form action/admin/user/doAdd method“post” enctype“multipart/form-data” 用户名 input type“text” name“username” placeholder“用户名” br br 头 像 input type“file” name“face”br br input typesubmit value提交 /form /body /html {{ end }} 2、定义业务逻辑 func (c UserController) DoAdd(ctx *gin.Context) { username : ctx.PostForm(“username”) //1、获取上传的文件 file, err1 : ctx.FormFile(“face”) if err1 nil {//2、获取后缀名 判断类型是否正确 .jpg .png .gif .jpegextName : path.Ext(file.Filename)allowExtMap : map[string]bool{.jpg: true,.png: true,.gif: true,.jpeg: true,}if _, ok : allowExtMap[extName]; !ok {ctx.String(200, 文件类型不合法)return}//3、创建图片保存目录 static/upload/20200623day : models.GetDay()dir : ./static/upload/ dayif err : os.MkdirAll(dir, 0666); err ! nil {log.Error(err)}//4、生成文件名称 144325235235.pngfileUnixName : strconv.FormatInt(models.GetUnix(), 10)//static/upload/20200623/144325235235.pngsaveDir : path.Join(dir, fileUnixNameextName)ctx.SaveUploadedFile(file, saveDir) } ctx.JSON(http.StatusOK, gin.H{message: 文件上传成功,username: username, }) // ctx.String(200, username) } 3、models/tools.go package models import ( “crypto/md5” “fmt” “time” github.com/astaxie/beego ) //时间戳间戳转换成日期 func UnixToDate(timestamp int) string { t : time.Unix(int64(timestamp), 0)return t.Format(2006-01-02 15:04:05) } //日期转换成时间戳 2020-05-02 15:04:05 func DateToUnix(str string) int64 { template : “2006-01-02 15:04:05” t, err : time.ParseInLocation(template, str, time.Local) if err ! nil { beego.Info(err) return 0 } return t.Unix() } func GetUnix() int64 { return time.Now().Unix() } func GetDate() string { template : “2006-01-02 15:04:05” return time.Now().Format(template) } func GetDay() string { template : “20060102” return time.Now().Format(template) } func Md5(str string) string { data : []byte(str) return fmt.Sprintf(%x\n, md5.Sum(data)) } func Hello(in string) (out string) { out in “world” return } 十二、Gin中的Cookie 12.1、Cookie介绍 ● HTTP是无状态协议。简单地说当你浏览了一个页面然后转到同一个网站的另一个页面服务器无法认识到这是同一个浏览器在访问同一个网站。每一次的访问都是没有任何关系的。如果我们要实现多个页面之间共享数据的话我们就可以使用Cookie或者Session实现 ● cookie 是存储于访问者计算机的浏览器中。可以让我们用同一个浏览器访问同一个域名的时候共享数据。 12.2、Cookie能实现的功能 1、保持用户登录状态 2、保存用户浏览的历史记录 3、猜你喜欢智能推荐 4、电商网站的加入购物车 12.3、设置和获取 Cookie 设置和获取 Cookie | Gin Web Framework 设置Cookie c.SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) 第一个参数 key 第二个参数 value 第三个参数 过期时间.如果只想设置Cookie的保存路径而不想设置存活时间可以在第三个参数中传递nil 第四个参数 cookie的路径 第五个参数 cookie的路径Domain作用域 本地调试配置成 localhost , 正式上线配置成域名 第六个参数是secure 当 secure 值为 true 时cookie 在 HTTP 中是无效在 HTTPS 中才有效 第七个参数 httpOnly是微软对COOKIE做的扩展。如果在COOKIE中设置了“httpOnly”属性则通过程序JS脚本、applet等将无法读取到COOKIE信息防止XSS攻击产生 获取Cookie cookie, err : c.Cookie(“name”) 完整demo package main import ( “gin_demo/models” “html/template” github.com/gin-gonic/gin ) func main() { r : gin.Default() r.SetFuncMap(template.FuncMap{ “unixToDate”: models.UnixToDate, }) r.GET(/, func(c *gin.Context) { c.SetCookie(usrename, 张三, 3600, /, localhost, false, true)c.String(200, 首页) })r.GET(/user, func(c *gin.Context) {username, _ : c.Cookie(usrename)c.String(200, 用户-username) })r.Run(:8080) } 12.4 、多个二级域名共享cookie 1、分别把a.itying.com 和 b.itying.com解析到我们的服务器 2、我们想的是用户在a.itying.com中设置Cookie信息后在b.itying.com中获取刚才设置的cookie也就是实现多个二级域名共享cookie 这时候的话我们就可以这样设置cookie c.SetCookie(“usrename”, “张三”, 3600, “/”, “.itying.com”, false, true) 十三、Gin中的Session 13.1、Session简单介绍 session是另一种记录客户状态的机制不同的是Cookie保存在客户端浏览器中而session保存在服务器上。 13.2、Session的工作流程 当客户端浏览器第一次访问服务器并发送请求时服务器端会创建一个session对象生成一个类似于key,value的键值对 然后将key(cookie)返回到浏览器(客户)端浏览器下次再访问时携带key(cookie)找到对应的session(value)。 13.3、Gin中使用 Session Gin官方没有给我们提供Session相关的文档这个时候我们可以使用第三方的Session中间件来实现 GitHub - gin-contrib/sessions: Gin middleware for session management gin-contrib/sessions中间件支持的存储引擎 •cookie •memstore •redis •memcached •mongodb 13.4、基于Cookie存储Session 1、安装session包 go get github.com/gin-contrib/sessions 2、基本的session用法 package main import ( “github.com/gin-contrib/sessions” “github.com/gin-contrib/sessions/cookie” “github.com/gin-gonic/gin” ) func main() { r : gin.Default() // 创建基于cookie的存储引擎secret11111 参数是用于加密的密钥 store : cookie.NewStore([]byte(“secret11111”)) // 设置session中间件参数mysession指的是session的名字也是cookie的名字 // store是前面创建的存储引擎我们可以替换成其他存储引擎 r.Use(sessions.Sessions(“mysession”, store)) r.GET(/, func(c *gin.Context) {//初始化session对象session : sessions.Default(c)//设置过期时间session.Options(sessions.Options{MaxAge: 3600 * 6, // 6hrs})//设置Sessionsession.Set(username, 张三)session.Save()c.JSON(200, gin.H{msg: session.Get(username)}) }) r.GET(/user, func(c *gin.Context) {// 初始化session对象session : sessions.Default(c)// 通过session.Get读取session值username : session.Get(username)c.JSON(200, gin.H{username: username}) })r.Run(:8000) } 13.5、基于Redis存储Session 如果我们想将session数据保存到redis中只要将session的存储引擎改成redis即可。 使用redis作为存储引擎的例子 首先安装redis存储引擎的包 go get github.com/gin-contrib/sessions/redis 例子 package main import ( “github.com/gin-contrib/sessions” “github.com/gin-contrib/sessions/redis” “github.com/gin-gonic/gin” ) func main() { r : gin.Default() // 初始化基于redis的存储引擎 // 参数说明 // 第1个参数 - redis最大的空闲连接数 // 第2个参数 - 数通信协议tcp或者udp // 第3个参数 - redis地址, 格式host:port // 第4个参数 - redis密码 // 第5个参数 - session加密密钥 store, _ : redis.NewStore(10, “tcp”, “localhost:6379”, “”, []byte(“secret”)) r.Use(sessions.Sessions(“mysession”, store)) r.GET(/, func(c *gin.Context) {session : sessions.Default(c)session.Set(username, 李四)session.Save()c.JSON(200, gin.H{username: session.Get(username)}) })r.GET(/user, func(c *gin.Context) {// 初始化session对象session : sessions.Default(c)// 通过session.Get读取session值username : session.Get(username)c.JSON(200, gin.H{username: username}) }) r.Run(:8000) }
http://www.w-s-a.com/news/21703/

相关文章:

  • 天河建网站装修公司线上推广方式
  • 超市网站怎么做的目前最流行的拓客方法
  • 做文字logo的网站贵阳商城网站开发
  • 沧州有没有做网站的中国建筑设计
  • 建设网站 系统占用空间在线代理浏览网站
  • 做海报有什么参考的网站网站建设验收合同
  • 酒店网站制作wordpress文章评论设置
  • 造一个官方网站wordpress mysql类
  • 怎么做卡商网站河南做网站找谁
  • 网站建设招标方案模板上线啦 图谱智能网站
  • 龙口网站建设公司哪家好wordpress 上传类型
  • 做外贸主要看什么网站服务平台的宗旨
  • 宜昌营销型网站购买网站
  • 如何查询网站建设时间wordpress 框架解析
  • 网站建设年终总结网站建设公司顺义
  • 网页给别人做的 网站后续收费吗获取更多付费流量
  • 金融交易网站建设金融 网站建设
  • 长沙网站建设联系电话怎么做表格
  • 网站怎么做域名实名认证龙华网站 建设信科网络
  • 企业网站规划方案网站是做排行榜
  • 万维网网站个人申请网站
  • 我想做网站怎么做昆山网站建设 全是乱码
  • 单位做网站怎么做圣诞树html网页代码
  • 网页开发与网站开发企业网站托管服务常用指南
  • 一站式服务图片临沂做进销存网站
  • 鸣蝉智能建站标准物质网站建设模板
  • 电商网站建设技术员的工作职责商业网站制作价格
  • 网站html模板免费下载公司的网站建设费用入什么科目
  • 高中生做网站网页网页制作教程零基础学会
  • 做金融网站有哪些要求WordPress站内搜索代码