Golang之路
下载
https://golang.google.cn/
https://golang.google.cn/dl/
版本: go.1.18
安装
- GOROOT=D:\go1.18
- GOPATH=D:\gopath1.18
- GO111MODULE=on
- GOPROXY=https://goproxy.cn,direct
go mod 创建项目
- 新建目录: D:\gopath1.18\cdr
- 进入该目录下: …
- 初始化项目: go mod init cdr
- 下载包: go get github.com/gin-gonic/gin (现在完在这里:D:\gopath1.18\pkg\mod)
- 刷新包: go mod tidy
- Goland打开项目,import后根据红线提示编目index,再开始丝滑
gin
在线文档: https://www.itying.com/gin
我的专栏: https://www.itying.com/category-79-b0.html
官网: https://gin-gonic.com/zh-cn
gin基本结构
r := gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/",funcName)
1.GET 查
2.POST 增
3.PUT 改
4.DELETE 删
funcName(c *gin.Context){
c.string(200,"aaaaaaaaaaa")
}
1. c.string 返回字符串
2. c.json 返回json
3. c.jsonp 返回jsonp
4. c.xml 返回xml
5. c.html 返回网页,需要先加载模板:r.LoadHTMLGlob("templates/*") {{.变量名称}}
r.Run(":8080")
gin模板放在不同目录里面的配置方法
//引擎
r.LoadHTMLGlob("templates/**/*")
//模板起名
{{ define "aaa/a111.html" }}
{{ end }}
//路由方法使用模板
c.html(200,"aaa/a111.html",map[string]{})
gin模板嵌套
{{ template "aaa/a111.html" . }}
gin前端变量
{{ $a := .name }}
gin前端移除空格
{{- .name -}}
gin前端比较函数
eq lt gt le ge ne
gin前端条件判断
{{ if gt .score 80 }}
优秀
{{ else if gt $score 60 }}
及格
{{ else }}
不及格
{{ end }}
gin前端range循环
<dl>
{{ range $i,$v := .obj }}
<li> {{ key为$i,值为$v }} </li>
{{ else }}
a数组为空
{{ end }}
</dl>
gin前端with解构
{{ with .atype }}
//然后a结构体就被赋值给.了
gin前端预定义函数
and , or , not , len , index
gin自定义函数
r.SetFuncMap(template.FuncMap{
"formatDate":formatAsDate,
})
gin静态文件服务
func main(){
r := gin.Default()
r.Static("/static","./static")
}
//把程序本目录下的s目录映给s路由
get传值给go
r.GET("/getValue",func(c *gin.Context){
username := c.Query("username")
age := c.Query("age")
page := c.DefaultQuery("page","2")
c.JSON(200,gin.H{
"username" : username,
"age" : age,
"page" : page,
})
})
//测试: http://1.1.1.1:8080/getValue?username=%E6%B1%AA%E4%BC%9F&age=99
post传值给go
//去到表单页
r.GET("/addUser",func(c *gin.Context){
c.HTML(200,"default/addUser.html",map[string]interface{}{})
})
<!-- 表单提交给路由 -->
<form action="/doAddUser" method="post">
用户名:<input type="text" name="username" /> <br><br>
密 码:<input type="password" name="password" /> <br><br>
<input type="submit" value="提交">
</form>
//执行路由post方法,golang获取表单值
r.POST("/doAddUser", func(c *gin.Context) {
username := c.PostForm("username")
password := c.PostForm("password")
age := c.DefaultPostForm("age", "26")
c.JSON(200, gin.H{
"username": username,
"password": password,
"age": age,
})
})
get传值绑定到结构体
type UserInfo struct{
Username string `json:"username" form:"username"`
Password string `json:"password" form:"password"`
}
r.GET("/getUser",func(c *gin.Context){
user := &UserInfo{}
if err := c.ShouldBind(&user); err == nil {
c.JSON(200,user)
} else {
c.JSON(200,gin.H{
"ERR" : err.Error(),
})
}
})
// 测试 : http://1.1.1.1:8080/getUser?username=%E6%B1%AA%E4%BC%9F&password=0998*aa
post传值绑定到结构体
//去到表单页
r.GET("/addUser",func(c *gin.Context){
c.HTML(200,"default/addUser.html",map[string]interface{}{})
})
<!-- 表单提交给路由 -->
<form action="/doAddUser2" method="post">
用户名:<input type="text" name="username" /> <br><br>
密 码:<input type="password" name="password" /> <br><br>
<input type="submit" value="提交">
</form>
r.POST("/doAddUser2",func(c *gin.Context){
user := &UserInfo{}
if err := c.ShouldBind(&user); err == nil {
c.JSON(200,user)
} else {
c.JSON(400,gin.H{
"ERR" : err.Error(),
})
}
})
xml数据绑定到结构体
<?xml version="1.0" encoding="UTF-8"?>
<article>
<content type="string">我是张三</content>
<title type="string">张三</title>
</article>
type Article struct{
Title string `json:"title" xml:"title"`
Content string `json:"content" xml:"content"`
}
r.POST("/xml",func(c *gin.Context){
article := &Article{}
xmlSliceDate,_ = c.GetRawDate() //获取c.Request.Body字节流
if err := xml.Unmarshal(xmlSliceDate,&article); err == nil {
c.JSON(200,article)
} else {
c.JSON(400,gin.H{
"ERR" : err.Error(),
})
}
})
gin动态路由
r.GET("/list/:cid", func(c *gin.Context){
cid := c.Param("cid")
c.String(200,"%v",cid)
})
gin加载css文件和jsp文件
参考网站: https://blog.51cto.com/dongweizhen/3606790
新增目录结构:
templates/statics/index.css
templates/statics/index.js
main.go内容
package main
import (
"github.com/gin-gonic/gin"
"html/template"
"net/http"
)
func main() {
//定义一个路由
r := gin.Default()
//加载静态文件
r.Static("/dwz","templates/statics")
//添加自定义函数,解析下面的“百度一下”html代码
r.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML{
return template.HTML(str)
},
})
//模板解析
r.LoadHTMLGlob("templates/**/*")
//模板渲染
r.GET("/posts", func(c *gin.Context) {
c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts index",
})
})
r.GET("/users", func(c *gin.Context) {
c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "<a href='https://www.baidu.com'>百度一下</a>",
})
})
r.Run(":9090")
}
templates/statics/index.css内容
body {
background-color: cadetblue;
}
templates/statics/index.js内容
alert(123);
templates/users/index.tmpl内容
{{define "users/index.tmpl"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/dwz/index.css">
<title>Title</title>
</head>
<body>
{{.title | safe}}
<script src="/dwz/index.js"></script>
</body>
</html>
{{end}}
运行程序:
go run main.go
浏览器访问:
登录后复制
http://ip:9090/users
gin上传单文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>演示文件上传</h2>
<form action="/upload" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username" placeholder="用户名" />
<br><br>
头像:<input type="file" name="face" />
<br><br>
<input type="submit" value="提交" />
</form>
</body>
</html>
package main
import (
"fmt"
"log"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*")
//上传操作页
//设置内存限制(默认是32M),这里设置为8M
r.MaxMultipartMemory = 8 << 20 //8M
fmt.Println(r.MaxMultipartMemory)
r.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("face")
if err != nil {
fmt.Println("读取表单失败")
return
}
log.Println(file.Filename)
path := `D:\go_ftp_dir`
pathFile := path + "/" + file.Filename
c.SaveUploadedFile(file, pathFile)
c.String(200, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
//上传接口页
r.GET("/upload", func(ctx *gin.Context) {
ctx.HTML(200, "upload.html", gin.H{})
})
r.Run(":8080")
}
crul 命令 也可以发送POST请求
curl -X POST http://localhost:8080/upload \
-F "file=@/tmp/aaa.zip" \
-H "Content-Type: multipart/form-data"
gin上传和下载
批量上传
httpRouter.POST("/upload", func(ctx *gin.Context) {
forms, err := ctx.MultipartForm()
if err != nil {
fmt.Println("error", err)
}
files := forms.File["fileName"]
for _, v := range files {
if err := ctx.SaveUploadedFile(v, fmt.Sprintf("%s%s", "./file/", v.Filename)); err != nil {
fmt.Println("保存文件失败")
}
}
})
其实下载文件,通过http的get请求就行了,回去ctx.file()。
httpRouter.GET("/download", func(ctx *gin.Context) {
filePath := ctx.Query("url")
//打开文件
file, err := os.Open("./" + filePath)
if err != nil {
fmt.Println("打开文件错误", err)
}
defer file.Close()
//获取文件的名称
fileName := path.Base(filePath)
ctx.Header("Content-Type", "application/octet-stream")
ctx.Header("Content-Disposition", "attachment; url="+fileName)
ctx.Header("Content-Transfer-Encoding", "binary")
ctx.Header("Cache-Control", "no-cache")
ctx.File("./" + filePath)
})
自恢复集群启动命令oninitdb的设计与实现 之golang知识点
go执行os系统命令
参考网站: https://zhuanlan.zhihu.com/p/296409942
package main
import (
"bytes"
"fmt"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("ls", "-l", "/var/log/*.log")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout // 标准输出
cmd.Stderr = &stderr // 标准错误
err := cmd.Run()
outStr, errStr := stdout.String(), stderr.String()
fmt.Printf("out:\n%s\nerr:\n%s\n", outStr, errStr)
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
}
go发送get请求并解析网页的BodyString数据
参考网站:https://cloud.tencent.com/developer/article/1849807
func main(){
//主addrss
fmt.Println("远程添加")
u := "http://" + zhuip + ":" + zhuport + "/addrss?my=" + my
fmt.Println(u)
response, err := http.Get(u)
if err != nil {
fmt.Println("http.Get addrss 时遇到异常")
}
buf, _ := ioutil.ReadAll(response.Body)
s := string(buf)
if s == "run addrss ok" {
fmt.Println("run addrss ok")
} else {
fmt.Println("run addrss err")
}
}
go返送get请求并解析网页BodyJSON数据到结构体
知识点:
- ioutil.ReadAll(response.Body) 读取所有Body数据
- json.Unmarshal(buf, &infoList[i]) 使用一个结构体地址解析json字符串
type Info struct {
Servername string `JSON:"servername"`
Mode string `JSON:"mode"`
Running string `JSON:"running"`
}
var infoList [3]Info
func info() {
//查看db节点infof
fmt.Println("查看集群")
for i, n := range webList {
response, err := http.Get("http://" + n.ip + ":" + n.port + "/info")
if err != nil {
fmt.Println("info API 未正常提供服务,Docker可能已经异常。")
continue
}
buf, _ := ioutil.ReadAll(response.Body)
json.Unmarshal(buf, &infoList[i])
fmt.Println(infoList[i])
}
}
golang使用sftp和ssh
参考网站: https://www.programminghunter.com/article/35971402517/
sftp.go
package sshclient
import (
"fmt"
"log"
"net"
"os"
"path"
"time"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
func connect(user, password, host string, port int) (*sftp.Client, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
sshClient *ssh.Client
sftpClient *sftp.Client
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
hostKeyCallbk := func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
}
clientConfig = &ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 1 * time.Second,
HostKeyCallback: hostKeyCallbk,
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if sshClient, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, err
}
// create sftp client
if sftpClient, err = sftp.NewClient(sshClient); err != nil {
return nil, err
}
return sftpClient, nil
}
//发送文件
func SftpPut(user, password, host, fileName string) {
var (
err error
sftpClient *sftp.Client
)
// 这里换成实际的 SSH 连接的 用户名,密码,主机名或IP,SSH端口
sftpClient, err = connect(user, password, host, 22)
if err != nil {
log.Fatal(err)
}
defer sftpClient.Close()
// 用来测试的本地文件路径 和 远程机器上的文件夹
var localFilePath = fileName
var remoteDir = "/tmp/"
srcFile, err := os.Open(localFilePath)
if err != nil {
log.Fatal(err)
}
defer srcFile.Close()
var remoteFileName = path.Base(localFilePath)
dstFile, err := sftpClient.Create(path.Join(remoteDir, remoteFileName))
if err != nil {
log.Fatal(err)
}
defer dstFile.Close()
buf := make([]byte, 1024)
for {
n, _ := srcFile.Read(buf)
if n == 0 {
break
}
dstFile.Write(buf[:n])
}
fmt.Println("copy file to remote server finished!")
}
//下载文件
func SftpGet(user, password, host, fileName string) {
var (
err error
sftpClient *sftp.Client
)
// 这里换成实际的 SSH 连接的 用户名,密码,主机名或IP,SSH端口
sftpClient, err = connect(user, password, host, 22)
if err != nil {
log.Fatal(err)
}
defer sftpClient.Close()
// 用来测试的远程文件路径 和 本地文件夹
var remoteFilePath = "/tmp/" + fileName
var localDir = "lib/sshclient/sftpput/"
srcFile, err := sftpClient.Open(remoteFilePath)
if err != nil {
log.Fatal(err)
}
defer srcFile.Close()
var localFileName = path.Base(remoteFilePath)
dstFile, err := os.Create(path.Join(localDir, localFileName))
if err != nil {
log.Fatal(err)
}
defer dstFile.Close()
if _, err = srcFile.WriteTo(dstFile); err != nil {
log.Fatal(err)
}
fmt.Println("copy file from remote server finished!")
}
sshclient.go
package sshclient
/*
go 1.14:
mkdir -p $GOPATH/src/golang.org/x/
cd $GOPATH/src/golang.org/x/
git clone https://github.com/golang/crypto.git
go 1.18
go get golang.org/x/crypto/ssh
*/
import (
"bytes"
"fmt"
"net"
"strings"
"time"
"golang.org/x/crypto/ssh"
)
// SSHConnect ssh连接
func SSHConnect(user, password, host string, port int) (*ssh.Client, *ssh.Session, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
client *ssh.Client
session *ssh.Session
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
hostKeyCallbk := func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
}
clientConfig = &ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 1 * time.Second,
HostKeyCallback: hostKeyCallbk,
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if client, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, nil, err
}
// create session
if session, err = client.NewSession(); err != nil {
return client, nil, err
}
return client, session, nil
}
// RunSSHpiliang 执行ssh 批量登陆执行
func RunSSHpiliang(user, password, host, cmdshell string) string {
var stdOut, stdErr bytes.Buffer
client, session, err := SSHConnect(user, password, host, 22)
if client != nil {
defer client.Close()
}
if session != nil {
defer session.Close()
}
if err != nil {
//fmt.Println(err," wei----------------------------------------")
if strings.Contains(err.Error(), "i/o timeout") {
return "连接主机的22端口时出错"
}
if strings.Contains(err.Error(), "unable to authenticate") {
return "密码或SSHKEY验证时出错"
}
return "登录主机时出错"
}
session.Stdout = &stdOut
session.Stderr = &stdErr
if err := session.Run(cmdshell); err != nil {
// fmt.Println(err.Error())
// fmt.Println(stdOut.String())
return "执行命令时出错!"
}
return stdOut.String()
}
golang 文件IO/目录IO/行IO/字节BUFIO
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func weiShuoMing() {
// 删除覆盖 os.OpenFile("aaa", os.O_CREATE|os.O_RDWR, 6)
// 行写文件 os.Openfile("aaa", os.O_CREATE|os.O_RDWD|os.O_APPEND,6) f.WriteString("")
// reader定义 reader,err := bufio.Reader(f)
// 行读文件 os.Openfile("aaa",io.O_RDONLY,6) 或者用 os.Open("aaa") f.ReadBytes('\n')
// 偏移量 io.Seek(-12,io.SeekBeging) 还有Current和End
// buf大小 buf := make([]byte,4096)
// 字节写文件 n,err:=reader.write(buf)
// 字节读文件 n,err:=reader.read(buf)
// 打开目录 os.Openfile("aaa",io.O_RDONLY,os.ModeDir)
// 读取目录项 f.Readdir(-1) 返回[{Size() Name() IsDir() Modetime()}...]
// https://studygolang.com/pkgdoc
// https://www.bilibili.com/video/BV1TK4y1a7ex?from=search&seid=18159148304738299137
}
func main() {
// 创建覆盖文件
os.Create("aaa")
// 打开文件aaa
f, err := os.OpenFile("aaa", os.O_RDWR|os.O_APPEND, 6)
if err != nil && err != io.EOF {
fmt.Println("OpenFile打开文件aaa出错")
}
defer f.Close()
// 写入5行数据
f.WriteString("写入数据0001\n")
f.WriteString("写入数据0002\n写入数据0003\n")
f.WriteString("写入数据0004\n写入数据0005\n")
// 移至文件开头
f.Seek(0, io.SeekStart)
// 读取第2,3行的数据
reader := bufio.NewReader(f)
i := 0
for {
hang, err := reader.ReadBytes('\n')
if err == io.EOF {
break
} else {
i++
}
if i == 2 || i == 3 {
fmt.Print(string(hang))
}
}
// buf读
// 偏移15字节再读取第12,13,14,15,16,17,18,19个字节 (utf8一个汉字3个字节,换行\n为一个字节)
f.Seek(15, io.SeekStart)
buf := make([]byte, 8)
f.Read(buf) //从f中读取一个buf空间的内容,给buf赋值。这个函数还返回n,err其中n是实际读取的切片长度。
fmt.Printf("%q\n", buf)
// buf写
f.Seek(0, io.SeekEnd)
f.Write(buf)
f.Close()
// 读取文件夹
fd, err := os.OpenFile("D:/w_gopath/src/wei01/w_go_pg_tidb/05.go_wei", os.O_RDONLY, os.ModeDir)
defer fd.Close()
fdreader, err := fd.Readdir(-1)
for zixiang, info := range fdreader {
fmt.Println(zixiang, info.Name(), info.Size(), info.ModTime(), info.IsDir())
}
}
// 大文件复制
func weicopy() {
f4, err := os.Open("wei.mp3")
if err != nil && err != io.EOF {
fmt.Println("打开mp3失败")
}
defer f4.Close()
f5, err := os.Create("wei_2.mp3")
if err != nil && err != io.EOF {
fmt.Println("打开mp3失败")
}
defer f5.Close()
buf4k := make([]byte, 4096)
for {
n, err := f4.Read(buf4k)
f5.Write(buf4k[:n])
if err != nil && err != io.EOF {
fmt.Println("读取文件出错")
break
}
if n == 0 {
fmt.Println("文件全部读完了")
break
}
fmt.Println(n)
}
}