Go起步及创建WEB项目(iris)

2021-04-19 15:26:09 浏览数 (1)

创建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

代码语言:javascript复制
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 文件夹,那么按照如下配置就可以了

代码语言:javascript复制
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数据。

  1. struct、slice、array、map都可以转换成json
  2. struct转换成json的时候,只有字段首字母大写的才会被转换
  3. map转换的时候,key必须为string
  4. 封装的时候,如果是指针,会追踪指针指向的对象进行封装

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配置文件就能完全解析了

0 人点赞