文章目录
- go常用库使用教程
- go idea环境搭建
- 插件安装
- 新建项目
- 配置GOPATH
- 库介绍
- go常用内置库
- 文件相关
- 时间相关
- 正则相关
- 线程相关
- 线程操作
- waitgroup
- 信号sig
- context
- mysql
- json
- hash
- go常用第三方库
- mitchellh命令行帮助
- beego web开发
- 项目环境配置
- beego脚手架安装
- beego生成代码
- gin web开发
- 编译运行consul
go常用库使用教程
go idea环境搭建
插件安装
idea选择插件搜索go 安装
新建项目
idea-File-New-Project 选择 Go Modules(vgo)
新建的项目根目录下多了go.mod和go.sum文件,此时可编写go文件运行程序了,当import模块时会自动添加到go.mod文件
中,如果未加入可使用快捷键alt+回车。
配置GOPATH
go允许项目自定义Project GOPATH和全局Root GOPATH隔离,源代码就可以新建在Project GOPATH/src下
临时设置set GOPATH=C:\Go\gopath;C:\Users\GVT\go
或者在idea中Setting-Languages & FrameWorks-Go-GOPATH
一般GOPATH目录结构为:
库介绍
go常用内置库
文件相关
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
)
/**
字节流读取
*/
func readByteFile() string{
file,_:=os.Open("f:/a.json")
defer file.Close()
fi, _ :=file.Stat()
size:=fi.Size()
b := make([]byte, size)
file.Read(b)
return string(b)
}
/**
字符流读取
*/
func readBufferFile() string{
file,_:=os.Open("f:/a.json")
reader:=bufio.NewReader(file)
defer file.Close()
var result string="";
for {
str,err:=reader.ReadString('\n')
if(err==io.EOF){
break;
}
result=result+str;
}
return result
}
func writeContent(){
path := "f:/cw.txt"
file,_:=os.OpenFile(path,os.O_CREATE|os.O_WRONLY,0666)
defer file.Close()
result:="hello world\n"
file.Write([]byte(result))
writer:=bufio.NewWriter(file);
writer.WriteString("zs")
writer.Flush()
}
func main(){
//获取临时目录
fmt.Println(os.TempDir())
//Mkdir 用于创建单个目录。 MkdirAll用于创建多个目录
os.Mkdir("f:/testtt",os.ModePerm)
//Remove 用于删除单个目录下所有文件和目录,不能删除子目录。 RemoveAll用于删除目录,包含所有
os.Remove("f:/testtt")
return;
fmt.Println(readByteFile())
fmt.Println(readBufferFile())
content,_:=ioutil.ReadFile("f:/a.json")
fmt.Println(string(content))
writeContent()
//io.copy
}
时间相关
package main
import (
"fmt"
"time"
)
/**
操作时间
*/
func datetime(){
now:=time.Now();
fmt.Println(now.String()) //获取字符串 2020-05-13 16:45:19.0916627 +0800 CST m=+0.006016001
fmt.Println(now.UnixNano()) //获取时间戳 1589359519091662700
fmt.Println(now.Date()) //获取年月份 2020 May 13
fmt.Println(now.Clock()) //获取时分秒 16 45 19
time.Sleep(time.Second*1) //休眠10s
fmt.Println(now.Format("2006-01-02 15:04:05"))//格式化日期
//操作时间
timeDur := time.Duration(10)*time.Second + time.Duration(1)*time.Minute
fmt.Println(now.Add(timeDur).Add(10*time.Hour))
fmt.Println(now.Add(timeDur).Add(10*time.Hour).After(now))
//休眠指定时间
time.Sleep(10*time.Second)
}
/**
定时器
timer只能在时间到了执行一次
*/
func timer(){
t:=time.NewTimer(2*time.Second)
defer t.Stop()
<-t.C //t.C是 一个chan 到了指定时候自动写入数据到通道这里会阻塞等到数据,这样实现定时器
fmt.Println("2s时间到了")
}
/**
timer实现每隔n秒之心过一次
*/
func timerContinue(){
t:=time.NewTimer(2*time.Second)
defer t.Stop()
for {
<-t.C //t.C是 一个chan 到了指定时候自动写入数据到通道这里会阻塞等到数据,这样实现定时器
fmt.Println("2s时间到了")
//重置重新等待2s
t.Reset(2*time.Second)
}
}
/**
ticker每隔n秒自动执行
*/
func ticker(){
t:=time.NewTicker(2*time.Second)
defer t.Stop()
for {
<-t.C //t.C是 一个chan 到了指定时候自动写入数据到通道这里会阻塞等到数据,这样实现定时器
fmt.Println("2s时间到了")
}
}
func main(){
timerContinue()
}
正则相关
package main
import (
"fmt"
"regexp"
)
func main() {
rege,_ :=regexp.Compile("[0-9]{11}")
fmt.Println(rege.MatchString("13537643253")) //匹配字符串
rege1,_ :=regexp.Compile(`age=(\d+)`) //替换字符串
fmt.Println(rege1.ReplaceAllString("hello,age=80","aa=$1"))
}
线程相关
线程操作
package main
import (
"fmt"
"time"
)
func async() {
fmt.Println("子线程打印结果")
}
func addTest(i int, j int, ch *int) {
*ch = i + j;
}
func chanelTest(i int, j int, ch chan int) {
ch <- i + j;
}
func main() {
//可能子线程来不及调用就退除主线程 子线程打印结果不一定会出现
go async()
fmt.Println("父线程打印结果")
//如果sleep了基本上只要线程运行时间不超过暂停时间都能打印
time.Sleep(time.Second * 1)
i, j := 5, 6
resu := 0
// go直接调用时异步 没办法保证addTest执行完成了到后面所有resu可能是0也可能是11,但执行到后面肯定是11
go addTest(i, j, &resu)
fmt.Println(resu)
time.Sleep(time.Second * 1)
fmt.Println(resu)
//通道 保证同步
ch := make(chan int)
go chanelTest(i, j, ch)
result := <-ch
fmt.Println(result)
//带缓冲区通道
ch1 := make(chan int, 2)
// 因为 ch 是带缓冲的通道,我们可以同时发送两个数据
// 而不用立刻需要去同步读取数据
ch1 <- 1
ch1 <- 2
// 获取这两个数据
fmt.Println(<-ch1)
fmt.Println(<-ch1)
//缓冲区只有两个 获取第三次永远获取不到直接all goroutines are asleep - deadlock!
//panic("会报错,打断程序运行。但是不会阻止defer运行")
fmt.Println(<-ch1)
}
waitgroup
package main
import (
"fmt"
"io/ioutil"
"net/http"
"sync"
)
func main() {
urls:=[]string{
"http://www.baidu.com",
"http://www.qq.com",
}
var wg sync.WaitGroup
for _,url:= range urls{
//wg加1表示开始1个任务
wg.Add(1)
go func(url string) {
//完成一个 wg自动-1
defer wg.Done()
resp,_:=http.Get(url)
bytes, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(bytes))
}(url)
}
//等待wg的值==0 就停止等待 相当于java中CountDownLatch
wg.Wait()
}
信号sig
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
fmt.Println(os.Getpid())
//定义通道 是信号类型
cb:=make(chan os.Signal)
//定义一个信号监听,signal.Notify(cb)监听所有信号,下面指定监听interrupt信号ctrl+c触发
signal.Notify(cb,syscall.SIGINT)
//阻塞等待一个信号 <-cb可以不给变量赋值,下面是赋值
//使用 go run sig.go运行 ctrl+c收到一个interrupt的信号 linux下可以使用kill -l查看信号 使用kill -s 信号id 进程号发送信号
s:=<-cb
fmt.Println(s)
}
/**
信号类型(kill -l)
个平台的信号定义或许有些不同。下面列出了POSIX中定义的信号。
Linux 使用34-64信号用作实时系统中。
命令 man 7 signal 提供了官方的信号介绍。
在POSIX.1-1990标准中定义的信号列表
信号 值 动作 说明
SIGHUP 1 Term 终端控制进程结束(终端连接断开)
SIGINT 2 Term 用户发送INTR字符(Ctrl+C)触发
SIGQUIT 3 Core 用户发送QUIT字符(Ctrl+/)触发
SIGILL 4 Core 非法指令(程序错误、试图执行数据段、栈溢出等)
SIGABRT 6 Core 调用abort函数触发
SIGFPE 8 Core 算术运行错误(浮点运算错误、除数为零等)
SIGKILL 9 Term 无条件结束程序(不能被捕获、阻塞或忽略)
SIGSEGV 11 Core 无效内存引用(试图访问不属于自己的内存空间、对只读内存空间进行写操作)
SIGPIPE 13 Term 消息管道损坏(FIFO/Socket通信时,管道未打开而进行写操作)
SIGALRM 14 Term 时钟定时信号
SIGTERM 15 Term 结束程序(可以被捕获、阻塞或忽略)
SIGUSR1 30,10,16 Term 用户保留
SIGUSR2 31,12,17 Term 用户保留
SIGCHLD 20,17,18 Ign 子进程结束(由父进程接收)
SIGCONT 19,18,25 Cont 继续执行已经停止的进程(不能被阻塞)
SIGSTOP 17,19,23 Stop 停止进程(不能被捕获、阻塞或忽略)
SIGTSTP 18,20,24 Stop 停止进程(可以被捕获、阻塞或忽略)
SIGTTIN 21,21,26 Stop 后台程序从终端中读取数据时触发
SIGTTOU 22,22,27 Stop 后台程序向终端中写数据时触发
在SUSv2和POSIX.1-2001标准中的信号列表:
信号 值 动作 说明
SIGTRAP 5 Core Trap指令触发(如断点,在调试器中使用)
SIGBUS 0,7,10 Core 非法地址(内存地址对齐错误)
SIGPOLL Term Pollable event (Sys V). Synonym for SIGIO
SIGPROF 27,27,29 Term 性能时钟信号(包含系统调用时间和进程占用CPU的时间)
SIGSYS 12,31,12 Core 无效的系统调用(SVr4)
SIGURG 16,23,21 Ign 有紧急数据到达Socket(4.2BSD)
SIGVTALRM 26,26,28 Term 虚拟时钟信号(进程占用CPU的时间)(4.2BSD)
SIGXCPU 24,24,30 Core 超过CPU时间资源限制(4.2BSD)
SIGXFSZ 25,25,31 Core 超过文件大小资源限制(4.2BSD)
*/
context
package main
import (
"context"
"fmt"
"time"
)
func add(context context.Context,p1 int) int {
var result int=0
for i:=0;;i++ {
//golang 的 select 的功能和 select, poll, epoll 相似,就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。
select{
//发现存在canel()动作就是有io动作 此时会触发
case <-context.Done():
return result
default:
}
time.Sleep(100*time.Millisecond)
result=result+1
}
return result;
}
/**
模拟一个累加的动作,超过2s自动取消这个累加线程
*/
func testContextCanel(){
//context表示上下文,canel是一个取消方法调用会发送一个通道数据 context.Done就会存在io操作,监听到这个动作就应该自定义取消逻辑
contenxt,canel:=context.WithCancel(context.Background())
go func() {
//模拟2s后就调用取消
time.Sleep(2*time.Second)
canel()
}()
fmt.Println(add(contenxt,1))
}
/**
上面testContextCanel简洁版
*/
func testContextTimeout(){
//context表示上下文,当超过指定时间自动调用会发送一个通道数据 context.Done就会存在io操作,监听到这个动作就应该自定义取消逻辑
contenxt,canel:=context.WithTimeout(context.Background(),2*time.Second)
//可以在超时前手动去取消 这里不需要
defer canel()
fmt.Println(add(contenxt,1))
}
/**
上面testContextCanel简洁版 deanline传入的是时间 timeout传入的间隔时间
*/
func testContextDeadLine(){
//context表示上下文,当超过指定时间自动调用会发送一个通道数据 context.Done就会存在io操作,监听到这个动作就应该自定义取消逻辑
contenxt,canel:=context.WithDeadline(context.Background(),time.Now().Add(2*time.Second))
//可以在超时前手动去取消 这里不需要
defer canel()
fmt.Println(add(contenxt,1))
}
func main() {
testContextDeadLine()
}
mysql
package main
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
_ "github.com/go-sql-driver/mysql" //引入驱动包
)
type UserRole struct {
UserId int64
RoleId int64
}
func getDB() (*sql.DB){
db, _ := sql.Open("mysql", "root:Qjkj2018@tcp(192.168.1.230:3306)/ums_docker_dev")
return db
}
/**
查询sql
*/
func query(){
var user UserRole
DB:=getDB()
defer DB.Close()
//设置数据库最大连接数
DB.SetConnMaxLifetime(100)
//设置上数据库最大闲置连接数
DB.SetMaxIdleConns(10)
//验证连接
if err := DB.Ping(); err != nil {
fmt.Println("open database fail")
return
}
rows, e := DB.Query("select user_id as UserId,role_id as RoleId from user_role_rel")
defer rows.Close()
if e == nil {
errors.New("query incur error")
}
for rows.Next(){
//字段名称必须和数据库返回的列名完全相同,所有sql上用as指定别名
e := rows.Scan(&user.UserId, &user.RoleId)
if e == nil{
//json对应实体字段必须是大写,才能转换成对应字段 否则为nil
result, _ := json.Marshal(user)
fmt.Println(string(result))
}
}
}
/**
执行sql
*/
func execute(sql string) int64{
DB:=getDB()
defer DB.Close()
result,_:=DB.Exec(sql)
affectRow,_:=result.RowsAffected()
return affectRow
}
/**
预处理防止sql注入
*/
func executeFmt(sql string,args ...interface{}) int64{
DB:=getDB()
defer DB.Close()
stmt,_:=DB.Prepare(sql)
result,_:=stmt.Exec(args...)
affectRow,_:=result.RowsAffected()
return affectRow
}
func main() {
query()
fmt.Println(execute("delete from user_role_rel where user_id=-1"));
fmt.Println(executeFmt("delete from user_role_rel where user_id=?","-1"))
}
json
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
Name string
Price float64
test int //注意首字母小写字段无法转换为json字段
}
func main() {
p:=Product{
Name:"zs",
}
p.Price=100
fmt.Println(p.Name)
//对象转换成json字节数组
result,_:=json.Marshal(p)
fmt.Println(string(result))
p1:=Product{}
//将字节数组转换为json
json.Unmarshal(result,&p1) //传入引用才能获取真实的对象,否则返回是没有赋值的空对象
fmt.Println(p1.Price)
}
hash
package main
import (
"crypto/md5"
"crypto/sha1"
"encoding/hex"
"fmt"
)
/**
md5
*/
func hash_md5(str string){
md:=md5.New()
md.Write([]byte(str))
fmt.Println(hex.EncodeToString(md.Sum(nil)))
}
/**
shaXX系列
sha1
sha256
sha512
*/
func hash_sha1(str string){
md:=sha1.New()
md.Write([]byte(str))
fmt.Println(hex.EncodeToString(md.Sum(nil)))
}
/**
对称加密系列 :des,aes
非对称加密 rsa
签名 dsa 暂不列出
*/
func main() {
hash_md5("hello")
hash_sha1("hello")
}
go常用第三方库
mitchellh命令行帮助
框架是个人开发的命令行程序框架,作者还成立了公司(HashiCorp),其公司的产品也采用这个CLI框架
框架的思路是:把命令和执行方法以map的形式记录在内部,然后根据用户输入的命令,决定执行哪个方法。实际上记录的是命令字符串和CommandFactory,由CommandFactory创建Command然后执行。
框架默认支持version和help两个功能。
目前在注册中心Consul, Vault, Terraform, and Nomad.中有使用该框架。
package main
import (
"fmt"
"log"
"os"
"github.com/mitchellh/cli"
)
func main() {
/**
go run cli.go
I am foo command
Usage: app [--version] [--help] <command> [<args>] 这里会显示app名称也就是NewCLI第一个参数
go run cli.go --version 就会显示后面定义的版本号参数
*/
c := cli.NewCLI("app", "1.0.100")
// go run cli.go aa bb 后面所有的参数 比如 aa 和bb
c.Args = os.Args[1:]
ui := &cli.BasicUi{Writer: os.Stdout, ErrorWriter: os.Stderr,Reader:os.Stdin}
//打印内容到输出流
ui.Output("打印到界面")
//打印到ErrorWriter
//ui.Error("出错了")
//用户交互输入内容
commd,_:=ui.Ask("请输入您的命令:")
fmt.Println(commd)
c.Commands = map[string]cli.CommandFactory{
"foo": fooCommandFactory,
//"bar": barCommandFactory,
}
exitStatus, err := c.Run()
if err != nil {
log.Println(err)
}
os.Exit(exitStatus)
}
/**
定义命名适配工厂,返回实际执行命令的对象
对象包含3个方法 帮助,执行,摘要
*/
func fooCommandFactory() (cli.Command, error) {
fmt.Println("I am foo command")
return new(FooCommand), nil
}
type FooCommand struct{}
/**
帮助方法 比如 go run cli.go foo --help 就会执行这个方法
*/
func (f *FooCommand) Help() string {
return "help foo"
}
/**
参数执行方法 比如 go run cli.go foo 就会执行这个方法
args就是所有参数 go run cli.go foo aa bb 参数是aa和bb
*/
func (f *FooCommand) Run(args []string) int {
fmt.Println("Foo Command is running")
return 1
}
/**
摘要方法 不加入任何参数时 列表所有参数 参数摘要在参数后
F:\code\go\liblearn>go run cli.go
I am foo command
Usage: app [--version] [--help] <command> [<args>]
Available commands are:
foo foo command Synopsis
*/
func (f *FooCommand) Synopsis() string {
return "foo command Synopsis"
}
beego web开发
beego 相比于martini revel等其他优秀golang框架 来说就是 beego为 web开发人员提供了非常完善的组件(session,log,router, filter, validation, orm …), 并且中文文档丰富, 是一个非常好的goweb入门框架,
使用javaspring的开发人员入门go,非常适合使用beego。
项目环境配置
打开idea,随便新建一个项目,点击菜单File-Other Settings和Settings(统一都设置),点击Languages & Frameworks,新建一个project gopath用于存放项目和项目相关包
打开Terminal终端,设置GOPATH
set GOPATH=D:\code\mygopath
设置临时GOPATH是为了让beego生成代码到你的GOPATH中,beego只认环境的GOPATH
beego脚手架安装
下载bee脚手架生成工具:https://github.com/beego/bee/releases
如window下 下载后拷贝到 go的bin目录即可
beego生成代码
idea新建一个vgo项名称这里叫gpm,项目根目录新建一个src目录。
通过命令生成mvc模板
bee new beego
会在新设置的GOPATH中生成代码
D:\code\gpm\front>set GOPATH=D:\code\mygopath
D:\code\gpm\front>bee new gpm
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.10.0
2020/08/13 10:35:38 WARN ▶ 0001 You current workdir is not inside $GOPATH/src.
2020/08/13 10:35:38 INFO ▶ 0002 Creating application...
create D:\code\mygopath\src\gpm\
create D:\code\mygopath\src\gpm\conf\
create D:\code\mygopath\src\gpm\controllers\
create D:\code\mygopath\src\gpm\models\
create D:\code\mygopath\src\gpm\routers\
create D:\code\mygopath\src\gpm\tests\
create D:\code\mygopath\src\gpm\static\
create D:\code\mygopath\src\gpm\static\js\
create D:\code\mygopath\src\gpm\static\css\
create D:\code\mygopath\src\gpm\static\img\
create D:\code\mygopath\src\gpm\views\
create D:\code\mygopath\src\gpm\conf\app.conf
create D:\code\mygopath\src\gpm\controllers\default.go
create D:\code\mygopath\src\gpm\views\index.tpl
create D:\code\mygopath\src\gpm\routers\router.go
create D:\code\mygopath\src\gpm\tests\default_test.go
create D:\code\mygopath\src\gpm\main.go
2020/08/13 10:35:38 SUCCESS ▶ 0003 New application successfully created!
使用idea打开 GOPATH/src下新生成的项目
bee默认生成的项目没有使用gomode,在项目根目录执行
D:\code\mygopath\src\gpm>go mod init
go: creating new go.mod: module gpm
在go.mod上右键 sync go,此时代码中没有红色错误标记,所有依赖包自动下载到pkg目录,
go.mod
module gpm
go 1.14
require (
github.com/astaxie/beego v1.12.2
github.com/smartystreets/goconvey v1.6.4
)
如果同步无效可以在import包的代码处 alt+/导入
具体开发请参考:https://beego.me/quickstart
gin web开发
Gin 是一个 go 写的 web 框架,具有高性能的优点。官方地址:https://github.com/gin-gonic/gin
性能相对来说强于beego,实际却没有http包构建的一半性能。
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.Writer.Write([]byte("hello"))
})
r.Run(":8888") // listen and serve on 0.0.0.0:8080
}
编译运行consul
克隆最新源码:go clone https://github.com/hashicorp/consul.git
使用idea工具打开 sync go module
选择main.go,添加项目参数:
agent -server -ui -bootstrap-expect=1 -data-dir=F:/code/go/consul-master/datadir -node=agent-1 -client=0.0.0.0 -bind=192.168.40.77 -datacenter=dc1
–bind是绑定本机的ip地址
–data-dir指定存储数据目录
运行后访问:
http://localhost:8500正常启动