8000 Create 2021-4-22-gohttpserver.md · vltavaw/vltavaw.github.io@1bce7c4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1bce7c4

Browse files
authored
Create 2021-4-22-gohttpserver.md
1 parent b590ad1 commit 1bce7c4

File tree

1 file changed

+222
-0
lines changed

1 file changed

+222
-0
lines changed

_posts/2021-4-22-gohttpserver.md

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
---
2+
title: 一个简单的Go语言http server
3+
categories:
4+
- Go
5+
---
6+
7+
8+
#### 1. HelloWorld
9+
10+
首先我们建立一个迷你服务器,在`localhost:8000`上显示Hello, World.
11+
12+
```Go
13+
import(
14+
"fmt"
15+
"log"
16+
"net/http"
17+
"github.com/gorilla/mux"
18+
)
19+
20+
func main() {
21+
router := mux.NewRouter()
22+
router.HandleFunc("/", index)
23+
24+
log.Fatal(http.ListenAndServe("localhost:8000", router))
25+
}
26+
27+
func index(w http.ResponseWriter, r *http.Request) {
28+
fmt.Fprintf(w, "Hello, World!")
29+
}
30+
```
31+
32+
好像没有太多要解释的,因为工作都让库函数做完了。这里用了`github.com/gorilla/mux`这个包而不是书上的http自带,因为这个包可以更方便的管理http method,不然就要类似`switch r.Method`这样,不是很美观。现在`go run server.go &`,打开浏览器就可以在对应地址看到hw了。
33+
34+
#### 2. 几个简单的接口
35+
36+
接下来加入一些Restful接口。具体如下:
37+
38+
```Go
39+
func main() {
40+
router := mux.NewRouter()
41+
router.HandleFunc("/", index)
42+
router.HandleFunc("/accounts", createAccount).Methods("POST")
43+
router.HandleFunc("/accounts/{id}", deleteAccount).Methods("DELETE")
44+
router.HandleFunc("/accounts", updateAccount).Methods("PUT")
45+
router.HandleFunc("/accounts", getAccount).Methods("GET")
46+
router.HandleFunc("/accounts/{id}", getAccountByID).Methods("GET")
47+
48+
log.Fatal(http.ListenAndServe("localhost:8000", router))
49+
}
50+
```
51+
52+
#### 3.连接数据库
53+
54+
接下来我们需要引入mysql,首先导入包:
55+
```Go
56+
import(
57+
"database/sql"
58+
_ "github.com/go-sql-driver/mysql"
59+
"encoding/json"
60+
"strconv"
61+
)
62+
```
63+
定义数据结构来对应数据库:
64+
65+
```Go
66+
type Account struct {
67+
Id int
68+
Name string
69+
Amount int
70+
}
71+
```
72+
73+
写了如下的辅助函数来连接数据库:
74+
75+
```Go
76+
func connectDB() *sql.DB {
77+
db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/dbname")
78+
if err != nil {
79+
fmt.Println(err)
80+
panic(err.Error())
81+
}
82+
fmt.Println("Successfully connected to database.")
83+
return db
84+
}
85+
```
86+
87+
其中`username:password@tcp(127.0.0.1:3306)/dbname`表示了用户名、密码、地址跟数据库名字的格式。
88+
89+
#### 4.增删改查
90+
新增一个账号,这里在RequestBody里填写一个json表单,然后用`json.Decoder.Decode`读取到Go的数据结构里。用`db.Prepare`生成mysql statement,然后用`stmt.Exec`执行。需要研究的地方是怎么设置id自增而不是手动填写。
91+
```Go
92+
func createAccount(w http.ResponseWriter, r *http.Request) {
93+
db := connectDB()
94+
95+
var account Account
96+
decoder := json.NewDecoder(r.Body)
97+
err := decoder.Decode(&account)
98+
99+
stmt, err := db.Prepare("INSERT into account SET Id=?, Name=?, Amount=?")
100+
if err != nil {
101+
fmt.Println(err)
102+
}
103+
104+
_, err2 := stmt.Exec(account.Id, account.Name, account.Amount)
105+
if err2 != nil {
106+
fmt.Println(err2)
107+
}
108+
}
109+
```
110+
111+
删除账号,这里通过url里的id来进行删除,所以用了`mux.Vars``strconv`来获取id。
112+
```Go
113+
func deleteAccount(w http.ResponseWriter, r *http.Request) {
114+
db := connectDB()
115+
params := mux.Vars(r)
116+
id, _ := strconv.Atoi(params["id"])
117+
118+
stmt, err := db.Prepare("DELETE FROM account WHERE id=?")
119+
if err != nil{
120+
fmt.Println(err)
121+
}
122+
123+
result, err := stmt.Exec(id)
124+
if err != nil{
125+
fmt.Println(err)
126+
}
127+
json, _ := json.Marshal(result)
128+
w.Write(json)
129+
}
130+
```
131+
132+
更新账号信息,同样是通过RequestBody。这里通过`RowsAffected`判断有没有处理到,讲道理并不是最好的解法,因为并不一定是没有这个id才会发生这件事,应该先查找有没有对应的id,只不过会引入新的开销。
133+
```Go
134+
func updateAccount(w http.ResponseWriter, r *http.Request) {
135+
db := connectDB()
136+
var account Account
137+
decoder := json.NewDecoder(r.Body)
138+
err := decoder.Decode(&account)
139+
140+
stmt, err := db.Prepare("UPDATE account SET Name=?, Amount=? WHERE id=?")
141+
if err != nil{
142+
fmt.Println(err)
143+
}
144+
145+
result, err := stmt.Exec(account.Name, account.Amount, account.Id)
146+
if err != nil{
147+
fmt.Println(err)
148+
}
149+
150+
cnt, _ := result.RowsAffected();
151+
if(cnt == 0) {
152+
w.Write([]byte("Could not find account with id: " + strconv.Itoa(account.Id)))
153+
} else {
154+
fmt.Println(result)
155+
}
156+
}
157+
```
158+
159+
最后是查找,首先是展示全部的账号信息,会返回`sql.Rows`然后进行遍历,把结果存到Account的slice里,用`json.Marshal`输出成可以给`w.Write``[]byte`类型。
160+
```Go
161+
func getAccount(w http.ResponseWriter, r *http.Request) {
162+
db := connectDB()
163+
164+
rows, err := db.Query("SELECT * FROM account")
165+
if err != nil{
166+
fmt.Println(err)
167+
}
168+
169+
results := []Account{}
170+
account := Account{}
171+
172+
for rows.Next() {
173+
e := rows.Scan(&account.Id, &account.Name, &account.Amount)
174+
if e != nil {
175+
fmt.Println(err)
176+
}
177+
results = append(results, account)
178+
}
179+
180+
rows.Close()
181+
json, _ := json.Marshal(results)
182+
w.Write(json)
183+
}
184+
```
185+
186+
还写了一个通过id查找,原理类似。显然,可以模块化一下输出的部分。
187+
```Go
188+
func getAccountByID(w http.ResponseWriter, r *http.Request) {
189+
db := connectDB()
190+
params := mux.Vars(r)
191+
id, _ := strconv.Atoi(params["id"])
192+
193+
rows, err := db.Query("SELECT * FROM account WHERE Id=?", id)
194+
if err != nil {
195+
fmt.Println(err)
196+
}
197+
198+
results := []Account{}
199+
account := Account{}
200+
201+
if rows.Next() {
202+
e := rows.Scan(&account.Id, &account.Name, &account.Amount)
203+
if e != nil {
204+
fmt.Println(err)
205+
}
206+
results = append(results, account)
207+
} else {
208+
w.Write([]byte("Could not find account with id: " + params["id"]))
209+
return
210+
}
211+
212+
rows.Close()
213+
json, _ := json.Marshal(results)
214+
w.Write(json)
215+
}
216+
```
217+
218+
#### 5.测试
219+
用postman简单测试了一下各个接口,但是~~懒得~~忘记截图了!
220+
221+
那么祝您身体健康
222+

0 commit comments

Comments
 (0)
0