前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go起步及创建WEB项目(iris)

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

作者头像
码客说
发布2021-04-19 15:26:09
8390
发布2021-04-19 15:26:09
举报
文章被收录于专栏:码客码客

创建WEB项目(iris)

仓库地址:https://github.com/kataras/iris/

文档:http://www.topgoer.com/Iris/

创建

mkdir ZDevOpsGo
cd ZDevOpsGo
go mod init ZDevOpsGo
go get github.com/kataras/iris/v12@master

创建main.go

输入如下内容

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()
}

运行

go run main.go

或者编译后运行exe文件

go build

这样就可以访问

http://127.0.0.1:8080/

使用模板

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

<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

加载配置文件

// 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文件解析

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

{
  "port":8080,
  "project_name":"码客说"
}

注意

JSON库在转换的时候会首字母大写,但是project_name这样的会解析为Project_name, 而不是ProjectName

Marshal():Go数据对象 -> json数据

UnMarshal():Json数据 -> Go数据对象

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:\Tools\mingw64\bin添加到系统环境变量Path

添加后重启开发软件,后输入

go get github.com/mattn/go-sqlite3

示例

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

下载依赖

go get github.com/go-sql-driver/mysql

示例

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配置

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 %d\n", 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 %d\n", 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配置

# 这是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;
    }
}

解析后的数据

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-04-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建WEB项目(iris)
  • 使用模板
  • 使用配置文件
  • 项目下的静态文件
  • JSON文件解析
  • Sqlite
  • Mysql
  • 解析Nginx配置
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档