优化

1. 数据库查询优化

package dao

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"net/url"
	"reflect"
	"strconv"
	"time"
)

type MsDB struct {
	*sql.DB
}
var DB MsDB
func init()  {
	//执行main之前 先执行init方法
	dataSourceName := fmt.Sprintf("root:root@tcp(localhost:3306)/goblog?charset=utf8&loc=%s&parseTime=true",url.QueryEscape("Asia/Shanghai"))
	db, err := sql.Open("mysql", dataSourceName)
	if err != nil {
		log.Println("连接数据库异常")
		panic(err)
	}
	//最大空闲连接数,默认不配置,是2个最大空闲连接
	db.SetMaxIdleConns(5)
	//最大连接数,默认不配置,是不限制最大连接数
	db.SetMaxOpenConns(100)
	// 连接最大存活时间
	db.SetConnMaxLifetime(time.Minute * 3)
	//空闲连接最大存活时间
	db.SetConnMaxIdleTime(time.Minute * 1)
	err = db.Ping()
	if err != nil {
		log.Println("数据库无法连接")
		_ = db.Close()
		panic(err)
	}
	DB = MsDB{db}
}

func (d *MsDB) QueryOne(model interface{},sql string,args... interface{}) error {
	rows,err := d.Query(sql, args...)
	if err != nil {
		return err
	}
	columns, err := rows.Columns()
	if err != nil {
		return  err
	}
	vals := make([][]byte,len(columns))
	scans := make([]interface{},len(columns))
	for k := range vals{
		scans[k] = &vals[k]
	}
	if rows.Next() {
		err = rows.Scan(scans...)
		if err != nil {
			return err
		}
	}
	var result = make(map[string]interface{})
	elem := reflect.ValueOf(model).Elem()
	for index,val := range columns{
		result[val] = string(vals[index])
	}
	for i :=0 ;i <elem.NumField();i++{
		structField := elem.Type().Field(i)
		fieldInfo := structField.Tag.Get("orm")
		v := result[fieldInfo]
		t := structField.Type
		switch t.String() {
		case "int":
			s := v.(string)
			vInt,_ := strconv.Atoi(s)
			elem.Field(i).Set(reflect.ValueOf(vInt))
		case "string":
			elem.Field(i).Set(reflect.ValueOf(v.(string)))
		case "int64":
			s := v.(string)
			vInt64,_ := strconv.ParseInt(s,10,64)
			elem.Field(i).Set(reflect.ValueOf(vInt64))
		case "int32":
			s := v.(string)
			vInt32,_ := strconv.ParseInt(s,10,32)
			elem.Field(i).Set(reflect.ValueOf(vInt32))
		case "time.Time":
			s := v.(string)
			t,_ := time.Parse(time.RFC3339,s)
			elem.Field(i).Set(reflect.ValueOf(t))
		}
	}
	return nil
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

2. 服务启动优化

package server

import (
	"log"
	"ms-go-blog/router"
	"net/http"
)

var App = &MsServer{}
type MsServer struct {
}

func (*MsServer) Start(ip,port string)  {
	server := http.Server{
		Addr: ip+":" + port,
	}
	//路由
	router.Router()
	if err := server.ListenAndServe();err != nil{
		log.Println(err)
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

3. 获取参数优化

package context

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"strings"
)

var Context = NewContext()
type MsContext struct {
	Request *http.Request
	W http.ResponseWriter
	routers map[string]func(ctx *MsContext)
	pathArgs map[string]map[string]string
}

func NewContext() *MsContext  {
	ctx := &MsContext{}
	ctx.routers = make(map[string]func(ctx2 *MsContext))
	ctx.pathArgs = make(map[string]map[string]string)
	return ctx
}
var UrlTree = NewTrie()
// 前缀树结构 用于路径参数匹配
type Trie struct {
	next map[string]*Trie
	isWord bool
}
func NewTrie() Trie {
	root := new(Trie)
	root.next = make(map[string]*Trie)
	root.isWord = false
	return *root
}
// 插入数据, 路由根据 "/" 进行拆分
func (t *Trie) Insert(word string) {
	for _, v := range strings.Split(word, "/") {
		if t.next[v] == nil {
			node := new(Trie)
			node.next = make(map[string]*Trie)
			node.isWord = false
			t.next[v] = node
		}
		// * 匹配所有
		// {X}  匹配路由参数 X
		if v == "*" || strings.Index(v, "{") != -1 {
			t.isWord = true
		}
		t = t.next[v]
	}
	t.isWord = true
}
// 匹配路由
func (t *Trie) Search(word string) (isHave bool, arg map[string]string) {
	arg = make(map[string]string)
	isHave = false
	for _, v := range strings.Split(word, "/") {
		if t.isWord {
			for k,_ := range t.next {
				if strings.Index(k, "{") != -1 {
					key := strings.Replace(k, "{", "", -1)
					key = strings.Replace(key, "}", "", -1)
					arg[key] = v
				}
				v = k
			}
			//log.Println("v = ", v)
		}
		if t.next[v] == nil {
			log.Println("找不到了, 匹配不上")
			return
		}
		t = t.next[v]
	}
	//log.Println(t.next, len(t.next))
	// 必须匹配全  比如: /v1/{b}/{a}  /v1/123匹配不到, /v1/123/456才可匹配
	if len(t.next) == 0 {
		isHave = t.isWord
		return
	}
	return
}
func (ctx *MsContext) ServeHTTP(w http.ResponseWriter,r *http.Request)  {
	ctx.W = w
	ctx.Request = r
	path := r.URL.Path
	f := ctx.routers[path]
	if f == nil {
		for key,value := range ctx.routers {
			//判断是否为携带路径参数的
			reg,_ := regexp.Compile("(/\\w+)*(/{\\w+})+(/\\w+)*")
			match := reg.MatchString(key)
			if !match {
				continue
			}
			isHav,args := UrlTree.Search(path)
			if isHav {
				//匹配上 存储路径对应参数
				ctx.pathArgs[path] = args
				value(ctx)
			}
		}
	}else{
		f(ctx)
	}
}

func (ctx *MsContext) Handler(url string,f func(context *MsContext))  {
	UrlTree.Insert(url)
	ctx.routers[url] = f
}

func (ctx *MsContext) GetPathVariable(key string) string {
	return ctx.pathArgs[ctx.Request.URL.Path][key]
}

func (ctx *MsContext) GetForm(key string) (string,error) {
	if err := ctx.Request.ParseForm();err != nil{
		log.Println("表单获取失败:",err)
		return "",err
	}
	return ctx.Request.Form.Get(key),nil
}
func (ctx *MsContext) GetJson(key string) interface{} {
	var params map[string]interface{}
	body, _ := ioutil.ReadAll(ctx.Request.Body)
	_ = json.Unmarshal(body, &params)
	return params[key]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132