go语言入门教程02-go常用库+编译consul

文章目录

  • 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 安装
go语言入门教程02-go常用库+编译consul_第1张图片

新建项目

idea-File-New-Project 选择 Go Modules(vgo)
go语言入门教程02-go常用库+编译consul_第2张图片
新建的项目根目录下多了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
go语言入门教程02-go常用库+编译consul_第3张图片
一般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]  [] 这里会显示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]  []

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用于存放项目和项目相关包
go语言入门教程02-go常用库+编译consul_第4张图片
打开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下新生成的项目
go语言入门教程02-go常用库+编译consul_第5张图片
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+/导入
go语言入门教程02-go常用库+编译consul_第6张图片
具体开发请参考: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指定存储数据目录
go语言入门教程02-go常用库+编译consul_第7张图片
运行后访问:
http://localhost:8500正常启动

你可能感兴趣的:(go)