创建WEB项目(iris)
仓库地址:https://github.com/kataras/iris/
文档:http://www.topgoer.com/Iris/
创建
代码语言:javascript复制mkdir ZDevOpsGo
cd ZDevOpsGo
go mod init ZDevOpsGo
go get github.com/kataras/iris/v12@master
创建main.go
输入如下内容
代码语言:javascript复制package main
import "github.com/kataras/iris/v12"
func main() {
app := iris.Default()
app.Use(myMiddleware)
app.Handle("GET", "/", func(ctx iris.Context) {
ctx.JSON(iris.Map{"message": "hello world"})
})
// Listens and serves incoming http requests
// on http://localhost:8080.
app.Run(iris.Addr(":8080"))
}
func myMiddleware(ctx iris.Context) {
ctx.Application().Logger().Infof("Runs before %s", ctx.Path())
ctx.Next()
}
运行
代码语言:javascript复制go run main.go
或者编译后运行exe文件
代码语言:javascript复制go build
这样就可以访问
http://127.0.0.1:8080/
使用模板
代码语言:javascript复制package main
import "github.com/kataras/iris/v12"
func main() {
app := iris.New()
// Load all templates from the "./views" folder
// where extension is ".html" and parse them
// using the standard `html/template` package.
app.RegisterView(iris.HTML("./views", ".html"))
// Method: GET
// Resource: http://localhost:8080
app.Get("/", func(ctx iris.Context) {
// Bind: {{.message}} with "Hello world!"
ctx.ViewData("message", "Hello world!")
// Render template file: ./views/index.html
ctx.View("index.html")
})
// Method: GET
// Resource: http://localhost:8080/user/42
// 也可以使用正则表达式
// app.Get("/user/{id:string regexp(^[0-9] $)}")
app.Get("/user/{id:uint64}", func(ctx iris.Context) {
userID, _ := ctx.Params().GetUint64("id")
ctx.Writef("User ID: %d", userID)
})
// Start the server using a network address.
app.Run(iris.Addr(":8080"))
}
模板文件
views/index.html
代码语言:javascript复制<html>
<head>
<title>Hello Page</title>
</head>
<body>
<h1>{{ .message }}</h1>
</body>
</html>
运行就可以访问
http://localhost:8080 http://localhost:8080/user/42
使用配置文件
项目根目录创建iris.yml
FireMethodNotAllowed: true
DisableBodyConsumptionOnUnmarshal: true
TimeFormat: Mon, 01 Jan 2006 15:04:05 GMT
Charset: UTF-8
加载配置文件
代码语言:javascript复制// Start the server using a network address.
config := iris.WithConfiguration(iris.YAML("./iris.yml"))
app.Run(iris.Addr(":8080"), config)
项目下的静态文件
假如我们想要处理 http://localhost:8080/static/**/*
的请求都访问项目目录下的 ./static
文件夹,那么按照如下配置就可以了
app := iris.New()
app.HandleDir("/static", "./static")
app.Run(iris.Addr(":8080"))
app.HandleDir("/static", "./static")
的第一个参数为请求的URL,第二个参数为本地文件夹
一般前后端不分离我们可以这样配置,让项目可以访问前端的样式、JS、静态页面、图片等等静态的资源。
JSON文件解析
代码语言:javascript复制package utils
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path"
)
type Config struct {
Port int32
Project_name string
}
func init() {
fmt.Println("config初始化")
}
func ReadConfig() Config {
ExecPath, _ := os.Getwd()
filepath := path.Join(ExecPath, "config", "config.json")
data, err := ioutil.ReadFile(filepath)
fmt.Println("filepath:", filepath)
v := Config{}
if err != nil {
fmt.Println("读取配置文件失败", err)
return v
}
fmt.Println(string(data))
//读取的数据为json格式,需要进行解码
err = json.Unmarshal(data, &v)
if err != nil {
fmt.Println("解析json失败", err)
} else {
fmt.Println("port:", v.Port)
fmt.Println("Project_name:", v.Project_name)
}
return v
}
对应的JSON文件
config/config.json
代码语言:javascript复制{
"port":8080,
"project_name":"码客说"
}
注意
JSON库在转换的时候会首字母大写,但是
project_name
这样的会解析为Project_name
, 而不是ProjectName
Marshal():Go数据对象 -> json数据
UnMarshal():Json数据 -> Go数据对象
代码语言:javascript复制func Marshal(v interface{}) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error
构建json数据
Marshal()和MarshalIndent()函数可以将数据封装成json数据。
- struct、slice、array、map都可以转换成json
- struct转换成json的时候,只有字段首字母大写的才会被转换
- map转换的时候,key必须为string
- 封装的时候,如果是指针,会追踪指针指向的对象进行封装
Marshal函数将会递归遍历整个对象,依次按成员类型对这个对象进行编码,类型转换规则如下:
Golang 数据类型 | JSON 数据类型 |
---|---|
bool | Boolean |
int float | Number |
string | String |
struct | JSON Object 再根据成员递归打包 |
数组或切片 | JSON Array |
[]byte | base64编码后的JSON String |
map | JSON Object, key必须是string |
interface{} | 按照内部实际进行转换 |
nil | null |
channel, func | UnsupportedTypeError |
注意
JSON转换不支持list
Sqlite
安装GCC环境
在Sourceforge官网,下载MinGW-W64 GCC-8.1
下载x86_64-win32-sjlj
解压后把类似于D:Toolsmingw64bin
添加到系统环境变量Path
里
添加后重启开发软件,后输入
代码语言:javascript复制go get github.com/mattn/go-sqlite3
示例
代码语言:javascript复制package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./mydb.db")
checkErr(err)
//创建表
sql_table := `
CREATE TABLE IF NOT EXISTS userinfo(
uid INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(64) NULL,
departname VARCHAR(64) NULL,
created DATE NULL
);
`
db.Exec(sql_table)
//插入数据
stmt, err := db.Prepare("INSERT INTO userinfo(username, departname, created) values(?,?,?)")
checkErr(err)
res, err := stmt.Exec("小红", "研发部门", "2012-12-09")
checkErr(err)
id, err := res.LastInsertId()
checkErr(err)
fmt.Println("插入用户ID:", id)
//更新数据
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
checkErr(err)
res, err = stmt.Exec("小明", id)
checkErr(err)
affect, err := res.RowsAffected()
checkErr(err)
fmt.Println("更新用户条数:", affect)
//查询数据
rows, err := db.Query("SELECT * FROM userinfo")
checkErr(err)
for rows.Next() {
var uid int
var username string
var department string
var created string
err = rows.Scan(&uid, &username, &department, &created)
checkErr(err)
fmt.Println("uid:", uid)
fmt.Println("username:", username)
fmt.Println("department:", department)
fmt.Println("created:", created)
}
//删除数据
stmt, err = db.Prepare("delete from userinfo where uid=?")
checkErr(err)
res, err = stmt.Exec(id)
checkErr(err)
affect, err = res.RowsAffected()
checkErr(err)
fmt.Println("删除条数:", affect)
db.Close()
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
注意
panic 会触发程序崩溃,正式上线不要用
Mysql
下载依赖
代码语言:javascript复制go get github.com/go-sql-driver/mysql
示例
代码语言:javascript复制package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
func initDB() {
//"用户名:密码@[连接方式](主机名:端口号)/数据库名"
db, _ = sql.Open("mysql", "root:123456@(127.0.0.1:3306)/zdb") // 设置连接数据库的参数
db.SetMaxOpenConns(20)
db.SetMaxIdleConns(5)
}
func main() {
initDB()
defer db.Close() //关闭数据库
err := db.Ping() //连接数据库
if err != nil {
fmt.Println("数据库连接失败")
return
}
//操作一:执行数据操作语句
sql := "insert into t_user (name) values ('berry')"
result, _ := db.Exec(sql) //执行SQL语句
n, _ := result.RowsAffected() //获取受影响的记录数
fmt.Println("受影响的记录数是", n)
//操作二:执行预处理
users := [2][]string{{"ketty"}, {"rose"}}
stmt, _ := db.Prepare("insert into t_user (name) values (?)") //获取预处理语句对象
for _, s := range users {
stmt.Exec(s[0]) //调用预处理语句
}
//操作三:单行查询
// var id, name string
// rows := db.QueryRow("select * from t_user where id=4") //获取一行数据
// rows.Scan(&id, &name)
// fmt.Println(id, "--", name)
//操作四:多行查询
rows, _ := db.Query("select * from t_user") //获取所有数据
var id, name string
for rows.Next() { //循环显示所有的数据
rows.Scan(&id, &name)
fmt.Println(id, "--", name)
}
rows.Close()
}
注意
defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。
连接池的实现关键在于SetMaxOpenConns和SetMaxIdleConns,其中:
SetMaxOpenConns用于设置最大打开的连接数,默认值为0表示不限制。 SetMaxIdleConns用于设置闲置的连接数。
设置最大的连接数,可以避免并发太高导致连接mysql出现too many connections的错误。设置闲置的连接数则当开启的一个连接使用完成后可以放在池里等候下一次使用。
解析Nginx配置
代码语言:javascript复制package utils
import (
"bufio"
"encoding/json"
"fmt"
"io"
"os"
"path"
"strings"
)
func init() {
fmt.Println("nginx_config初始化")
}
// 定义存储的结构体
type NginxConfig struct {
Name string
Value string
Comment []string
Children *[]NginxConfig
}
// 读取Nginx配置
func ReadNginxConfig(filepath string) []NginxConfig {
f, err := os.Open(filepath)
if err != nil {
fmt.Println(err.Error())
}
config_arr := []string{}
//建立缓冲区,把文件内容放到缓冲区中
buf := bufio.NewReader(f)
for {
//遇到n结束读取
b, errR := buf.ReadBytes('n')
if errR != nil {
if errR == io.EOF {
break
}
fmt.Println(errR.Error())
}
config_arr = append(config_arr, strings.TrimSpace(string(b)))
}
configlist := []NginxConfig{}
level := 0
lastchar := ' '
levelConf := []NginxConfig{}
var conf *NginxConfig
lastComment := []string{}
for line_num, v := range config_arr {
if strings.HasPrefix(v, "#") {
lastComment = append(lastComment, strings.Replace(v, "#", "", 1))
} else if strings.Contains(v, "{") {
if lastchar == '{' {
level = 1
}
if level < len(levelConf) {
conf = &levelConf[level]
} else {
conf = new(NginxConfig)
conf.Children = new([]NginxConfig)
levelConf = append(levelConf, *conf)
}
if len(lastComment) > 0 {
if conf != nil {
conf.Comment = lastComment
lastComment = []string{}
}
}
tempstr := strings.Split(v, "{")[0]
tempstr = strings.TrimSpace(tempstr)
tem_arr := strings.Split(tempstr, " ")
// fmt.Println("tem_arr:", tem_arr)
if len(tem_arr) > 0 {
conf.Name = tem_arr[0]
if len(tem_arr) > 1 {
conf.Value = tem_arr[1]
}
}
if level == 0 {
configlist = append(configlist, *conf)
} else {
lastLevelConfig := &levelConf[level-1]
*lastLevelConfig.Children = append(*lastLevelConfig.Children, *conf)
}
fmt.Printf("%d %s level %dn", line_num, v, level)
lastchar = '{'
} else if strings.Contains(v, "}") {
if lastchar == '}' {
level -= 1
}
levelConf = levelConf[:len(levelConf)-1]
if level < len(levelConf) {
conf = &levelConf[level]
} else {
conf = nil
}
fmt.Printf("%d %s level %dn", line_num, v, level)
lastchar = '}'
} else {
if conf != nil {
tempstr := strings.TrimSpace(v)
if len(tempstr) > 0 {
var confitem *NginxConfig = new(NginxConfig)
tem_arr := strings.Split(tempstr, " ")
if len(tem_arr) >= 2 {
confitem.Name = tem_arr[0]
rightstr := strings.Join(tem_arr[1:], " ")
if strings.Contains(rightstr, ";") {
confitem.Value = strings.Split(rightstr, ";")[0]
if len(lastComment) > 0 {
confitem.Comment = lastComment
lastComment = []string{}
}
*conf.Children = append(*conf.Children, *confitem)
}
}
}
}
}
}
return configlist
}
// 写入Nginx配置
func WriteConfig(filepath string, NginxConfig []NginxConfig) {
strArr := new([]string)
for _, value := range NginxConfig {
writeConfigStr(value, strArr, 0)
}
// fmt.Println("*strArr", *strArr)
file, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println("文件打开失败", err)
}
//及时关闭file句柄
defer file.Close()
//写入文件时,使用带缓存的 *Writer
write := bufio.NewWriter(file)
for i := 0; i < len(*strArr); i {
write.WriteString((*strArr)[i] "n")
}
//Flush将缓存的文件真正写入到文件中
write.Flush()
}
func spaceByLevel(level int) string {
str := ""
for i := 0; i < level; i {
str = " "
}
return str
}
func writeConfigStr(NginxConfig NginxConfig, strArr *[]string, level int) {
spacestr := spaceByLevel(level)
if len(NginxConfig.Comment) != 0 {
for i := 0; i < len(NginxConfig.Comment); i {
*strArr = append(*strArr, spacestr "#" NginxConfig.Comment[i])
}
}
if NginxConfig.Children != nil {
*strArr = append(*strArr, spacestr NginxConfig.Name " " NginxConfig.Value " {")
for _, value := range *NginxConfig.Children {
writeConfigStr(value, strArr, level 1)
}
*strArr = append(*strArr, spacestr "}")
} else {
*strArr = append(*strArr, spacestr NginxConfig.Name " " NginxConfig.Value ";")
}
}
func main() {
ExecPath, _ := os.Getwd()
filepath := path.Join(ExecPath, "nginx", "test.psvmc.cn.conf")
configlist := ReadNginxConfig(filepath)
showLog := false
if showLog {
jsondata, err := json.Marshal(configlist)
if err != nil {
fmt.Println(err)
}
fmt.Println("configlist:", len(configlist))
fmt.Println("configlist:", string(jsondata))
}
filepath2 := path.Join(ExecPath, "nginx", "test.psvmc.cn2.conf")
WriteConfig(filepath2, configlist)
}
nginx配置
代码语言:javascript复制# 这是upstream
upstream test_psvmc_cn {
server 110.110.110.110:8080;
server 120.120.120.120:8080;
}
server {
# 这是http
listen 80;
# 这是https
listen 443;
server_name test.psvmc.cn;
client_max_body_size 200m;
ssl on;
ssl_certificate /etc/nginx/cert/xhkjedu.pem;
ssl_certificate_key /etc/nginx/cert/xhkjedu.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
# 路径映射
location / {
proxy_pass http://test_psvmc_cn/;
proxy_cookie_path / /;
proxy_redirect / /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 200m;
client_body_buffer_size 128k;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_buffer_size 64k;
proxy_buffers 8 64k;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 128k;
send_timeout 60;
}
}
解析后的数据
代码语言:javascript复制[
{
"Name": "upstream",
"Value": "test_psvmc_cn",
"Comment": [
" 这是upstream"
],
"Children": [
{
"Name": "server",
"Value": "110.110.110.110:8080",
"Comment": null,
"Children": null
},
{
"Name": "server",
"Value": "120.120.120.120:8080",
"Comment": null,
"Children": null
}
]
},
{
"Name": "server",
"Value": "",
"Comment": null,
"Children": [
{
"Name": "listen",
"Value": "80",
"Comment": [
" 这是http"
],
"Children": null
},
{
"Name": "listen",
"Value": "443",
"Comment": [
" 这是https"
],
"Children": null
},
{
"Name": "server_name",
"Value": "test.psvmc.cn",
"Comment": null,
"Children": null
},
{
"Name": "client_max_body_size",
"Value": "200m",
"Comment": null,
"Children": null
},
{
"Name": "ssl",
"Value": "on",
"Comment": null,
"Children": null
},
{
"Name": "ssl_certificate",
"Value": "/etc/nginx/cert/xhkjedu.pem",
"Comment": null,
"Children": null
},
{
"Name": "ssl_certificate_key",
"Value": "/etc/nginx/cert/xhkjedu.key",
"Comment": null,
"Children": null
},
{
"Name": "ssl_session_timeout",
"Value": "5m",
"Comment": null,
"Children": null
},
{
"Name": "ssl_ciphers",
"Value": "ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4",
"Comment": null,
"Children": null
},
{
"Name": "ssl_protocols",
"Value": "TLSv1 TLSv1.1 TLSv1.2",
"Comment": null,
"Children": null
},
{
"Name": "ssl_prefer_server_ciphers",
"Value": "on",
"Comment": null,
"Children": null
},
{
"Name": "location",
"Value": "/",
"Comment": [
" 路径映射"
],
"Children": [
{
"Name": "proxy_pass",
"Value": "http://test_psvmc_cn/",
"Comment": null,
"Children": null
},
{
"Name": "proxy_cookie_path",
"Value": "/ /",
"Comment": null,
"Children": null
},
{
"Name": "proxy_redirect",
"Value": "/ /",
"Comment": null,
"Children": null
},
{
"Name": "proxy_set_header",
"Value": "Host $host",
"Comment": null,
"Children": null
},
{
"Name": "proxy_set_header",
"Value": "X-Real-IP $remote_addr",
"Comment": null,
"Children": null
},
{
"Name": "proxy_set_header",
"Value": "X-Forwarded-For $proxy_add_x_forwarded_for",
"Comment": null,
"Children": null
},
{
"Name": "client_max_body_size",
"Value": "200m",
"Comment": null,
"Children": null
},
{
"Name": "client_body_buffer_size",
"Value": "128k",
"Comment": null,
"Children": null
},
{
"Name": "proxy_connect_timeout",
"Value": "300s",
"Comment": null,
"Children": null
},
{
"Name": "proxy_send_timeout",
"Value": "300s",
"Comment": null,
"Children": null
},
{
"Name": "proxy_read_timeout",
"Value": "300s",
"Comment": null,
"Children": null
},
{
"Name": "proxy_busy_buffers_size",
"Value": "64k",
"Comment": null,
"Children": null
},
{
"Name": "proxy_temp_file_write_size",
"Value": "64k",
"Comment": null,
"Children": null
},
{
"Name": "proxy_buffer_size",
"Value": "64k",
"Comment": null,
"Children": null
},
{
"Name": "proxy_buffers",
"Value": "8 64k",
"Comment": null,
"Children": null
},
{
"Name": "fastcgi_buffer_size",
"Value": "128k",
"Comment": null,
"Children": null
},
{
"Name": "fastcgi_buffers",
"Value": "4 128k",
"Comment": null,
"Children": null
},
{
"Name": "send_timeout",
"Value": "60",
"Comment": null,
"Children": null
}
]
}
]
}
]
这样Nginx配置文件就能完全解析了