Go 原生开发博客项目系列(第六篇)

98 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情

项目原视频地址:www.bilibili.com/video/BV1VS…

文章详情

和之前一样,需要在 router.go 中配置。

e-book-website/router/router.go

func Router() {
   http.HandleFunc("/p/", views.HTML.Detail)
}

通过 common.Template 加载页面

e-book-website/views/post.go

func (*HTMLApi) Detail(w http.ResponseWriter, r *http.Request) {
   detail := common.Template.Detail

   path := r.URL.Path
   pIdStr := strings.TrimPrefix(path, "/p/")
   pIdStr = strings.TrimSuffix(pIdStr, ".html")
   pid, err := strconv.Atoi(pIdStr)
   if err != nil {
      detail.WriteError(w, errors.New("不识别此请求路径"))
      return
   }
   // 根据 URL 的 id,获取文章详情
   postRes, err := service.GetPostDetail(pid)
   if err != nil {
      detail.WriteError(w, errors.New("查询出错"))
      return
   }
   detail.WriteData(w, postRes)
}

e-book-website/service/post.go

根据 id,获取文章详情

func GetPostDetail(pid int) (*models.PostRes, error) {
   post, err := databases.GetPostById(pid)
}

e-book-website/databases/post.go

func GetPostById(pid int) (*models.Post, error) {
   post := &models.Post{}
   row := DB.QueryRow("select * from post where pid=?", pid)
   if row.Err() != nil {
      return post, row.Err()
   }
   err := row.Scan(
      &post.Pid,
      &post.Title,
      &post.Content,
      &post.Markdown,
      &post.CategoryId,
      &post.UserId,
      &post.ViewCount,
      &post.Type,
      &post.Slug,
      &post.CreateAt,
      &post.UpdateAt,
   )
   if err != nil {
      return post, row.Err()
   }
   return post, nil
}

返回的数据中包含分类名称和用户名称,因此需要调用之前写的 GetCategoryNameByIdGetUserNameById

func GetPostDetail(pid int) (*models.PostRes, error) {
   post, err := databases.GetPostById(pid)
   if err != nil {
      return nil, err
   }
   categoryName := databases.GetCategoryNameById(post.CategoryId)
   userName := databases.GetUserNameById(post.UserId)
   postMore := models.PostMore{
      post.Pid,
      post.Title,
      post.Slug,
      template.HTML(post.Content),
      post.CategoryId,
      categoryName,
      post.UserId,
      userName,
      post.ViewCount,
      post.Type,
      models.DateDay(post.CreateAt),
      models.DateDay(post.UpdateAt),
   }
   var postRes = &models.PostRes{
      config.Cfg.Viewer,
      config.Cfg.System,
      postMore,
   }
   return postRes, nil
}

重启,刷新页面。

图片.png

文章评论

Valine - 一款快速、简洁且高效的无后端评论系统。

图片.png

注册并且实名认证之后,创建应用。

图片.png

在设置中,点击应用凭证,填入 config.yaml 中。

图片.png

重启项目,就可以评论了。

写文章

一样的步骤

渲染 HTML

func Router() {
   http.HandleFunc("/writing", views.HTML.Writing)
}

e-book-website/views/Writing.go

func (*HTMLApi) Writing(w http.ResponseWriter, r *http.Request) {
   writing := common.Template.Writing
   wr := service.Writing()
   writing.WriteData(w, wr)
}

e-book-website/service/post.go

func Writing() (wr models.WritingRes) {
   wr.Title = config.Cfg.Viewer.Title
   wr.CdnURL = config.Cfg.System.CdnURL
   category, err := databases.GetAllCategory()
   if err != nil {
      log.Println(err)
      return
   }
   wr.Categorys = category
   return
}

重启项目,刷新页面

图片.png

发布文章

http.HandleFunc("/api/v1/post", api.API.SaveAndUpdatePost)

在发布之前,应该验证当前用户是否处于登录状态。

e-book-website/utils/jwt.go

func ParseToken(tokenStr string) (*gojwt.Token, *Claims, error) {
   claims := &Claims{}
   token, err := gojwt.ParseWithClaims(tokenStr, claims, func(t *gojwt.Token) (interface{}, error) {
      return jwtKey, nil
   })
   if err != nil {
      return nil, nil, err
   }
   return token, claims, err
}

token 验证通过之后,拿到用户的 id。

func (*Api) SaveAndUpdatePost(w http.ResponseWriter, r *http.Request) {
   token := r.Header.Get("Authorization")
   _, claim, err := utils.ParseToken(token)
   if err != nil {
      log.Println("登录已过期")
      return
   }
   uid := claim.Uid
}

通过 GetRequestJsonParam 方法获取 post 传递过来的参数。将传递过来的参数,通过 DB.Exec 保存在数据库中。

e-book-website/databases/post.go

func SavePost(post *models.Post) {
   ret, err := DB.Exec("insert into post "+
      "(title,content,markdown,categoryId,userId,viewCount,type,slug,create_at,update_at) "+
      "values(?,?,?,?,?,?,?,?,?,?)",
      post.Title,
      post.Content,
      post.Markdown,
      post.CategoryId,
      post.UserId,
      post.ViewCount,
      post.Type,
      post.Slug,
      post.CreateAt,
      post.UpdateAt,
   )
   if err != nil {
      log.Println(err)
   }
   pid, _ := ret.LastInsertId()
   post.Pid = int(pid)
}

e-book-website/service/post.go

func SavePost(post *models.Post) {
   databases.SavePost(post)
}

e-book-website/api/post.go

func (*Api) SaveAndUpdatePost(w http.ResponseWriter, r *http.Request) {
   //获取用户id,判断用户是否登录
   token := r.Header.Get("Authorization")
   _, claim, err := utils.ParseToken(token)
   if err != nil {
      log.Println("登录已过期")
      return
   }
   uid := claim.Uid
   //POST  save
   method := r.Method
   switch method {
   case http.MethodPost:
      params := common.GetRequestJsonParam(r)
      cId := params["categoryId"].(string)
      categoryId, _ := strconv.Atoi(cId)
      content := params["content"].(string)
      markdown := params["markdown"].(string)
      slug := params["slug"].(string)
      title := params["title"].(string)
      postType := params["type"].(float64)
      pType := int(postType)
      post := &models.Post{
         -1,
         title,
         slug,
         content,
         markdown,
         categoryId,
         uid,
         0,
         pType,
         time.Now(),
         time.Now(),
      }
      service.SavePost(post)
      common.Success(w, post)
   }
}

重启项目,添加文字内容,点击发布,完美 <( ̄▽ ̄)/咩哈哈

编辑文章

编辑就是根据文章ID获取文章,返回前端 + 用户修改过的内容,根据 ID,重新写入数据库。

http.HandleFunc("/api/v1/post/", api.API.GetPost)

e-book-website/api/post.go

func (*Api) GetPost(w http.ResponseWriter, r *http.Request) {
   path := r.URL.Path
   pIdStr := strings.TrimPrefix(path, "/api/v1/post/")
   pid, err := strconv.Atoi(pIdStr)
   if err != nil {
      log.Println("不识别此请求路径")
      return
   }
   post, err := databases.GetPostById(pid)
   if err != nil {
      log.Println(err)
      return
   }
   common.Success(w, post)
}

e-book-website/api/post.go

func (*Api) SaveAndUpdatePost(w http.ResponseWriter, r *http.Request) {
   // ....
   switch method {
   case http.MethodPost:
      // ...
   case http.MethodPut:
      // update
      params := common.GetRequestJsonParam(r)
      cId := params["categoryId"].(float64)
      categoryId := int(cId)
      content := params["content"].(string)
      markdown := params["markdown"].(string)
      slug := params["slug"].(string)
      title := params["title"].(string)
      postType := params["type"].(float64)
      pidFloat := params["pid"].(float64)
      pType := int(postType)
      pid := int(pidFloat)
      post := &models.Post{
         pid,
         title,
         slug,
         content,
         markdown,
         categoryId,
         uid,
         0,
         pType,
         time.Now(),
         time.Now(),
      }
      service.UpdatePost(post)
      common.Success(w, post)
   }
}

e-book-website/service/post.go

func UpdatePost(post *models.Post) {
   databases.UpdatePost(post)
}

e-book-website/databases/post.go

func UpdatePost(post *models.Post) {
   _, err := DB.Exec("update post set title=?,content=?,markdown=?,categoryId=?,type=?,slug=?,update_at=? where pid=?",
      post.Title,
      post.Content,
      post.Markdown,
      post.CategoryId,
      post.Type,
      post.Slug,
      post.UpdateAt,
      post.Pid,
   )
   if err != nil {
      log.Println(err)
   }
}

一样的操作,重启项目,编辑文章。