@ -0,0 +1,252 @@ |
|||
# 12.1 应用日志 |
|||
我们期望开发的Web应用程序能够把整个程序运行过程中出现的各种事件一一记录下来,Go语言中提供了一个简易的log包,我们使用该包可以方便的实现日志记录的功能,这些日志都是基于fmt包的打印再结合panic之类的函数来进行一般的打印、抛出错误处理。Go目前标准包只是包含了简单的功能,如果我们想把我们的应用日志保存到文件,然后又能够结合日志实现很多复杂的功能(编写过Java或者C++的读者应该都使用过log4j和log4cpp之类的日志工具),可以使用第三方开发的日志系统:[logrus](https://github.com/sirupsen/logrus)和[seelog](https://github.com/cihub/seelog),它们实现了很强大的日志功能,可以结合自己项目选择。接下来我们介绍如何通过该日志系统来实现我们应用的日志功能。 |
|||
|
|||
## logrus介绍 |
|||
logrus是用Go语言实现的一个日志系统,与标准库log完全兼容并且核心API很稳定,是Go语言目前最活跃的日志库 |
|||
|
|||
首先安装logrus |
|||
```Go |
|||
|
|||
go get -u github.com/sirupsen/logrus |
|||
|
|||
``` |
|||
|
|||
简单例子: |
|||
|
|||
```Go |
|||
|
|||
package main |
|||
|
|||
import ( |
|||
log "github.com/Sirupsen/logrus" |
|||
) |
|||
|
|||
func main() { |
|||
log.WithFields(log.Fields{ |
|||
"animal": "walrus", |
|||
}).Info("A walrus appears") |
|||
} |
|||
``` |
|||
### 基于logrus的自定义日志处理 |
|||
```Go |
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"os" |
|||
|
|||
log "github.com/Sirupsen/logrus" |
|||
) |
|||
|
|||
func init() { |
|||
// 日志格式化为JSON而不是默认的ASCII |
|||
log.SetFormatter(&log.JSONFormatter{}) |
|||
|
|||
// 输出stdout而不是默认的stderr,也可以是一个文件 |
|||
log.SetOutput(os.Stdout) |
|||
|
|||
// 只记录严重或以上警告 |
|||
log.SetLevel(log.WarnLevel) |
|||
} |
|||
|
|||
func main() { |
|||
log.WithFields(log.Fields{ |
|||
"animal": "walrus", |
|||
"size": 10, |
|||
}).Info("A group of walrus emerges from the ocean") |
|||
|
|||
log.WithFields(log.Fields{ |
|||
"omg": true, |
|||
"number": 122, |
|||
}).Warn("The group's number increased tremendously!") |
|||
|
|||
log.WithFields(log.Fields{ |
|||
"omg": true, |
|||
"number": 100, |
|||
}).Fatal("The ice breaks!") |
|||
|
|||
// 通过日志语句重用字段 |
|||
// logrus.Entry返回自WithFields() |
|||
contextLogger := log.WithFields(log.Fields{ |
|||
"common": "this is a common field", |
|||
"other": "I also should be logged always", |
|||
}) |
|||
|
|||
contextLogger.Info("I'll be logged with common and other field") |
|||
contextLogger.Info("Me too") |
|||
} |
|||
``` |
|||
|
|||
## seelog介绍 |
|||
seelog是用Go语言实现的一个日志系统,它提供了一些简单的函数来实现复杂的日志分配、过滤和格式化。主要有如下特性: |
|||
|
|||
- XML的动态配置,可以不用重新编译程序而动态的加载配置信息 |
|||
- 支持热更新,能够动态改变配置而不需要重启应用 |
|||
- 支持多输出流,能够同时把日志输出到多种流中、例如文件流、网络流等 |
|||
- 支持不同的日志输出 |
|||
|
|||
- 命令行输出 |
|||
- 文件输出 |
|||
- 缓存输出 |
|||
- 支持log rotate |
|||
- SMTP邮件 |
|||
|
|||
上面只列举了部分特性,seelog是一个特别强大的日志处理系统,详细的内容请参看官方wiki。接下来我将简要介绍一下如何在项目中使用它: |
|||
|
|||
首先安装seelog |
|||
```Go |
|||
|
|||
go get -u github.com/cihub/seelog |
|||
|
|||
``` |
|||
然后我们来看一个简单的例子: |
|||
```Go |
|||
|
|||
package main |
|||
|
|||
import log "github.com/cihub/seelog" |
|||
|
|||
func main() { |
|||
defer log.Flush() |
|||
log.Info("Hello from Seelog!") |
|||
} |
|||
|
|||
``` |
|||
编译后运行如果出现了`Hello from seelog`,说明seelog日志系统已经成功安装并且可以正常运行了。 |
|||
|
|||
### 基于seelog的自定义日志处理 |
|||
seelog支持自定义日志处理,下面是我基于它自定义的日志处理包的部分内容: |
|||
```Go |
|||
|
|||
package logs |
|||
|
|||
import ( |
|||
// "errors" |
|||
"fmt" |
|||
// "io" |
|||
|
|||
seelog "github.com/cihub/seelog" |
|||
) |
|||
|
|||
var Logger seelog.LoggerInterface |
|||
|
|||
func loadAppConfig() { |
|||
appConfig := ` |
|||
<seelog minlevel="warn"> |
|||
<outputs formatid="common"> |
|||
<rollingfile type="size" filename="/data/logs/roll.log" maxsize="100000" maxrolls="5"/> |
|||
<filter levels="critical"> |
|||
<file path="/data/logs/critical.log" formatid="critical"/> |
|||
<smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword"> |
|||
<recipient address="xiemengjun@gmail.com"/> |
|||
</smtp> |
|||
</filter> |
|||
</outputs> |
|||
<formats> |
|||
<format id="common" format="%Date/%Time [%LEV] %Msg%n" /> |
|||
<format id="critical" format="%File %FullPath %Func %Msg%n" /> |
|||
<format id="criticalemail" format="Critical error on our server!\n %Time %Date %RelFile %Func %Msg \nSent by Seelog"/> |
|||
</formats> |
|||
</seelog> |
|||
` |
|||
logger, err := seelog.LoggerFromConfigAsBytes([]byte(appConfig)) |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
return |
|||
} |
|||
UseLogger(logger) |
|||
} |
|||
|
|||
func init() { |
|||
DisableLog() |
|||
loadAppConfig() |
|||
} |
|||
|
|||
// DisableLog disables all library log output |
|||
func DisableLog() { |
|||
Logger = seelog.Disabled |
|||
} |
|||
|
|||
// UseLogger uses a specified seelog.LoggerInterface to output library log. |
|||
// Use this func if you are using Seelog logging system in your app. |
|||
func UseLogger(newLogger seelog.LoggerInterface) { |
|||
Logger = newLogger |
|||
} |
|||
``` |
|||
上面主要实现了三个函数, |
|||
|
|||
- `DisableLog` |
|||
|
|||
初始化全局变量Logger为seelog的禁用状态,主要为了防止Logger被多次初始化 |
|||
- `loadAppConfig` |
|||
|
|||
根据配置文件初始化seelog的配置信息,这里我们把配置文件通过字符串读取设置好了,当然也可以通过读取XML文件。里面的配置说明如下: |
|||
|
|||
- seelog |
|||
|
|||
minlevel参数可选,如果被配置,高于或等于此级别的日志会被记录,同理maxlevel。 |
|||
- outputs |
|||
|
|||
输出信息的目的地,这里分成了两份数据,一份记录到log rotate文件里面。另一份设置了filter,如果这个错误级别是critical,那么将发送报警邮件。 |
|||
|
|||
- formats |
|||
|
|||
定义了各种日志的格式 |
|||
|
|||
- `UseLogger` |
|||
|
|||
设置当前的日志器为相应的日志处理 |
|||
|
|||
上面我们定义了一个自定义的日志处理包,下面就是使用示例: |
|||
```Go |
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"net/http" |
|||
"project/logs" |
|||
"project/configs" |
|||
"project/routes" |
|||
) |
|||
|
|||
func main() { |
|||
addr, _ := configs.MainConfig.String("server", "addr") |
|||
logs.Logger.Info("Start server at:%v", addr) |
|||
err := http.ListenAndServe(addr, routes.NewMux()) |
|||
logs.Logger.Critical("Server err:%v", err) |
|||
} |
|||
``` |
|||
## 发生错误发送邮件 |
|||
上面的例子解释了如何设置发送邮件,我们通过如下的smtp配置用来发送邮件: |
|||
```html |
|||
|
|||
<smtp formatid="criticalemail" senderaddress="astaxie@gmail.com" sendername="ShortUrl API" hostname="smtp.gmail.com" hostport="587" username="mailusername" password="mailpassword"> |
|||
<recipient address="xiemengjun@gmail.com"/> |
|||
</smtp> |
|||
``` |
|||
邮件的格式通过criticalemail配置,然后通过其他的配置发送邮件服务器的配置,通过recipient配置接收邮件的用户,如果有多个用户可以再添加一行。 |
|||
|
|||
要测试这个代码是否正常工作,可以在代码中增加类似下面的一个假消息。不过记住过后要把它删除,否则上线之后就会收到很多垃圾邮件。 |
|||
```Go |
|||
|
|||
logs.Logger.Critical("test Critical message") |
|||
``` |
|||
现在,只要我们的应用在线上记录一个Critical的信息,你的邮箱就会收到一个Email,这样一旦线上的系统出现问题,你就能立马通过邮件获知,就能及时的进行处理。 |
|||
## 使用应用日志 |
|||
对于应用日志,每个人的应用场景可能会各不相同,有些人利用应用日志来做数据分析,有些人利用应用日志来做性能分析,有些人来做用户行为分析,还有些就是纯粹的记录,以方便应用出现问题的时候辅助查找问题。 |
|||
|
|||
举一个例子,我们需要跟踪用户尝试登陆系统的操作。这里会把成功与不成功的尝试都记录下来。记录成功的使用"Info"日志级别,而不成功的使用"warn"级别。如果想查找所有不成功的登陆,我们可以利用linux的grep之类的命令工具,如下: |
|||
```Go |
|||
|
|||
# cat /data/logs/roll.log | grep "failed login" |
|||
2012-12-11 11:12:00 WARN : failed login attempt from 11.22.33.44 username password |
|||
``` |
|||
通过这种方式我们就可以很方便的查找相应的信息,这样有利于我们针对应用日志做一些统计和分析。另外我们还需要考虑日志的大小,对于一个高流量的Web应用来说,日志的增长是相当可怕的,所以我们在seelog的配置文件里面设置了logrotate,这样就能保证日志文件不会因为不断变大而导致我们的磁盘空间不够引起问题。 |
|||
|
|||
## 小结 |
|||
通过上面对seelog系统及如何基于它进行自定义日志系统的学习,现在我们可以很轻松的随需构建一个合适的功能强大的日志处理系统了。日志处理系统为数据分析提供了可靠的数据源,比如通过对日志的分析,我们可以进一步优化系统,或者应用出现问题时方便查找定位问题,另外seelog也提供了日志分级功能,通过对minlevel的配置,我们可以很方便的设置测试或发布版本的输出消息级别。 |
|||
|
|||
## links |
|||
* [目录](<preface.md>) |
|||
* 上一章: [部署与维护](<12.0.md>) |
|||
* 下一节: [网站错误处理](<12.2.md>) |
@ -0,0 +1,12 @@ |
|||
# 14 扩展Web框架 |
|||
第十三章介绍了如何开发一个Web框架,通过介绍MVC、路由、日志处理、配置处理完成了一个基本的框架系统,但是一个好的框架需要一些方便的辅助工具来快速的开发Web,那么我们这一章将就如何提供一些快速开发Web的工具进行介绍,第一小节介绍如何处理静态文件,如何利用现有的twitter开源的bootstrap进行快速的开发美观的站点,第二小节介绍如何利用前面介绍的session来进行用户登录处理,第三小节介绍如何方便的输出表单、这些表单如何进行数据验证,如何快速的结合model进行数据的增删改操作,第四小节介绍如何进行一些用户认证,包括http basic认证、http digest认证,第五小节介绍如何利用前面介绍的i18n支持多语言的应用开发。第六小节介绍了如何集成Go的pprof包用于性能调试。 |
|||
|
|||
通过本章的扩展,beego框架将具有快速开发Web的特性,最后我们将讲解如何利用这些扩展的特性扩展开发第十三章开发的博客系统,通过开发一个完整、美观的博客系统让读者了解beego开发带给你的快速。 |
|||
|
|||
## 目录 |
|||
![](images/navi14.png?raw=true) |
|||
|
|||
## links |
|||
* [目录](<preface.md>) |
|||
* 上一章: [第十三章总结](<13.6.md>) |
|||
* 下一节: [静态文件支持](<14.1.md>) |
@ -0,0 +1,81 @@ |
|||
# 14.1 静态文件支持 |
|||
我们在前面已经讲过如何处理静态文件,这小节我们详细的介绍如何在beego里面设置和使用静态文件。通过再介绍一个twitter开源的html、css框架bootstrap,无需大量的设计工作就能够让你快速地建立一个漂亮的站点。 |
|||
|
|||
## beego静态文件实现和设置 |
|||
Go的net/http包中提供了静态文件的服务,`ServeFile`和`FileServer`等函数。beego的静态文件处理就是基于这一层处理的,具体的实现如下所示: |
|||
```Go |
|||
|
|||
//static file server |
|||
for prefix, staticDir := range StaticDir { |
|||
if strings.HasPrefix(r.URL.Path, prefix) { |
|||
file := staticDir + r.URL.Path[len(prefix):] |
|||
http.ServeFile(w, r, file) |
|||
w.started = true |
|||
return |
|||
} |
|||
} |
|||
``` |
|||
StaticDir里面保存的是相应的url对应到静态文件所在的目录,因此在处理URL请求的时候只需要判断对应的请求地址是否包含静态处理开头的url,如果包含的话就采用http.ServeFile提供服务。 |
|||
|
|||
举例如下: |
|||
```Go |
|||
|
|||
beego.StaticDir["/asset"] = "/static" |
|||
``` |
|||
那么请求url如`http://www.beego.me/asset/bootstrap.css`就会请求`/static/bootstrap.css`来提供反馈给客户端。 |
|||
|
|||
## bootstrap集成 |
|||
Bootstrap是Twitter推出的一个开源的用于前端开发的工具包。对于开发者来说,Bootstrap是快速开发Web应用程序的最佳前端工具包。它是一个CSS和HTML的集合,它使用了最新的HTML5标准,给你的Web开发提供了时尚的版式,表单,按钮,表格,网格系统等等。 |
|||
|
|||
- 组件 |
|||
Bootstrap中包含了丰富的Web组件,根据这些组件,可以快速的搭建一个漂亮、功能完备的网站。其中包括以下组件: |
|||
下拉菜单、按钮组、按钮下拉菜单、导航、导航条、面包屑、分页、排版、缩略图、警告对话框、进度条、媒体对象等 |
|||
- Javascript插件 |
|||
Bootstrap自带了13个jQuery插件,这些插件为Bootstrap中的组件赋予了“生命”。其中包括: |
|||
模式对话框、标签页、滚动条、弹出框等。 |
|||
- 定制自己的框架代码 |
|||
可以对Bootstrap中所有的CSS变量进行修改,依据自己的需求裁剪代码。 |
|||
|
|||
![](images/14.1.bootstrap.png?raw=true) |
|||
|
|||
图14.1 bootstrap站点 |
|||
|
|||
接下来我们利用bootstrap集成到beego框架里面来,快速的建立一个漂亮的站点。 |
|||
|
|||
1. 首先把下载的bootstrap目录放到我们的项目目录,取名为static,如下截图所示 |
|||
|
|||
![](images/14.1.bootstrap2.png?raw=true) |
|||
|
|||
图14.2 项目中静态文件目录结构 |
|||
|
|||
2. 因为beego默认设置了StaticDir的值,所以如果你的静态文件目录是static的话就无须再增加了: |
|||
```Go |
|||
|
|||
StaticDir["/static"] = "static" |
|||
``` |
|||
3. 模板中使用如下的地址就可以了: |
|||
|
|||
```html |
|||
|
|||
//css文件 |
|||
<link href="/static/css/bootstrap.css" rel="stylesheet"> |
|||
|
|||
//js文件 |
|||
<script src="/static/js/bootstrap-transition.js"></script> |
|||
|
|||
//图片文件 |
|||
<img src="/static/img/logo.png"> |
|||
``` |
|||
上面可以实现把bootstrap集成到beego中来,如下展示的图就是集成进来之后的展现效果图: |
|||
|
|||
![](images/14.1.bootstrap3.png?raw=true) |
|||
|
|||
图14.3 构建的基于bootstrap的站点界面 |
|||
|
|||
这些模板和格式bootstrap官方都有提供,这边就不再重复贴代码,大家可以上bootstrap官方网站学习如何编写模板。 |
|||
|
|||
|
|||
## links |
|||
* [目录](<preface.md>) |
|||
* 上一节: [扩展Web框架](<14.0.md>) |
|||
* 下一节: [Session支持](<14.2.md>) |
@ -0,0 +1,265 @@ |
|||
# 14.4 用户认证 |
|||
在开发Web应用过程中,用户认证是开发者经常遇到的问题,用户登录、注册、登出等操作,而一般认证也分为三个方面的认证 |
|||
|
|||
- HTTP Basic和 HTTP Digest认证 |
|||
- 第三方集成认证:QQ、微博、豆瓣、OPENID、google、GitHub、facebook和twitter等 |
|||
- 自定义的用户登录、注册、登出,一般都是基于session、cookie认证 |
|||
|
|||
beego目前没有针对这三种方式进行任何形式的集成,但是可以充分的利用第三方开源库来实现上面的三种方式的用户认证,不过后续beego会对前面两种认证逐步集成。 |
|||
|
|||
## HTTP Basic和 HTTP Digest认证 |
|||
这两个认证是一些应用采用的比较简单的认证,目前已经有开源的第三方库支持这两个认证: |
|||
```Go |
|||
|
|||
github.com/abbot/go-http-auth |
|||
``` |
|||
下面代码演示了如何把这个库引入beego中从而实现认证: |
|||
```Go |
|||
|
|||
package controllers |
|||
|
|||
import ( |
|||
"github.com/abbot/go-http-auth" |
|||
"github.com/astaxie/beego" |
|||
) |
|||
|
|||
func Secret(user, realm string) string { |
|||
if user == "john" { |
|||
// password is "hello" |
|||
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1" |
|||
} |
|||
return "" |
|||
} |
|||
|
|||
type MainController struct { |
|||
beego.Controller |
|||
} |
|||
|
|||
func (this *MainController) Prepare() { |
|||
a := auth.NewBasicAuthenticator("example.com", Secret) |
|||
if username := a.CheckAuth(this.Ctx.Request); username == "" { |
|||
a.RequireAuth(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
} |
|||
} |
|||
|
|||
func (this *MainController) Get() { |
|||
this.Data["Username"] = "astaxie" |
|||
this.Data["Email"] = "astaxie@gmail.com" |
|||
this.TplNames = "index.tpl" |
|||
} |
|||
``` |
|||
上面代码利用了beego的prepare函数,在执行正常逻辑之前调用了认证函数,这样就非常简单的实现了http auth,digest的认证也是同样的原理。 |
|||
|
|||
## oauth和oauth2的认证 |
|||
oauth和oauth2是目前比较流行的两种认证方式,还好第三方有一个库实现了这个认证,但是是国外实现的,并没有QQ、微博之类的国内应用认证集成: |
|||
```Go |
|||
|
|||
github.com/bradrydzewski/go.auth |
|||
``` |
|||
下面代码演示了如何把该库引入beego中从而实现oauth的认证,这里以GitHub为例演示: |
|||
|
|||
1. 添加两条路由 |
|||
```Go |
|||
|
|||
beego.RegisterController("/auth/login", &controllers.GithubController{}) |
|||
beego.RegisterController("/mainpage", &controllers.PageController{}) |
|||
``` |
|||
2. 然后我们处理GithubController登陆的页面: |
|||
```Go |
|||
package controllers |
|||
|
|||
import ( |
|||
"github.com/astaxie/beego" |
|||
"github.com/bradrydzewski/go.auth" |
|||
) |
|||
|
|||
const ( |
|||
githubClientKey = "a0864ea791ce7e7bd0df" |
|||
githubSecretKey = "a0ec09a647a688a64a28f6190b5a0d2705df56ca" |
|||
) |
|||
|
|||
type GithubController struct { |
|||
beego.Controller |
|||
} |
|||
|
|||
func (this *GithubController) Get() { |
|||
// set the auth parameters |
|||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV") |
|||
auth.Config.LoginSuccessRedirect = "/mainpage" |
|||
auth.Config.CookieSecure = false |
|||
|
|||
githubHandler := auth.Github(githubClientKey, githubSecretKey) |
|||
|
|||
githubHandler.ServeHTTP(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
} |
|||
|
|||
``` |
|||
3. 处理登陆成功之后的页面 |
|||
```Go |
|||
package controllers |
|||
|
|||
import ( |
|||
"github.com/astaxie/beego" |
|||
"github.com/bradrydzewski/go.auth" |
|||
"net/http" |
|||
"net/url" |
|||
) |
|||
|
|||
type PageController struct { |
|||
beego.Controller |
|||
} |
|||
|
|||
func (this *PageController) Get() { |
|||
// set the auth parameters |
|||
auth.Config.CookieSecret = []byte("7H9xiimk2QdTdYI7rDddfJeV") |
|||
auth.Config.LoginSuccessRedirect = "/mainpage" |
|||
auth.Config.CookieSecure = false |
|||
|
|||
user, err := auth.GetUserCookie(this.Ctx.Request) |
|||
|
|||
//if no active user session then authorize user |
|||
if err != nil || user.Id() == "" { |
|||
http.Redirect(this.Ctx.ResponseWriter, this.Ctx.Request, auth.Config.LoginRedirect, http.StatusSeeOther) |
|||
return |
|||
} |
|||
|
|||
//else, add the user to the URL and continue |
|||
this.Ctx.Request.URL.User = url.User(user.Id()) |
|||
this.Data["pic"] = user.Picture() |
|||
this.Data["id"] = user.Id() |
|||
this.Data["name"] = user.Name() |
|||
this.TplNames = "home.tpl" |
|||
} |
|||
|
|||
``` |
|||
整个的流程如下,首先打开浏览器输入地址: |
|||
|
|||
![](images/14.4.github.png?raw=true) |
|||
|
|||
图14.4 显示带有登录按钮的首页 |
|||
|
|||
然后点击链接出现如下界面: |
|||
|
|||
![](images/14.4.github2.png?raw=true) |
|||
|
|||
图14.5 点击登录按钮后显示GitHub的授权页 |
|||
|
|||
然后点击Authorize app就出现如下界面: |
|||
|
|||
![](images/14.4.github3.png?raw=true) |
|||
|
|||
图14.6 授权登录之后显示的获取到的GitHub信息页 |
|||
|
|||
## 自定义认证 |
|||
自定义的认证一般都是和session结合验证的,如下代码来源于一个基于beego的开源博客: |
|||
```Go |
|||
|
|||
//登陆处理 |
|||
func (this *LoginController) Post() { |
|||
this.TplNames = "login.tpl" |
|||
this.Ctx.Request.ParseForm() |
|||
username := this.Ctx.Request.Form.Get("username") |
|||
password := this.Ctx.Request.Form.Get("password") |
|||
md5Password := md5.New() |
|||
io.WriteString(md5Password, password) |
|||
buffer := bytes.NewBuffer(nil) |
|||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil)) |
|||
newPass := buffer.String() |
|||
|
|||
now := time.Now().Format("2006-01-02 15:04:05") |
|||
|
|||
userInfo := models.GetUserInfo(username) |
|||
if userInfo.Password == newPass { |
|||
var users models.User |
|||
users.Last_logintime = now |
|||
models.UpdateUserInfo(users) |
|||
|
|||
//登录成功设置session |
|||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
sess.Set("uid", userInfo.Id) |
|||
sess.Set("uname", userInfo.Username) |
|||
|
|||
this.Ctx.Redirect(302, "/") |
|||
} |
|||
} |
|||
|
|||
//注册处理 |
|||
func (this *RegController) Post() { |
|||
this.TplNames = "reg.tpl" |
|||
this.Ctx.Request.ParseForm() |
|||
username := this.Ctx.Request.Form.Get("username") |
|||
password := this.Ctx.Request.Form.Get("password") |
|||
usererr := checkUsername(username) |
|||
fmt.Println(usererr) |
|||
if usererr == false { |
|||
this.Data["UsernameErr"] = "Username error, Please to again" |
|||
return |
|||
} |
|||
|
|||
passerr := checkPassword(password) |
|||
if passerr == false { |
|||
this.Data["PasswordErr"] = "Password error, Please to again" |
|||
return |
|||
} |
|||
|
|||
md5Password := md5.New() |
|||
io.WriteString(md5Password, password) |
|||
buffer := bytes.NewBuffer(nil) |
|||
fmt.Fprintf(buffer, "%x", md5Password.Sum(nil)) |
|||
newPass := buffer.String() |
|||
|
|||
now := time.Now().Format("2006-01-02 15:04:05") |
|||
|
|||
userInfo := models.GetUserInfo(username) |
|||
|
|||
if userInfo.Username == "" { |
|||
var users models.User |
|||
users.Username = username |
|||
users.Password = newPass |
|||
users.Created = now |
|||
users.Last_logintime = now |
|||
models.AddUser(users) |
|||
|
|||
//登录成功设置session |
|||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
sess.Set("uid", userInfo.Id) |
|||
sess.Set("uname", userInfo.Username) |
|||
this.Ctx.Redirect(302, "/") |
|||
} else { |
|||
this.Data["UsernameErr"] = "User already exists" |
|||
} |
|||
|
|||
} |
|||
|
|||
func checkPassword(password string) (b bool) { |
|||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", password); !ok { |
|||
return false |
|||
} |
|||
return true |
|||
} |
|||
|
|||
func checkUsername(username string) (b bool) { |
|||
if ok, _ := regexp.MatchString("^[a-zA-Z0-9]{4,16}$", username); !ok { |
|||
return false |
|||
} |
|||
return true |
|||
} |
|||
``` |
|||
有了用户登陆和注册之后,其他模块的地方可以增加如下这样的用户是否登陆的判断: |
|||
```Go |
|||
|
|||
func (this *AddBlogController) Prepare() { |
|||
sess := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
sess_uid := sess.Get("userid") |
|||
sess_username := sess.Get("username") |
|||
if sess_uid == nil { |
|||
this.Ctx.Redirect(302, "/admin/login") |
|||
return |
|||
} |
|||
this.Data["Username"] = sess_username |
|||
} |
|||
``` |
|||
## links |
|||
* [目录](<preface.md>) |
|||
* 上一节: [表单及验证支持](<14.3.md>) |
|||
* 下一节: [多语言支持](<14.5.md>) |
@ -0,0 +1,122 @@ |
|||
<!-- {% raw %} --> |
|||
# 14.5 多语言支持 |
|||
我们在第十章介绍过国际化和本地化,开发了一个go-i18n库,这小节我们将把该库集成到beego框架里面来,使得我们的框架支持国际化和本地化。 |
|||
|
|||
## i18n集成 |
|||
beego中设置全局变量如下: |
|||
```Go |
|||
|
|||
Translation i18n.IL |
|||
Lang string //设置语言包,zh、en |
|||
LangPath string //设置语言包所在位置 |
|||
``` |
|||
初始化多语言函数: |
|||
```Go |
|||
|
|||
func InitLang(){ |
|||
beego.Translation:=i18n.NewLocale() |
|||
beego.Translation.LoadPath(beego.LangPath) |
|||
beego.Translation.SetLocale(beego.Lang) |
|||
} |
|||
``` |
|||
为了方便在模板中直接调用多语言包,我们设计了三个函数来处理响应的多语言: |
|||
```Go |
|||
|
|||
beegoTplFuncMap["Trans"] = i18n.I18nT |
|||
beegoTplFuncMap["TransDate"] = i18n.I18nTimeDate |
|||
beegoTplFuncMap["TransMoney"] = i18n.I18nMoney |
|||
|
|||
func I18nT(args ...interface{}) string { |
|||
ok := false |
|||
var s string |
|||
if len(args) == 1 { |
|||
s, ok = args[0].(string) |
|||
} |
|||
if !ok { |
|||
s = fmt.Sprint(args...) |
|||
} |
|||
return beego.Translation.Translate(s) |
|||
} |
|||
|
|||
func I18nTimeDate(args ...interface{}) string { |
|||
ok := false |
|||
var s string |
|||
if len(args) == 1 { |
|||
s, ok = args[0].(string) |
|||
} |
|||
if !ok { |
|||
s = fmt.Sprint(args...) |
|||
} |
|||
return beego.Translation.Time(s) |
|||
} |
|||
|
|||
func I18nMoney(args ...interface{}) string { |
|||
ok := false |
|||
var s string |
|||
if len(args) == 1 { |
|||
s, ok = args[0].(string) |
|||
} |
|||
if !ok { |
|||
s = fmt.Sprint(args...) |
|||
} |
|||
return beego.Translation.Money(s) |
|||
} |
|||
``` |
|||
## 多语言开发使用 |
|||
1. 设置语言以及语言包所在位置,然后初始化i18n对象: |
|||
```Go |
|||
|
|||
beego.Lang = "zh" |
|||
beego.LangPath = "views/lang" |
|||
beego.InitLang() |
|||
``` |
|||
2. 设计多语言包 |
|||
|
|||
上面讲了如何初始化多语言包,现在设计多语言包,多语言包是json文件,如第十章介绍的一样,我们需要把设计的文件放在LangPath下面,例如zh.json或者en.json |
|||
```json |
|||
|
|||
# zh.json |
|||
|
|||
{ |
|||
"zh": { |
|||
"submit": "提交", |
|||
"create": "创建" |
|||
} |
|||
} |
|||
|
|||
# en.json |
|||
|
|||
{ |
|||
"en": { |
|||
"submit": "Submit", |
|||
"create": "Create" |
|||
} |
|||
} |
|||
``` |
|||
3. 使用语言包 |
|||
|
|||
我们可以在controller中调用翻译获取响应的翻译语言,如下所示: |
|||
```Go |
|||
|
|||
func (this *MainController) Get() { |
|||
this.Data["create"] = beego.Translation.Translate("create") |
|||
this.TplNames = "index.tpl" |
|||
} |
|||
``` |
|||
我们也可以在模板中直接调用响应的翻译函数: |
|||
```Go |
|||
|
|||
//直接文本翻译 |
|||
{{.create | Trans}} |
|||
|
|||
//时间翻译 |
|||
{{.time | TransDate}} |
|||
|
|||
//货币翻译 |
|||
{{.money | TransMoney}} |
|||
``` |
|||
## links |
|||
* [目录](<preface.md>) |
|||
* 上一节: [用户认证](<14.4.md>) |
|||
* 下一节: [pprof支持](<14.6.md>) |
|||
<!-- {% endraw %} --> |
@ -0,0 +1,110 @@ |
|||
# 14.6 pprof支持 |
|||
Go语言有一个非常棒的设计就是标准库里面带有代码的性能监控工具,在两个地方有包: |
|||
```Go |
|||
|
|||
net/http/pprof |
|||
|
|||
runtime/pprof |
|||
``` |
|||
其实net/http/pprof中只是使用runtime/pprof包来进行封装了一下,并在http端口上暴露出来 |
|||
|
|||
## beego支持pprof |
|||
目前beego框架新增了pprof,该特性默认是不开启的,如果你需要测试性能,查看相应的执行goroutine之类的信息,其实Go的默认包"net/http/pprof"已经具有该功能,如果按照Go默认的方式执行Web,默认就可以使用,但是由于beego重新封装了ServHTTP函数,默认的包是无法开启该功能的,所以需要对beego的内部改造支持pprof。 |
|||
|
|||
- 首先在beego.Run函数中根据变量是否自动加载性能包 |
|||
```Go |
|||
|
|||
if PprofOn { |
|||
BeeApp.RegisterController(`/debug/pprof`, &ProfController{}) |
|||
BeeApp.RegisterController(`/debug/pprof/:pp([\w]+)`, &ProfController{}) |
|||
} |
|||
``` |
|||
- 设计ProfController |
|||
```Go |
|||
|
|||
package beego |
|||
|
|||
import ( |
|||
"net/http/pprof" |
|||
) |
|||
|
|||
type ProfController struct { |
|||
Controller |
|||
} |
|||
|
|||
func (this *ProfController) Get() { |
|||
switch this.Ctx.Param[":pp"] { |
|||
default: |
|||
pprof.Index(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
case "": |
|||
pprof.Index(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
case "cmdline": |
|||
pprof.Cmdline(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
case "profile": |
|||
pprof.Profile(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
case "symbol": |
|||
pprof.Symbol(this.Ctx.ResponseWriter, this.Ctx.Request) |
|||
} |
|||
this.Ctx.ResponseWriter.WriteHeader(200) |
|||
} |
|||
|
|||
``` |
|||
## 使用入门 |
|||
|
|||
通过上面的设计,你可以通过如下代码开启pprof: |
|||
```Go |
|||
|
|||
beego.PprofOn = true |
|||
``` |
|||
然后你就可以在浏览器中打开如下URL就看到如下界面: |
|||
![](images/14.6.pprof.png?raw=true) |
|||
|
|||
图14.7 系统当前goroutine、heap、thread信息 |
|||
|
|||
点击goroutine我们可以看到很多详细的信息: |
|||
|
|||
![](images/14.6.pprof2.png?raw=true) |
|||
|
|||
图14.8 显示当前goroutine的详细信息 |
|||
|
|||
我们还可以通过命令行获取更多详细的信息 |
|||
```Go |
|||
|
|||
go tool pprof http://localhost:8080/debug/pprof/profile |
|||
``` |
|||
这时候程序就会进入30秒的profile收集时间,在这段时间内拼命刷新浏览器上的页面,尽量让cpu占用性能产生数据。 |
|||
|
|||
(pprof) top10 |
|||
|
|||
Total: 3 samples |
|||
|
|||
1 33.3% 33.3% 1 33.3% MHeap_AllocLocked |
|||
|
|||
1 33.3% 66.7% 1 33.3% os/exec.(*Cmd).closeDescriptors |
|||
|
|||
1 33.3% 100.0% 1 33.3% runtime.sigprocmask |
|||
|
|||
0 0.0% 100.0% 1 33.3% MCentral_Grow |
|||
|
|||
0 0.0% 100.0% 2 66.7% main.Compile |
|||
|
|||
0 0.0% 100.0% 2 66.7% main.compile |
|||
|
|||
0 0.0% 100.0% 2 66.7% main.run |
|||
|
|||
0 0.0% 100.0% 1 33.3% makeslice1 |
|||
|
|||
0 0.0% 100.0% 2 66.7% net/http.(*ServeMux).ServeHTTP |
|||
|
|||
0 0.0% 100.0% 2 66.7% net/http.(*conn).serve |
|||
|
|||
(pprof)web |
|||
|
|||
![](images/14.6.pprof3.png?raw=true) |
|||
|
|||
图14.9 展示的执行流程信息 |
|||
|
|||
## links |
|||
* [目录](<preface.md>) |
|||
* 上一节: [多语言支持](<14.5.md>) |
|||
* 下一节: [小结](<14.7.md>) |
@ -0,0 +1,6 @@ |
|||
# 14.7 小结 |
|||
这一章主要阐述了如何基于beego框架进行扩展,这包括静态文件的支持,静态文件主要讲述了如何利用beego进行快速的网站开发,利用bootstrap搭建漂亮的站点;第二小结讲解了如何在beego中集成sessionManager,方便用户在利用beego的时候快速的使用session;第三小结介绍了表单和验证,基于Go语言的struct的定义使得我们在开发Web的过程中从重复的工作中解放出来,而且加入了验证之后可以尽量做到数据安全,第四小结介绍了用户认证,用户认证主要有三方面的需求,http basic和http digest认证,第三方认证,自定义认证,通过代码演示了如何利用现有的第三方包集成到beego应用中来实现这些认证;第五小节介绍了多语言的支持,beego中集成了go-i18n这个多语言包,用户可以很方便的利用该库开发多语言的Web应用;第六小节介绍了如何集成Go的pprof包,pprof包是用于性能调试的工具,通过对beego的改造之后集成了pprof包,使得用户可以利用pprof测试基于beego开发的应用,通过这六个小节的介绍我们扩展出来了一个比较强壮的beego框架,这个框架足以应付目前大多数的Web应用,用户可以继续发挥自己的想象力去扩展,我这里只是简单的介绍了我能想的到的几个比较重要的扩展。 |
|||
|
|||
## links |
|||
* [目录](<preface.md>) |
|||
* 上一节: [pprof支持](<14.6.md>) |
@ -0,0 +1,2 @@ |
|||
# Go Web 编程 |
|||
Go web编程是因为我喜欢Web编程,所以写了这本书,希望大家喜欢 |
@ -0,0 +1,96 @@ |
|||
* [Go环境配置](01.0.md) |
|||
* [Go安装](01.1.md) |
|||
* [Go Module, GOPATH 与工作空间](01.2.md) |
|||
* [Go 命令](01.3.md) |
|||
* [Go开发工具](01.4.md) |
|||
* [小结](01.5.md) |
|||
* [Go语言基础](02.0.md) |
|||
* [你好,Go](02.1.md) |
|||
* [Go基础](02.2.md) |
|||
* [流程和函数](02.3.md) |
|||
* [struct](02.4.md) |
|||
* [面向对象](02.5.md) |
|||
* [interface](02.6.md) |
|||
* [并发](02.7.md) |
|||
* [小结](02.8.md) |
|||
* [Web基础](03.0.md) |
|||
* [web工作方式](03.1.md) |
|||
* [Go搭建一个简单的web服务](03.2.md) |
|||
* [Go如何使得web工作](03.3.md) |
|||
* [Go的http包详解](03.4.md) |
|||
* [小结](03.5.md) |
|||
* [表单](04.0.md) |
|||
* [处理表单的输入](04.1.md) |
|||
* [验证表单的输入](04.2.md) |
|||
* [预防跨站脚本](04.3.md) |
|||
* [防止多次递交表单](04.4.md) |
|||
* [处理文件上传](04.5.md) |
|||
* [小结](04.6.md) |
|||
* [访问数据库](05.0.md) |
|||
* [database/sql接口](05.1.md) |
|||
* [使用MySQL数据库](05.2.md) |
|||
* [使用SQLite数据库](05.3.md) |
|||
* [使用PostgreSQL数据库](05.4.md) |
|||
* [使用beedb库进行ORM开发](05.5.md) |
|||
* [NOSQL数据库操作](05.6.md) |
|||
* [小结](05.7.md) |
|||
* [session和数据存储](06.0.md) |
|||
* [session和cookie](06.1.md) |
|||
* [Go如何使用session](06.2.md) |
|||
* [session存储](06.3.md) |
|||
* [预防session劫持](06.4.md) |
|||
* [小结](06.5.md) |
|||
* [文本文件处理](07.0.md) |
|||
* [XML处理](07.1.md) |
|||
* [JSON处理](07.2.md) |
|||
* [正则处理](07.3.md) |
|||
* [模板处理](07.4.md) |
|||
* [文件操作](07.5.md) |
|||
* [字符串处理](07.6.md) |
|||
* [小结](07.7.md) |
|||
* [Web服务](08.0.md) |
|||
* [Socket编程](08.1.md) |
|||
* [WebSocket](08.2.md) |
|||
* [REST](08.3.md) |
|||
* [RPC](08.4.md) |
|||
* [小结](08.5.md) |
|||
* [安全与加密](09.0.md) |
|||
* [预防CSRF攻击](09.1.md) |
|||
* [确保输入过滤](09.2.md) |
|||
* [避免XSS攻击](09.3.md) |
|||
* [避免SQL注入](09.4.md) |
|||
* [存储密码](09.5.md) |
|||
* [加密和解密数据](09.6.md) |
|||
* [小结](09.7.md) |
|||
* [国际化和本地化](10.0.md) |
|||
* [设置默认地区](10.1.md) |
|||
* [本地化资源](10.2.md) |
|||
* [国际化站点](10.3.md) |
|||
* [小结](10.4.md) |
|||
* [错误处理,调试和测试](11.0.md) |
|||
* [错误处理](11.1.md) |
|||
* [使用GDB调试](11.2.md) |
|||
* [Go怎么写测试用例](11.3.md) |
|||
* [小结](11.4.md) |
|||
* [部署与维护](12.0.md) |
|||
* [应用日志](12.1.md) |
|||
* [网站错误处理](12.2.md) |
|||
* [应用部署](12.3.md) |
|||
* [备份和恢复](12.4.md) |
|||
* [小结](12.5.md) |
|||
* [如何设计一个Web框架](13.0.md) |
|||
* [项目规划](13.1.md) |
|||
* [自定义路由器设计](13.2.md) |
|||
* [controller设计](13.3.md) |
|||
* [日志和配置设计](13.4.md) |
|||
* [实现博客的增删改](13.5.md) |
|||
* [小结](13.6.md) |
|||
* [扩展Web框架](14.0.md) |
|||
* [静态文件支持](14.1.md) |
|||
* [Session支持](14.2.md) |
|||
* [表单支持](14.3.md) |
|||
* [用户认证](14.4.md) |
|||
* [多语言支持](14.5.md) |
|||
* [pprof支持](14.6.md) |
|||
* [小结](14.7.md) |
|||
* [参考资料](ref.md) |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 240 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 123 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 24 KiB |
@ -0,0 +1,110 @@ |
|||
* 1.[Go环境配置](01.0.md) |
|||
- 1.1. [安装Go](01.1.md) |
|||
- 1.2. [GOPATH 与工作空间](01.2.md) |
|||
- 1.3. [Go 命令](01.3.md) |
|||
- 1.4. [Go开发工具](01.4.md) |
|||
- 1.5. [小结](01.5.md) |
|||
|
|||
* 2.[Go语言基础](02.0.md) |
|||
- 2.1. [你好,Go](02.1.md) |
|||
- 2.2. [Go基础](02.2.md) |
|||
- 2.3. [流程和函数](02.3.md) |
|||
- 2.4. [struct](02.4.md) |
|||
- 2.5. [面向对象](02.5.md) |
|||
- 2.6. [interface](02.6.md) |
|||
- 2.7. [并发](02.7.md) |
|||
- 2.8. [小结](02.8.md) |
|||
|
|||
* 3.[Web基础](03.0.md) |
|||
- 3.1 [web工作方式](03.1.md) |
|||
- 3.2 [Go搭建一个简单的web服务](03.2.md) |
|||
- 3.3 [Go如何使得web工作](03.3.md) |
|||
- 3.4 [Go的http包详解](03.4.md) |
|||
- 3.5 [小结](03.5.md) |
|||
|
|||
* 4.[表单](04.0.md) |
|||
- 4.1 [处理表单的输入](04.1.md) |
|||
- 4.2 [验证表单的输入](04.2.md) |
|||
- 4.3 [预防跨站脚本](04.3.md) |
|||
- 4.4 [防止多次递交表单](04.4.md) |
|||
- 4.5 [处理文件上传](04.5.md) |
|||
- 4.6 [小结](04.6.md) |
|||
|
|||
* 5.[访问数据库](05.0.md) |
|||
- 5.1 [database/sql接口](05.1.md) |
|||
- 5.2 [使用MySQL数据库](05.2.md) |
|||
- 5.3 [使用SQLite数据库](05.3.md) |
|||
- 5.4 [使用PostgreSQL数据库](05.4.md) |
|||
- 5.5 [使用Beego orm库进行ORM开发](05.5.md) |
|||
- 5.6 [NOSQL数据库操作](05.6.md) |
|||
- 5.7 [小结](05.7.md) |
|||
|
|||
* 6.[session和数据存储](06.0.md) |
|||
- 6.1 [session和cookie](06.1.md) |
|||
- 6.2 [Go如何使用session](06.2.md) |
|||
- 6.3 [session存储](06.3.md) |
|||
- 6.4 [预防session劫持](06.4.md) |
|||
- 6.5 [小结](06.5.md) |
|||
|
|||
* 7.[文本文件处理](07.0.md) |
|||
- 7.1 [XML处理](07.1.md) |
|||
- 7.2 [JSON处理](07.2.md) |
|||
- 7.3 [正则处理](07.3.md) |
|||
- 7.4 [模板处理](07.4.md) |
|||
- 7.5 [文件操作](07.5.md) |
|||
- 7.6 [字符串处理](07.6.md) |
|||
- 7.7 [小结](07.7.md) |
|||
|
|||
* 8.[Web服务](08.0.md) |
|||
- 8.1 [Socket编程](08.1.md) |
|||
- 8.2 [WebSocket](08.2.md) |
|||
- 8.3 [REST](08.3.md) |
|||
- 8.4 [RPC](08.4.md) |
|||
- 8.5 [小结](08.5.md) |
|||
|
|||
* 9.[安全与加密](09.0.md) |
|||
- 9.1 [预防CSRF攻击](09.1.md) |
|||
- 9.2 [确保输入过滤](09.2.md) |
|||
- 9.3 [避免XSS攻击](09.3.md) |
|||
- 9.4 [避免SQL注入](09.4.md) |
|||
- 9.5 [存储密码](09.5.md) |
|||
- 9.6 [加密和解密数据](09.6.md) |
|||
- 9.7 [小结](09.7.md) |
|||
|
|||
* 10.[国际化和本地化](10.0.md) |
|||
- 10.1 [设置默认地区](10.1.md) |
|||
- 10.2 [本地化资源](10.2.md) |
|||
- 10.3 [国际化站点](10.3.md) |
|||
- 10.4 [小结](10.4.md) |
|||
|
|||
* 11.[错误处理,调试和测试](11.0.md) |
|||
- 11.1 [错误处理](11.1.md) |
|||
- 11.2 [使用GDB调试](11.2.md) |
|||
- 11.3 [Go怎么写测试用例](11.3.md) |
|||
- 11.4 [小结](11.4.md) |
|||
|
|||
* 12.[部署与维护](12.0.md) |
|||
- 12.1 [应用日志](12.1.md) |
|||
- 12.2 [网站错误处理](12.2.md) |
|||
- 12.3 [应用部署](12.3.md) |
|||
- 12.4 [备份和恢复](12.4.md) |
|||
- 12.5 [小结](12.5.md) |
|||
|
|||
* 13.[如何设计一个Web框架](13.0.md) |
|||
- 13.1 [项目规划](13.1.md) |
|||
- 13.2 [自定义路由器设计](13.2.md) |
|||
- 13.3 [controller设计](13.3.md) |
|||
- 13.4 [日志和配置设计](13.4.md) |
|||
- 13.5 [实现博客的增删改](13.5.md) |
|||
- 13.6 [小结](13.6.md) |
|||
|
|||
* 14.[扩展Web框架](14.0.md) |
|||
- 14.1 [静态文件支持](14.1.md) |
|||
- 14.2 [Session支持](14.2.md) |
|||
- 14.3 [表单支持](14.3.md) |
|||
- 14.4 [用户认证](14.4.md) |
|||
- 14.5 [多语言支持](14.5.md) |
|||
- 14.6 [pprof支持](14.6.md) |
|||
- 14.7 [小结](14.7.md) |
|||
|
|||
* 附录A [参考资料](ref.md) |
@ -0,0 +1,15 @@ |
|||
# 附录A 参考资料 |
|||
|
|||
这本书的内容基本上是我学习Go过程以及以前从事Web开发过程中的一些经验总结,里面部分内容参考了很多站点的内容,感谢这些站点的内容让我能够总结出来这本书,参考资料如下: |
|||
|
|||
1. [golang blog](http://blog.golang.org) |
|||
2. [Russ Cox blog](http://research.swtch.com/) |
|||
3. [go book](http://go-book.appsp0t.com/) |
|||
4. [golangtutorials](http://golangtutorials.blogspot.com) |
|||
5. [轩脉刃de刀光剑影](http://www.cnblogs.com/yjf512/) |
|||
6. [Go 官网文档](http://golang.org/doc/) |
|||
7. [Network programming with Go](http://jan.newmarch.name/go/) |
|||
8. [setup-the-rails-application-for-internationalization](http://guides.rubyonrails.org/i18n.html#setup-the-rails-application-for-internationalization) |
|||
9. [The Cross-Site Scripting (XSS) FAQ](http://www.cgisecurity.com/xss-faq.html) |
|||
10. [Network programming with Go](http://jan.newmarch.name/go) |
|||
11. [RESTful](http://www.ruanyifeng.com/blog/2011/09/restful.html) |
@ -0,0 +1,5 @@ |
|||
package main |
|||
|
|||
func main() { |
|||
|
|||
} |
@ -0,0 +1,115 @@ |
|||
# 什么是Beego |
|||
|
|||
> beego 是一个快速开发Go应用的http框架,go 语言方面技术大牛。 |
|||
> |
|||
> beego 可以用来快速开发API、Web、后端服务等各种应用,是一个RESTFul的框架,主要设计灵感来源于tornado、sinatra、flask这三个框架,但是结合了Go本身的一些特性(interface、struct继承等)而设计的一个框架。 |
|||
|
|||
### 官方网站 |
|||
|
|||
Beego官网:[https://beego.me/](https://beego.me/) |
|||
|
|||
### 框架源码 |
|||
|
|||
Beego框架源码地址:[https://github.com/beego/beego](https://github.com/beego/beego) |
|||
|
|||
### 框架学习文档 |
|||
|
|||
「推荐」Beego框架中文学习文档: [https://beego.me/docs/intro/](https://beego.me/docs/intro/) |
|||
当然,还有其他相关资料,比如说xorm框架等,这些我们在后面的课程文档中学习到以后再做解释和说明。 |
|||
|
|||
# 开发环境 |
|||
|
|||
- GoLand 2019.2 EAP |
|||
- GoLang 1.11.5 |
|||
- 采用 Bee工具 进行项目管理 |
|||
|
|||
## Beego 开发环境搭建 |
|||
|
|||
> go get -u -v github.com/beego/beego |
|||
> |
|||
## Bee 开发工具安装和打包 |
|||
|
|||
> go get -u -v github.com/beego/bee |
|||
|
|||
## 生成 Bee 工具包 |
|||
|
|||
``` |
|||
$ cd $GOPATH/src/github.com/beego/bee |
|||
$ go build -o bee beego.go |
|||
``` |
|||
|
|||
# 简单示例 |
|||
下面这个示例程序将会在浏览器中打印 “Hello world”,以此说明使用 beego 构建 Web 应用程序是多么的简单! |
|||
|
|||
``` |
|||
package main |
|||
|
|||
import ( |
|||
"github.com/beego/beego/v2/server/web" |
|||
) |
|||
|
|||
type MainController struct { |
|||
web.Controller |
|||
} |
|||
|
|||
func (this *MainController) Get() { |
|||
this.Ctx.WriteString("hello world") |
|||
} |
|||
|
|||
func main() { |
|||
web.Router("/", &MainController{}) |
|||
web.Run() |
|||
} |
|||
``` |
|||
把上面的代码保存为 hello.go,然后通过命令行进行编译并执行: |
|||
|
|||
``` |
|||
$ go build -o hello hello.go |
|||
$ ./hello |
|||
``` |
|||
这个时候你可以打开你的浏览器,通过这个地址浏览 http://127.0.0.1:8080 返回 “hello world”。 |
|||
|
|||
那么上面的代码到底做了些什么呢? |
|||
|
|||
> 1、首先我们导入了包 `github.com/beego/beego/v2/server/web`。我们知道 Go 语言里面被导入的包会按照深度优先的顺序去执行导入包的初始化(变量和 init 函数,更多详情),beego 包中会初始化一个 BeeAPP 的应用和一些参数。 |
|||
> |
|||
> 2、定义 Controller,这里我们定义了一个 struct 为 `MainController`,充分利用了 Go 语言的组合的概念,匿名包含了 `web.Controller`,这样我们的 `MainController` 就拥有了 `web.Controller` 的所有方法。 |
|||
> |
|||
> 3、定义 RESTful 方法,通过匿名组合之后,其实目前的 `MainController` 已经拥有了 `Get`、`Post`、`Delete`、`Put` 等方法,这些方法是分别用来对应用户请求的 Method 函数,如果用户发起的是 `POST` 请求,那么就执行 `Post` 函数。所以这里我们定义了 MainController 的 Get 方法用来重写继承的 Get 函数,这样当用户发起 GET 请求的时候就会执行该函数。 |
|||
> |
|||
> 4、定义 main 函数,所有的 Go 应用程序和 C 语言一样都是 main 函数作为入口,所以我们这里定义了我们应用的入口。 |
|||
> |
|||
> 5、Router 注册路由,路由就是告诉 beego,当用户来请求的时候,该如何去调用相应的 Controller,这里我们注册了请求 `/` 的时候,请求到 `MainController`。这里我们需要知道,Router 函数的两个参数函数,第一个是路径,第二个是 Controller 的指针。 |
|||
> |
|||
> 6、Run 应用,最后一步就是把在步骤 1 中初始化的 BeeApp 开启起来,其实就是内部监听了 8080 端口:Go 默认情况会监听你本机所有的 IP 上面的 8080 端口。 |
|||
|
|||
停止服务的话,请按 `Ctrl+c`。 |
|||
|
|||
下面为 windows 下的快捷操作批处理文件: |
|||
在 `%GOPATH%/src` 目录下分别创建文件 `step1.install-bee.bat 和 step2.new-beego-app.bat`。 |
|||
|
|||
`step1.install-bee.bat` 文件内容: |
|||
``` |
|||
set GOPATH=%~dp0.. |
|||
go build github.com\beego\bee |
|||
|
|||
copy bee.exe %GOPATH%\bin\bee.exe |
|||
del bee.exe |
|||
pause |
|||
``` |
|||
`step2.new-beego-app.bat` 文件内容: |
|||
``` |
|||
@echo 设置 App 的值为您的应用文件夹名称 |
|||
set APP=coscms.com |
|||
set GOPATH=%~dp0.. |
|||
set BEE=%GOPATH%\bin\bee |
|||
%BEE% new %APP% |
|||
cd %APP% |
|||
echo %BEE% run %APP%.exe > run.bat |
|||
echo pause >> run.bat |
|||
start run.bat |
|||
pause |
|||
start http://127.0.0.1:8080 |
|||
``` |
|||
依次点击上面创建的两个文件即可快速开启 beego 之旅。 |
|||
以后只需要到您的应用目录下点击 `run.bat` 即可。 |
@ -0,0 +1,398 @@ |
|||
# 模板处理 |
|||
|
|||
## 什么是模板 |
|||
|
|||
你一定听说过一种叫做MVC的设计模式,Model处理数据,View展现结果,Controller控制用户的请求,至于View层的处理,在很多动态语言里面都是通过在静态HTML中插入动态语言生成的数据,例如JSP中通过插入`<%=....=%>`,PHP中通过插入`<?php.....?>`来实现的。 |
|||
|
|||
通过下面这个图可以说明模板的机制 |
|||
|
|||
![图7.1 模板机制图](img/7.4.template.png?raw=true) |
|||
|
|||
Web应用反馈给客户端的信息中的大部分内容是静态的,不变的,而另外少部分是根据用户的请求来动态生成的,例如要显示用户的访问记录列表。用户之间只有记录数据是不同的,而列表的样式则是固定的,此时采用模板可以复用很多静态代码。 |
|||
|
|||
## Go模板使用 |
|||
|
|||
在Go语言中,我们使用`template`包来进行模板处理,使用类似`Parse`、`ParseFile`、`Execute`等方法从文件或者字符串加载模板,然后执行类似上面图片展示的模板的merge操作。请看下面的例子: |
|||
|
|||
```Go |
|||
func handler(w http.ResponseWriter, r *http.Request) { |
|||
t := template.New("some template") //创建一个模板 |
|||
t, _ = t.ParseFiles("tmpl/welcome.html") //解析模板文件 |
|||
user := GetUser() //获取当前用户信息 |
|||
t.Execute(w, user) //执行模板的merger操作 |
|||
} |
|||
``` |
|||
|
|||
通过上面的例子我们可以看到Go语言的模板操作非常的简单方便,和其他语言的模板处理类似,都是先获取数据,然后渲染数据。 |
|||
|
|||
为了演示和测试代码的方便,我们在接下来的例子中采用如下格式的代码 |
|||
|
|||
- 使用Parse代替ParseFiles,因为Parse可以直接测试一个字符串,而不需要额外的文件 |
|||
- 不使用handler来写演示代码,而是每个测试一个main,方便测试 |
|||
- 使用`os.Stdout`代替`http.ResponseWriter`,因为`os.Stdout`实现了`io.Writer`接口 |
|||
|
|||
## 模板中如何插入数据? |
|||
|
|||
上面我们演示了如何解析并渲染模板,接下来让我们来更加详细的了解如何把数据渲染出来。一个模板都是应用在一个Go的对象之上,Go对象的字段如何插入到模板中呢? |
|||
|
|||
### 字段操作 |
|||
|
|||
Go语言的模板通过`{{}}`来包含需要在渲染时被替换的字段,`{{.}}`表示当前的对象,这和Java或者C++中的this类似,如果要访问当前对象的字段通过`{{.FieldName}}`,但是需要注意一点:这个字段必须是导出的(字段首字母必须是大写的),否则在渲染的时候就会报错,请看下面的这个例子: |
|||
|
|||
```Go |
|||
package main |
|||
|
|||
import ( |
|||
"html/template" |
|||
"os" |
|||
) |
|||
|
|||
type Person struct { |
|||
UserName string |
|||
} |
|||
|
|||
func main() { |
|||
t := template.New("fieldname example") |
|||
t, _ = t.Parse("hello {{.UserName}}!") |
|||
p := Person{UserName: "Astaxie"} |
|||
t.Execute(os.Stdout, p) |
|||
} |
|||
``` |
|||
|
|||
上面的代码我们可以正确的输出`hello Astaxie`,但是如果我们稍微修改一下代码,在模板中含有了未导出的字段,那么就会报错 |
|||
|
|||
```Go |
|||
type Person struct { |
|||
UserName string |
|||
email string //未导出的字段,首字母是小写的 |
|||
} |
|||
|
|||
t, _ = t.Parse("hello {{.UserName}}! {{.email}}") |
|||
``` |
|||
|
|||
上面的代码就会报错,因为我们调用了一个未导出的字段,但是如果我们调用了一个不存在的字段是不会报错的,而是输出为空。 |
|||
|
|||
如果模板中输出`{{.}}`,这个一般应用于字符串对象,默认会调用fmt包输出字符串的内容。 |
|||
|
|||
### 输出嵌套字段内容 |
|||
|
|||
上面我们例子展示了如何针对一个对象的字段输出,那么如果字段里面还有对象,如何来循环的输出这些内容呢?我们可以使用`{{with …}}…{{end}}`和`{{range …}}{{end}}`来进行数据的输出。 |
|||
|
|||
- {{range}} 这个和Go语法里面的range类似,循环操作数据 |
|||
- {{with}}操作是指当前对象的值,类似上下文的概念 |
|||
|
|||
详细的使用请看下面的例子: |
|||
|
|||
```Go |
|||
package main |
|||
|
|||
import ( |
|||
"html/template" |
|||
"os" |
|||
) |
|||
|
|||
type Friend struct { |
|||
Fname string |
|||
} |
|||
|
|||
type Person struct { |
|||
UserName string |
|||
Emails []string |
|||
Friends []*Friend |
|||
} |
|||
|
|||
func main() { |
|||
f1 := Friend{Fname: "minux.ma"} |
|||
f2 := Friend{Fname: "xushiwei"} |
|||
t := template.New("fieldname example") |
|||
t, _ = t.Parse(`hello {{.UserName}}! |
|||
{{range .Emails}} |
|||
an email {{.}} |
|||
{{end}} |
|||
{{with .Friends}} |
|||
{{range .}} |
|||
my friend name is {{.Fname}} |
|||
{{end}} |
|||
{{end}} |
|||
`) |
|||
p := Person{UserName: "Astaxie", |
|||
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"}, |
|||
Friends: []*Friend{&f1, &f2}} |
|||
t.Execute(os.Stdout, p) |
|||
} |
|||
``` |
|||
|
|||
### 条件处理 |
|||
|
|||
在Go模板里面如果需要进行条件判断,那么我们可以使用和Go语言的`if-else`语法类似的方式来处理,如果pipeline为空,那么if就认为是false,下面的例子展示了如何使用`if-else`语法: |
|||
|
|||
```Go |
|||
package main |
|||
|
|||
import ( |
|||
"os" |
|||
"text/template" |
|||
) |
|||
|
|||
func main() { |
|||
tEmpty := template.New("template test") |
|||
tEmpty = template.Must(tEmpty.Parse("空 pipeline if demo: {{if ``}} 不会输出. {{end}}\n")) |
|||
tEmpty.Execute(os.Stdout, nil) |
|||
|
|||
tWithValue := template.New("template test") |
|||
tWithValue = template.Must(tWithValue.Parse("不为空的 pipeline if demo: {{if `anything`}} 我有内容,我会输出. {{end}}\n")) |
|||
tWithValue.Execute(os.Stdout, nil) |
|||
|
|||
tIfElse := template.New("template test") |
|||
tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} if部分 {{else}} else部分.{{end}}\n")) |
|||
tIfElse.Execute(os.Stdout, nil) |
|||
} |
|||
``` |
|||
|
|||
通过上面的演示代码我们知道`if-else`语法相当的简单,在使用过程中很容易集成到我们的模板代码中。 |
|||
|
|||
> 注意:if里面无法使用条件判断,例如.Mail=="astaxie@gmail.com",这样的判断是不正确的,if里面只能是bool值 |
|||
|
|||
### pipelines |
|||
|
|||
Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的语法你是不是经常使用,过滤当前目录下面的文件,显示含有"beego"的数据,表达的意思就是前面的输出可以当做后面的输入,最后显示我们想要的数据,而Go语言模板最强大的一点就是支持pipe数据,在Go语言里面任何`{{}}`里面的都是pipelines数据,例如我们上面输出的email里面如果还有一些可能引起XSS注入的,那么我们如何来进行转化呢? |
|||
|
|||
```Go |
|||
{{. | html}} |
|||
|
|||
``` |
|||
|
|||
在email输出的地方我们可以采用如上方式可以把输出全部转化html的实体,上面的这种方式和我们平常写Unix的方式是不是一模一样,操作起来相当的简便,调用其他的函数也是类似的方式。 |
|||
|
|||
### 模板变量 |
|||
|
|||
有时候,我们在模板使用过程中需要定义一些局部变量,我们可以在一些操作中申明局部变量,例如`with``range``if`过程中申明局部变量,这个变量的作用域是`{{end}}`之前,Go语言通过申明的局部变量格式如下所示: |
|||
|
|||
```Go |
|||
$variable := pipeline |
|||
``` |
|||
|
|||
详细的例子看下面的: |
|||
|
|||
```Go |
|||
{{with $x := "output" | printf "%q"}}{{$x}}{{end}} |
|||
{{with $x := "output"}}{{printf "%q" $x}}{{end}} |
|||
{{with $x := "output"}}{{$x | printf "%q"}}{{end}} |
|||
|
|||
``` |
|||
|
|||
### 模板函数 |
|||
|
|||
模板在输出对象的字段值时,采用了`fmt`包把对象转化成了字符串。但是有时候我们的需求可能不是这样的,例如有时候我们为了防止垃圾邮件发送者通过采集网页的方式来发送给我们的邮箱信息,我们希望把`@`替换成`at`例如:`astaxie at beego.me`,如果要实现这样的功能,我们就需要自定义函数来做这个功能。 |
|||
|
|||
每一个模板函数都有一个唯一值的名字,然后与一个Go函数关联,通过如下的方式来关联 |
|||
|
|||
```Go |
|||
type FuncMap map[string]interface{} |
|||
``` |
|||
|
|||
例如,如果我们想要的email函数的模板函数名是`emailDeal`,它关联的Go函数名称是`EmailDealWith`,那么我们可以通过下面的方式来注册这个函数 |
|||
|
|||
```Go |
|||
t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith}) |
|||
``` |
|||
|
|||
`EmailDealWith`这个函数的参数和返回值定义如下: |
|||
|
|||
```Go |
|||
func EmailDealWith(args …interface{}) string |
|||
``` |
|||
|
|||
我们来看下面的实现例子: |
|||
|
|||
```Go |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"html/template" |
|||
"os" |
|||
"strings" |
|||
) |
|||
|
|||
type Friend struct { |
|||
Fname string |
|||
} |
|||
|
|||
type Person struct { |
|||
UserName string |
|||
Emails []string |
|||
Friends []*Friend |
|||
} |
|||
|
|||
func EmailDealWith(args ...interface{}) string { |
|||
ok := false |
|||
var s string |
|||
if len(args) == 1 { |
|||
s, ok = args[0].(string) |
|||
} |
|||
if !ok { |
|||
s = fmt.Sprint(args...) |
|||
} |
|||
// find the @ symbol |
|||
substrs := strings.Split(s, "@") |
|||
if len(substrs) != 2 { |
|||
return s |
|||
} |
|||
// replace the @ by " at " |
|||
return (substrs[0] + " at " + substrs[1]) |
|||
} |
|||
|
|||
func main() { |
|||
f1 := Friend{Fname: "minux.ma"} |
|||
f2 := Friend{Fname: "xushiwei"} |
|||
t := template.New("fieldname example") |
|||
t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith}) |
|||
t, _ = t.Parse(`hello {{.UserName}}! |
|||
{{range .Emails}} |
|||
an emails {{.|emailDeal}} |
|||
{{end}} |
|||
{{with .Friends}} |
|||
{{range .}} |
|||
my friend name is {{.Fname}} |
|||
{{end}} |
|||
{{end}} |
|||
`) |
|||
p := Person{UserName: "Astaxie", |
|||
Emails: []string{"astaxie@beego.me", "astaxie@gmail.com"}, |
|||
Friends: []*Friend{&f1, &f2}} |
|||
t.Execute(os.Stdout, p) |
|||
} |
|||
|
|||
``` |
|||
|
|||
上面演示了如何自定义函数,其实,在模板包内部已经有内置的实现函数,下面代码截取自模板包里面 |
|||
|
|||
```Go |
|||
var builtins = FuncMap{ |
|||
"and": and, |
|||
"call": call, |
|||
"html": HTMLEscaper, |
|||
"index": index, |
|||
"js": JSEscaper, |
|||
"len": length, |
|||
"not": not, |
|||
"or": or, |
|||
"print": fmt.Sprint, |
|||
"printf": fmt.Sprintf, |
|||
"println": fmt.Sprintln, |
|||
"urlquery": URLQueryEscaper, |
|||
} |
|||
|
|||
``` |
|||
|
|||
## Must操作 |
|||
|
|||
模板包里面有一个函数`Must`,它的作用是检测模板是否正确,例如大括号是否匹配,注释是否正确的关闭,变量是否正确的书写。接下来我们演示一个例子,用Must来判断模板是否正确: |
|||
|
|||
```Go |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"text/template" |
|||
) |
|||
|
|||
func main() { |
|||
tOk := template.New("first") |
|||
template.Must(tOk.Parse(" some static text /* and a comment */")) |
|||
fmt.Println("The first one parsed OK.") |
|||
|
|||
template.Must(template.New("second").Parse("some static text {{ .Name }}")) |
|||
fmt.Println("The second one parsed OK.") |
|||
|
|||
fmt.Println("The next one ought to fail.") |
|||
tErr := template.New("check parse error with Must") |
|||
template.Must(tErr.Parse(" some static text {{ .Name }")) |
|||
} |
|||
|
|||
``` |
|||
|
|||
将输出如下内容 |
|||
|
|||
``` |
|||
The first one parsed OK. |
|||
The second one parsed OK. |
|||
The next one ought to fail. |
|||
panic: template: check parse error with Must:1: unexpected "}" in command |
|||
``` |
|||
|
|||
## 嵌套模板 |
|||
|
|||
我们平常开发Web应用的时候,经常会遇到一些模板有些部分是固定不变的,然后可以抽取出来作为一个独立的部分,例如一个博客的头部和尾部是不变的,而唯一改变的是中间的内容部分。所以我们可以定义成`header`、`content`、`footer`三个部分。Go语言中通过如下的语法来申明 |
|||
|
|||
```Go |
|||
{{define "子模板名称"}}内容{{end}} |
|||
``` |
|||
|
|||
通过如下方式来调用: |
|||
|
|||
```Go |
|||
{{template "子模板名称"}} |
|||
``` |
|||
|
|||
接下来我们演示如何使用嵌套模板,我们定义三个文件,`header.tmpl`、`content.tmpl`、`footer.tmpl`文件,里面的内容如下 |
|||
|
|||
```html |
|||
//header.tmpl |
|||
{{define "header"}} |
|||
<html> |
|||
<head> |
|||
<title>演示信息</title> |
|||
</head> |
|||
<body> |
|||
{{end}} |
|||
|
|||
//content.tmpl |
|||
{{define "content"}} |
|||
{{template "header"}} |
|||
<h1>演示嵌套</h1> |
|||
<ul> |
|||
<li>嵌套使用define定义子模板</li> |
|||
<li>调用使用template</li> |
|||
</ul> |
|||
{{template "footer"}} |
|||
{{end}} |
|||
|
|||
//footer.tmpl |
|||
{{define "footer"}} |
|||
</body> |
|||
</html> |
|||
{{end}} |
|||
``` |
|||
|
|||
演示代码如下: |
|||
|
|||
```Go |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"os" |
|||
"text/template" |
|||
) |
|||
|
|||
func main() { |
|||
s1, _ := template.ParseFiles("header.tmpl", "content.tmpl", "footer.tmpl") |
|||
s1.ExecuteTemplate(os.Stdout, "header", nil) |
|||
fmt.Println() |
|||
s1.ExecuteTemplate(os.Stdout, "content", nil) |
|||
fmt.Println() |
|||
s1.ExecuteTemplate(os.Stdout, "footer", nil) |
|||
fmt.Println() |
|||
s1.Execute(os.Stdout, nil) |
|||
} |
|||
``` |
|||
|
|||
通过上面的例子我们可以看到通过`template.ParseFiles`把所有的嵌套模板全部解析到模板里面,其实每一个定义的{{define}}都是一个独立的模板,他们相互独立,是并行存在的关系,内部其实存储的是类似map的一种关系(key是模板的名称,value是模板的内容),然后我们通过`ExecuteTemplate`来执行相应的子模板内容,我们可以看到header、footer都是相对独立的,都能输出内容,content 中因为嵌套了header和footer的内容,就会同时输出三个的内容。但是当我们执行`s1.Execute`,没有任何的输出,因为在默认的情况下没有默认的子模板,所以不会输出任何的东西。 |
|||
|
|||
>同一个集合类的模板是互相知晓的,如果同一模板被多个集合使用,则它需要在多个集合中分别解析 |
|||
|
|||
## 总结 |
|||
|
|||
通过上面对模板的详细介绍,我们了解了如何把动态数据与模板融合:如何输出循环数据、如何自定义函数、如何嵌套模板等等。通过模板技术的应用,我们可以完成MVC模式中V的处理,接下来的章节我们将介绍如何来处理M和C。 |
@ -0,0 +1,9 @@ |
|||
module go_to_beego |
|||
|
|||
go 1.14 |
|||
|
|||
require ( |
|||
github.com/astaxie/beego v1.12.3 |
|||
github.com/beego/beego/v2 v2.0.1 |
|||
github.com/go-sql-driver/mysql v1.5.0 |
|||
) |
@ -0,0 +1,274 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= |
|||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= |
|||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= |
|||
github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ= |
|||
github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA= |
|||
github.com/beego/beego/v2 v2.0.1 h1:07a7Z0Ok5vbqyqh+q53sDPl9LdhKh0ZDy3gbyGrhFnE= |
|||
github.com/beego/beego/v2 v2.0.1/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI= |
|||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= |
|||
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= |
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= |
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= |
|||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= |
|||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= |
|||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= |
|||
github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= |
|||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= |
|||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= |
|||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= |
|||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= |
|||
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= |
|||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= |
|||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= |
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw= |
|||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= |
|||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= |
|||
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= |
|||
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= |
|||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= |
|||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= |
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= |
|||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= |
|||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= |
|||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= |
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= |
|||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= |
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= |
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= |
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= |
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= |
|||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= |
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= |
|||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= |
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= |
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= |
|||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= |
|||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= |
|||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= |
|||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= |
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= |
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= |
|||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= |
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= |
|||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= |
|||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= |
|||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= |
|||
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= |
|||
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= |
|||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= |
|||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= |
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= |
|||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= |
|||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= |
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= |
|||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= |
|||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= |
|||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= |
|||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= |
|||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= |
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
|||
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
|||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
|||
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= |
|||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= |
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= |
|||
go.etcd.io/etcd v3.3.25+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= |
|||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= |
|||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= |
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= |
|||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= |
|||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= |
|||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= |
|||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= |
|||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= |
|||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag= |
|||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= |
|||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= |
|||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= |
|||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= |
|||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= |
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= |
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= |
|||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= |
|||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= |
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= |
|||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
|||
honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= |
@ -0,0 +1,62 @@ |
|||
package main |
|||
|
|||
import "github.com/beego/beego/v2/server/web" |
|||
|
|||
type User struct { |
|||
Name string |
|||
} |
|||
|
|||
type MainController struct { |
|||
web.Controller |
|||
} |
|||
|
|||
// Get 单值映射
|
|||
// 127.0.0.1:8080/hello?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie
|
|||
func (this *MainController) Get() { |
|||
|
|||
// 1、方式一 使用 xx.Ctx.Input.Bind(&xx, "xx")
|
|||
user := new(User) |
|||
this.Ctx.Input.Bind(&user, "user") //user == {Name:"astaxie"} 【映射 结构体】
|
|||
// var name string this.Ctx.Input.Bind(&name, "name") //id ==123 【映射 字符串类型】
|
|||
// var id int this.Ctx.Input.Bind(&id, "id") //id ==123 【映射 整形】
|
|||
// var isok bool this.Ctx.Input.Bind(&isok, "isok") //isok ==true 【映射 布尔型】
|
|||
// var ft float64 this.Ctx.Input.Bind(&ft, "ft") //ft ==1.2 【映射 浮点型】
|
|||
// ol := make([]int, 0, 2) this.Ctx.Input.Bind(&ol, "ol") //ol ==[1 2] 【映射 数组】
|
|||
// ul := make([]string, 0, 2) this.Ctx.Input.Bind(&ul, "ul") //ul ==[str array] 【映射 字符串数组】
|
|||
|
|||
this.Ctx.WriteString("hello world - get" + user.Name) |
|||
} |
|||
func (this *MainController) Post() { |
|||
|
|||
// 获取用户传递的数据,包括 Get、POST 等方式的请求
|
|||
// 注意️:单个参数映射
|
|||
// GetString(key string) string
|
|||
// GetStrings(key string) []string
|
|||
// GetInt(key string) (int64, error)
|
|||
// GetBool(key string) (bool, error)
|
|||
// GetFloat(key string) (float64, error)
|
|||
|
|||
// 或者:this.Input().Get("id")
|
|||
|
|||
// 注意:结构体
|
|||
u := User{} |
|||
this.ParseForm(&u) // 结构体映射
|
|||
|
|||
this.Ctx.WriteString("hello world - post") |
|||
} |
|||
func (this *MainController) Delete() { |
|||
this.Ctx.WriteString("hello world - post") |
|||
} |
|||
|
|||
/** |
|||
main 获取请求内参数 |
|||
*/ |
|||
func main() { |
|||
// 请求:127.0.0.1:8080/hello?user.Name=astaxie
|
|||
web.Router("/hello", &MainController{}) |
|||
|
|||
// 请求:127.0.0.1:8080/user/:id
|
|||
web.Router("/user/:id", &MainController{}) |
|||
|
|||
web.Run("127.0.0.1:8080") |
|||
} |
@ -0,0 +1,8 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ProjectModuleManager"> |
|||
<modules> |
|||
<module fileurl="file://$PROJECT_DIR$/.idea/go_to_beego_init.iml" filepath="$PROJECT_DIR$/.idea/go_to_beego_init.iml" /> |
|||
</modules> |
|||
</component> |
|||
</project> |
@ -0,0 +1,7 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="VcsDirectoryMappings"> |
|||
<mapping directory="$PROJECT_DIR$/../../.." vcs="Git" /> |
|||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" /> |
|||
</component> |
|||
</project> |
@ -0,0 +1,511 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ChangeListManager"> |
|||
<list default="true" id="9651017f-2ab1-4d30-87c6-c6b0cac20b85" name="Default Changelist" comment=""> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_algorithm/Boyer-Moore算法.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_algorithm/KMP算法.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_algorithm/暴力匹配.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_base64/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_base64/rc.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_cmd/a.vbs" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_cmd/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_code/文字格式转换.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_command/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_contrast/字符串对比并输出到HTML.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_copy_a57/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_db_sql/查询数据库生成DML.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_dir/javaknowledge/创建Java知识结构目录程序.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_dir/proiject/创建项目常用目录程序.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_dir/readDir/获取某目录下所有文件.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_dir/writeDir/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_dos/addHzb/RunDosAddHzb.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_dos/demo/Demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_excel/README.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_excel/go_to_readExcel/读取文件内容.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_excel/go_to_styleExcel/为已有文件添加样式.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_excel/go_to_styleExcel/新增文件并添加样式.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_excel/go_to_validation/数据验证.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_excel/go_to_writeExcel/生成excel操作.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_excel/makeExcel/sheet-merge/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_copyfile/CopySQLXml.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_hzb/HZBFileComp.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_rename/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/readTXT/2019612005233.txt" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/readTXT/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/readTXT/一次读取.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/readTXT/分块读取.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/readTXT/读取文件.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/readTXT/逐行读取.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/writeTXT/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/go_to_txt/writeTXT/readFileDirTXT/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file/readfile/获取当前文件名称.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file_path/go/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_file_path/json/m.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_flag/demo01/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_flag/帮助文件.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_format/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo1/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo1/最小的带GUI.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo2/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo2/较为复杂界面.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo3/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo3/实现交互界面.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo4/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo4/替换应用左上角图标.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo5/imgcollector.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo5/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo5/文件收集器.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo6/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/demo6/基础的画布对象.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/img/1.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_fyne/帮助文件.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_generate/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_godotenv/main.env" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_godotenv/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_gosciter/learn/01HelloWord.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_govendor/Golang包管理工具之govendor的使用.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_goversioninfo/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_goversioninfo/rc.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_goversioninfo/resource.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_goversioninfo/versioninfo.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_goversioninfo/参数说明对比.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_goversioninfo/添加版心信息和图标信息.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_goversioninfo/说明.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_html/生成html文件.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_http/demo01/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_http/demo02/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_icon/main.exe.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_icon/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_icon/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_icon/rc.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_icon/【推荐】给go生成的windows exe文件添加icon图标.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_icon/帮助文档.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_icon/给go生成的windows exe文件添加icon图标.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_img/convert/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_img/demo01/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_img/demo02/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_img/main.exe.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_img/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_img/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_img/rc.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_inherit/demo1/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_inherit/demo2/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_inherit/demo3/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_inherit/demo4/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_inherit/demo5/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_ini/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_ini/demo/demo.ini" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_interface/README.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_interface/接口学习.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_interface/接口类型学习.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_interface/接口类型学习2.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_json/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_json/demo1/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_json/readJson/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_json/readJsonFile/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_json/writeJson/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_log/demo/60680606.txt" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_log/demo/Print到日志文件.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_log/log_analysis_system/Analyse.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_log/log_analysis_system/ask_testt_buzhi(1).log" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_log/log_analysis_system/ask_testt_buzhi.log" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_markdown/from_markdown_to_html.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_markdown/操作Markdown.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/MySQLLogForHzb/RunMySQLLog.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/demo/demo2.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/demo_insert_massive_info/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/demo_query_by_fmt/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/demo_query_by_sql/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/demo_query_by_type/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/go_to_hzb/Demo/ReadDBCode.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/go_to_hzb/HZBMySQLComp.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/go_to_hzb/Obj/OBJ.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/go_to_hzb/Obj/RunGo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/go_to_hzb/Obj/RunGo_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_mysql/查询mysql.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_obj/Obj/RunGo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_obj/Obj/RunGo_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_oracle/demo1/查询oracle.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_oracle/demo2/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_oracle/go_to_hzb/HZBOracleComp.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_ppt/ReadPPT.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_regexp/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_registry/Windows组册表.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_registry/addHzb/RunRegistyHzb.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_registry/demo/Demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_registry/demo/对应关系.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_reptile/from_html_to_mysql.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_reptile/reptile_av.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_reptile/reptile_demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_reptile/爬虫.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/bubble_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/bucket_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/count_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/heap_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/insert_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/merge_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/quick_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/select_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sort/shell_sort/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sql_xml/生成SQLXML文件.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sqlite/demo.db" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_sqlite/查询sqlite.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_struct/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_struct/说明.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_tcp/tcpClient.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_tcp/tcpServer.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_test/damo_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_test/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_test/main/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_threads/Go 语言多线程实例.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_threads/go 简单多线程处理数据.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_viper/config.yaml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_viper/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo01/img/rc.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo01/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo01/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo01/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo02/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo02/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo02/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo02/转大写界面程序.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo03/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo03/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo03/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo04/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo04/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo04/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo04/复制内容并显示到界面程序中.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo05/img/search.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo05/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo05/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo05/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo05/文件选择对话框.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo06/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo06/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo06/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo06/简单登陆页面.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo07/img/search.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo07/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo07/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo07/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo07/文本检索器.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo08/data.dat" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo08/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo08/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo08/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo08/邮件群发器.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo09/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo09/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo09/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo09/简单列表功能.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo10/img/search.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo10/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo10/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo10/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo10/博客搜索查看-展示图.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo10/博客搜索查看-效果图.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo10/帮助文档.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo11/img/search.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo11/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo11/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo11/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo12/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo12/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo12/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo13/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo13/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo13/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo13/最简单的GUI界面.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo14/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo14/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo14/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/demo14/最简单的进度条界面.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/img/1.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/img/2.png" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/学习笔记.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_walk/帮助文件.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_word/go_to_readWord/ReadWord.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo1/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo1/servers.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo1/说明.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo2/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo2/说明.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo3/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo3/说明.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo4/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml/demo4/说明.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_xml_log/生成XML工具_日志.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_yaml/config.yaml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_yaml/读取Yaml文件.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/ZipUtil/ZipUtil.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/ZipUtil/ZipUtil_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/demo1/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/demo2/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/demo3/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/readZip/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/writeZip/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_func/go_to_zip/writeZip/demo_mm.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/all_db/ForAllDB.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/all_db/SQL.ini" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/db_balance_dpacket/DBalancePacket.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/dl_a01_by_b0111/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/dl_a01_by_b0111/main.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/dl_a01_by_b0111/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/dl_a01_by_b0111/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/hy_balance/ForHyBalance.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/hy_mysql/ForHyMySQL.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/hy_mysql/SQL.ini" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/hzb_mysql/ForHZBMySQL.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/hzb_mysql/SQL.ini" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/hzbtj_mysql/ForHZBTJMySQL.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/hzbtj_mysql/SQL.ini" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance/main.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_a0221/ForHyBalanceA0221.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_a1517/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_a1517/main.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_a1517/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_a1517/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_gui/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_gui/main.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_gui/main.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_balance_gui/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_mysql/ForOnlyMySQL.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_db_excel/only_mysql/SQL.ini" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_excel_velidation/README.md" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_excel_velidation/config.yaml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_excel_velidation/使用配置文件执行校验规则.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_excel_velidation/使用配置文件添加校验规则.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hy_excel/main.exe.manifest" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hy_excel/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hy_excel/main.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hy_excel/rc.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A02.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A05.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A06.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A08.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A14.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A15.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A17.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A30.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A33.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A36.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A57.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A65.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/A99Z1.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/B01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/hzb/GwyInfo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A01.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A02.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A05.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A06.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A08.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A14.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A15.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A17.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A30.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A33.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A36.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A57.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A65.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/A99Z1.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/json/B01.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzb/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_hzbtj/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/go_to_json/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_json/makeStruct/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A02.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A05.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A06.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A08.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A14.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A15.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A17.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A30.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A33.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A36.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A57.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A65.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/A99Z1.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/B01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/hzb/GwyInfo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A01.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A02.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A05.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A06.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A08.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A14.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A15.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A17.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A30.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A33.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A36.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A57.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A65.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/A99Z1.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/B01.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzb/xml/GwyInfo.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/BS.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/HZB_REPORT_RECEIVEJ1901.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/HZB_REPORT_RECEIVEJ1902.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/HZB_REPORT_RECEIVEJ1903.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/HZB_REPORT_RECEIVEJ1904.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M02.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M03.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M04.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M05.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M06.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M07.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M08.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_M09.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_N01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_N02.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_N03.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_N04.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_N05.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_P01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_P02.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_P03.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q02.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q03.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q04.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q05.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q06.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q07.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q08.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q09.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q10.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q11.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q12.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_Q13.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_S01.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_S02.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_S03.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_S04.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_S05.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_S06.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/M_S07.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/TB_RPT_CV_CFG.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/TB_SET_UNIT.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/hzbtj/TJ_UN.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/dan/TB_RPT_CV_CFG(TB_RPT_CV_CFG).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/dan/TB_SET_UNIT(TB_SET_UNIT).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/dan/TJ_UN(TJ_UN).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/head.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/rep/J2001/hzb_report_receiveJ2001.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/交流情况(M_M04).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/单位信息(M_M01).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/变化情况(M_M05).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/在职情况(M_M02).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/培训情况(M_M03).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/奖惩情况(M_M06).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/考核结果(M_M09).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_hzbtj/xml/sp/J2003sp/职务职级晋升(M_M07).xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/go_to_xml/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/get_hzb_xml/makeStruct/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/go_SQLite_MySQL/RunMySQL.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/go_SQLite_MySQL/hy_qggwy.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/go_SQLite_Oracle/RunOracle.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/go_SQLite_Oracle/hy_qggwy.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/run_hy_mysql/main.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/run_hy_mysql/rc.ico" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/run_hy_mysql/resource.syso" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_office/run_hy_mysql/versioninfo.json" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/01.基础类型.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/02.数组类型.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/03.指针类型.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/04.1.结构体.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/04.2.条件语句.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/04.3.循环语句.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/05.切片Slice.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/06.范围Range.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/07.集合Map.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/08.接口interface.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/09.指针pointer.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/10.链表-单链表.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/11.树-机构树.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/12.递归函数.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/13.错误处理.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/14.1.并发处理.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/14.2.并发通道.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/14.3.并发通道缓冲区.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/14.4.并发遍历通道和关闭通道.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/15.栈.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/16.队列.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/go_to_init/demo/demo.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/other/数组DEMO.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/other/结构体-反射.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/data_type/other/遍历结构体.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/db_util.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/db_util_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/file_util.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/file_util_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/map_util.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/map_util_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/set_util.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/final_common/set_util_test.go" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/../../../golang_learn/go.mod" afterDir="false" /> |
|||
</list> |
|||
<option name="SHOW_DIALOG" value="false" /> |
|||
<option name="HIGHLIGHT_CONFLICTS" value="true" /> |
|||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> |
|||
<option name="LAST_RESOLUTION" value="IGNORE" /> |
|||
</component> |
|||
<component name="GOROOT" url="file://$PROJECT_DIR$/../../../../../Program Files/Go" /> |
|||
<component name="Git.Settings"> |
|||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../../.." /> |
|||
</component> |
|||
<component name="GoLibraries"> |
|||
<option name="indexEntireGoPath" value="false" /> |
|||
<option name="urls"> |
|||
<list> |
|||
<option value="file://$PROJECT_DIR$/../../../../../../go" /> |
|||
</list> |
|||
</option> |
|||
</component> |
|||
<component name="ProjectId" id="1sVS3lhgjccClrla0pDfmQeDlVq" /> |
|||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" /> |
|||
<component name="ProjectViewState"> |
|||
<option name="hideEmptyMiddlePackages" value="true" /> |
|||
<option name="showLibraryContents" value="true" /> |
|||
</component> |
|||
<component name="PropertiesComponent"> |
|||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" /> |
|||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" /> |
|||
<property name="WebServerToolWindowFactoryState" value="false" /> |
|||
<property name="configurable.GoLibrariesConfigurable.is.expanded" value="true" /> |
|||
<property name="go.import.settings.migrated" value="true" /> |
|||
<property name="go.sdk.automatically.set" value="true" /> |
|||
<property name="go.tried.to.enable.integration.vgo.integrator" value="true" /> |
|||
<property name="last_opened_file_path" value="$PROJECT_DIR$" /> |
|||
<property name="settings.editor.selected.configurable" value="project.propVCSSupport.Mappings" /> |
|||
</component> |
|||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" /> |
|||
<component name="TypeScriptGeneratedFilesManager"> |
|||
<option name="version" value="3" /> |
|||
</component> |
|||
<component name="Vcs.Log.Tabs.Properties"> |
|||
<option name="TAB_STATES"> |
|||
<map> |
|||
<entry key="MAIN"> |
|||
<value> |
|||
<State /> |
|||
</value> |
|||
</entry> |
|||
</map> |
|||
</option> |
|||
<option name="oldMeFiltersMigrated" value="true" /> |
|||
</component> |
|||
<component name="VgoProject"> |
|||
<integration-enabled>true</integration-enabled> |
|||
</component> |
|||
</project> |
@ -0,0 +1,3 @@ |
|||
appname = go_to_beego_init |
|||
httpport = 8080 |
|||
runmode = dev |
@ -0,0 +1,18 @@ |
|||
package controllers |
|||
|
|||
import ( |
|||
beego "github.com/beego/beego/v2/server/web" |
|||
"go_to_beego_init/models" |
|||
) |
|||
|
|||
type MainController struct { |
|||
beego.Controller |
|||
} |
|||
|
|||
func (c *MainController) Get() { |
|||
hello := models.Hello{} |
|||
// c.Data["Website"] = new(models.Hello).Query()
|
|||
c.Data["Website"] = hello.Query() |
|||
c.Data["Email"] = "astaxie@gmail.com" |
|||
c.TplName = "index.tpl" |
|||
} |
@ -0,0 +1,7 @@ |
|||
module go_to_beego_init |
|||
|
|||
go 1.14 |
|||
|
|||
require github.com/beego/beego/v2 v2.0.1 |
|||
|
|||
require github.com/smartystreets/goconvey v1.6.4 |
@ -0,0 +1,277 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= |
|||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= |
|||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= |
|||
github.com/beego/beego/v2 v2.0.1 h1:07a7Z0Ok5vbqyqh+q53sDPl9LdhKh0ZDy3gbyGrhFnE= |
|||
github.com/beego/beego/v2 v2.0.1/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI= |
|||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= |
|||
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= |
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= |
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= |
|||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= |
|||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= |
|||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= |
|||
github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= |
|||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= |
|||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= |
|||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= |
|||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= |
|||
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= |
|||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= |
|||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= |
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw= |
|||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= |
|||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= |
|||
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= |
|||
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= |
|||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= |
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= |
|||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= |
|||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= |
|||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= |
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= |
|||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= |
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= |
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= |
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= |
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= |
|||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= |
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= |
|||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= |
|||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= |
|||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= |
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= |
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= |
|||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= |
|||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= |
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= |
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= |
|||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= |
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= |
|||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= |
|||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= |
|||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= |
|||
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= |
|||
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= |
|||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= |
|||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= |
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= |
|||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= |
|||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= |
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= |
|||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= |
|||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= |
|||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= |
|||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= |
|||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= |
|||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= |
|||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= |
|||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= |
|||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= |
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
|||
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
|||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
|||
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= |
|||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= |
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= |
|||
go.etcd.io/etcd v3.3.25+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= |
|||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= |
|||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= |
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= |
|||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= |
|||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= |
|||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= |
|||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= |
|||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= |
|||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag= |
|||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= |
|||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= |
|||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= |
|||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= |
|||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= |
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= |
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= |
|||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= |
|||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= |
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= |
|||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
|||
honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= |
@ -0,0 +1 @@ |
|||
{"D:\\EPWork\\goland\\workspace\\golang_frame\\go_to_beego\\go_to_beego_init\\controllers":1620872871216000000} |
@ -0,0 +1,36 @@ |
|||
package main |
|||
|
|||
import ( |
|||
beego "github.com/beego/beego/v2/server/web" |
|||
_ "go_to_beego_init/routers" |
|||
) |
|||
|
|||
func main() { |
|||
beego.Run() |
|||
|
|||
/* |
|||
main 函数里面的 web.Run, 执行那些事情: |
|||
1、解析配置文件 |
|||
beego 会自动解析在 conf 目录下面的配置文件 app.conf,通过修改配置文件相关的属性,我们可以定义:开启的端口,是否开启 session,应用名称等信息。 |
|||
|
|||
2、执行用户的 hookfunc |
|||
beego 会执行用户注册的 hookfunc,默认的已经存在了注册 mime,用户可以通过函数 AddAPPStartHook 注册自己的启动函数。 |
|||
|
|||
3、是否开启 session |
|||
会根据上面配置文件的分析之后判断是否开启 session,如果开启的话就初始化全局的 session。 |
|||
|
|||
4、是否编译模板 |
|||
beego 会在启动的时候根据配置把 views 目录下的所有模板进行预编译,然后存在 map 里面,这样可以有效的提高模板运行的效率,无需进行多次编译。 |
|||
|
|||
5、是否开启文档功能 |
|||
根据 EnableDocs 配置判断是否开启内置的文档路由功能 |
|||
|
|||
6、是否启动管理模块 |
|||
beego 目前做了一个很酷的模块,应用内监控模块,会在 8088 端口做一个内部监听,我们可以通过这个端口查询到 QPS、CPU、内存、GC、goroutine、thread 等统计信息。 |
|||
|
|||
7、监听服务端口 |
|||
这是最后一步也就是我们看到的访问 8080 看到的网页端口,内部其实调用了 ListenAndServe,充分利用了 goroutine 的优势 |
|||
|
|||
最后:一旦 run 起来之后,我们的服务就监听在两个端口了,一个服务端口 8080 作为对外服务,另一个 8088 端口实行对内监控。 |
|||
*/ |
|||
} |
@ -0,0 +1,11 @@ |
|||
package models |
|||
|
|||
import "fmt" |
|||
|
|||
type Hello struct { |
|||
} |
|||
|
|||
func (hello *Hello) Query() string { |
|||
retStr := fmt.Sprintln("调用结构体:", "vivib@foxmail.com") |
|||
return retStr |
|||
} |
@ -0,0 +1,10 @@ |
|||
package routers |
|||
|
|||
import ( |
|||
beego "github.com/beego/beego/v2/server/web" |
|||
"go_to_beego_init/controllers" |
|||
) |
|||
|
|||
func init() { |
|||
beego.Router("/", &controllers.MainController{}) |
|||
} |
@ -0,0 +1 @@ |
|||
function b(a){var c=new WebSocket(a);c.onclose=function(){setTimeout(function(){b(a)},2E3)};c.onmessage=function(){location.reload()}}try{if(window.WebSocket)try{b("ws://localhost:12450/reload")}catch(a){console.error(a)}else console.log("Your browser does not support WebSockets.")}catch(a){console.error("Exception during connecting to Reload:",a)}; |
@ -0,0 +1,40 @@ |
|||
package test |
|||
|
|||
import ( |
|||
"net/http" |
|||
"net/http/httptest" |
|||
"path/filepath" |
|||
"runtime" |
|||
"testing" |
|||
|
|||
"github.com/beego/beego/v2/core/logs" |
|||
|
|||
_ "go_to_beego_init/routers" |
|||
|
|||
beego "github.com/beego/beego/v2/server/web" |
|||
. "github.com/smartystreets/goconvey/convey" |
|||
) |
|||
|
|||
func init() { |
|||
_, file, _, _ := runtime.Caller(0) |
|||
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator)))) |
|||
beego.TestBeegoInit(apppath) |
|||
} |
|||
|
|||
// TestBeego is a sample to run an endpoint test
|
|||
func TestBeego(t *testing.T) { |
|||
r, _ := http.NewRequest("GET", "/", nil) |
|||
w := httptest.NewRecorder() |
|||
beego.BeeApp.Handlers.ServeHTTP(w, r) |
|||
|
|||
logs.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String()) |
|||
|
|||
Convey("Subject: Test Station Endpoint\n", t, func() { |
|||
Convey("Status Code Should Be 200", func() { |
|||
So(w.Code, ShouldEqual, 200) |
|||
}) |
|||
Convey("The Result Should Not Be Empty", func() { |
|||
So(w.Body.Len(), ShouldBeGreaterThan, 0) |
|||
}) |
|||
}) |
|||
} |
@ -0,0 +1,42 @@ |
|||
package main |
|||
|
|||
import "github.com/beego/beego/v2/server/web" |
|||
|
|||
type FormController struct { |
|||
web.Controller |
|||
} |
|||
|
|||
/* |
|||
Post 模版: |
|||
<form enctype="multipart/form-data" method="post"> |
|||
<input type="file" name="uploadname" /> |
|||
<input type="submit"> |
|||
</form> |
|||
*/ |
|||
func (c *FormController) Post() { |
|||
f, h, err := c.GetFile("uploadname") |
|||
if err != nil { |
|||
panic(err) |
|||
} |
|||
defer f.Close() |
|||
c.SaveToFile("uploadname", "static/upload/"+h.Filename) // 保存位置在 static/upload, 没有文件夹要先创建
|
|||
|
|||
} |
|||
|
|||
/** |
|||
main |
|||
默认情况下,MaxMemory应该设置得比MaxUploadSize小,这种情况下两个参数合并在一起的效果则是: |
|||
1、如果文件大小小于MaxMemory,则直接在内存中处理; |
|||
2、如果文件大小介于MaxMemory和MaxUploadSize之间,那么比MaxMemory大的部分将会放在临时目录; |
|||
3、文件大小超出MaxUploadSize,直接拒绝请求,返回响应码 413 |
|||
|
|||
Beego 提供了两个很方便的方法来处理文件上传: |
|||
> GetFile(key string) (multipart.File, *multipart.FileHeader, error) |
|||
该方法主要用于用户读取表单中的文件名 the_file,然后返回相应的信息,用户根据这些变量来处理文件上传:过滤、保存文件等。 |
|||
|
|||
> SaveToFile(fromfile, tofile string) error |
|||
该方法是在 GetFile 的基础上实现了快速保存的功能,fromfile 是提交时候的 html 表单中的 name |
|||
*/ |
|||
func main() { |
|||
web.Run("127.0.0.1:8080") |
|||
} |
@ -0,0 +1,28 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"github.com/beego/beego/v2/server/web" |
|||
) |
|||
|
|||
// MainController
|
|||
// 1、设置结构体默认继承 web.Controller 属性
|
|||
type MainController struct { |
|||
web.Controller |
|||
} |
|||
|
|||
// Get
|
|||
// 2、实现 Get 类似 实现 get 请求
|
|||
// 同时可以实现接口的多个方法, 类似实现多个 不同类型 请求
|
|||
func (this *MainController) Get() { |
|||
this.Ctx.WriteString("hello world - get") |
|||
} |
|||
func (this *MainController) Post() { |
|||
this.Ctx.WriteString("hello world - post") |
|||
} |
|||
|
|||
// 请求:127.0.0.1:8080
|
|||
func main() { |
|||
// 3、设置 监控路由 ,同时使用 &xxx{} 调取对应结构体实现的方法
|
|||
web.Router("/", &MainController{}) |
|||
web.Run("127.0.0.1:8080") |
|||
} |
@ -0,0 +1,107 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"github.com/astaxie/beego/orm" |
|||
_ "github.com/go-sql-driver/mysql" |
|||
"time" |
|||
) |
|||
|
|||
type A struct { |
|||
Id int `json:"id"` |
|||
Aa string `json:"aa"` |
|||
Bb string `json:"bb"` |
|||
Vv string `json:"vv"` |
|||
} |
|||
|
|||
var DbOrm orm.Ormer |
|||
|
|||
func init() { |
|||
// ORM 必须注册一个别名为 default 的数据库,作为默认使用。
|
|||
orm.RegisterDriver("mysql", orm.DRMySQL) |
|||
|
|||
maxIdle := 30 |
|||
maxConn := 30 |
|||
|
|||
// 参数1 数据库的别名,用来在ORM中切换数据库使用
|
|||
// 参数2 driverName
|
|||
// 参数3 对应的链接字符串
|
|||
// 参数4(可选)设置最大空j闲连接
|
|||
// 参数5(可选)设置最大数据库连接(go >= 1.2)
|
|||
// 注意:这里必须使用 tcp() 包裹 IP+PORT 参数
|
|||
orm.DefaultTimeLoc = time.UTC |
|||
orm.RegisterDataBase("default", "mysql", "viviman:asdfghjklm123.@tcp(139.199.117.32:3306)/viviman?charset=utf8", maxIdle, maxConn) |
|||
|
|||
// 注册 model / RegisterModel 也可以同时注册多个 model
|
|||
orm.RegisterModel(new(A)) |
|||
//orm.RegisterModel(new(User), new(Profile), new(Post))
|
|||
|
|||
// 创建table
|
|||
// orm.RunSyncdb("default", false, true)
|
|||
} |
|||
|
|||
func main() { |
|||
// orm.Debug = true
|
|||
o := orm.NewOrm() |
|||
// 在model里面 去Using 一个你自己的库 并且定义成全局变量方便在别的文件中使用
|
|||
// o.Using("main")
|
|||
|
|||
// 定义操作对象
|
|||
i := A{Id: 999, Aa: "liw", Bb: "L", Vv: "110110"} |
|||
|
|||
// 1、【增】插入表
|
|||
id, err := o.Insert(&i) |
|||
fmt.Printf("ID: %d, ERR: %v\n", id, err) |
|||
|
|||
// 2、【改】更新表
|
|||
u := A{Id: 1} |
|||
u.Aa = "lis" |
|||
num, err := o.Update(&u) |
|||
fmt.Printf("NUM: %d, ERR: %v\n", num, err) |
|||
|
|||
// 3、【查】读取 one
|
|||
s := A{Id: 2} |
|||
err = o.Read(&s) |
|||
// err = o.Read(&u, "Id")
|
|||
fmt.Printf("ERR: %v\n", err) |
|||
|
|||
// 4、【删】删除表
|
|||
d := A{Id: 3} |
|||
num, err = o.Delete(&d) |
|||
fmt.Printf("NUM: %d, ERR: %v\n", num, err) |
|||
|
|||
// *-- 其他操作 --*
|
|||
selOrCra := A{Id: 4} |
|||
// 5、三个返回参数依次为:是否新创建的,对象 Id 值,错误
|
|||
if created, id, err := o.ReadOrCreate(&selOrCra, "Id"); err == nil { |
|||
if created { |
|||
// 实现了 - 尝试从数据库读取,不存在的话就创建一个
|
|||
fmt.Println("New Insert an object. Id:", id) |
|||
} else { |
|||
// 实现了 - 查
|
|||
fmt.Println("Get an object. Id:", id) |
|||
} |
|||
} |
|||
|
|||
// 6、插入多条记录
|
|||
insts := []A{ |
|||
{Id: 5}, |
|||
{Id: 6}, |
|||
{Id: 7}, |
|||
} |
|||
num, err = o.InsertMulti(100, &insts) |
|||
fmt.Printf("NUM: %d, ERR: %v\n", num, err) |
|||
|
|||
// 7.1、高级查询
|
|||
// 获取 QuerySeter 对象,user 为表名
|
|||
qs := o.QueryTable("user") |
|||
fmt.Println(qs) |
|||
|
|||
// 7.2、也可以直接使用 Model 结构体作为表名
|
|||
qs = o.QueryTable(&s) |
|||
fmt.Println(qs) |
|||
|
|||
// 7.3、也可以直接使用对象作为表名
|
|||
user := new(A) |
|||
qs = o.QueryTable(user) // 返回 QuerySeter
|
|||
} |
@ -0,0 +1,5 @@ |
|||
package main |
|||
|
|||
func main() { |
|||
|
|||
} |
@ -0,0 +1,5 @@ |
|||
package main |
|||
|
|||
func main() { |
|||
|
|||
} |
@ -0,0 +1,6 @@ |
|||
# Gin 是 Golang 框架 |
|||
|
|||
> 官网: https://gin-gonic.com/zh-cn/docs |
|||
|
|||
* 安装命令 |
|||
> go get -u github.com/gin-gonic/gin |
@ -0,0 +1,51 @@ |
|||
# Gin 大结局 |
|||
|
|||
* 非本人所写,但是作者良心,是我张献维学习对象 |
|||
|
|||
|
|||
|
|||
花费了半个多月,将 Gin 十三篇教程完成,这是算作第二次写系列文章,但是绝对是第一次写如此长系列的文章。其中也有很多不足。该篇主要是对 Gin 系列写完之后的一些感悟和总结。 |
|||
|
|||
距离最后的一篇文章完成已经过去三四天了,也在静静的思考这半个多月带来的收获。 |
|||
|
|||
|
|||
|
|||
# 开始 |
|||
|
|||
写文章初期,大概对文章的章节进行了一次规划,包括对章节内容都有一些模糊的设想,可能大家看得出来,前期的文章都是一步步迭代,带大家去做一个网站。然而更新到第九章的时候发现,如果继续使用 restful 去搭建,是可以的,但是通过 ajax 请求js操作DOM和数据,好像又和 Gin 给定的 tmpl 模板,又有点矛盾。所以我放弃了。这是源于我对整个系列考虑不周的情况。但是并不代表文章前面的所讲述的技术和方法,后面章节中无法使用。无论是使用模板还是返回 json 数据,这是视图的不同,所有的技术都是可以使用的,这一点是无需担心的。 |
|||
|
|||
# 撰写 |
|||
|
|||
写作期间,收到了很多的鼓励和催更。技术文章不同于其他类别,不能胡说,不能瞎写,本着每一行代码都要对读者负责,每次确定章节主题后,都要先调试代码,将本章节用到的相关代码都敲一遍,确保项目可以正确运行,并且按照章节将代码上传到 Github ,哪怕文章中出现错误,读者仍旧是可以看到正确的代码。 |
|||
|
|||
# 收获 |
|||
|
|||
文章主要发在了个人博客 ISLAND 、微信公众号**代码猎奇站** 和 掘金上。博客的访问量期间多了,微信的公众号关注数也慢慢的上涨,收到了掘金老站长的邀请加入了一个 golang 用户群,还收到了 CSDN 运营的邀请。每当有读者说,这个文章对他有所帮助,那么我觉得我的文章就算是没有白写。 |
|||
|
|||
文章发布后,还是出现了不少的错误,感谢中评论里指出错误的各位读者。你们对错误的指出不仅仅是帮助了我,也是帮助了以后阅读的读者。 |
|||
|
|||
# 文章说明 |
|||
|
|||
Gin 系列文章并没有去深入的讲解为什么,更多的讲解了怎么用,可以算是多官网文档的一个补充说明,更多的面向读者是 Go 语言初学者,Gin框架初学者。文章基本可以分为三部分,1 - 9 章是对 Gin 的基本介绍,介绍了 Gin 给的一些 API,Gin 的一些方法和功能的实现。而到了10 - 12章,是对 Gin 项目的一些扩展,将不同的服务集成到 Gin 上,让你使用 Gin 的时候更加高效。而最后一章则是对我们开发的项目一个收尾,如何部署上线。 |
|||
|
|||
# 源代码使用 |
|||
|
|||
文章所有用到的源代码全部托管于 Github,大家可以查看不同的分支来找到各个章节的代码。 |
|||
|
|||
|
|||
|
|||
# 结尾 |
|||
|
|||
最后,开始思考下一步的方向,GoLang 是我喜欢的一个语言,我相信该系列不是我对 GoLang 介绍的最后一个系列,这是一个开始。 |
|||
|
|||
最后的最后,开通了一个小专栏,叫做 Gin 的入门到放弃 售价仅仅一元(阅读原文购买),和之前发布的文章一模一样,如果你觉得本系列对你有所帮助,可以购买,支持一下博主,当然不买也是可以的,**郑重承诺**:该系列文章永远会免费阅读。 |
|||
|
|||
|
|||
|
|||
在这里更加推荐您到个人博客上进行阅读,文章后期发生修改可以第一时间看到。 |
|||
|
|||
|
|||
|
|||
ISLAND 个人博客 : https://youngxhui.top |
|||
|
|||
Github 地址:https://github.com/youngxhui/GinHello |
@ -0,0 +1,201 @@ |
|||
# 什么是Gin |
|||
|
|||
> Gin 是一个用 Golang 写的 http web 框架。 |
|||
|
|||
### 官方网站 |
|||
|
|||
Gin官网:[https://gin-gonic.com/](https://gin-gonic.com/) |
|||
|
|||
### 框架源码 |
|||
|
|||
Gin框架源码地址:[https://github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) |
|||
|
|||
### 框架学习文档 |
|||
|
|||
「推荐」Gin框架中文学习文档: [https://gin-gonic.com/zh-cn/docs/](https://gin-gonic.com/zh-cn/docs/) |
|||
当然,还有其他相关资料,比如说xorm框架等,这些我们在后面的课程文档中学习到以后再做解释和说明。 |
|||
|
|||
# 开发环境 |
|||
|
|||
- GoLand 2019.2 EAP |
|||
- GoLang 1.11.5 |
|||
- 采用 Go Modules 进行管理 |
|||
|
|||
|
|||
## Gin 开发环境搭建 |
|||
|
|||
> go get -u -v github.com/gin-gonic/gin |
|||
|
|||
|
|||
# 快速入门 |
|||
|
|||
用 `GoLand` 新建项目的时候,我们选择 `Go Modules(vgo)` ,填写我们的项目地址和项目名称,我们命名为 `GinHello` 。 |
|||
|
|||
![创建项目](./img/1.1.jpeg) |
|||
|
|||
点击 `Create` ,此时 `Goland` 为我们生成了项目目录,`Go` 项目的目录永远是那么的简单,比 `Java` 的 `Maven` 或者 `Gradle` 生成的项目目录简单多了。 |
|||
|
|||
``` |
|||
GinHello |
|||
| |
|||
|-go.mod |
|||
``` |
|||
|
|||
对,就是一个文件 ,一个 `Go module` 文件。`go mod` 是 `Go` 官方引入的一个依赖管理工具。 |
|||
|
|||
|
|||
|
|||
## 添加依赖 |
|||
|
|||
通过 `go mod` 文件进行依赖的。 |
|||
|
|||
`require github.com/gin-gonic/gin v1.4.0` |
|||
|
|||
我们把上面的依赖进行添加到 `go module` 中, `goLand` 会自动帮我们进行依赖的下载和管理。 |
|||
|
|||
|
|||
|
|||
## Hello Gin |
|||
|
|||
当完成依赖的添加,就可以开始写代码了。 |
|||
|
|||
新建一个 `main.go` 文件。 |
|||
|
|||
``` |
|||
package main |
|||
|
|||
import ( |
|||
"github.com/gin-gonic/gin" |
|||
) |
|||
|
|||
func main() { |
|||
router := gin.Default() |
|||
router.Run() |
|||
} |
|||
``` |
|||
|
|||
`Gin` 只需要两行代码就可以把我们的服务跑起来。 |
|||
|
|||
我们只要点击运行,项目便会启动一个 `8080` 端口,打开浏览器 `localhost:8080` 我们便可以看到页面上提示出 `404 page not found` ,这是因为我们的根路由上并没有返回任何结果。同时我们可以在控制台上看到一些打印信息,其中就包括我们刚刚访问根路由的端口。 |
|||
|
|||
## 产生接口 |
|||
|
|||
项目已经启动了,那么如何返回一个接口呢? |
|||
|
|||
通过 `router` 的 `Handle` 进行配置我们返回的参数。 |
|||
|
|||
``` |
|||
// 省略代码 |
|||
// 添加 Get 请求路由 |
|||
router.GET("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin") |
|||
}) |
|||
// 省略代码 |
|||
``` |
|||
|
|||
此时我们重启项目,重新访问页面 `localhost:808`,此刻的页面上已经显示了 `hello gin`。 |
|||
|
|||
同样,我们还可以进行 `POST`,`PUT`,`DELETE`等请求方式。 |
|||
|
|||
|
|||
|
|||
## 单元测试 |
|||
|
|||
单元测试是项目不能缺少的模块,也是保障项目可以正常运行的重要依赖。下面就对 Gin 进行单元测试。 |
|||
|
|||
为了方便单元测试,我们首先要对我们的项目进行一下抽取。 |
|||
|
|||
新建立一个文件夹叫做 `initRouter` |
|||
|
|||
建立 `go` 文件 `initRouter.go` |
|||
|
|||
``` |
|||
package initRouter |
|||
|
|||
import ( |
|||
"github.com/gin-gonic/gin" |
|||
"net/http" |
|||
) |
|||
|
|||
func SetupRouter() *gin.Engine { |
|||
router := gin.Default() |
|||
// 添加 Get 请求路由 |
|||
router.GET("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin") |
|||
}) |
|||
return router |
|||
} |
|||
``` |
|||
|
|||
同时修改 `main.go` |
|||
|
|||
|
|||
|
|||
``` |
|||
package main |
|||
|
|||
import ( |
|||
"GinHello/initRouter" |
|||
) |
|||
|
|||
func main() { |
|||
router := initRouter.SetupRouter() |
|||
_ = router.Run() |
|||
} |
|||
``` |
|||
|
|||
完成了项目测试的初步建立。 |
|||
|
|||
建立 `test` 目录, `golang` 的单元测试都是以 `_test` 结尾,建立 `index_test.go` 文件。 |
|||
|
|||
``` |
|||
package test |
|||
|
|||
import ( |
|||
"GinHello/initRouter" |
|||
"github.com/stretchr/testify/assert" |
|||
"net/http" |
|||
"net/http/httptest" |
|||
"testing" |
|||
) |
|||
|
|||
func TestIndexGetRouter(t *testing.T) { |
|||
router := initRouter.SetupRouter() |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodGet, "/", nil) |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
assert.Equal(t, "hello gin", w.Body.String()) |
|||
} |
|||
``` |
|||
|
|||
通过 `assert` 进行断言,来判断返回状态码和返回值是否与代码中的值一致。 |
|||
|
|||
此时的项目目录为: |
|||
|
|||
``` |
|||
GinHello |
|||
| |
|||
|-initRouter |
|||
| |-initRouter.go |
|||
| |
|||
|-test |
|||
| |-index_test.go |
|||
| |
|||
|-main.go |
|||
|-go.mod |
|||
|-go.sum |
|||
``` |
|||
|
|||
运行单元测试,控制台打印出单元测试结果。 |
|||
|
|||
|
|||
|
|||
> — PASS: TestIndexGetRouter (0.02s) |
|||
> PASS |
|||
|
|||
|
|||
|
|||
# 总结 |
|||
|
|||
通过简单的搭建一个 Gin 项目,可以看到 Go 语言搭建一个 Http 服务器很简单,也很方便,零配置即可完成项目并运行起来。 |
@ -0,0 +1,266 @@ |
|||
# Gin(二):路由Router |
|||
|
|||
经过[上一章节](https://youngxhui.top/2019/07/gin一hello/)的介绍,搭建一个简单的 `Gin` `web` 项目非常容易,同时也引入了一些新的概念,比如说:**路由** `Router`。 |
|||
|
|||
**路由**是一个非常重要的概念,所有的接口都要有路由来进行管理。 |
|||
|
|||
|
|||
|
|||
# 请求方法 |
|||
|
|||
`Gin` 的路由支持 `GET` , `POST` , `PUT` , `DELETE` , `PATCH` , `HEAD` , `OPTIONS` 请求,同时还有一个 `Any` 函数,可以同时支持以上的所有请求。 |
|||
|
|||
将上一章节的代码添加其他请求方式的路由,并编写单元测试。 |
|||
|
|||
``` |
|||
// 省略其他代码 |
|||
// 添加 Get 请求路由 |
|||
router.GET("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin get method") |
|||
}) |
|||
// 添加 Post 请求路由 |
|||
router.POST("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin post method") |
|||
}) |
|||
// 添加 Put 请求路由 |
|||
router.PUT("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin put method") |
|||
}) |
|||
// 添加 Delete 请求路由 |
|||
router.DELETE("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin delete method") |
|||
}) |
|||
// 添加 Patch 请求路由 |
|||
router.PATCH("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin patch method") |
|||
}) |
|||
// 添加 Head 请求路由 |
|||
router.HEAD("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin head method") |
|||
}) |
|||
// 添加 Options 请求路由 |
|||
router.OPTIONS("/", func(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin options method") |
|||
}) |
|||
// 省略其他代码 |
|||
``` |
|||
|
|||
单元测试,只展示一个 `Post` 请求函数,基本与 `Get` 请求一致,其他代码详见文末 Github 地址。 |
|||
|
|||
``` |
|||
// router("/") post 测试 |
|||
func TestIndexPostRouter(t *testing.T) { |
|||
router := initRouter.SetupRouter() |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodPost, "/", nil) |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
assert.Equal(t, "hello gin post method", w.Body.String()) |
|||
} |
|||
``` |
|||
|
|||
此时运行单元测试,所有测试完美通过。 |
|||
|
|||
但是也有一个问题,所有的请求对应的路由内函数基本一样,只是有细微的差别,但是我们却每个路由里都完完整整的写了一遍,所以我们要将公共逻辑抽取出来。 |
|||
|
|||
``` |
|||
func retHelloGinAndMethod(context *gin.Context) { |
|||
context.String(http.StatusOK, "hello gin "+strings.ToLower(context.Request.Method)+" method") |
|||
} |
|||
``` |
|||
|
|||
我们将方法的公共部分抽取出来,并通过 `context.Request.Method` 将请求的方法提取出来 ,并将其转化为小写。此时就可以改造我们的路由了,将原有的路由中的函数去掉换成我们所编写的新的函数。 |
|||
|
|||
``` |
|||
// 添加 Get 请求路由 |
|||
router.GET("/", retHelloGinAndMethod) |
|||
// 添加 Post 请求路由 |
|||
router.POST("/", retHelloGinAndMethod) |
|||
// 添加 Put 请求路由 |
|||
router.PUT("/", retHelloGinAndMethod) |
|||
// 添加 Delete 请求路由 |
|||
router.DELETE("/", retHelloGinAndMethod) |
|||
// 添加 Patch 请求路由 |
|||
router.PATCH("/", retHelloGinAndMethod) |
|||
// 添加 Head 请求路由 |
|||
router.HEAD("/", retHelloGinAndMethod) |
|||
// 添加 Options 请求路由 |
|||
router.OPTIONS("/", retHelloGinAndMethod) |
|||
``` |
|||
|
|||
此时运行单元测试,仍旧是完美通过。 |
|||
|
|||
# Handler 处理器 |
|||
|
|||
经过上面简单的例子的演示和操作,现在我们大概可以了解到路由需要传入两个参数,一个为路径,另一个为路由执行的方法,我们叫做它处理器 `Handler` ,而且,该参数是可变长参数。也就是说,可以传入多个 handler,形成一条 handler chain 。 |
|||
|
|||
同时对 handler 该函数有着一些要求,该函数需要传入一个 `Gin.Context` **指针**,同时要通过该指针进行值得处理。 |
|||
|
|||
Handler 函数可以对前端返回 字符串,Json,Html 等多种格式或形式文件,之后我们会慢慢逐一介绍。 |
|||
|
|||
# 获取路由路径中参数 |
|||
|
|||
知道了路由支持的方法和对应的处理器,那么接下来就应该了解如何从路由中获取参数。 |
|||
|
|||
编写一个新的路由,如下: |
|||
|
|||
``` |
|||
//省略其他代码 |
|||
// 添加 user |
|||
router.GET("/user/:name",handler.Save) |
|||
// 省略其他代码 |
|||
``` |
|||
|
|||
此时我们发现,在原来只有 `/` 分隔符的情况下出现了 `/:` 该符号就表示后面的字符串为一个占位符,用于将要进行的传值。,此时我们的路由为 `/user/{name}` |
|||
|
|||
我们没有必要把所有的 Handler 都写到一个文件夹中,那样会臃肿不堪,所以我们新建一个文件夹`handler`,在文件夹下建立 `userHandler.go` 文件,编写该文件。 |
|||
|
|||
``` |
|||
package handler |
|||
|
|||
import ( |
|||
"github.com/gin-gonic/gin" |
|||
"net/http" |
|||
) |
|||
|
|||
func UserSave(context *gin.Context) { |
|||
username := context.Param("name") |
|||
context.String(http.StatusOK, "用户已经保存") |
|||
} |
|||
``` |
|||
|
|||
同样,我们用 `context.Param` 可以获取路由路径中的参数。 |
|||
|
|||
此时,就可以编写我们的单元测试。 |
|||
|
|||
新建立一个 `user_test.go` 文件。 |
|||
|
|||
``` |
|||
func TestUserSave(t *testing.T) { |
|||
username := "lisi" |
|||
router := initRouter.SetupRouter() |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodGet, "/user/"+username, nil) |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
assert.Equal(t, "用户"+username+"已经保存", w.Body.String()) |
|||
} |
|||
``` |
|||
|
|||
运行单元测试,测试通过。同样我们可以运行我们的项目在浏览器中输入 `localhost:8080/user/lisi` 在浏览器页面上也可以看到 `用户lisi已经保存` |
|||
|
|||
当然,获取参数的方法不止这一个。针对不同的路由,Gin 给出了不同的获取参数的方法,比如形如:`/user?name=lisi&age=18`。 |
|||
|
|||
我们再次添加一个 `Handler`,做为处理。在 `userHandler` 中添加下面的方法。 |
|||
|
|||
``` |
|||
// 通过 query 方法进行获取参数 |
|||
func UserSaveByQuery(context *gin.Context) { |
|||
username := context.Query("name") |
|||
age := context.Query("age") |
|||
context.String(http.StatusOK, "用户:"+username+",年龄:"+age+"已经保存") |
|||
} |
|||
``` |
|||
|
|||
同时对路由进行添加和完善。 |
|||
|
|||
``` |
|||
router.GET("/user", handler.UserSaveByQuery) |
|||
``` |
|||
|
|||
完成路由之后,就可以重新编写单元测试,完善项目。 |
|||
|
|||
``` |
|||
func TestUserSaveQuery(t *testing.T) { |
|||
username := "lisi" |
|||
age := 18 |
|||
router := initRouter.SetupRouter() |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodGet, "/user?name="+username+"&age="+strconv.Itoa(age), nil) |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
assert.Equal(t, "用户:"+username+",年龄:"+strconv.Itoa(age)+"已经保存", w.Body.String()) |
|||
} |
|||
``` |
|||
|
|||
运行测试,测试通过。并且可以通过 浏览器访问`localhost:8080/user?name=lisi`,页面上打印出`用户:lisi,年龄:18已经保存` 。 |
|||
|
|||
当然,还可以通过 `context.DefaultQuery` 方法,在获取时,如果没有该值则赋给一个默认值。 |
|||
|
|||
重新修改获取年龄的代码,将其改为以下代码 |
|||
|
|||
``` |
|||
age := context.DefaultQuery("age", "20") |
|||
``` |
|||
|
|||
重新编写我们的单元测试,并运行。 |
|||
|
|||
``` |
|||
func TestUserSaveWithNotAge(t *testing.T) { |
|||
username := "lisi" |
|||
router := initRouter.SetupRouter() |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodGet, "/user?name="+username, nil) |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
assert.Equal(t, "用户:"+username+",年龄:20已经保存", w.Body.String()) |
|||
} |
|||
``` |
|||
|
|||
同样也可以通过浏览器访问 `/user?name=lisi` 可以看到浏览器上显示 |
|||
|
|||
`用户:lisi,年龄:20已经保存` 。 |
|||
|
|||
当然,还提供了其他参数获取方法, `QueryArray` 获取数组和 `QueryMap` 获取 map。 |
|||
|
|||
# 路由分组 |
|||
|
|||
此时我们再次看 `SetupRouter` 方法时,里面的路由基本可以分为两大类 `/` 和 `/user`,如果日后在进行功能的添加,那么势必会出现大量的路由,所以我们需要对路由进行一下管理,Gin 给我们提供了路由分组。 |
|||
|
|||
先把 `/` 的路由写到一起,运行 `index_test.go` 单元测试。 |
|||
|
|||
``` |
|||
index := router.Group("/"){ |
|||
// 添加 Get 请求路由 |
|||
index.GET("", retHelloGinAndMethod) |
|||
// 添加 Post 请求路由 |
|||
index.POST("", retHelloGinAndMethod) |
|||
// 添加 Put 请求路由 |
|||
index.PUT("", retHelloGinAndMethod) |
|||
// 添加 Delete 请求路由 |
|||
index.DELETE("", retHelloGinAndMethod) |
|||
// 添加 Patch 请求路由 |
|||
index.PATCH("", retHelloGinAndMethod) |
|||
// 添加 Head 请求路由 |
|||
index.HEAD("", retHelloGinAndMethod) |
|||
// 添加 Options 请求路由 |
|||
index.OPTIONS("", retHelloGinAndMethod) |
|||
} |
|||
``` |
|||
|
|||
通过 `router.Group` 返回一个新的分组路由,通过新的分组路由把之前的路由进行简单的修改。当然分组里面仍旧可以嵌套分组。 |
|||
|
|||
之前在请求方法中说到有一个 `Any` 函数可以通过任何请求,此时我们就可以把 `index` 里面所有的请求替换为 `Any` |
|||
|
|||
``` |
|||
index := router.Group("/"){ |
|||
index.Any("", retHelloGinAndMethod) |
|||
} |
|||
``` |
|||
|
|||
运行单元测试,测试都可以通过。 |
|||
|
|||
此时也发现了单元测试的好处,虽说之前花费了时间和经历编写了单元测试,但是日后的功能上修改,只需要进行运行单元测试就可以知道我们的功能是否正确,在后期的功能测试上大大减少了经历和时间。 |
|||
|
|||
同样我们把 `user` 也进行分组,分组不仅仅是将相同逻辑的代码放到一起,而且可以提供相同的路由前缀,修改后的路由仍旧和之前一致。运行单元测试 `user_test.go` ,单元测试可以完全通过,证明我们的代码没有问题。 |
|||
|
|||
``` |
|||
userRouter := router.Group("/user"){ |
|||
userRouter.GET("/:name", handler.UserSave) |
|||
userRouter.GET("", handler.UserSaveByQuery) |
|||
} |
|||
``` |
|||
|
|||
# 总结 |
|||
|
|||
通过简单的路由的使用,基本明白了路由在 Gin 中的地位,也对一些常见的使用方式有了一些直观的认识。 |
@ -0,0 +1,226 @@ |
|||
# Gin(三):模板tmlp |
|||
|
|||
前面的学习已经对 Gin 有了一个初步的认识和了解,对 `router` 的简单使用也有了一定的掌握,那么今天就来使用 Gin 来渲染出我们的 `html` 页面吧。 |
|||
|
|||
|
|||
|
|||
# 添加模板 |
|||
|
|||
我们仍旧是在上一章节的项目中进行修改。 |
|||
|
|||
首先新建一个 `templates` 文件夹,用于存放我们的模板文件,在文件夹中新建立 `index.tmpl`。并且编写我们的模板。 |
|||
|
|||
``` |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" |
|||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
<title>Gin Hello</title> |
|||
</head> |
|||
<body> |
|||
<main>{{ .title }}</main> |
|||
</body> |
|||
</html> |
|||
``` |
|||
|
|||
**小提示** GoLand 现在还未对 tmpl 有高亮显示语法,我们可以将 .tmpl 后缀文件添加到 go Template 模板。方法如下:`File-settings-Editor-File Types`。(或者我们直接使用 *.gohtml 做为模板也是可以的)如图: |
|||
|
|||
![设置模版](./img/3.1.jpeg) |
|||
|
|||
我们可以通过 `LoadHTMLGlob` 和 `LoadHTMLFiles` 两个方法来对我们的模板进行加载。其中 `LoadHTMLGlob` 方法可以将一个目录下所有的模板进行加载,而`LoadHTMLFiles`只会加载一个文件,他的参数为可变长参数,需要我们一个一个的手动将模板文件填写。这里我们使用 `LoadHTMLGlob` 方法。 |
|||
|
|||
``` |
|||
router.LoadHTMLGlob("templates/*") |
|||
``` |
|||
|
|||
此时我们需要修改我们的 `/` 路由了,不再是让它返回一个字符串,而是返回我们的页面模板。 |
|||
|
|||
在 `handler` 中新建立一个 `indexHandler.go` ,用来处理我们的 `/` 路由。 |
|||
|
|||
``` |
|||
func Index(context *gin.Context) { |
|||
context.HTML(http.StatusOK, "index.tmpl", gin.H{ |
|||
"title": "hello gin " + strings.ToLower(context.Request.Method) + " method", |
|||
}) |
|||
} |
|||
``` |
|||
|
|||
此时在访问我们的页面,仍旧是 `hello gin get method`,但是这和我们之前返回的字符串是不同的。 |
|||
|
|||
打开 `浏览器-Network` 就可以看到这两个页面的不同,一个是 **text** 一个是 **html** |
|||
|
|||
![效果设计](./img/3.2.jpeg) |
|||
|
|||
写完具体功能,我们需要改造一下我们的单元测试,针对新的接口逻辑原有的单元测试已经行不通了。 |
|||
|
|||
重新修改单元测试。 |
|||
|
|||
``` |
|||
func TestIndexHtml(t *testing.T) { |
|||
router := initRouter.SetupRouter() |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodGet, "/", nil) |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
} |
|||
``` |
|||
|
|||
进行单元测试的时候,发现报错了,报错原因是竟然是找不到 `html`。 |
|||
|
|||
``` |
|||
--- FAIL: TestIndexGetRouter (0.00s) |
|||
panic: html/template: pattern matches no files: `templates/*` [recovered] |
|||
panic: html/template: pattern matches no files: `templates/*` |
|||
``` |
|||
|
|||
此时就感到很奇怪了,为什么网页上可以很好的访问到,在测试中却无法访问呢? |
|||
|
|||
查了很多资料没有找到原因,很多解决方法是将 `templates` 写成全路径,这显然不是很好的解决方法。官方对于单元测试介绍少的可怜。 |
|||
|
|||
这里我介绍一种方法: |
|||
|
|||
我们需要修改方法,通过判断不同的模式(`debug`,`release`,`test`)来加载不同路径下的 `templates`。 |
|||
|
|||
`initRouter.go` |
|||
|
|||
``` |
|||
// 省略部分代码 |
|||
if mode := gin.Mode(); mode == gin.TestMode { |
|||
router.LoadHTMLGlob("./../templates/*") |
|||
} else { |
|||
router.LoadHTMLGlob("templates/*") |
|||
} |
|||
``` |
|||
|
|||
同时,也需要修改 `test`,我们要写个 `init` 方法,这里的 `init` 方法就好比 `java` 中 `Junit` 中的 `@Before` |
|||
|
|||
``` |
|||
package test |
|||
|
|||
import ( |
|||
"GinHello/initRouter" |
|||
"github.com/gin-gonic/gin" |
|||
"github.com/stretchr/testify/assert" |
|||
"net/http" |
|||
"net/http/httptest" |
|||
"testing" |
|||
) |
|||
|
|||
var router *gin.Engine |
|||
|
|||
func init() { |
|||
gin.SetMode(gin.TestMode) |
|||
router = initRouter.SetupRouter() |
|||
} |
|||
|
|||
func TestIndexHtml(t *testing.T) { |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodGet, "/", nil) |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
assert.Contains(t,w.Body.String(),"hello gin get method","返回的HTML页面中应该包含 hello gin get method") |
|||
} |
|||
``` |
|||
|
|||
这样完善了单元测试,方便日后的功能更改。 |
|||
|
|||
|
|||
|
|||
# 添加静态资源 |
|||
|
|||
当网页可以正常显示的时候,我们可以添加一些静态资源来使我们的页面更加美观。我在这里选择了 `Bootstrap 4` 做为一个 UI 界面框架。[Bootstrap 4 下载](https://github.com/twbs/bootstrap/releases/download/v4.3.1/bootstrap-4.3.1-dist.zip) |
|||
|
|||
同时还要引入 [Jquery](https://code.jquery.com/jquery-3.0.0.min.js) 和 [Popper](https://unpkg.com/popper.js@1.15.0/dist/umd/popper.min.js)。 |
|||
|
|||
我们新建一个 `statics` 文件夹,将我们 `Bootstrap` 解压,将 `js` 和 `css` 复制到 `statics` 目录下。 |
|||
|
|||
在我们的 `initRouter` 中,对静态资源进行添加。 |
|||
|
|||
``` |
|||
router.Static("/statics","./statics") |
|||
``` |
|||
|
|||
新建 `header.tmpl` |
|||
|
|||
``` |
|||
{{ define "header" }} |
|||
<nav class="navbar navbar-expand-lg navbar-light bg-light"> |
|||
<a class="navbar-brand" href="#">Gin Hello</a> |
|||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" |
|||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> |
|||
<span class="navbar-toggler-icon"></span> |
|||
</button> |
|||
|
|||
<div class="collapse navbar-collapse" id="navbarSupportedContent"> |
|||
<ul class="navbar-nav mr-auto"> |
|||
<li class="nav-item active"> |
|||
<a class="nav-link" href="#">主页 <span class="sr-only">(current)</span></a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" href="#">文章列表</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link " href="#" tabindex="-1" aria-disabled="true">关于</a> |
|||
</li> |
|||
</ul> |
|||
<form class="form-inline my-2 my-lg-0"> |
|||
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search"> |
|||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">搜索</button> |
|||
</form> |
|||
<ul class="navbar-nav "> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" href="#">登录</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" href="#">注册</a> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</nav> |
|||
{{end}} |
|||
``` |
|||
|
|||
并在我们的 `index.tmpl` 上进行添加 |
|||
|
|||
``` |
|||
<head> |
|||
<link rel="stylesheet" href="/statics/css/bootstrap.min.css"> |
|||
<link rel="stylesheet" href="/statics/css/bootstrap-grid.min.css"> |
|||
<link rel="stylesheet" href="/statics/css/bootstrap-reboot.min.css"> |
|||
<link href="/favicon.ico" rel="icon"/> |
|||
<script src="/statics/js/jquery.min.js" rel="script"></script> |
|||
<script src="/statics/js/Popper.js" rel="script"></script> |
|||
<script rel="script" src="/statics/js/bootstrap.bundle.js"></script> |
|||
</head> |
|||
<body> |
|||
<header> |
|||
{{template "header"}} |
|||
</header> |
|||
<main> |
|||
{{ .title }} |
|||
</main> |
|||
</body> |
|||
``` |
|||
|
|||
此时运行我们的网站,出现下图样式。 |
|||
|
|||
![效果](./img/3.3.jpeg) |
|||
|
|||
# 添加网站图标 |
|||
|
|||
万事俱备,只欠一个 `icon`。 |
|||
|
|||
网站此时还缺少网站的图标,网站图标也是通过 Gin 给定的函数设置。我们将 `.ico` 图片放到项目根目录下,然后在 `initRouter` 中设置。 |
|||
|
|||
``` |
|||
router.StaticFile("/favicon.ico","./favicon.ico") |
|||
``` |
|||
|
|||
再次运行我们的网站,此时就会发现网站的左上角标签页中出现了设置好的图标。 |
|||
|
|||
# 总结 |
|||
|
|||
通过本章节的介绍和学习,可以很快的使用 Gin 中的静态资源,定义网站图标等。 |
@ -0,0 +1,160 @@ |
|||
# Gin(四):表单提交校验和模型绑定 |
|||
|
|||
上一个章节中已经开始逐渐搭建了一个 web 页面,现在我们开始逐步完善页面上的功能,首先要完成的是登录和注册功能。 |
|||
|
|||
# 接受表单数据 |
|||
|
|||
注册页面的 HTML 元素不在详细写出,具体页面代码可以直接参考[Github](https://github.com/youngxhui/GinHello/tree/gin_form/templates) 上代码。 |
|||
|
|||
页面完成后布局: |
|||
|
|||
![页面效果](./img/4.1.jpeg) |
|||
|
|||
注册页面有三个输入框,分别为 `email` ,`password` 和 `password again` 。 |
|||
|
|||
完善后端 Gin 代码。我们在 `initRouter` 中 `userGroup` 中编写新的接口。 |
|||
|
|||
``` |
|||
userRouter.POST("/register", handler.UserRegister) |
|||
``` |
|||
|
|||
编写完新的接口就要开始编写 `Handler`。 |
|||
|
|||
``` |
|||
func UserRegister(context *gin.Context) { |
|||
email := context.PostForm("email") |
|||
password := context.DefaultPostForm("password", "Wa123456") |
|||
passwordAgain := context.DefaultPostForm("password-again", "Wa123456") |
|||
println("email", email, "password", password, "password again", passwordAgain) |
|||
} |
|||
``` |
|||
|
|||
`UserRegister` 方法中采用新的方式来接受 Post 请求提交的表单参数,`PostForm` 和 `DefaultPostForm` 。`PostForm` 直接接受参数,而 `DefaultPostForm` 可以设置一个默认值,如果前端没有进行传值,那么我们可以设置默认值,如上面的代码,如果前端没有将密码传输过来我们可以设置一个默认密码。 |
|||
|
|||
当我们运行并且输入的时候,在控制台上可以清楚的看到我们在表单上的输入。 |
|||
|
|||
当我们项目功能完善的时候,就可以完善我们的单元测试。 |
|||
|
|||
此时的单元测试交之前有点复杂。 |
|||
|
|||
首先我们要构造一个结构,该结构是为了帮助我们将我们要提交的信息存放到表单中,同时要指定请求头信息。 |
|||
|
|||
```go |
|||
func TestUserPostForm(t *testing.T) { |
|||
value := url.Values{} |
|||
value.Add("email", "youngxhui@gmail.com") |
|||
value.Add("password", "1234") |
|||
value.Add("password-again", "1234") |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodPost, "/user/register", bytes.NewBufferString(value.Encode())) |
|||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded; param=value") |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
} |
|||
``` |
|||
|
|||
单元测试编写完成后可以运行单元测试,发现控制台答应了我们在测试中写的数据。 |
|||
|
|||
# 模型绑定 |
|||
|
|||
上例中我们的表单仅仅传输了三个参数,如果后期项目出现了十多个参数,每次写一遍都很花费时间,也很消耗经历。下面就对该方法进行改善 |
|||
|
|||
Gin 中提供了 模型绑定,将我们的表单数据与我们的模型进行一样绑定。Gin会将数据统一封装到模型中,方便我们日后使用。 |
|||
|
|||
首先定义我们的模型,新建 `model` 文件夹,建立 `userModel.go` |
|||
|
|||
```go |
|||
package model |
|||
|
|||
type UserModel struct { |
|||
Email string `form:"email"` |
|||
Password string `form:"password"` |
|||
PasswordAgain string `form:"password-again"` |
|||
} |
|||
``` |
|||
|
|||
通过 `form:"email"` 来对表单中的 `email` 输入数据进行绑定。然后需要修改一下 `Handler` 方法。 |
|||
|
|||
```go |
|||
func UserRegister(context *gin.Context) { |
|||
var user model.UserModel |
|||
if err := context.ShouldBind(&user); err != nil { |
|||
println("err ->", err.Error()) |
|||
return |
|||
} |
|||
println("email", user.Email, "password", user.Password, "password again", user.PasswordAgain) |
|||
} |
|||
``` |
|||
|
|||
此时我们的模型绑定已经写好,运行 `TestUserPostForm` 测试用例,测试用例可以完美的通过。说明我们的模型绑定方法是正确的。同时模型绑定还是从 `json`, `xml` ,`yml` 等格式数据的绑定,日后会有介绍和说明。当然也可以通过浏览器中的注册表单进行提交。 |
|||
|
|||
# 数据校验 |
|||
|
|||
做后端开发的人都明白一个道理:永远不要相信前端传过来的数据。所有的数据在进过后端时,务必要进行数据的校验。 |
|||
|
|||
在模型中可用 `binding` 来对数据进行校验。Gin 对于数据校验使用的是 `validator.v8` 库,该库提供多种校验方法。通过 `binding:""` 方式来进行对数据的校验。 |
|||
|
|||
我们将 `UserModel` 进行修改,添加一些规则,邮箱验证和密码校验,要求第二次重复密码要和第一次密码一致。更多的校验规则可以看[官方文档](https://godoc.org/gopkg.in/go-playground/validator.v9) |
|||
|
|||
```go |
|||
type UserModel struct { |
|||
Email string `form:"email" binding:"email"` |
|||
Password string `form:"password"` |
|||
PasswordAgain string `form:"password-again" binding:"eqfield=Password"` |
|||
} |
|||
``` |
|||
|
|||
我们重新写一个测试用例用来测试邮箱和密码校验是否有效。 |
|||
|
|||
```go |
|||
func TestUserPostFormEmailErrorAndPasswordError(t *testing.T) { |
|||
value := url.Values{} |
|||
value.Add("email", "youngxhui") |
|||
value.Add("password", "1234") |
|||
value.Add("password-again", "qwer") |
|||
w := httptest.NewRecorder() |
|||
req, _ := http.NewRequest(http.MethodPost, "/user/register", bytes.NewBufferString(value.Encode())) |
|||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded; param=value") |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, http.StatusOK, w.Code) |
|||
} |
|||
``` |
|||
|
|||
运行测试,发现测试虽然通过了,但是会有两行 `error` 信息 |
|||
|
|||
``` |
|||
err -> Key: 'UserModel.Email' Error:Field validation for 'Email' failed on the 'email' tag |
|||
Key: 'UserModel.PasswordAgain' Error:Field validation for 'PasswordAgain' failed on the 'eqfield' tag |
|||
|
|||
``` |
|||
|
|||
该信息说明了我们的 `Email` 和 `PasswordAgain` 信息校验没有通过。 |
|||
|
|||
# 使用Log和重定向 |
|||
|
|||
测试通过是因为无论我们代码如何都会返回 200 状态码,这是不符合http 状态码的规范的,所以我们要对http状态码进行规范化。同时我们之前的代码中一直使用 `Printf` 来打印日志信息,也是不规范的,因为 `Printf` 打印的日志信息相对局限,所以应该选用 `Log` 进行日志打印。 |
|||
|
|||
```go |
|||
func UserRegister(context *gin.Context) { |
|||
var user model.UserModel |
|||
if err := context.ShouldBind(&user); err != nil { |
|||
log.Println("err ->", err.Error()) |
|||
context.String(http.StatusBadRequest, "输入的数据不合法") |
|||
} else { |
|||
log.Println("email", user.Email, "password", user.Password, "password again", user.PasswordAgain) |
|||
context.Redirect(http.StatusMovedPermanently, "/") |
|||
} |
|||
} |
|||
``` |
|||
|
|||
首先我们将原来只用 `Println` 打印的数据都改成了 `log` 去打印数据。 |
|||
|
|||
同时将原来的状态码都进行了更改,不同的状态码代表不同的请求响应结果。 |
|||
|
|||
最后在请求成功的时候我们对路由进行了重定向,将页面转跳到首页。 |
|||
|
|||
同时我们也要将测试用例里的返回状态码进行修改。 |
|||
|
|||
# 总结 |
|||
|
|||
本节将表单提交,模型绑定和数据校验有了一个相对细致的介绍,代码中也通过不同的测试用例来检查代码是否正确。 |
@ -0,0 +1,157 @@ |
|||
# Gin(五):连接MySQL |
|||
|
|||
之前我们完成了注册,接下来要完成登录功能,但是有个问题,我们的数据没有持久化,无法得知有哪些用户注册了,这样就无法在登录时进行校验。 |
|||
|
|||
所以接下来我们要将数据持久化,也就是存储到数据库中,这里使用 `MySQL` |
|||
|
|||
# 建立数据库 |
|||
|
|||
首先我们要新建一个库,用来存放项目数据,建立一个名为 `ginhello` 的库。 |
|||
|
|||
```mysql |
|||
create database ginhello; |
|||
``` |
|||
|
|||
当我们建立好数据库时,就可以通过 `Goland`进行数据库连接和使用。 |
|||
|
|||
选择 `Goland` 右侧的 `Database`,,点击 + 号,选择 `MySQL`。填写相关信息,账户名,密码,要连接的数据库库名等信息,进行连接。 |
|||
|
|||
之后我们就可以通过 `Goland` 的图形化界面去新建立表。 |
|||
|
|||
右键选择刚刚连接的 `ginhello` ,`new` , `table` 然后填写字段名称和属性。下面给出建表语句。 |
|||
|
|||
```mysql |
|||
create table user( |
|||
id int auto_increment primary key, |
|||
email varchar(30) not null, |
|||
password varchar(40) not null |
|||
) comment '用户表'; |
|||
``` |
|||
|
|||
# 连接数据库 |
|||
|
|||
数据库的表已经建立成功,那么省下来就该与我们的 Gin 建立联系,通过代码连接到数据库。 |
|||
|
|||
新建文件夹 `initDB` 新建 `initDB.go`。 |
|||
|
|||
```go |
|||
package initDB |
|||
|
|||
import ( |
|||
"database/sql" |
|||
_ "github.com/go-sql-driver/mysql" |
|||
"log" |
|||
) |
|||
|
|||
var Db *sql.DB |
|||
|
|||
func init() { |
|||
var err error |
|||
Db, err = sql.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/ginhello") |
|||
if err != nil { |
|||
log.Panicln("err:", err.Error()) |
|||
} |
|||
Db.SetMaxOpenConns(10) |
|||
Db.SetMaxIdleConns(10) |
|||
} |
|||
``` |
|||
|
|||
首先新建一个全局变量`sql.DB`方便我们后期调用,然后通过 `sql.Open`对数据进行连接。`SetMaxOpenConns` 是对 最大链接数的设置 `SetMaxIdleConns` 是设置最大空闲链接数 |
|||
|
|||
经过简单的设置,我们的程序就可以连接到数据库。 |
|||
|
|||
# 增加用户 |
|||
|
|||
当数据库连接上时,就可以完善我们的注册功能。 |
|||
|
|||
修改 `userModel.go` 对 `user` 添加新的方法。 |
|||
|
|||
```go |
|||
func (user *UserModel) Save() int64 { |
|||
result, e := initDB.Db.Exec("insert into ginhello.user (email, password) values (?,?);", user.Email, user.Password) |
|||
if e != nil { |
|||
log.Panicln("user insert error", e.Error()) |
|||
} |
|||
id, err := result.LastInsertId(); |
|||
if err != nil { |
|||
log.Panicln("user insert id error", err.Error()) |
|||
} |
|||
return id |
|||
} |
|||
``` |
|||
|
|||
该方法是对 `user` 类型进行添加的方法,最后返回一个新增行id |
|||
|
|||
> **小提示** 在编写 `SQL` 语句时,通过`ctrl+enter` 快捷键组合,选择 `Edit Mysql Fragment` ,会在编辑器下方重写打开一个编辑界面用来写SQL,并且带有自动提示,提示内容和我们链接的数据库相关。 |
|||
|
|||
最后修改 `UserRegister` 方法,当数据校验合格的时候进行存储。 |
|||
|
|||
```go |
|||
func UserRegister(context *gin.Context) { |
|||
var user model.UserModel |
|||
if err := context.ShouldBind(&user); err != nil { |
|||
context.String(http.StatusBadRequest, "输入的数据不合法") |
|||
log.Panicln("err ->", err.Error()) |
|||
} |
|||
id := user.Save() |
|||
log.Println("id is ", id) |
|||
context.Redirect(http.StatusMovedPermanently, "/") |
|||
} |
|||
``` |
|||
|
|||
当都写完的时候就可以运行我们的测试 `TestUserPostForm` 和 `TestUserPostFormEmailErrorAndPasswordError` 两个测试用例。 |
|||
|
|||
测试可以正常通过,此时检测我们的数据库。打开 `User` 表,里面只会有一条信息。 |
|||
|
|||
此时我们的注册也就完成了。 |
|||
|
|||
# 登录 |
|||
|
|||
接下来快速完成登录功能。 |
|||
|
|||
具体的前端代码请看 [Github](https://github.com/youngxhui/GinHello/tree/gin_db/templates)下面贴出来具体的后端代码 |
|||
|
|||
我们要根据 `Email` 和 `Password` 校验用户数据是否正确。 |
|||
|
|||
`userModel.go` 根据 `Email` 查询代码,该文件其他代码也有略微变化,请注意查看。 |
|||
|
|||
```go |
|||
func (user *UserModel) QueryByEmail() UserModel { |
|||
u := UserModel{} |
|||
row := initDB.Db.QueryRow("select * from user where email = ?;", user.Email) |
|||
e := row.Scan(&u.Id, &u.Email, &u.Password) |
|||
if e != nil { |
|||
log.Panicln(e) |
|||
} |
|||
return u |
|||
} |
|||
``` |
|||
|
|||
通过对比页面上传入的密码和数据库中的密码是否一致来确定用户是否可以登录。 |
|||
|
|||
`userHandler.go` |
|||
|
|||
```go |
|||
func UserLogin(context *gin.Context) { |
|||
var user model.UserModel |
|||
if e := context.Bind(&user); e != nil { |
|||
log.Panicln("login 绑定错误", e.Error()) |
|||
} |
|||
|
|||
u := user.QueryByEmail() |
|||
if u.Password == user.Password { |
|||
log.Println("登录成功", u.Email) |
|||
context.HTML(http.StatusOK, "index.tmpl", gin.H{ |
|||
"email": u.Email, |
|||
}) |
|||
} |
|||
} |
|||
``` |
|||
|
|||
每当一个功能编写完成的时候,切记要写上单元测试,这将会帮助我们在日后的项目中更加完善。 |
|||
|
|||
用户登录测试。 |
|||
|
|||
# 总结 |
|||
|
|||
本节通过链接数据库,完成了数据库的增加和查询功能,并且完成了注册和登录的相关功能。 |
@ -0,0 +1,326 @@ |
|||
# Gin(六):文件上传 |
|||
|
|||
之前使用了数据库做了简单的增加和查询功能,今天再次使用数据库完成一些其他功能,比如说头像的上传和显示。 |
|||
|
|||
# 新增用户头像 |
|||
|
|||
当用户登录完成后,页面右上角会显示当前用户的用户 `email` 。下面我们做点击 `email` 进入用户详情页,并可以修改信息。 |
|||
|
|||
先完善后端接口。通过用户的 `id` 来获取用户的详细信息,同时我们写了一个错误页 `error.tmpl`,来进行错误信息的展示。 |
|||
|
|||
`userHandler.go` |
|||
|
|||
```go |
|||
func UserProfile(context *gin.Context) { |
|||
id := context.Query("id") |
|||
var user model.UserModel |
|||
i, err := strconv.Atoi(id) |
|||
u, e := user.QueryById(i) |
|||
if e != nil || err != nil { |
|||
context.HTML(http.StatusOK, "error.tmpl", gin.H{ |
|||
"error": e, |
|||
}) |
|||
} |
|||
context.HTML(http.StatusOK, "user_profile.tmpl", gin.H{ |
|||
"user": u, |
|||
}) |
|||
} |
|||
``` |
|||
|
|||
代码中获取前端传递的id,通过 `strconv.Atoi()` 将String 类型转化为 int 类型。`user.QueryById()` 方法是我们用来进行对id查询的方法。 |
|||
|
|||
在进行 `QueryById` 方法之前,我们要对 `user` 结构体和数据库进行一下简单的修改。 |
|||
|
|||
```go |
|||
type UserModel struct { |
|||
Id int `form:"id"` |
|||
Email string `form:"email" binding:"email"` |
|||
Password string `form:"password" ` |
|||
Avatar sql.NullString |
|||
} |
|||
``` |
|||
|
|||
我们新增一行 `Avatar` ,类型为 `sql.NullString` 。为什么是 `sql.NullString` ?因为我们数据库中该字段初始时为 `null` ,而 `string` 类型是不可以接收 `null` 类型的,所以我们只能采用 `NullString` 来对 `null` 字符串进行处理。 |
|||
|
|||
同时,要对数据库进行添加,新增一列 `avatar` 字段。 |
|||
|
|||
修改后数据库 |
|||
|
|||
```sql |
|||
create table user ( |
|||
id int auto_increment |
|||
primary key, |
|||
email varchar(30) not null, |
|||
password varchar(40) not null, |
|||
avatar varchar(100) null |
|||
) comment '用户表'; |
|||
``` |
|||
|
|||
完成前期的修改工作,可以做剩下的事情。 |
|||
|
|||
# 获取用户信息 |
|||
|
|||
在 `userModel.go` 中获取用户信息,完成 `QueryById` 方法 |
|||
|
|||
```go |
|||
func (user *UserModel) QueryById(id int) (UserModel, error) { |
|||
u := UserModel{} |
|||
row := initDB.Db.QueryRow("select * from user where id = ?;", id) |
|||
e := row.Scan(&u.Id, &u.Email, &u.Password, &u.Avatar) |
|||
if e != nil { |
|||
log.Panicln(e) |
|||
} |
|||
return u, e |
|||
} |
|||
``` |
|||
|
|||
该方法基本和上一节的通过邮箱查询用户方法基本一致。 |
|||
|
|||
完成该方法后,就可以将我们的路由添加上。 |
|||
|
|||
```go |
|||
userRouter.GET("/profile/", handler.UserProfile) |
|||
``` |
|||
|
|||
此时就完成了后台的工作,剩下来就是对前端进行修改。 |
|||
|
|||
首先要重写划分一下前端的代码块。 |
|||
|
|||
```html |
|||
template |
|||
| |
|||
|-error.tmpl |
|||
|-header.tmpl |
|||
|-index.tmpl |
|||
|-login.tmpl |
|||
|-nav.tmpl |
|||
|-user_profile.tmpl |
|||
``` |
|||
|
|||
我们将原来 `index` 中 `head` 标签部分的代码移动到 `header` 中,将 `header` 原有的代码移动到 `nav.tmpl` 中。 |
|||
|
|||
`index.tmpl` |
|||
|
|||
```html |
|||
{{template "header"}} |
|||
<header> |
|||
{{template "nav" .}} |
|||
</header> |
|||
<main> |
|||
|
|||
</main> |
|||
``` |
|||
|
|||
`header.tmpl` |
|||
|
|||
```html |
|||
{{ define "header" }} |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" |
|||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
<link rel="stylesheet" href="/statics/css/bootstrap.min.css"> |
|||
<link rel="stylesheet" href="/statics/css/bootstrap-grid.min.css"> |
|||
<link rel="stylesheet" href="/statics/css/bootstrap-reboot.min.css"> |
|||
<script src="/statics/js/jquery.min.js" rel="script"></script> |
|||
<script src="/statics/js/Popper.js" rel="script"></script> |
|||
<script rel="script" src="/statics/js/bootstrap.bundle.js"></script> |
|||
<title>Gin Hello</title> |
|||
</head> |
|||
{{end}} |
|||
``` |
|||
|
|||
在 `nav.tmpl` 中 |
|||
|
|||
```html |
|||
{{ if .email }} |
|||
<ul class="navbar-nav "> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" href="/user/profile?id={{.id}}">{{ .email }}</a> |
|||
</li> |
|||
</ul> |
|||
{{ else }} |
|||
<ul class="navbar-nav "> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" data-toggle="modal" data-target="#login-modal">登录</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" data-toggle="modal" data-target="#register-modal">注册</a> |
|||
</li> |
|||
</ul> |
|||
{{end}} |
|||
``` |
|||
|
|||
通过路径 `/user/profile?id={{ .id }}` 将 `id` 数据传递后台。 |
|||
|
|||
当数据获取成功后,会转跳到 `user_profile.tmpl` 中 |
|||
|
|||
`user_profile.tmpl` |
|||
|
|||
```html |
|||
{{template "header"}} |
|||
{{template "nav"}} |
|||
<div class="container"> |
|||
<div class="row"> |
|||
<div class="col-sm"> |
|||
|
|||
<div> |
|||
<img src="{{ .user.Avatar.String }}" alt="avatar" class="rounded-circle"> |
|||
</div> |
|||
|
|||
</div> |
|||
<div class="col-sm"> |
|||
<form method="post" action="/user/update" enctype="multipart/form-data"> |
|||
<div class="form-group" hidden> |
|||
<label for="user-id">id</label> |
|||
<input type="text" id="user-id" |
|||
name="id" |
|||
value="{{ .user.Id }}"> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="user-email">Email</label> |
|||
<input type="email" class="form-control" id="user-email" aria-describedby="emailHelp" |
|||
name="email" |
|||
readonly |
|||
placeholder="Enter email" |
|||
value="{{ .user.Email }}"> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="user-password">密码</label> |
|||
<input type="password" class="form-control" id="user-password" placeholder="密码" name="password" |
|||
value="{{.user.Password}}"> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="user-avatar">上传头像</label> |
|||
<input type="file" class="form-control-file" id="user-avatar" name="avatar-file"> |
|||
</div> |
|||
<button type="submit" class="btn btn-primary">保存</button> |
|||
</form> |
|||
</div> |
|||
<div class="col-sm"></div> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
该页面的 Email 不可编辑,密码可以修改,头像可以上传。 |
|||
|
|||
此时我们的页面就完成了。 |
|||
|
|||
# 上传头像 |
|||
|
|||
完成了基本页面,就要进行头像上传了。 |
|||
|
|||
在 `userHandler.go` 添加 `UpdateUserProfile` 方法 |
|||
|
|||
```go |
|||
func UpdateUserProfile(context *gin.Context) { |
|||
var user model.UserModel |
|||
if err := context.ShouldBind(&user); err != nil { |
|||
context.HTML(http.StatusOK, "error.tmpl", gin.H{ |
|||
"error": err.Error(), |
|||
}) |
|||
log.Panicln("绑定发生错误 ", err.Error()) |
|||
} |
|||
file, e := context.FormFile("avatar-file") |
|||
if e != nil { |
|||
context.HTML(http.StatusOK, "error.tmpl", gin.H{ |
|||
"error": e, |
|||
}) |
|||
log.Panicln("文件上传错误", e.Error()) |
|||
} |
|||
} |
|||
``` |
|||
|
|||
通过数据绑定来将 `id` `email` 和 密码进行绑定,然后通过 `context.FormFile()` 将文件数据进行获取。 |
|||
|
|||
文件数据可以获取,那么获取的文件应该进行保存。 |
|||
|
|||
先写一个工具类来获取我们的项目根路径。 |
|||
|
|||
新建一个 `utils` 文件夹, `utils` 中新建 `pathUtils.go` |
|||
|
|||
```go |
|||
package utils |
|||
|
|||
import ( |
|||
"log" |
|||
"os" |
|||
"os/exec" |
|||
"strings" |
|||
) |
|||
|
|||
func RootPath() string { |
|||
s, err := exec.LookPath(os.Args[0]) |
|||
if err != nil { |
|||
log.Panicln("发生错误",err.Error()) |
|||
} |
|||
i := strings.LastIndex(s, "\\") |
|||
path := s[0 : i+1] |
|||
return path |
|||
} |
|||
``` |
|||
|
|||
编写工具类,方便我们日后对它直接使用。 |
|||
|
|||
``` |
|||
// 省略部分代码 |
|||
path := utils.RootPath() |
|||
path = filepath.Join(path, "avatar") |
|||
e = os.MkdirAll(path, os.ModePerm) |
|||
if e != nil { |
|||
context.HTML(http.StatusOK, "error.tmpl", gin.H{ |
|||
"error": e, |
|||
}) |
|||
log.Panicln("无法创建文件夹", e.Error()) |
|||
} |
|||
fileName := strconv.FormatInt(time.Now().Unix(), 10) + file.Filename |
|||
e = context.SaveUploadedFile(file, path+fileName) |
|||
if e != nil { |
|||
context.HTML(http.StatusOK, "error.tmpl", gin.H{ |
|||
"error": e, |
|||
}) |
|||
log.Panicln("无法保存文件", e.Error()) |
|||
} |
|||
|
|||
``` |
|||
|
|||
通过获取当前时间来确保图片的唯一性,保障上传的图片不会因为重名而覆盖。 |
|||
|
|||
在这里要思考一个问题,既然我们上传了头像,就要在页面上进行展示,头像展示需要获取地址,那么如何获取图片保存后的地址? |
|||
|
|||
在之前设置路由的时候,我们设置过一次静态文件目录,头像图片也属于静态文件,所以我们要对我们的上传目录再进行设置。 |
|||
|
|||
`initRouter.go` |
|||
|
|||
```go |
|||
router.StaticFS("/avatar", http.Dir(utils.RootPath()+"avatar/")) |
|||
``` |
|||
|
|||
我们将我们上传的路径,映射为 `/avatar` 之后,我们就可以通过改路径进行访问资源。 |
|||
|
|||
完善我们最后的代码 |
|||
|
|||
``` |
|||
avatarUrl := "http://localhost:8080/avatar/" + fileName |
|||
user.Avatar = sql.NullString{String: avatarUrl} |
|||
e = user.Update(user.Id) |
|||
if e != nil { |
|||
context.HTML(http.StatusOK, "error.tmpl", gin.H{ |
|||
"error": e, |
|||
}) |
|||
log.Panicln("数据无法更新", e.Error()) |
|||
} |
|||
context.Redirect(http.StatusMovedPermanently, "/user/profile?id="+strconv.Itoa(user.Id)) |
|||
|
|||
``` |
|||
|
|||
当图片进行报错后我们再次重定向到 `/user/profile` 路由,这也页面上就会显示我们新的数据。 |
|||
|
|||
![页面效果图](./img/6.1.jpeg) |
|||
|
|||
# 总结 |
|||
|
|||
通过本章节的学习 再次使用到了数据库的一些操作,同时也对文件上传进行了学习,并且完善了页面对于静态文件的显示。 |
@ -0,0 +1,110 @@ |
|||
# Gin(七):中间件的使用和定义 |
|||
|
|||
中间件 `middleware` 在 `golang` 中是一个很重要的概念,与 `java` 中拦截器很相似。通过 gin 源代码来看看中间件代码使用。 |
|||
|
|||
# 中间件使用 |
|||
|
|||
我们还是回到了 `initRouter` 中 `SetupRouter` 这个方法。 |
|||
|
|||
```go |
|||
router := gin.Default() |
|||
``` |
|||
|
|||
我们的项目是从这一行代码开始的,所以我们看看这一行代码做了些什么。打开 `Default` 源码, |
|||
|
|||
```go |
|||
func Default() *Engine { |
|||
debugPrintWARNINGDefault() |
|||
engine := New() |
|||
engine.Use(Logger(), Recovery()) |
|||
return engine |
|||
} |
|||
``` |
|||
|
|||
源码中,首先是 `New` 了一个 `engine` ,紧接着通过 `Use` 方法,传入了 `Logger()` 和 `Recovery()` ,而 `Logger`和 `Recovery` 就是两个中间件。 |
|||
|
|||
其中 `Logger` 是对日志进行记录,而 `Recovery` 是对有 `painc`时, 进行 500 的错误处理 |
|||
|
|||
查看了源码之后,那么我们也就知道如何使用中间件了。 |
|||
|
|||
# 自定义一个中间件 |
|||
|
|||
中间件【称为middleware】需要返回 `gin.HandlerFunc` 函数,所以定义返回函数。 |
|||
|
|||
```go |
|||
// HandleFunc defines the handler used by gin middleware as return value. |
|||
type HandleFunc func(*Context) |
|||
``` |
|||
|
|||
而且 中间件有个 `Next` 函数,在我们定义的众多中间件,会形成一条中间件链,而通过 `Next` 函数来对后面的中间件进行执行。`Next` 函数是在请求前执行,而 `Next` 函数后是在请求后执行。 |
|||
|
|||
我们来自己定义一个 `Logger` 日志,新建一个 `middleware` 文件夹,里面新建 `Logger.go`,进行我们自定义的日志展示。 |
|||
|
|||
```go |
|||
package middleware |
|||
|
|||
import ( |
|||
"fmt" |
|||
"github.com/gin-gonic/gin" |
|||
"time" |
|||
) |
|||
|
|||
func Logger() gin.HandlerFunc { |
|||
return func(context *gin.Context) { |
|||
host := context.Request.Host |
|||
url := context.Request.URL |
|||
method := context.Request.Method |
|||
fmt.Printf("%s::%s \t %s \t %s ", time.Now().Format("2006-01-02 15:04:05"), host, url, method) |
|||
context.Next() |
|||
fmt.Println(context.Writer.Status()) |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## 全局中间件 |
|||
|
|||
修改 `initRouter` 中的 `SetupRouter` 方法,将我们自定义的中间件进行添加。 |
|||
|
|||
```go |
|||
router := gin.New() |
|||
// 添加自定义的 logger 中间件 |
|||
router.Use(middleware.Logger(), gin.Recovery()) |
|||
``` |
|||
|
|||
此时重新启动我们的项目,访问`localhost:8080`端口,控制台上就会打印出我们新的格式日志。 |
|||
|
|||
> 2019-07-23 18:17:58::localhost:8080 / GET 200 |
|||
|
|||
当然,此时此刻的 `Logger` 中间件是全局使用,我们也可以给特定的路由进行使用。 |
|||
|
|||
## 局部中间件 |
|||
|
|||
比如我们规定某些路由需要登录后才能访问,那么我们可以给这些路由进行授权管理。 |
|||
|
|||
我们重新写一个 `Auth` 中间件来进行管理,这里不具体实现该中间件,后期会实现,这里只进行展示。 |
|||
|
|||
```go |
|||
package middleware |
|||
|
|||
import "github.com/gin-gonic/gin" |
|||
|
|||
func Auth() gin.HandlerFunc { |
|||
return func(context *gin.Context) { |
|||
println("已经授权") |
|||
context.Next() |
|||
} |
|||
} |
|||
``` |
|||
|
|||
我们在 用户信息修改和用户信息展示的路由上进行该中间件的添加。 |
|||
|
|||
```go |
|||
userRouter.GET("/profile/", middleware.Auth(), handler.UserProfile) |
|||
userRouter.POST("/update", middleware.Auth(), handler.UpdateUserProfile) |
|||
``` |
|||
|
|||
再次运行项目,当我们对用户详情页进行访问的时候,控制台上会打印出 已经授权 的日志,而访问其他页面则不会出现,说明我们的中间件使用成功。 |
|||
|
|||
# 总结 |
|||
|
|||
通过本次的中间件了解,基本掌握了中间件如何编写和使用,对于全局和局部的两种中间件也有着不同的使用方法和使用范围。 |
@ -0,0 +1,95 @@ |
|||
# Gin(八):cookie的使用 |
|||
|
|||
上一章节我们留下了一个小尾巴,那就是权限校验中间件并没有进行完善,那么今天就对它进行完善。 |
|||
|
|||
## Cookies |
|||
|
|||
接上回,如何来判断用户是否登录呢? `cookie` 就是一个很好的凭证,`cookie` 会保留到浏览器上,每次访问请求的时候就会携带上,后端通过对 `cookie` 的识别,来判断用户是否登录。 |
|||
|
|||
由此一来,首先我们是要在登录的时候保存 `cookie` 。修改 `userHandler` 中 `UserLogin` 代码 |
|||
|
|||
在判断密码正确的时候,对 `cookie` 进行添加。 |
|||
|
|||
```go |
|||
context.SetCookie("user_cookie", string(u.Id), 1000, "/", "localhost", false, true) |
|||
``` |
|||
|
|||
这里来介绍一下这些参数,第一个参数为 cookie 名;第二个参数为 cookie 值;第三个参数为 cookie 有效时长,当 cookie 存在的时间超过设定时间时,cookie 就会失效,它就不再是我们有效的 cookie;第四个参数为 cookie 所在的目录;第五个为所在域,表示我们的 cookie 作用范围;第六个表示是否只能通过 https 访问;第七个表示 cookie 是否可以通过 js代码进行操作。 |
|||
|
|||
启动我们的项目,进行登录操作,F12 打开我们的控制台,选择Application ,在侧边栏找到 cookie,并且选择我们的站点,此时就可以在我们的右侧看到我们刚刚设置的 cookie 信息 |
|||
|
|||
![控制台效果](./img/8.1.jpeg) |
|||
|
|||
并且有 Expires/Max-Age 属性,该属性表示 cookie 的过期时间,一旦超过这个时间,cookie 就会自动消失。 |
|||
|
|||
此时,已经表明我们的 cookie 设置成功。 |
|||
|
|||
## 通过中间件获取Cookie |
|||
|
|||
既然 cookie 已经获取成功,那么就该对我们新写的 Auth 中间件进行修改了。 |
|||
|
|||
我们首先建立一个 401.tmpl 文件,用于展示我们的权限不足时的信息。 |
|||
|
|||
```html |
|||
{{template "header"}} |
|||
|
|||
{{template "nav"}} |
|||
|
|||
请先登录:<a href="/">首页</a> |
|||
``` |
|||
|
|||
当我们要访问需要权限的路由时,恰巧我们权限不足,就会转跳到该页面。 |
|||
|
|||
此时再完善我们的中间件。 |
|||
|
|||
```go |
|||
func Auth() gin.HandlerFunc { |
|||
return func(context *gin.Context) { |
|||
_, e := context.Request.Cookie("user_cookie") |
|||
if e == nil { |
|||
context.Next() |
|||
} else { |
|||
context.Abort() |
|||
context.HTML(http.StatusUnauthorized, "401.tmpl", nil) |
|||
} |
|||
|
|||
} |
|||
} |
|||
``` |
|||
|
|||
在这里我们通过 `context.Request.Cookie()` 来获取指定的 `cookie` 。这里还有一个函数 `context.Abort()`表示对当前的请求进行中止。 |
|||
|
|||
重新启动项目,直接去访问 `http://localhost:8080/user/profile/?id=5`,会出现我们的`401` 页面。当我们登录后再进行访问,就可以正常访问。 |
|||
|
|||
此时此刻说明我们的 `auth` 中间件起到了作用。 |
|||
|
|||
## 刷新 cookie |
|||
|
|||
在上面的 `cookie` 设置中有一个参数是为了设置过期时间,那么过期时间到底设置多长呢?过期时间设置过长,那么可能留下安全隐患,如果设置过短,又给用户带来不方便。 |
|||
|
|||
所以我们要在 `cookie` 请求成功的时候自动刷新我们的 `cookie` 时间。 |
|||
|
|||
修改我们中间件代码。 |
|||
|
|||
首先是获取到原来的 `cookie` ,然后就是重新设置一个 `cookie`。 |
|||
|
|||
```go |
|||
func Auth() gin.HandlerFunc { |
|||
return func(context *gin.Context) { |
|||
cookie, e := context.Request.Cookie("user_cookie") |
|||
if e == nil { |
|||
context.SetCookie(cookie.Name, cookie.Value, 1000, cookie.Path, cookie.Domain, cookie.Secure, cookie.HttpOnly) |
|||
context.Next() |
|||
} else { |
|||
context.Abort() |
|||
context.HTML(http.StatusUnauthorized, "401.tmpl", nil) |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
重新启动我们的项目,仍旧是打开我们项目的控制台,每次访问需要权限的接口时,都会看到cookie的过期时间在重新刷新。 |
|||
|
|||
## 总结 |
|||
|
|||
本章节主要讲述了 `cookie` 如何添加,如何获取,又如何通过中间件来校验 `cookie` 和刷新 `cookie` |
@ -0,0 +1,162 @@ |
|||
# Gin(九):生成restful接口 |
|||
|
|||
经过前面几章节的学习,基本对 Gin 中的一些概念和函数有所了解和掌握,也知道如何在代码中对其进行使用,那么接下来,我们将目光回到很久很久以前,具体多久呢?估摸着就是你在学习第二章 Gin 路由 的时候。 |
|||
|
|||
今天,不在模板上做文章了,而是要开启新的章节,我们叫它 **restful**。 |
|||
|
|||
# restful 是什么 |
|||
|
|||
说到 `restful` 相信很多乃至大量的朋友们都不陌生,如果你已经知道那就直接看下一个章节,但还是有很多小伙伴是第一次接触,那么这里就简单介绍一下`restful`。 |
|||
|
|||
简单的说 `restful` 就是一种 接口定义风格,比如说之前我们的接口对于更新用户可能这样定义, `/update_user` 对于获取当前用户可能是 `get_user` ,删除当前用户为 `/delete_user` ,而现在使用 `restful` 风格的接口,那么我们对于更新用户的接口定义为 `/user`,获取用户定义为 `/user` ,删除用户为 `/user` 。 |
|||
|
|||
所以一个完整的 `restful` 请求需要加上请求方式。对于更新用户我们的接口应该是用 `update` 请求 `/user`,对于获取用户应该用`get`请求方式`/user`,对于删除用户应该用`delete`请求`/user` 接口。 |
|||
|
|||
这里只对 `restful` 请求方式做最简单的介绍。 |
|||
|
|||
# 第一个接口 |
|||
|
|||
我们现在来进行一个关于文章接口的展示,仍旧是连接上数据库,数据存在数据库中。 |
|||
|
|||
首先建立数据库,仍旧是在我们之前使用的数据库上建立新的表 `article` ,下面为建表语句,并且连接数据库。 |
|||
|
|||
```sql |
|||
create table article ( |
|||
id int auto_increment |
|||
primary key, |
|||
type varchar(20) null, |
|||
content text not null |
|||
); |
|||
``` |
|||
|
|||
首先我们要有一个模型来和表结构对应,也用于我们接收前端的数据绑定。 |
|||
|
|||
新建 `model` 文件夹,在 `model` 文件夹中建立 `article.go` |
|||
|
|||
```go |
|||
type Article struct { |
|||
Id int `json:"id"` |
|||
Type string `json:"type"` |
|||
Content string `json:"content"` |
|||
} |
|||
``` |
|||
|
|||
通过标注 `json` 来进行对前端数据获取是的绑定。 |
|||
|
|||
接下来就可以完成第一个功能了,向数据库新增一个 `article` 。在 `article.go` 中完成向数据添加数据的代码,这里代码不做解释,和之前一致。 |
|||
|
|||
```go |
|||
func (article Article) Insert() int { |
|||
result, e := initDB.Db.Exec("insert into `article` (type, content) values (?, ?);", article.Type, article.Content) |
|||
if e != nil { |
|||
log.Panicln("文章添加失败", e.Error()) |
|||
} |
|||
i, _ := result.LastInsertId() |
|||
return int(i) |
|||
} |
|||
``` |
|||
|
|||
完成 `model` 层,就可以完成 `handler` |
|||
|
|||
在 `handler` 下新建 `article/articleHandler.go` 。 |
|||
|
|||
我们首要要获取前端穿过来的数据。通过 `context.ShouldBindJSON` 来对数据进行绑定。如果绑定成功,则调用我们上面写的增加方法进行添加。当完成后,通过 `context.JSON` 返回 `json` 数据。 |
|||
|
|||
```go |
|||
func Insert(context *gin.Context) { |
|||
article := model.Article{} |
|||
var id = -1 |
|||
if e := context.ShouldBindJSON(&article); e == nil { |
|||
id = article.Insert() |
|||
} |
|||
context.JSON(http.StatusOK, gin.H{ |
|||
"id": id, |
|||
}) |
|||
} |
|||
``` |
|||
|
|||
最后,我们完成对应的路由。 |
|||
|
|||
在 `initRouter` 中的 `SetupRouter` 中完善路由配置。 |
|||
|
|||
```go |
|||
articleRouter := router.Group(""){ |
|||
// 添加一篇文章 |
|||
articleRouter.POST("/article", article.Insert) |
|||
} |
|||
``` |
|||
|
|||
# 测试 |
|||
|
|||
当这一切完成后就是运行测试了。 |
|||
|
|||
当然我们最好编写单元测试。 |
|||
|
|||
在 `test` 文件夹中,新建 `article_test.go` 测试文件。 |
|||
|
|||
``` |
|||
package test |
|||
|
|||
import ( |
|||
"GinHello/initRouter" |
|||
"GinHello/model" |
|||
"bytes" |
|||
"encoding/json" |
|||
"github.com/gin-gonic/gin" |
|||
"gopkg.in/go-playground/assert.v1" |
|||
"net/http" |
|||
"net/http/httptest" |
|||
"testing" |
|||
) |
|||
|
|||
var router *gin.Engine |
|||
|
|||
func init() { |
|||
router = initRouter.SetupRouter() |
|||
} |
|||
|
|||
func TestInsertArticle(t *testing.T) { |
|||
article := model.Article{ |
|||
Type: "go", |
|||
Content: "hello gin", |
|||
} |
|||
marshal, _ := json.Marshal(article) |
|||
w := httptest.NewRecorder() |
|||
req := httptest.NewRequest(http.MethodPost, "/article", bytes.NewBufferString(string(marshal))) |
|||
req.Header.Add("content-type", "application/json") |
|||
router.ServeHTTP(w, req) |
|||
assert.Equal(t, w.Code, http.StatusOK) |
|||
assert.NotEqual(t, "{id:-1}", w.Body.String()) |
|||
} |
|||
|
|||
``` |
|||
|
|||
在测试用例里创建一个 `article` 对象,并且赋值,通过 `json` 方法建对象转换为 `json`,最后发起请求。 |
|||
|
|||
运行测试用例,如果我们的代码写的 没有问题的话,测试通过,并且数据库中会对应添加该数据。 |
|||
|
|||
当然你不想写单元测试也是可以的,可以通过 `Postman` 等来进行测试,这里给大家简单的介绍一下 `GoLand` `Http` 测试工具。 |
|||
|
|||
我们新建立一个 `http_test` 文件夹,在文件夹下面新建一个 `.http` 文件,命名为 `article.http` |
|||
|
|||
![测试工具类](./img/9.1.jpeg) |
|||
|
|||
对文件进行编写,编写如下,指定我们的请求地址,指定要求的数据。在POST 左侧就会出现一个 运行按钮,点击运行按钮,控制台会出现返回结果。运行该文件时,要将我们的项目启动起来。 |
|||
|
|||
```http |
|||
POST http://localhost:8080/article |
|||
Content-Type: application/json |
|||
|
|||
{ |
|||
"type": "go", |
|||
"content": "Hello Go" |
|||
} |
|||
``` |
|||
|
|||
其他的 `.http` 文件的语法规则 请看[官方文档](https://www.jetbrains.com/help/idea/exploring-http-syntax.html)。 |
|||
|
|||
这样就完成了第一个 `restful` 接口,同样可以完成其他的接口。其他的接口示例请看 `Github` 上代码。 |
|||
|
|||
# 总结 |
|||
|
|||
本章节主要讲述了如何构建一套 `restful` 接口,`restful` 接口对于现在的开发是越来越重要了,大量的接口都是 `restful` 风格。Github 上代码完成了查询,添加,删除等接口,篇幅有限,不展开多讲了。 |
@ -0,0 +1,182 @@ |
|||
# Gin(十):集成 Swagger |
|||
|
|||
你喜欢写文档吗? ~~我喜欢~~。 |
|||
|
|||
所以说文档成了开发心中的一个痛。尤其是使用 `restful` 接口,成了必须要写文档,否者前端同学根本不知道你写了什么。那么让我写文档,还不如杀了我呢!!! |
|||
|
|||
接下来介绍一款神器 — **swagger** |
|||
|
|||
# 什么是swagger |
|||
|
|||
`Swagger` 是一个 `API` 生成工具,可以生成文档。 `Swagger` 是通过编写 `yaml` 和 `json` 来实现文档化。并且可以进行测试等工作。 |
|||
|
|||
通过 `swagger` 可以方便的生成接口文档,方便前端进行查看和测试。 |
|||
|
|||
# 安装 swagger |
|||
|
|||
上面说了一堆 `swagger` 怎么样,说到头还是要自己编写?其实并不是的,让我们的项目中集成 `swagger`,以后项目的接口文档便可以自动生成。 |
|||
|
|||
首先要安装 `swagger` 。 |
|||
|
|||
```go |
|||
go get -u github.com/swaggo/swag/cmd/swag |
|||
``` |
|||
|
|||
等待安装完成,在我们的终端中执行 `swag init`,目录为根目录,于 `main.go` 同目录。 |
|||
|
|||
执行完成后,会在根目录下新建一个 `docs` 文件夹。 |
|||
|
|||
```html |
|||
docs |
|||
| |
|||
|-docs.go |
|||
|-swagger.json |
|||
|-swagger.yaml |
|||
``` |
|||
|
|||
接下来就可以完善项目了。 |
|||
|
|||
将下面两行放入 `initRouter` 中的 `import` 中。 |
|||
|
|||
```go |
|||
swaggerFiles "github.com/swaggo/files" |
|||
ginSwagger "github.com/swaggo/gin-swagger" |
|||
``` |
|||
|
|||
选择 `Sync packages of GinHello`,此时 `IDE` 就会自动帮我下载,并添加到 `go.mod` 中。 |
|||
|
|||
如果这里提示下载失败,请对 `go mod` 添加代理。 |
|||
|
|||
> **添加代理** File-Setting-Go-Go Modules(vgo)-Proxy |
|||
> 代理添加 https://mirrors.aliyun.com/goproxy/ 这是最近阿里建立的 go mod 镜像。当然你也可以选择其他镜像代理。 |
|||
> |
|||
> ![配置页面](./img/10.1.jpeg) |
|||
> |
|||
> |
|||
|
|||
等待包下载完成。 |
|||
|
|||
# 集成 swagger |
|||
|
|||
对 `swagger` 安装完成后,我们就可以对项目进行集成了。 |
|||
|
|||
在 `initRouter` 中添加路由,这个路由是对 `swagger` 的访问地址来进行添加的 |
|||
|
|||
```go |
|||
url := ginSwagger.URL("http://localhost:8080/swagger/doc.json") router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url)) |
|||
``` |
|||
|
|||
其中 `url` 定义了 `swagger` 的 `doc.json` 路径,我们可以直接访问该 `json` 来进行查看。 |
|||
|
|||
接下来就是完善文档的时间。 |
|||
|
|||
在 `main.go` 中 `main` 方法上添加注释。同时引入我们生成 `docs.go` |
|||
|
|||
``` |
|||
package main |
|||
|
|||
import ( |
|||
_ "GinHello/docs" |
|||
"GinHello/initRouter" |
|||
) |
|||
|
|||
// @title Gin swagger |
|||
// @version 1.0 |
|||
// @description Gin swagger 示例项目 |
|||
|
|||
// @contact.name youngxhu |
|||
// @contact.url https://youngxhui.top |
|||
// @contact.email youngxhui@g mail.com |
|||
|
|||
// @license.name Apache 2.0 |
|||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html |
|||
|
|||
// @host localhost:8080 |
|||
func main() { |
|||
// 省略其他代码 |
|||
} |
|||
|
|||
``` |
|||
|
|||
上述的注释基本都是很好理解的,不做过多解释。 |
|||
|
|||
主要的项目介绍注释就是这些,接下来进行我们的接口方法注释。 |
|||
|
|||
在我们的 `handler` 中添加注释 |
|||
|
|||
打开 `articleHandler.go` ,在 `Insert` 方法上添加。 |
|||
|
|||
```go |
|||
// @Summary 提交新的文章内容 |
|||
// @Id 1 |
|||
// @Tags 文章 |
|||
// @version 1.0 |
|||
// @Accept application/x-json-stream |
|||
// @Param article body model.Article true "文章" |
|||
// @Success 200 object model.Result 成功后返回值 |
|||
// @Failure 409 object model.Result 添加失败 |
|||
// @Router /article [post] |
|||
``` |
|||
|
|||
- @Summary 是对该接口的一个描述 |
|||
- @Id 是一个全局标识符,所有的接口文档中 Id 不能标注 |
|||
- @Tags 是对接口的标注,同一个 tag 为一组,这样方便我们整理接口 |
|||
- @Version 表明该接口的版本 |
|||
- @Accept 表示该该请求的请求类型 |
|||
- @Param 表示参数 分别有以下参数 参数名词 参数类型 数据类型 是否必须 注释 属性(可选参数),参数之间用空格隔开。 |
|||
- @Success 表示请求成功后返回,它有以下参数 请求返回状态码,参数类型,数据类型,注释 |
|||
- @Failure 请求失败后返回,参数同上 |
|||
- @Router 该函数定义了请求路由并且包含路由的请求方式。 |
|||
|
|||
具体参数类型,数据类型等可以查看[官方文档](https://swaggo.github.io/swaggo.io/declarative_comments_format/api_operation.html) |
|||
|
|||
其中文档中没有说明的地方这里说明一下,关于 `Param` 的参数类型有以下几种 |
|||
|
|||
- query 形如 `\user?username=Jack&age=18` |
|||
- body 需要将数据放到 body 中进行请求 |
|||
- path 形如 `\user\1` |
|||
|
|||
不同的参数类型对应的不同请求,请对应使用。 |
|||
|
|||
这样我们就完成了添加接口的文档注释。 |
|||
|
|||
我们用通用的方法来完善一下根据 `id` 查询数据的接口文档。 |
|||
|
|||
在 `GetOne` 的方法上添加如上注释。 |
|||
|
|||
```go |
|||
// @Summary 通过文章 id 获取单个文章内容 |
|||
// @version 1.0 |
|||
// @Accept application/x-json-stream |
|||
// @Param id path int true "id" |
|||
// @Success 200 object model.Result 成功后返回值 |
|||
// @Router /article/{id} [get] |
|||
``` |
|||
|
|||
我们对形如 `/article/:id` 的接口,最后的 id 通过 `{}` 包裹。 |
|||
|
|||
细心的小伙伴可能会发现我们最后的返回结果为 `model.Result` ,这是为了我们统一返回结果而新建的一个结构体,方便前端进行解析。具体函数如下 |
|||
|
|||
```go |
|||
package model |
|||
|
|||
type Result struct { |
|||
Code int `json:"code" example:"000"` |
|||
Message string `json:"message" example:"请求信息"` |
|||
Data interface{} `json:"data" ` |
|||
} |
|||
``` |
|||
|
|||
我们在对 `Result` 中的 `tag` 会有 `example` ,这个仍旧是 `swagger` 的标签,用来给该结构体一个示例。 |
|||
|
|||
同理,我们可以对之前的 `article` 进行注释。 |
|||
|
|||
当我们完成了所有的代码注释时,在控制台中重新执行 `swag init`,它会根据我们的注释生成 `docs.go` 及其对应的 json 和 yaml 文件。 |
|||
|
|||
启动我们的项目,访问 `hppt://localhost:8080/swagger/index.html` 就可以查看我们的文档,效果如下 |
|||
|
|||
![测试效果图](./img/10.2.jpeg) |
|||
|
|||
# 总结 |
|||
|
|||
通过本章节的学习,将我们的项目和文档相结合起来,反正要写注释,现在是一举两得,即完成了代码注释,也完成了项目文档。 |
@ -0,0 +1,163 @@ |
|||
# Gin(十一):配合orm框架-gorm |
|||
|
|||
随着项目的不断扩大,总有一天,项目中的表和表中的字段多的数不胜数,如果此时仍旧使用 SQL 语言来执行增删改查,务必会带来很多繁琐的事情,比如说我们要添加一个字段有十多个的结构体,要把结构体中的每个属性都要写一遍。极大的降低了开发速度,也会引入一些错误,所以我们要引入一些框架来对数据库进行管理,方便我们完成项目。这里我们介绍一下 **gorm** |
|||
|
|||
## gorm |
|||
|
|||
`gorm` 是 `Go` 语言中比较知名的 `orm` 框架之一。`gorm` 对于常见的功能基本都已实现。 在 `gin` 中添加 `gorm` 是非常简单的。 |
|||
|
|||
首先打开我们的 `initDB` 文件夹。 将原来 `sql.Open` 改为 `gorm.Open` 同时引入 `gorm` , 同时对 `Db` 的定义类型进行更改,`*gorm.DB` 。 具体代码如下: |
|||
|
|||
```go |
|||
package initDB |
|||
|
|||
import ( |
|||
_ "github.com/go-sql-driver/mysql" |
|||
"github.com/jinzhu/gorm" |
|||
_ "github.com/jinzhu/gorm/dialects/mysql" |
|||
"log" |
|||
) |
|||
|
|||
var Db *gorm.DB |
|||
|
|||
func init() { |
|||
var err error |
|||
Db, err = gorm.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/ginhello") |
|||
if err != nil { |
|||
log.Panicln("err:", err.Error()) |
|||
} |
|||
} |
|||
``` |
|||
|
|||
此时我们的对框架的引入就已经完成了。 |
|||
|
|||
因为我们将 `Db` 的属性进行了修改,此时的 `article.go` 中出现了错误。 |
|||
|
|||
所以我们修改,利用 `gorm` 的 `api` 来进行。 |
|||
|
|||
## 实现增删改查 |
|||
|
|||
### 增加 |
|||
|
|||
增加方法,之前使用 `SQL` 语言来实现添加的,如下: |
|||
|
|||
```go |
|||
result, e := initDB.Db.Exec("insert into ` article` (type, content) values (?, ?);", article.Type, article.Content) |
|||
``` |
|||
|
|||
现在我们要通过框架来实现这一个过程。 |
|||
|
|||
```go |
|||
create := initDB.Db.Create(&article) |
|||
``` |
|||
|
|||
### 查询单个 |
|||
|
|||
通过 `article.Id` 传入限制条件,该方法仅仅是用于 主键为 `int` 类型时。 |
|||
|
|||
```go |
|||
initDB.Db.First(&article, article.Id) |
|||
return article |
|||
``` |
|||
|
|||
### 查询所有 |
|||
|
|||
```go |
|||
var articles []Article |
|||
initDB.Db.Find(&articles) |
|||
return articles |
|||
``` |
|||
|
|||
### 删除 |
|||
|
|||
```go |
|||
initDB.Db.Delete(article) |
|||
``` |
|||
|
|||
通过以上的一些方法可以看出来,基本对之前的增删改查代码有了极大的缩短,大大的减少了错误的发生。 |
|||
|
|||
此时就可以运行我们的代码,通过 `.http` 也好,通过单元测试也好,但是一运行就会报错。报错如下: |
|||
|
|||
```go |
|||
Error 1146: Table 'ginhello.articles' doesn't exist |
|||
``` |
|||
|
|||
说在 `ginhello` 库中并没有 `articles` 表。 这句话说的没有毛病啊,我们的确没有 `articles` 表,我们建立的是 `article` 表。 |
|||
|
|||
原来 `gorm` 在对应的结构体默认会加个 `s`,所以我们现在有两个办法,第一个就是改表明,但是表明往往是不可以随便修改的。第二个是修改代码,让它之道我们要找的表为 `article` 而不是 `articles`。 |
|||
|
|||
```go |
|||
func (article Article) TableName() string { |
|||
return "article" |
|||
} |
|||
``` |
|||
|
|||
实现该接口,该接口返回一个字符串,通过字符串来定义我们需要关联的表。 |
|||
|
|||
此时再次运行我们的代码,发现功能可以完整的使用,并且没有报错。 |
|||
|
|||
## 自动建表 |
|||
|
|||
加入现在是一个新的项目,还没有建立数据库表,或者项目迁移到另一个环境,环境上还没有数据库表,怎么办? |
|||
|
|||
`gorm` 给我们提供了建立数据库表的功能。 |
|||
|
|||
我们新建立一个 `model` 叫做 `comment` ,管理评论。 |
|||
|
|||
```go |
|||
package model |
|||
|
|||
type Comment struct { |
|||
ID int |
|||
content string |
|||
} |
|||
``` |
|||
|
|||
**这里的 `ID` 要全部进行大写**。 |
|||
|
|||
建立好结构体后就可以对结构体进行建立对应的数据库表。 |
|||
|
|||
对于建表 我们首要检查一下表是否存在,如果存在就不需要重新建立了,不能每次运行项目就把之前的数据覆盖掉。 |
|||
|
|||
```go |
|||
func init() { |
|||
table := initDB.Db.HasTable(Comment{}) |
|||
if !table { |
|||
initDB.Db.CreateTable(Comment{}) |
|||
} |
|||
} |
|||
``` |
|||
|
|||
运行我们的项目就会发现数据库中已经新建立了表,如果我们想在建立的时候同时为 `id` 建立索引,我们可以对结构体 `tag` 上标明。如下 |
|||
|
|||
```go |
|||
type Comment struct { |
|||
ID int `gorm:"index:idx_id"` |
|||
Content string |
|||
} |
|||
``` |
|||
|
|||
将刚刚建立的表删除掉,重新运行代码。数据库表中会添加 `idx_id` 索引。 |
|||
|
|||
## gorm model 的使用 |
|||
|
|||
我们在建立数据库的时候,每个表都会建立主键 `ID` ,如果你读过 [*阿里巴巴 Java 开发规范*](https://youngxhui.top/2019/07/gin十一配合orm框架/) 的话,还应该知道一些其他的必要信息,比如说创建时间,修改时间等。 |
|||
|
|||
此时 `gorm model` 就起到了作用,他已经给我们封装了一下属性。 |
|||
|
|||
我们需要将结构体改为下面的样子 |
|||
|
|||
```go |
|||
type Comment struct { |
|||
gorm.Model |
|||
Content string |
|||
} |
|||
``` |
|||
|
|||
删除了之前的表结构,重新运行项目,此时就会生成新的表结构。 |
|||
|
|||
![表结构](./img/11.1.jpeg) |
|||
|
|||
## 总结 |
|||
|
|||
通过本章节的简答学习,基本可以将 `gorm` 融入到我们的 gin 项目中,并且操作数据库,极大的减少了我们的代码量。如果有时间的话,后期可能会专门出一起 `gorm` 的使用介绍。 |
@ -0,0 +1,263 @@ |
|||
# Gin(十二):JWT使用 |
|||
|
|||
在前后端分离的项目中,越来越多的项目采用 `JWT` 代替传统的 `cookie` ,这里我们来使用 `JWT` 结合 `Gin` 来作为一个登录授权和权限校验。 |
|||
|
|||
# 什么是 JWT |
|||
|
|||
JWT 的全称叫做 JSON WEB TOKEN,在目前前后端系统中使用较多。 |
|||
|
|||
## JWT 构成 |
|||
|
|||
JWT 是由三段构成的。分别是 HEADER,PAYLOAD,VERIFY SIGNATURE,它们生成的信息通过 `.` 分割。 |
|||
|
|||
![用例](./img/12.1.jpeg) |
|||
|
|||
### HEADER |
|||
|
|||
header 是由 一个 `typ` 和 `alg` 组成,`typ` 会指明为 JWT,而 `alg` 是所使用的加密算法。 |
|||
|
|||
```json |
|||
{ |
|||
"alg": "HS256", |
|||
"typ": "JWT" |
|||
} |
|||
``` |
|||
|
|||
### PAYLOAD |
|||
|
|||
payload 是 JWT 的载体,也就是我们要承载的信息。这段信息是我们可以自定义的,可以定义我们要存放什么信息,那些字段。该部分信息不宜过多,它会影响 JWT 生成的大小,还有就是请勿将敏感数据存入该部分,该端数据前端是可以解析获取 token 内信息的。 |
|||
|
|||
官方给了七个默认字段,我们可以不全部使用,也可以加入我们需要的字段。 |
|||
|
|||
| 名称 | 含义 | |
|||
| --------- | ------------- | |
|||
| Audience | 表示JWT的受众 | |
|||
| ExpiresAt | 失效时间 | |
|||
| Id | 签发编号 | |
|||
| IssuedAt | 签发时间 | |
|||
| Issuer | 签发人 | |
|||
| NotBefore | 生效时间 | |
|||
| Subject | 主题 | |
|||
|
|||
### VERIFY SIGNATURE |
|||
|
|||
这也是 JWT 的最后一段,该部分是由算法计算完成的。 |
|||
|
|||
对刚刚的 header 进行 base64Url 编码,对 payload 进行 base64Url 编码,两端完成编码后通过 `.` 进行连接起来。 |
|||
|
|||
```json |
|||
base64UrlEncode(header).base64UrlEncode(payload) |
|||
``` |
|||
|
|||
完成上述步骤后,就要通过我们 header 里指定的加密算法对上部分进行加密,同时我们还要插入我们的一个密钥,来确保我的 JWT 签发是安全的。 |
|||
|
|||
这便是我们的第三部分。 |
|||
|
|||
当三部分都完成后,通过使用 `.` 将三部分分割,生成了上图所示的 JWT 。 |
|||
|
|||
## JWT 登录原理 |
|||
|
|||
简单的说就是当用户登录的时候,服务器校验登录名称和密码是否正确,正确的话,会生成 JWT 返回给客户端。客户端获取到 JWT 后要进行保存,之后的每次请求都会讲 JWT 携带在头部,每次服务器都会获取头部的 JWT 是否正确,如果正确则正确执行该请求,否者验证失败,重新登录。 |
|||
|
|||
![请求逻辑](./img/12.2.jpeg) |
|||
|
|||
# Gin 生成 JWT |
|||
|
|||
go 语言的 JWT 库有很多。[jwt.io](https://jwt.io/) 上也给出了很多 。这里使用 `jwt-go` |
|||
|
|||
``` |
|||
"github.com/dgrijalva/jwt-go" |
|||
``` |
|||
|
|||
我们对登录方法进行改造。 |
|||
|
|||
```go |
|||
// 省略代码 |
|||
expiresTime := time.Now().Unix() + int64(config.OneDayOfHours) |
|||
claims := jwt.StandardClaims{ |
|||
Audience: user.Username, // 受众 |
|||
ExpiresAt: expiresTime, // 失效时间 |
|||
Id: string(user.ID), // 编号 |
|||
IssuedAt: time.Now().Unix(), // 签发时间 |
|||
Issuer: "gin hello", // 签发人 |
|||
NotBefore: time.Now().Unix(), // 生效时间 |
|||
Subject: "login", // 主题 |
|||
} |
|||
var jwtSecret = []byte(config.Secret) |
|||
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
|||
// 省略代码 |
|||
``` |
|||
|
|||
这里的 `config.OneDayOfHours` 设定了过期时间,这里设定了一天。通过 `StandardClaims` 生成标准的载体,也就是上文提到的七个字段,其中 编号设定为 用户 id。其中的 `jwtSecret` 是我们设定的密钥, |
|||
|
|||
我们这里通过 HS256 算法生成 `tokenClaims` ,这就是我们的 HEADER 部分和 PAYLOAD。 |
|||
|
|||
```go |
|||
token, err := tokenClaims.SignedString(jwtSecret) |
|||
``` |
|||
|
|||
这样便生成了我们的 token 。我们要将我们的 token 和 Bearer 拼接在一起,同时中间用空格隔开。 |
|||
|
|||
```go |
|||
token = "Bearer "+ token |
|||
``` |
|||
|
|||
生成 Bearer Token 。 |
|||
|
|||
当我们用户进行登录的时候,就可以通过该片段生成 JWT。 |
|||
|
|||
下面是完整代码: |
|||
|
|||
```go |
|||
func CreateJwt(ctx *gin.Context) { |
|||
// 获取用户 |
|||
user := &model.User{} |
|||
result := &model.Result{ |
|||
Code: 200, |
|||
Message: "登录成功", |
|||
Data: nil, |
|||
} |
|||
if e := ctx.BindJSON(&user); e != nil { |
|||
result.Message = "数据绑定失败" |
|||
result.Code = http.StatusUnauthorized |
|||
ctx.JSON(http.StatusUnauthorized, gin.H{ |
|||
"result": result, |
|||
}) |
|||
} |
|||
u := user.QueryByUsername() |
|||
if u.Password == user.Password { |
|||
expiresTime := time.Now().Unix() + int64(config.OneDayOfHours) |
|||
claims := jwt.StandardClaims{ |
|||
Audience: user.Username, // 受众 |
|||
ExpiresAt: expiresTime, // 失效时间 |
|||
Id: string(user.ID), // 编号 |
|||
IssuedAt: time.Now().Unix(), // 签发时间 |
|||
Issuer: "gin hello", // 签发人 |
|||
NotBefore: time.Now().Unix(), // 生效时间 |
|||
Subject: "login", // 主题 |
|||
} |
|||
var jwtSecret = []byte(config.Secret) |
|||
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
|||
if token, err := tokenClaims.SignedString(jwtSecret); err == nil { |
|||
result.Message = "登录成功" |
|||
result.Data = "Bearer " + token |
|||
result.Code = http.StatusOK |
|||
ctx.JSON(result.Code, gin.H{ |
|||
"result": result, |
|||
}) |
|||
} else { |
|||
result.Message = "登录失败" |
|||
result.Code = http.StatusOK |
|||
ctx.JSON(result.Code, gin.H{ |
|||
"result": result, |
|||
}) |
|||
} |
|||
} else { |
|||
result.Message = "登录失败" |
|||
result.Code = http.StatusOK |
|||
ctx.JSON(result.Code, gin.H{ |
|||
"result": result, |
|||
}) |
|||
} |
|||
} |
|||
|
|||
``` |
|||
|
|||
通过 .http 请求测试,结果如下 |
|||
|
|||
```json |
|||
{ |
|||
"result": { |
|||
"code": 200, |
|||
"message": "登录成功", |
|||
"data": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxMjMiLCJleHAiOjE1NjQ3OTY0MzksImp0aSI6Ilx1MDAwMCIsImlhdCI6MTU2NDc5NjQxOSwiaXNzIjoiZ2luIGhlbGxvIiwibmJmIjoxNTY0Nzk2NDE5LCJzdWIiOiJsb2dpbiJ9.CpacmfBSMgmK2TgrT-KwNB60bsvwgyryGQ0pWZr8laU" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
这个便完成了token的生成。 |
|||
|
|||
# Gin 校验 Token |
|||
|
|||
那么,接下来就需要完成 token 的验证。 |
|||
|
|||
还记得之前我们验证用户是否授权采用的办法吗?是的,在中间件里查看用户 cookie。同样的方法,我们这里校验用户 JWT 是否有效。 |
|||
|
|||
编写我们的中间件。 |
|||
|
|||
新建立 `middleware/Auth.go` |
|||
|
|||
首先先编写我们的解析 token 方法,`parseToken()` |
|||
|
|||
```go |
|||
func parseToken(token string) (*jwt.StandardClaims, error) { |
|||
jwtToken, err := jwt.ParseWithClaims(token, &jwt.StandardClaims{}, func(token *jwt.Token) (i interface{}, e error) { |
|||
return []byte(config.Secret), nil |
|||
}) |
|||
if err == nil && jwtToken != nil { |
|||
if claim, ok := jwtToken.Claims.(*jwt.StandardClaims); ok && jwtToken.Valid { |
|||
return claim, nil |
|||
} |
|||
} |
|||
return nil, err |
|||
} |
|||
``` |
|||
|
|||
通过传入我们的 token , 来对 token 进行解析。 |
|||
|
|||
完整的中间件代码 |
|||
|
|||
```go |
|||
func Auth() gin.HandlerFunc { |
|||
return func(context *gin.Context) { |
|||
result := model.Result{ |
|||
Code: http.StatusUnauthorized, |
|||
Message: "无法认证,重新登录", |
|||
Data: nil, |
|||
} |
|||
auth := context.Request.Header.Get("Authorization") |
|||
if len(auth) == 0 { |
|||
context.Abort() |
|||
context.JSON(http.StatusUnauthorized, gin.H{ |
|||
"result": result, |
|||
}) |
|||
} |
|||
auth = strings.Fields(auth)[1] |
|||
// 校验token |
|||
_, err := parseToken(auth) |
|||
if err != nil { |
|||
context.Abort() |
|||
result.Message = "token 过期" + err.Error() |
|||
context.JSON(http.StatusUnauthorized, gin.H{ |
|||
"result": result, |
|||
}) |
|||
} else { |
|||
println("token 正确") |
|||
} |
|||
context.Next() |
|||
} |
|||
} |
|||
``` |
|||
|
|||
首先在请求头获取 token ,然后对先把 token 进行解析,将 Bearer 和 JWT 拆分出来,将 JWT 进行校验。 |
|||
|
|||
我们只需要对我们需要校验的路由进行添加中间件校验即可。 |
|||
|
|||
```go |
|||
router.GET("/", middleware.Auth(), func(context *gin.Context) { |
|||
context.JSON(http.StatusOK, time.Now().Unix()) |
|||
}) |
|||
``` |
|||
|
|||
当我们访问 `/` 的时候就需要携带 token 了 |
|||
|
|||
``` |
|||
GET http://localhost:8080 |
|||
Content-Type: application/json |
|||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIxMjMiLCJleHAiOjE1NjQ3OTQzNjIsImp0aSI6Ilx1MDAwMCIsImlhdCI6MTU2NDc5NDM0MiwiaXNzIjoiZ2luIGhlbGxvIiwibmJmIjoxNTY0Nzk0MzQyLCJzdWIiOiJsb2dpbiJ9.uQxGMsftyVFtYIGwQVm1QB2djw-uMfDbw81E5LMjliU |
|||
|
|||
``` |
|||
|
|||
# 总结 |
|||
|
|||
本章节对什么是 JWT,Gin 中如何使用 JWT 做了介绍。但是不要过于迷信 JWT,JWT 还有很多问题,比如说 JWT 失效只能是时间过期,如果修改密码或者账户注销等操作需要我们另外添加逻辑判断。适合的地方选用适合的技术才能发挥最大的优势。 |
@ -0,0 +1,170 @@ |
|||
# Gin(十三):交叉编译和Docker部署 |
|||
|
|||
陆陆续续已经更新到了第十三期,基本的知识点都已经讲解的差不多,那么最后一步就是对项目进行部署。这里我们将项目部署到 Linux 的服务器 Docker 上。本期知识点包括**交叉编译**和**Docker部署**。 |
|||
|
|||
# 交叉编译 |
|||
|
|||
什么是交叉编译呢?交叉编辑简单的说就是一个平台生成另一个平台的可执行程序。我们大部分开发环境是 windows 或者 macOS ,当然也有使用 linux 用户(其实在 windows 上更加推荐使用 WSL 进行开发),而我们的上线服务器一般都是 linux,所以我们要进行项目的交叉编译。Go 中对交叉编译相对简单,我们只需要进行简单的设置即可完成交叉编译。 |
|||
|
|||
打开我们的项目根目录,打开终端,设置 GOOS 和 GOARCH。 |
|||
|
|||
在 windows 下编译为 linux 程序。 |
|||
|
|||
```powershell |
|||
SET CGO_ENABLED=0 |
|||
SET GOOS=linux |
|||
SET GOARCH=amd64 |
|||
go build -o out/linux/gin_hello . |
|||
``` |
|||
|
|||
这里的 `go build -o out/linux/gin_hello` 是指将编译后的文件输出到 out/linux 下,编译后的二进制叫做 gin_hello 。 |
|||
|
|||
我将命令写到了 `.bat` 方便处理,不用每次都执行贴一下这几行命令。 |
|||
|
|||
在项目根目录下新建立 `build.bat` ,然后执行该文件。当然,很多工程或者项目使用 `Makefile` 进行的编译 |
|||
|
|||
```cmd |
|||
SET CGO_ENABLED=0 |
|||
SET GOOS=linux |
|||
SET GOARCH=amd64 |
|||
go build -o out/linux/gin_hello . |
|||
exit |
|||
``` |
|||
|
|||
执行完该文件就会在 out/linux 下出现 gin_hello |
|||
|
|||
这里我们便完成了交叉编译,编译后的程序是 linux 下的可执行文件。 |
|||
|
|||
# 安装 Dokcer |
|||
|
|||
这里使用的操作系统为 centos 7 ,安装前要更新一下软件源 `sudo yum update` ,之后对 Docker 软件源进行添加。 |
|||
|
|||
```shell |
|||
sudo yum-config-manager \ |
|||
--add-repo \ |
|||
https://download.docker.com/linux/centos/docker-ce.repo |
|||
``` |
|||
|
|||
再次更新一下软件源 `sudo yum update` ,最后就可以安装我们的 docker 了 |
|||
|
|||
```shell |
|||
sudo yum install docker-ce |
|||
``` |
|||
|
|||
添加到开机启动 |
|||
|
|||
```shell |
|||
sudo systemctl enable docker |
|||
``` |
|||
|
|||
启动Docker |
|||
|
|||
```shell |
|||
sudo systemctl start docker |
|||
``` |
|||
|
|||
此时,我们的 Docker 已经完成安装。但是我们还需要为我们的 Docker 设置远程连接,让我们本地开发可以连接到服务器。 |
|||
|
|||
> **警告** 下面的方法仅仅是为了教程演示 **请勿在生成环境中使用该方法,该方法存在缺陷,使 Docker 端口暴漏在公网环境中,任何人都可以在Docker进行部署。如果需要生产环境中打开远程端口,需要配置权限认证方式,这里不过多做介绍** |
|||
|
|||
在 Centos 7 中,进行对下面的文件进行编辑 |
|||
|
|||
```shell |
|||
vim /usr/lib/systemd/system/docker.service |
|||
``` |
|||
|
|||
找到 ExecStart 开头的进行如下添加和修改。 |
|||
|
|||
```shell |
|||
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock -H fd:// --containerd=/run/containerd/containerd.sock |
|||
``` |
|||
|
|||
此时,重启服务器或者重新启动 Docker 就完成了 Docker 的远程连接。 |
|||
|
|||
# 安装数据库 |
|||
|
|||
首先我们要在 dockers 上进行 数据库 MySQL 的安装。首先在执行我们的搜索命令,看看能不能找到MySQL 相关的信息 `docker search mysql` 。 |
|||
|
|||
![安装目录情况](./img/13.1.jpeg) |
|||
|
|||
确认可以查找到 MySQL 后,就可以完成 MySQL 进行的拉取 ,通过命令 `docker pull mysql` 拉取 MySQL 镜像。此时并没有指定 MySQL 的版本,会给我们拉取最新的 MySQL 版本。 |
|||
|
|||
拉取完毕,通过 `docker iamges` 查看当前所有的镜像,这里我们只有一个 MySQL 。 |
|||
|
|||
![安装情况](./img/13.2.jpeg) |
|||
|
|||
我已经对 MySQL 镜像进行了获取,那么接下来就是通过镜像创建容器。 |
|||
|
|||
```shell |
|||
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=1234 -d mysql |
|||
``` |
|||
|
|||
此时我们的 MySQL 容器就创建成功,并且启动完成,而且我们制定了 MySQL 的密码为 1234,端口为 3306。 |
|||
|
|||
```shell |
|||
docker exec -it mysql /bin/bash |
|||
``` |
|||
|
|||
我们为 MySQL 指定一个终端,来进行数据库的创建。 |
|||
|
|||
输入 `mysql -u root -p` 回车后输入密码 `1234`,进入数据库。输入 `create database ginhello` 和我们本地数据库名称一致。 |
|||
|
|||
这样,我们在服务器上的操作就完成了。 |
|||
|
|||
# Goland 连接 Docker,并部署项目 |
|||
|
|||
首先我们要对我们的代码进行简单的修改,之前我们一直是 DEBUG 模式在运行项目,而现在我们要正式上线了,需要修改我们的启动模式,在 `main.go` 中进行添加。 |
|||
|
|||
```go |
|||
gin.SetMode(gin.ReleaseMode) |
|||
``` |
|||
|
|||
此时就可以执行我们的交叉编译时候写的脚本 build.bat,会生成新的 linux 可执行文件。 |
|||
|
|||
新建 Dockerfile,编写 Dockerfile |
|||
|
|||
```dockerfile |
|||
FROM alpine |
|||
|
|||
WORKDIR /web/gin |
|||
|
|||
COPY ./out/linux/. . |
|||
|
|||
CMD ./gin_hello |
|||
``` |
|||
|
|||
简单的说一下这些含义,拉取一个 alpine 的镜像,这基本是最小的 linux , 指定我们的 WORKDIR, 将我们生成的 linux 可执行程序复制到 WORKDIR 下,运行项目。 |
|||
|
|||
当然这些还不够,当我们编写完成该文件的时候,在第一行会出现运行按钮。 |
|||
|
|||
单击运行按钮,选择 **Edit ‘Dockerfile’** |
|||
|
|||
![操作代码设置](./img/13.3.jpeg) |
|||
|
|||
会出现下面的界面。点击 ① 处的省略号,出现旁边的界面,进行 Docker 的配置,在 ② 处填写我们的 IP 端口为 2375 设置完成后,等待,看看 ③ 处是否有 Connection successful 。否者链接失败,查看上述步骤是否出错。完成后点击 OK。 |
|||
|
|||
![操作代码设置1](./img/13.4.jpeg) |
|||
|
|||
完成 Docker 的配置,接着完成端口映射。 |
|||
|
|||
![操作代码设置2](./img/13.5.jpeg) |
|||
|
|||
Host port 表示宿主主机端口,就是我们的服务器端口,而 Container port 表示我们的 容器的端口。因为 gin 项目运行在容器内,且启动端口为 8080,我们通过端口映射,访问宿主主机 80 端口,而映射到 8080 端口。 |
|||
|
|||
完成上述设置,就可以点击启动我们的 Dockerfile。 |
|||
|
|||
![操作代码设置3](./img/13.6.jpeg) |
|||
|
|||
我们可以在 Goland 的 Service 中找到当前进度。 |
|||
|
|||
等待完成,打开服务器公网IP。 |
|||
|
|||
![页面效果](./img/13.7.jpeg) |
|||
|
|||
可以看到我们之前写的代码。 |
|||
|
|||
此时我们就完成了部署。 |
|||
|
|||
# 总结 |
|||
|
|||
通过本章节的 交叉编译,Docker 安装,Docker 镜像安装和启动容器,部署 Gin 项目,完成了一个项目通过 Docker上线部署的过程。 |
@ -0,0 +1,156 @@ |
|||
# [Gin中context的使用](https://www.cnblogs.com/peteremperor/p/14033453.html) |
|||
|
|||
`Gin`封装的最好的地方就是`context`和对response的处理。本篇文章主要解释context的使用方法, 以及其设计原理 |
|||
|
|||
# 将Request的处理封装到Context中优点 |
|||
|
|||
在阅读gin的源码时, 请求的处理是使用`type HandlerFunc func(*Context)`来处理的. 也就是 |
|||
|
|||
``` |
|||
func(context *gin.Context) { |
|||
context.String(http.StatusOK, "some post") |
|||
} |
|||
``` |
|||
|
|||
参数是`gin.Context`, 但是查看源码发现其实`gin.Context`在整个框架处理的地方只有下面这段 |
|||
|
|||
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);) |
|||
|
|||
``` |
|||
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { |
|||
c := engine.pool.Get().(*Context) |
|||
c.writermem.reset(w) |
|||
c.Request = req |
|||
c.reset() |
|||
engine.handleHTTPRequest(c) |
|||
engine.pool.Put(c) |
|||
} |
|||
``` |
|||
|
|||
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);) |
|||
|
|||
为什么还要利用Context来处理呢? |
|||
|
|||
gin的context实现了的context.Context `Interface`.经过查看`context.Context`相关资料, Context的最佳运用场景就是对Http的处理.。**封装成Conetxt另外的好处就是`WithCancel`, `WithDeadline`, `WithTimeout`, `WithValue`这些context包衍生的子Context就可以直接来使用.** |
|||
|
|||
# gin.Context的设计 |
|||
|
|||
## **`gin.Context`主要由下面几部分组成:** |
|||
|
|||
### Metadata Management (我自己叫法:Key-Value) |
|||
|
|||
这个模块比较简单, 就是从gin.Context中Set Key-Value, 以及各种个样的Get方法, 如`GetBool`, `GetString`等 |
|||
|
|||
实现这些功能也很简单, 其实就是一个`map` |
|||
|
|||
``` |
|||
// Keys is a key/value pair exclusively for the context of each request. |
|||
Keys map[string]interface{} |
|||
``` |
|||
|
|||
### Input Data |
|||
|
|||
这个模块相当重要了, gin的`README`基本上都在介绍这个模块的用法 |
|||
|
|||
### Param ( 路由变量) |
|||
|
|||
gin的标准叫法是Parameters in path. restful风格api如`/user/john`, 这个路由在gin里面是`/user/:name`, 要获取`john`就需要使用Param函数 |
|||
|
|||
``` |
|||
name := c.Param("name") |
|||
``` |
|||
|
|||
这个方法实现也很简单, 就是在`tree.go`里面根据路由相关规则解析出来然后赋值给`gin.Context`的`Params`. |
|||
|
|||
``` |
|||
handlers, params, tsr := root.getValue(path, c.Params, unescape) |
|||
``` |
|||
|
|||
### Query |
|||
|
|||
`/welcome?firstname=Jane&lastname=Doe`这样一个路由, `first`, `last`即是`Querystring parameters`, 要获取他们就需要使用`Query`相关函数. |
|||
|
|||
``` |
|||
c.Query("first") // Jane |
|||
c.Query("last") // Doe |
|||
``` |
|||
|
|||
当然还有其他相关函数: |
|||
|
|||
- QueryMap |
|||
- DefaultQuery 这个默认值的实现更加简单, 当QueryString中不包含这个值, 直接返回填入的值 |
|||
|
|||
这些方法是的实现是利用`net/http`的`Request`的方法实现的 |
|||
|
|||
### PostForm |
|||
|
|||
对于`POST`, `PUT`等这些能够传递参数Body的请求, 要获取其参数, 需要使用PostForm |
|||
|
|||
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);) |
|||
|
|||
``` |
|||
POST /user/1 |
|||
|
|||
{ |
|||
"name":manu, |
|||
"message":this_is_great |
|||
} |
|||
``` |
|||
|
|||
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);) |
|||
|
|||
``` |
|||
name := c.PostForm("name") |
|||
message := c.PostForm("message") |
|||
``` |
|||
|
|||
其他相关函数 |
|||
|
|||
- DefaultPostForm |
|||
|
|||
这些相关的方法是实现还是利用`net/http`的`Request`的方法实现的 |
|||
|
|||
### FormFile |
|||
|
|||
对于文件相关的操作, 一般生产情况下不建议这样使用, 因为把文件上传到服务器磁盘, 还得磁盘相关的监控. 我觉得最好利用云服务商相关的`对象存储`, 如:阿里云OSS, 七牛云对象存储, AWS的对象存储等来做文件的相关操作. |
|||
|
|||
### Bind |
|||
|
|||
内置的有`json`, `xml`, `protobuf`, `form`, `query`, `yaml`. 这些Bind极大的减少我们自己去解析各种个样的数据格式, 提高我们的开发速度 |
|||
|
|||
Bind的实现都在`gin/binding`里面. 这些内置的Bind都实现了`Binding`接口, 主要是`Bind()`函数. |
|||
|
|||
- context.BindJSON() 支持MIME为application/json的解析 |
|||
- context.BindXML() 支持MIME为application/xml的解析 |
|||
- context.BindYAML() 支持MIME为application/x-yaml的解析 |
|||
- context.BindQuery() 只支持QueryString的解析, 和Query()函数一样 |
|||
- context.BindUri() 只支持路由变量的解析 |
|||
- Context.Bind() 支持所有的类型的解析, 这个函数尽量还是少用(当QueryString, PostForm, 路由变量在一块同时使用时会产生意想不到的效果), 目前测试Bind不支持路由变量的解析, Bind()函数的解析比较复杂, 这部分代码后面再看 |
|||
|
|||
|
|||
|
|||
### Response |
|||
|
|||
#### 对Header的支持 |
|||
|
|||
- Header |
|||
- GetHeader |
|||
|
|||
这里的Header是写到Response里面的Header. 对于客户端发的请求的Header可以通过`context.Request.Header.Get("Content-Type")`获取 |
|||
|
|||
#### Cookie |
|||
|
|||
提供对session, cookie的支持 |
|||
|
|||
#### render |
|||
|
|||
做api常用到的其实就是gin封装的各种render. 目前支持的有: |
|||
|
|||
- func (c *Context) JSON(code int, obj interface{}) |
|||
- func (c *Context) Protobuf(code int, obj interface{}) |
|||
- func (c *Context) YAML(code int, obj interface{}) |
|||
... |
|||
|
|||
当然我们可以自定义渲染, 只要实现`func (c *Context) Render(code int, r render.Render)`即可. |
|||
|
|||
这里我们常用的是一个方法是: `gin.H{"error": 111}`. 这个结构相当实用, 各种render都支持. 其实这个结构很简单就是`type H map[string]interface{}`, 当我们要从map转换各种各样结构时, 不妨参考gin这里的代码 |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 119 KiB |
@ -0,0 +1,5 @@ |
|||
module go_to_gin |
|||
|
|||
go 1.14 |
|||
|
|||
require github.com/gin-gonic/gin v1.7.1 |
@ -0,0 +1,54 @@ |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= |
|||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= |
|||
github.com/gin-gonic/gin v1.7.1 h1:qC89GU3p8TvKWMAVhEpmpB2CIb1hnqt2UdKZaP93mS8= |
|||
github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= |
|||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= |
|||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= |
|||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= |
|||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= |
|||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= |
|||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= |
|||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= |
|||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= |
|||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= |
|||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= |
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= |
|||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= |
|||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= |
|||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= |
|||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= |
|||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= |
|||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= |
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= |
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= |
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= |
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
|||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= |
|||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= |
|||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= |
|||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= |
|||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= |
|||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@ -0,0 +1,6 @@ |
|||
{ |
|||
"app_name": "viviman", |
|||
"app_mode": "debug", |
|||
"app_host": "127.0.0.1", |
|||
"app_port": "8080" |
|||
} |
@ -0,0 +1,24 @@ |
|||
package controller |
|||
|
|||
import ( |
|||
"github.com/gin-gonic/gin" |
|||
"go_to_gin_init/service" |
|||
) |
|||
|
|||
// 1、定义结构体为了实现下列方法可以被调用处理
|
|||
type HelloController struct { |
|||
} |
|||
|
|||
// 2、定义与当前结构体相关的请求路由
|
|||
// 注意:参数为 *gin.Engine
|
|||
// 模拟请求操作:http://127.0.0.1:8080/hello
|
|||
func (hello *HelloController) Router(engine *gin.Engine) { |
|||
engine.GET("/hello", hello.Hello) |
|||
} |
|||
|
|||
// 3、定义与当前结构体相关的请求处理函数
|
|||
// 注意:参数为 *gin.Context
|
|||
func (hello *HelloController) Hello(context *gin.Context) { |
|||
path := new(service.HelloService).Hello(context.FullPath()) |
|||
context.Writer.WriteString(path) |
|||
} |
@ -0,0 +1,5 @@ |
|||
module go_to_gin_init |
|||
|
|||
go 1.16 |
|||
|
|||
require github.com/gin-gonic/gin v1.7.2 |
@ -0,0 +1,27 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"github.com/gin-gonic/gin" |
|||
"go_to_gin_init/controller" |
|||
"go_to_gin_init/tool" |
|||
) |
|||
|
|||
func main() { |
|||
// 1、引入全剧配置文件,用于控制全局参数
|
|||
cfg, err := tool.ParseConfig("./config/app.json") |
|||
if err != nil { |
|||
panic(err.Error()) |
|||
} |
|||
|
|||
app := gin.Default() |
|||
|
|||
registerRouter(app) |
|||
|
|||
// app.Run(new(tool.Config).HostPort())
|
|||
app.Run(cfg.AppHost + ":" + cfg.AppPort) |
|||
} |
|||
|
|||
// 2、定义全局路由组册器
|
|||
func registerRouter(router *gin.Engine) { |
|||
new(controller.HelloController).Router(router) |
|||
} |
@ -0,0 +1,11 @@ |
|||
package service |
|||
|
|||
type HelloService struct { |
|||
} |
|||
|
|||
func (hello *HelloService) Hello(path string) string { |
|||
if path == "" { |
|||
return "这是空的!" |
|||
} |
|||
return path |
|||
} |
@ -0,0 +1,46 @@ |
|||
package tool |
|||
|
|||
import ( |
|||
"bufio" |
|||
"encoding/json" |
|||
"os" |
|||
) |
|||
|
|||
// 1、定义与 app.json 对应的结构体
|
|||
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 GetCfg() *Config { |
|||
return cfg |
|||
} |
|||
|
|||
// 2、定义读取配置文件函数
|
|||
// ParseConfig 返回类别为Config的指针
|
|||
func ParseConfig(path string) (*Config, error) { |
|||
|
|||
file, err := os.Open(path) |
|||
if err != nil { |
|||
panic(err.Error()) |
|||
} |
|||
defer file.Close() |
|||
|
|||
reader := bufio.NewReader(file) |
|||
decoder := json.NewDecoder(reader) |
|||
err = decoder.Decode(&cfg) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return cfg, nil |
|||
} |
|||
|
|||
// 自定义函数
|
|||
func (cfg *Config) HostPort() string { |
|||
return cfg.AppHost + ":" + cfg.AppPort |
|||
} |
@ -0,0 +1,36 @@ |
|||
# Gin后端框架搭建 |
|||
|
|||
|
|||
|
|||
## 1、项目介绍 |
|||
|
|||
项目分为用户客户端使用和商家数据端管理. |
|||
|
|||
## 1.1前端使用VUE |
|||
|
|||
* 安装Node.js |
|||
* 安装vue相关插件 |
|||
|
|||
## 1.2后端使用Gin |
|||
|
|||
* |
|||
|
|||
## 2、程序安装 |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
## 3、代码搭建 |
|||
|
|||
### 3.1配置文件引入 |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
## 4、代码测试 |
@ -0,0 +1,56 @@ |
|||
package main |
|||
|
|||
import "github.com/gin-gonic/gin" |
|||
|
|||
func main() { |
|||
|
|||
engine := gin.Default() |
|||
|
|||
// 1、使用 http://127.0.0.1:8090/hello?name=zhangsan
|
|||
// 4.1、handle处理请求
|
|||
// engine.Handle("GET", "/hello", iRouterFunc)
|
|||
engine.GET("/hello", func(context *gin.Context) { |
|||
/** |
|||
queryInfo := context.DefaultQuery("name", "这是默认") -- 存在默认值的获取参数值 |
|||
queryInfo := context.Query("name") -- 匹配参数值 |
|||
queryInfo, bool := context.GetQuery("name") -- 匹配参数值,并返回是否匹配结果 |
|||
|
|||
queryInfos := context.QueryArray("names") -- |
|||
queryInfos := context.QueryMap("names") -- |
|||
queryInfos, bool := context.GetQueryArray("names") -- |
|||
queryInfos, bool := context.GetQueryMap("names") -- |
|||
queryInfos := context.BindQuery(&names) -- |
|||
queryInfos := context.ShouldBindQuery(&names) -- |
|||
*/ |
|||
queryInfo := context.DefaultQuery("name", "这是默认") |
|||
context.Writer.Write([]byte("获取参数name=" + queryInfo)) |
|||
}) |
|||
|
|||
// 2、使用 http://127.0.0.1:8090/login
|
|||
// 4.2、handle处理请求
|
|||
// engine.Handle("POST", "/login", iRouterFunc)
|
|||
engine.POST("/login", func(context *gin.Context) { |
|||
/** |
|||
queryInfo := context.PostForm("f_xxx.name") -- |
|||
queryInfos := context.PostFormArray("f_xxx.names") -- |
|||
queryInfos, bool := context.GetPostForm("f_xxx.names") -- |
|||
queryInfos, bool := context.GetPostFormArray("f_xxx.names") -- |
|||
queryInfos, bool := context.GetPostFormMap("f_xxx.names") -- |
|||
*/ |
|||
queryInfo := context.PostForm("f_xxx.name") |
|||
context.Writer.Write([]byte("获取参数name=" + queryInfo)) |
|||
}) |
|||
|
|||
// 3、使用 http://127.0.0.1:8090/user/:id
|
|||
// 4.3、handle处理请求
|
|||
// engine.Handle("DELETE", "/user/:id", fiRouterFunc)
|
|||
engine.DELETE("/user/:id", func(context *gin.Context) { |
|||
/** |
|||
queryInfo := context.Param("name") -- 匹配":xx"类参数值 |
|||
*/ |
|||
queryInfo := context.Param("id") |
|||
context.Writer.Write([]byte("删除的id=" + queryInfo)) |
|||
}) |
|||
|
|||
engine.Run() |
|||
} |
@ -0,0 +1,14 @@ |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>测试模板设置</title> |
|||
</head> |
|||
<body> |
|||
<!-- 注意:这里的格式是“{{ .xxx }}” --> |
|||
{{.resp}} |
|||
|
|||
<div align="center"> |
|||
<img src="../img/tt.png"> |
|||
</div> |
|||
</body> |
|||
</html> |
After Width: | Height: | Size: 53 KiB |
@ -0,0 +1,29 @@ |
|||
module go_to_iris |
|||
|
|||
go 1.16 |
|||
|
|||
require ( |
|||
github.com/ajg/form v1.5.1 // indirect |
|||
github.com/beego/beego/v2 v2.0.1 |
|||
github.com/google/go-querystring v1.0.0 // indirect |
|||
github.com/gorilla/websocket v1.4.2 // indirect |
|||
github.com/imkira/go-interpol v1.1.0 // indirect |
|||
github.com/iris-contrib/jade v1.1.4 // indirect |
|||
github.com/iris-contrib/schema v0.0.2 // indirect |
|||
github.com/kataras/golog v0.0.18 // indirect |
|||
github.com/kataras/iris/v12 v12.1.8 |
|||
github.com/microcosm-cc/bluemonday v1.0.3 // indirect |
|||
github.com/moul/http2curl v1.0.0 // indirect |
|||
github.com/sergi/go-diff v1.1.0 // indirect |
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect |
|||
github.com/smartystreets/goconvey v1.6.4 // indirect |
|||
github.com/stretchr/testify v1.6.1 // indirect |
|||
github.com/valyala/fasthttp v1.24.0 // indirect |
|||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect |
|||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect |
|||
github.com/yudai/gojsondiff v1.0.0 // indirect |
|||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect |
|||
google.golang.org/protobuf v1.25.0 // indirect |
|||
gopkg.in/ini.v1 v1.57.0 // indirect |
|||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect |
|||
) |
@ -0,0 +1,442 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= |
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= |
|||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= |
|||
github.com/CloudyKit/jet/v3 v3.0.0 h1:1PwO5w5VCtlUUl+KTOBsTGZlhjWkcybsGaAau52tOy8= |
|||
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= |
|||
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= |
|||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= |
|||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= |
|||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4= |
|||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= |
|||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= |
|||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= |
|||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= |
|||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= |
|||
github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSULpEc= |
|||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= |
|||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= |
|||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= |
|||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= |
|||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns= |
|||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= |
|||
github.com/beego/beego/v2 v2.0.1 h1:07a7Z0Ok5vbqyqh+q53sDPl9LdhKh0ZDy3gbyGrhFnE= |
|||
github.com/beego/beego/v2 v2.0.1/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI= |
|||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= |
|||
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= |
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= |
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= |
|||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= |
|||
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= |
|||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= |
|||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= |
|||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= |
|||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= |
|||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= |
|||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= |
|||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= |
|||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= |
|||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= |
|||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= |
|||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= |
|||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= |
|||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= |
|||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= |
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= |
|||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= |
|||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= |
|||
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= |
|||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= |
|||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= |
|||
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= |
|||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= |
|||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= |
|||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= |
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= |
|||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= |
|||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= |
|||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= |
|||
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= |
|||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw= |
|||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= |
|||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= |
|||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= |
|||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= |
|||
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= |
|||
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= |
|||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= |
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
|||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= |
|||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= |
|||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= |
|||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= |
|||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= |
|||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= |
|||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= |
|||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= |
|||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= |
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= |
|||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= |
|||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= |
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= |
|||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= |
|||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= |
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= |
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= |
|||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= |
|||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= |
|||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= |
|||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= |
|||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= |
|||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= |
|||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= |
|||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= |
|||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= |
|||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= |
|||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= |
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= |
|||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= |
|||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= |
|||
github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4= |
|||
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= |
|||
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= |
|||
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= |
|||
github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0= |
|||
github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE= |
|||
github.com/iris-contrib/pongo2 v0.0.1 h1:zGP7pW51oi5eQZMIlGA3I+FHY9/HOQWDB+572yin0to= |
|||
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= |
|||
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= |
|||
github.com/iris-contrib/schema v0.0.2 h1:qd3RU2sLPaTTamv6BGn+PDD5Gmny+i3jO8xDAmWnNLs= |
|||
github.com/iris-contrib/schema v0.0.2/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= |
|||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= |
|||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= |
|||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= |
|||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= |
|||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= |
|||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= |
|||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= |
|||
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= |
|||
github.com/kataras/golog v0.0.18 h1:Td7hcKN25yzqB/0SO5iohOsMk5Mq5V9kDtM5apaJLY0= |
|||
github.com/kataras/golog v0.0.18/go.mod h1:jRYl7dFYqP8aQj9VkwdBUXYZSfUktm+YYg1arJILfyw= |
|||
github.com/kataras/iris/v12 v12.1.8 h1:O3gJasjm7ZxpxwTH8tApZsvf274scSGQAUpNe47c37U= |
|||
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= |
|||
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= |
|||
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= |
|||
github.com/kataras/pio v0.0.8 h1:6pX6nHJk7DAV3x1dEimibQF2CmJLlo0jWVmM9yE9KY8= |
|||
github.com/kataras/pio v0.0.8/go.mod h1:NFfMp2kVP1rmV4N6gH6qgWpuoDKlrOeYi3VrAIWCGsE= |
|||
github.com/kataras/sitemap v0.0.5 h1:4HCONX5RLgVy6G4RkYOV3vKNcma9p236LdGOipJsaFE= |
|||
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= |
|||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= |
|||
github.com/klauspost/compress v1.11.8 h1:difgzQsp5mdAz9v8lm3P/I+EpDKMU/6uTMw1y1FObuo= |
|||
github.com/klauspost/compress v1.11.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= |
|||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= |
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= |
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |
|||
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= |
|||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= |
|||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= |
|||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= |
|||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= |
|||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= |
|||
github.com/microcosm-cc/bluemonday v1.0.3 h1:EjVH7OqbU219kdm8acbveoclh2zZFqPJTJw6VUlTLAQ= |
|||
github.com/microcosm-cc/bluemonday v1.0.3/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= |
|||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= |
|||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= |
|||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= |
|||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |
|||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= |
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= |
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= |
|||
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= |
|||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= |
|||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= |
|||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= |
|||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= |
|||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= |
|||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= |
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= |
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= |
|||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= |
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= |
|||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= |
|||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= |
|||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= |
|||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= |
|||
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U= |
|||
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= |
|||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= |
|||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= |
|||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= |
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= |
|||
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= |
|||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= |
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
|||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= |
|||
github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= |
|||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= |
|||
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= |
|||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= |
|||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= |
|||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= |
|||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo= |
|||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= |
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= |
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= |
|||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= |
|||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= |
|||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= |
|||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= |
|||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= |
|||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= |
|||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= |
|||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= |
|||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= |
|||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= |
|||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= |
|||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= |
|||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= |
|||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= |
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= |
|||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
|||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= |
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |
|||
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
|||
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= |
|||
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= |
|||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= |
|||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= |
|||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= |
|||
github.com/valyala/fasthttp v1.24.0 h1:AAiG4oLDUArTb7rYf9oO2bkGooOqCaUF6a2u8asBP3I= |
|||
github.com/valyala/fasthttp v1.24.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU= |
|||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= |
|||
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= |
|||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= |
|||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= |
|||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= |
|||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= |
|||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= |
|||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= |
|||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= |
|||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= |
|||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= |
|||
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= |
|||
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= |
|||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= |
|||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= |
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
|||
github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= |
|||
go.etcd.io/etcd v3.3.25+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= |
|||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= |
|||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= |
|||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= |
|||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
|||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
|||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= |
|||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= |
|||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= |
|||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= |
|||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= |
|||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
|||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
|||
golang.org/x/net v0.0.0-20210226101413-39120d07d75e h1:jIQURUJ9mlLvYwTBtRHm9h58rYhSonLvRvgAnP8Nr7I= |
|||
golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M= |
|||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= |
|||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
|||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= |
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
|||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= |
|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= |
|||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
|||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= |
|||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag= |
|||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= |
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= |
|||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= |
|||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= |
|||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= |
|||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= |
|||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= |
|||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= |
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= |
|||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= |
|||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= |
|||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= |
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= |
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= |
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
|||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= |
|||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
|||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= |
|||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= |
|||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= |
|||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
|||
honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= |
@ -0,0 +1,30 @@ |
|||
# 什么是iris |
|||
|
|||
> Iris是一款Go语言中用来开发web应用的框架,该框架支持编写一次并在任何地方以最小的机器功率运行,如Android、ios、Linux和Windows等。该框架只需要一个可执行的服务就可以在平台上运行了。 |
|||
> |
|||
> Iris框架以简单而强大的api而被开发者所熟悉。iris除了为开发者提供非常简单的访问方式外,还同样支持MVC。另外,用iris构建微服务也很容易。 |
|||
> |
|||
|
|||
这是来自 iris [Github](https://github.com/kataras/iris) 上的描述。 |
|||
|
|||
### 官方网站 |
|||
|
|||
Iris官网:[https://iris-go.com/](https://iris-go.com/) |
|||
### 框架源码 |
|||
|
|||
Iris框架源码地址:[https://github.com/kataras/iris](https://github.com/kataras/iris) |
|||
### 框架学习文档 |
|||
|
|||
Iris框架中文学习文档: [https://studyiris.com/doc/](https://studyiris.com/doc/) |
|||
当然,还有其他相关资料,比如说xorm框架等,这些我们在后面的课程文档中学习到以后再做解释和说明。 |
|||
|
|||
# 开发环境 |
|||
|
|||
- GoLand 2019.2 EAP |
|||
- GoLang 1.11.5 |
|||
- 采用 Go Modules 进行管理 |
|||
|
|||
## iris 开发环境搭建 |
|||
|
|||
> go get -u github.com/kataras/iris |
|||
> |
@ -0,0 +1,13 @@ |
|||
package main |
|||
|
|||
import "fmt" |
|||
|
|||
func main() { |
|||
fmt.Println("Boyer-Moore算法 开始...") |
|||
|
|||
fmt.Println('a') |
|||
fmt.Println('A') |
|||
fmt.Println('Z') |
|||
fmt.Println(string(17)) |
|||
fmt.Println(91) |
|||
} |
@ -0,0 +1,17 @@ |
|||
package main |
|||
|
|||
import "fmt" |
|||
|
|||
/** |
|||
KMP算法中每一次的匹配, |
|||
|
|||
1、主串的起始位置 = 上一轮匹配的失配位置; |
|||
2、模式串的起始位置 = 重复字符结构的下一位字符(无重复字符结构,则模式串的首字符) |
|||
*/ |
|||
func main() { |
|||
fmt.Println("KMP算法 开始...") |
|||
strA := "ababcabcacbab" |
|||
strB := "abcac" |
|||
fmt.Println(strB, strA) |
|||
|
|||
} |
@ -0,0 +1,41 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
) |
|||
|
|||
/** |
|||
暴力匹配方法的思想非常朴素: |
|||
|
|||
1、依次从主串的首字符开始,与模式串逐一进行匹配; |
|||
2、遇到失配时,则移到主串的第二个字符,将其与模式串首字符比较,逐一进行匹配; |
|||
3、重复上述步骤,直至能匹配上,或剩下主串的长度不足以进行匹配。 |
|||
*/ |
|||
func main() { |
|||
fmt.Println("暴力匹配 字符串信息!") |
|||
strA := "ababcabcacbab" |
|||
strB := "abcac" |
|||
|
|||
ii := brute_force_match(strA, strB) |
|||
fmt.Println("截至到:", ii) |
|||
} |
|||
func brute_force_match(strA, strB string) int { |
|||
strALen := len(strA) |
|||
strBLen := len(strB) |
|||
var i, j, strCLen int |
|||
for ; i <= strALen-strBLen; i++ { |
|||
j = 0 |
|||
strCLen = i |
|||
for { |
|||
if strA[strCLen] == strB[j] && j < strBLen { |
|||
strCLen++ |
|||
j++ |
|||
} |
|||
break |
|||
} |
|||
if j == strBLen { |
|||
return i |
|||
} |
|||
} |
|||
return -1 |
|||
} |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,85 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"github.com/axgle/mahonia" |
|||
_ "golang.org/x/text/encoding/simplifiedchinese" |
|||
"log" |
|||
"os" |
|||
"strings" |
|||
"time" |
|||
) |
|||
|
|||
type Charset string |
|||
|
|||
const ( |
|||
UTF8 = Charset("UTF-8") |
|||
GB18030 = Charset("GB18030") |
|||
) |
|||
|
|||
/* 实现文本编码格式转换 */ |
|||
func main() { |
|||
//创建日志文件
|
|||
t := time.Now() |
|||
filepath := "./log_" + strings.Replace(t.String()[:19], ":", "_", 3) + ".txt" |
|||
file, err := os.OpenFile(filepath, os.O_CREATE, 0666) |
|||
if err != nil { |
|||
log.Fatal("create log file failed!") |
|||
} |
|||
defer file.Close() |
|||
wFile := bufio.NewWriter(file) |
|||
wFile.WriteString(readfile()) |
|||
wFile.Flush() |
|||
} |
|||
|
|||
/* 读取文本并转码 */ |
|||
func readfile() string { |
|||
f, err := os.Open("ex7.txt") |
|||
if err != nil { |
|||
return err.Error() |
|||
} |
|||
defer f.Close() |
|||
buf := make([]byte, 1024) |
|||
//文件ex7.txt的编码是gb18030
|
|||
decoder := mahonia.NewDecoder("gb18030") |
|||
if decoder == nil { |
|||
return "编码不存在!" |
|||
} |
|||
var str string = "" |
|||
for { |
|||
n, _ := f.Read(buf) |
|||
if 0 == n { |
|||
break |
|||
} |
|||
//解码为UTF-8
|
|||
str += decoder.ConvertString(string(buf[:n])) |
|||
} |
|||
return str |
|||
} |
|||
|
|||
/* 字符串从srcCode格式转为tagCode的格式 */ |
|||
/*func ConvertToString(src string, srcCode string, tagCode string) string { |
|||
srcCoder := mahonia.NewDecoder(srcCode) |
|||
srcResult := srcCoder.ConvertString(src) |
|||
tagCoder := mahonia.NewDecoder(tagCode) |
|||
_, cdata, _ := tagCoder.Translate([]byte(srcResult), true) |
|||
result := string(cdata) |
|||
return result |
|||
|
|||
}*/ |
|||
|
|||
/* golang处理中文时默认是utf8,当遇到其他如GBK字符是就会出现乱码 编码转换 */ |
|||
/* |
|||
func ConvertByte2String(byte []byte, charset Charset) string { |
|||
var str string |
|||
switch charset { |
|||
case GB18030: |
|||
var decodeBytes, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(byte) |
|||
str = string(decodeBytes) |
|||
case UTF8: |
|||
fallthrough |
|||
default: |
|||
str = string(byte) |
|||
} |
|||
return str |
|||
}*/ |
@ -0,0 +1,22 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"os" |
|||
) |
|||
|
|||
func main() { |
|||
|
|||
// 获取命令行参数
|
|||
fmt.Println("命令行参数数量:", len(os.Args)) |
|||
for k, v := range os.Args { |
|||
fmt.Printf("args[%v]=[%v]\n", k, v) |
|||
} |
|||
|
|||
for { |
|||
for a, _ := range `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏` { |
|||
// fmt.Printf("%d", a)
|
|||
fmt.Println(string(a)) |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,62 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"fmt" |
|||
"os" |
|||
"path/filepath" |
|||
"time" |
|||
) |
|||
|
|||
func main() { |
|||
fmt.Println("关于生成HTML") |
|||
//获取当前目录
|
|||
path, _ := filepath.Abs("./") |
|||
path = path + "\\结构对比-" + time.Now().Format("2006102150405") + ".html" |
|||
|
|||
//创建文件
|
|||
//Create函数也是调用的OpenFile
|
|||
file3, _ := os.Create(path) |
|||
|
|||
title := "1234" |
|||
strA := "李干杰指出,各级生态环境部门要大力支持服务民营企业绿色发展,坚决打好打胜污染防治攻坚战,推动生态环境保护事业和非公有制经济共同发展。\n他表示,民营企业作为推动绿色发展的重要力量、绿色技术创新的主力军、污染物减排的重要贡献者、践行绿色发展理念的受益者,在打好污染防治攻坚战中发挥了积极作用,并还将有更大作为。\n他还强调,近年来,生态环境部门将服务民营企业绿色发展作为打好污染防治攻坚战的重要内容,严格监管与优化服务并重,引导激励与约束惩戒并举,持续加大工作力度,出台一系列政策文件,着力推进依法依规监管、减少审批许可、加强帮扶指导、完善环境政策、倾听企业诉求等重点举措,在营造公平环境、释放发展活力、提供技术服务、稳定信心预期等方面取得积极进展和成效。\n李干杰要求,各级生态环境部门要发扬“店小二”精神,精准雪中送炭,用灵活多样、注重实效的方式服务企业、支持企业,切实帮助企业解决实际困难。要加强与工商联合作联动,健全工作机制,立足部门优势进一步深化合作,在环境信用、绩效评价、市场机制等方面开展更多探索创新。" |
|||
strB := "李干杰指出,各级生态环境部门要大力支持服务民营企业绿色发展,坚决打好打胜污染防治攻坚战,推动生态环境保护事业和非公有制经济共同发展。\n他表示,民营企业作为推动绿色发展的重要力量、绿色技术创新的主力军、污染物减排的重要贡献者、践行绿色发展理念的受益者,在打好污染防治攻坚战中发挥了积极作用,并还将有更大作为。\n他还强调,近年来,生态环境部门将服务民营企业绿色发展作为打好污染防治攻坚战的重要内容,严格监管与优化服务并重,引导激励与约束惩戒并举,持续加大工作力度,出台一系列政策文件,着力推进依法依规监管、减少审批许可、加强帮扶指导、完善环境政策、倾听企业诉求等重点举措,在营造公平环境、释放发展活力、提供技术服务、稳定信心预期等方面取得积极进展和成效。\n李干杰要求,各级生态环境部门要发扬“店小二”精神,精准雪中送炭,用灵活多样、注重实效的方式服务企业、支持企业,切实帮助企业解决实际困难。要加强与工商联合作联动,健全工作机制,立足部门优势进一步深化合作,在环境信用、绩效评价、市场机制等方面开展更多探索创新。" |
|||
|
|||
for _, char := range strA { |
|||
print(char) |
|||
} |
|||
|
|||
//写入头部份
|
|||
writeFrist(file3, title, strA, strB) |
|||
|
|||
//写入尾部份
|
|||
writeList(file3) |
|||
|
|||
//关闭文件
|
|||
file3.Close() |
|||
} |
|||
func writeList(file3 *os.File) { |
|||
file3.WriteString("\t</body>") |
|||
file3.WriteString("</html>") |
|||
} |
|||
|
|||
func writeFrist(file3 *os.File, title, strA, strB string) { |
|||
file3.WriteString("<!DOCTYPE html>\n") |
|||
file3.WriteString("<html>\n") |
|||
file3.WriteString("\t<head>\n") |
|||
file3.WriteString("\t\t<meta charset=\"utf-8\">\n") |
|||
file3.WriteString("\t\t<title>") |
|||
file3.WriteString(title) |
|||
file3.WriteString("</title>\n") |
|||
file3.WriteString("\t\t<style type=\"text/css\">\n") |
|||
file3.WriteString("\t\t\t.textareaclass{height: 300px;width: 49%;float: left;margin-left: 5px;}\n") |
|||
file3.WriteString("\t\t\t.fontclass{color: red;}\n") |
|||
file3.WriteString("\t\t</style>\n") |
|||
file3.WriteString("\t</head>\n") |
|||
file3.WriteString("\t<body>\n") |
|||
file3.WriteString("\t\t<textarea id=\"aaa\" class=\"textareaclass\">") |
|||
file3.WriteString(strA) |
|||
file3.WriteString("</textarea>\n") |
|||
file3.WriteString("\t\t<textarea id=\"bbb\" class=\"textareaclass\">") |
|||
file3.WriteString(strB) |
|||
file3.WriteString("</textarea>\n") |
|||
} |
@ -0,0 +1,67 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"database/sql" |
|||
"fmt" |
|||
_ "github.com/go-sql-driver/mysql" |
|||
) |
|||
|
|||
/* |
|||
DML(data manipulation language)是数据操纵语言:它们是SELECT、UPDATE、INSERT、DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言。 |
|||
|
|||
DDL(data definition language)是数据定义语言:DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定义或改变表(TABLE)的结构,数据类型,表之间的链接和约束等初始化工作上,他们大多在建立表时使用。 |
|||
|
|||
DCL(DataControlLanguage)是数据库控制语言:是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句。 |
|||
*/ |
|||
func main() { |
|||
fmt.Println("查询数据库生成DML") |
|||
//打开数据库
|
|||
//DSN数据源字符串:用户名:密码@协议(地址:端口)/数据库?参数=参数值
|
|||
db, err := sql.Open("mysql", "root:admin@tcp(127.0.0.1:45017)/zwhzyq?charset=utf8") |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
} |
|||
sqlstr := "select COLUMN_NAME,DATA_TYPE,COLUMN_COMMENT from information_schema.COLUMNS where table_schema = 'zwhzyq';" |
|||
//查询数据,指定字段名,返回sql.Rows结果集
|
|||
ABC := getTableStruct(db, sqlstr, err) |
|||
for _, b := range ABC { |
|||
for c, d := range b { |
|||
fmt.Println(c, d) |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
/* 获取表的结构体文件 */ |
|||
func getTableStruct(db *sql.DB, sqlstr string, err error) []map[string]string { |
|||
rows, _ := db.Query(sqlstr) |
|||
columns, _ := rows.Columns() |
|||
scanArgs := make([]interface{}, len(columns)) |
|||
values := make([]interface{}, len(columns)) |
|||
for i := range values { |
|||
scanArgs[i] = &values[i] |
|||
} |
|||
var result []map[string]string |
|||
for rows.Next() { |
|||
//将行数据保存到record字典
|
|||
err = rows.Scan(scanArgs...) |
|||
record := make(map[string]string) |
|||
for i, col := range values { |
|||
if col != nil { |
|||
record[columns[i]] = string(col.([]byte)) |
|||
} |
|||
} |
|||
result = append(result, record) |
|||
fmt.Println(record) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
func GetValueByWhere(db *sql.DB, selectStr, tableStr, whereStr string) string { |
|||
rows, _ := db.Query(fmt.Sprintf("select %s as selectStr from %s where %s", selectStr, tableStr, whereStr)) |
|||
for rows.Next() { |
|||
rows.Scan(&selectStr) |
|||
return selectStr |
|||
} |
|||
return "" |
|||
} |