前言
這是中山大學數據科學與計算機學院2019年服務計算的作業項目。所有代碼與博客將被上傳至github當中。
Github項目地址: https://github.com/BlogByFourMan
個人主頁: https://starashzero.github.io
概述
我們小組四人完成了一個前後端分離的web博客應用——Simple Blog
目前支持的功能有:
- 註冊
- 登陸
- 查看博客
- 查看評論
- 發表評論
工作簡述
我在小組中主要負責後端User相關的API代碼編寫
- 項目結構:
- db包存放數據庫相關代碼,數據庫使用BoltDB
- model包存放需要用到的數據結構
- go包實現api代碼
開發過程
-
db
db實現數據庫代碼,數據庫使用BoltDB,使用方法爲Key:Value
我實現了與User有關的數據庫代碼- GetUser
GetUser實現對用戶信息的查詢,輸入參數爲username,輸出結果爲User信息
默認將Username和Password均爲""的User作爲查詢失敗的標識func GetUser(username string) model.User { db, err := bolt.Open(GetDBPATH(), 0600, nil) if err != nil { log.Fatal(err) } defer db.Close() user := model.User{ Username: "", Password: "", } err = db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("user")) if b != nil { data := b.Get([]byte(username)) if data != nil { err := json.Unmarshal(data, &user) if err != nil { log.Fatal(err) } } } return nil }) if err != nil { log.Fatal(err) } return user }
- PutUsers
PutUsers實現User數據的添加,輸入參數爲User數組(支持一次添加多個),返回報錯信息func PutUsers(users []model.User) error { db, err := bolt.Open(GetDBPATH(), 0600, nil) if err != nil { log.Fatal(err) } defer db.Close() err = db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("user")) if b != nil { for i := 0; i < len(users); i++ { username := users[i].Username data, _ := json.Marshal(users[i]) b.Put([]byte(username), data) } } return nil }) if err != nil { return err } return nil }
- GetUser
-
model
在開發過程中需要用到幾個數據結構- User
User是存儲用戶信息的數據結構,目前比較簡單,只存放了用戶名和密碼type User struct { Username string `json:"username,omitempty"` Password string `json:"password,omitempty"` }
- Comment
Comment類存放評論信息,包括評論用戶、文章id、評論信息、評論內容等type Comment struct { User string `json:"user,omitempty"` ArticleId int64 `json:"article_id,omitempty"` Date string `json:"date,omitempty"` Content string `json:"content,omitempty"` }
- User
-
go
go包實現API代碼-
response.go
response.go用來統一處理Response
MyResponse結構用來存儲Response信息
Options單獨處理OPTIONS(當需要loken認證時,會提前收到一個OPTIONS包)
Response用來發送回覆信息type MyResponse struct { OkMessage interface{} `json:"ok,omitempty"` ErrorMessage interface{} `json:"error,omitempty"` } func Options(w http.ResponseWriter, r *http.Request){ w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.Header().Set("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Authorization, X-Requested-With") w.Header().Set("Access-Control-Allow-Origin", "*") w.WriteHeader(http.StatusOK) } func Response(response interface{}, w http.ResponseWriter, code int) { jsonData, jErr := json.Marshal(&response) if jErr != nil { log.Fatal(jErr.Error()) } w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.Header().Set("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Authorization, X-Requested-With") w.Header().Set("Access-Control-Allow-Origin", "*") w.Write(jsonData) w.WriteHeader(code) }
-
api_user.go
api_user.go實現User相關的API:- POST /article/{id}/comments
- POST /user/login
- POST /user/register
我主要負責這三個方面的開發,不過loken認證由另一位組員完成
- login與register
login和register的實現大同小異- 首先讀取body當中的參數,將其轉爲User結構體
err := json.NewDecoder(r.Body).Decode(&user)
- 從數據庫中獲得用戶名對應的User信息
check := db.GetUser(user.Username)
- 對用戶信息進行驗證,例如驗證用戶是否存在,賬戶與密碼是否對應等等
- 最後返回token
Response(MyResponse{ tokenString, nil, }, w, http.StatusOK)
- CommentPost
添加評論需要對用戶進行驗證,主要流程如下:-
驗證用戶token
token, isValid := ValidateToken(w, r)
-
讀入body參數,並解碼爲Comment結構
err := json.NewDecoder(r.Body).Decode(&comment)
-
根據token更新User
if v, ok := token.Claims.(jwt.MapClaims); ok { name, _ := v["name"].(string) comment.User = name }
-
獲得文章id
articleId := strings.Split(r.URL.Path, "/")[2] comment.ArticleId, err = strconv.ParseInt(articleId, 10, 64)
-
生成時間
comment.Date = fmt.Sprintf("%d-%d-%d", time.Now().Year(), time.Now().Month(), time.Now().Day())
-
將評論加入到數據庫中
for i := 0; i < len(articles); i++ { articles[i].Comments = append(articles[i].Comments, comment) } err = db.PutArticles(articles)
-
返回評論數據
Response(MyResponse{ comment, nil, }, w, http.StatusOK)
-
- 首先讀取body當中的參數,將其轉爲User結構體
-