web 服務與客戶端開發實戰總結

前言

這是中山大學數據科學與計算機學院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
      }
      
  • 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"`
      }
      
  • 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)
            
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章