🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### GoWeb开发实战Gin框架】微博项目实战-首页设计 # 首页设计 我们的想法是点击首页,就会自动查询数据库,显示文章。如果文章较多,我们可以实现分页。 ## 一、查询文章功能 ### 1.1 Controller 我们首先修改home\_controller.go文件,在Get()方法中,先查询所有的文章,并显示到页面上。因为文章可能很多,为了更好的用户体验,我们需要分页查询。默认查询第一页。 ~~~go func HomeGet(c *gin.Context) { //获取session,判断用户是否登录 islogin := GetSession(c) page := 1 var artList []models.Article artList, _ = models.FindArticleWithPage(page) html := models.MakeHomeBlocks(artList, islogin) c.HTML(http.StatusOK, "home.html", gin.H{"IsLogin": islogin, "Content": html}) } ~~~ ### 1.2 Model 先创建一个目录config,里面用来存储配置文件conf.go: ~~~go package config // 定义查询文章,每页显示的文章量 const NUM = 4 ~~~ 现在我们现在article\_model.go文件中,添加文章的查询,而且要分页查询: ~~~go //-----------查询文章--------- //根据页码查询文章 func FindArticleWithPage(page int) ([]Article, error) { page-- fmt.Println("---------->page", page) //从配置文件中获取每页的文章数量 return QueryArticleWithPage(page, config.NUM) } /** 分页查询数据库 limit分页查询语句, 语法:limit m,n m代表从多少位开始获取,与id值无关 n代表获取多少条数据 注意limit前面咩有where */ func QueryArticleWithPage(page, num int) ([]Article, error) { sql := fmt.Sprintf("limit %d,%d", page*num, num) return QueryArticlesWithCon(sql) } func QueryArticlesWithCon(sql string) ([]Article, error) { sql = "select id,title,tags,short,content,author,createtime from article " + sql rows, err := database.QueryDB(sql) if err != nil { return nil, err } var artList []Article for rows.Next() { id := 0 title := "" tags := "" short := "" content := "" author := "" var createtime int64 createtime = 0 rows.Scan(&id, &title, &tags, &short, &content, &author, &createtime) art := Article{id, title, tags, short, content, author, createtime} artList = append(artList, art) } return artList, nil } ~~~ 在models目录下创建一个go文件,用来控制首页显示内容: ~~~go type HomeBlockParam struct { Id int Title string Tags [] TagLink Short string Content string Author string CreateTime string //查看文章的地址 Link string //修改文章的地址 UpdateLink string DeleteLink string //记录是否登录 IsLogin bool } type TagLink struct { TagName string TagUrl string } ~~~ 我们需要将从数据库中查询出来的数据,转为对应的结构体对象,所以先设计结构体,这里我们需要考虑如果用户是登录状态,那么是可以修改或删除某一篇文章。当然,如果没有登录,那么只能查看。所以在设计结构体的时候,我们直接创建了修改和删除的链接字段。 接下来,我们添加一个方法,用于将文章中的内容,显示到页面上: ~~~go //----------首页显示内容--------- func MakeHomeBlocks(articles []Article, isLogin bool) template.HTML { htmlHome := "" for _, art := range articles { //将数据库model转换为首页模板所需要的model homeParam := HomeBlockParam{} homeParam.Id = art.Id homeParam.Title = art.Title homeParam.Tags = createTagsLinks(art.Tags) fmt.Println("tag-->", art.Tags) homeParam.Short = art.Short homeParam.Content = art.Content homeParam.Author = art.Author homeParam.CreateTime = utils.SwitchTimeStampToData(art.Createtime) homeParam.Link = "/show/" + strconv.Itoa(art.Id) homeParam.UpdateLink = "/article/update?id=" + strconv.Itoa(art.Id) homeParam.DeleteLink = "/article/delete?id=" + strconv.Itoa(art.Id) homeParam.IsLogin = isLogin //处理变量 //ParseFile解析该文件,用于插入变量 t, _ := template.ParseFiles("views/home_block.html") buffer := bytes.Buffer{} //就是将html文件里面的比那两替换为穿进去的数据 t.Execute(&buffer, homeParam) htmlHome += buffer.String() } fmt.Println("htmlHome-->",htmlHome) return template.HTML(htmlHome) } ~~~ 额外还需要一个方法: ~~~go //将tags字符串转化成首页模板所需要的数据结构 func createTagsLinks(tags string) []TagLink { var tagLink [] TagLink tagsPamar := strings.Split(tags, "&") for _, tag := range tagsPamar { tagLink = append(tagLink, TagLink{tag, "/?tag=" + tag}) } return tagLink } ~~~ ### 1.3 View 接下来我们设计一下页面,刚刚在model的MakeHomeBlocks()方法中,就是需要使用模板填充格式化html页面内容,所以我们在views目录下再创建一个html页面:home\_block.html,内容如下: ~~~html <div id="home-block-item"> <h2><a href="{{.Link}}">{{.Title}}</a></h2> <div> <span>{{.CreateTime}}</span> <span> {{range .Tags}} <a href="{{.TagUrl}}">&nbsp{{.TagName}}</a> {{end}} </span> </div> <p><a href={{.Link}}>{{.Short}}</a></p> {{if .IsLogin}} <div class="home-block-item-udpate"> <a href='javascript:if(confirm("确定删除吗?")){location="{{.DeleteLink}}"}'>删除</a> <a href={{.UpdateLink}}>修改</a> </div> {{end}} </div> ~~~ 我们现实了从数据中查询出的文章的数据,如果用户是登录状态,那么我们现实删除和修改,因为用户有这两个权限,否则就不显示。 ### 1.4 运行 我们在数据库中插入10条数据: ![gin_db11](http://image.chaindesk.cn/gin_db11.png/mark) 接下来我们设置一下配置文件,每页显示6条(也可以8条,10条。。), 修改config目录下的conf.go文件: ~~~go package config // 定义查询文章,每页显示的文章量 const NUM = 6 ~~~ 然后启动项目,打开浏览器输入网址:[http://127.0.0.1:8081/](http://127.0.0.1:8081/) ![gin_yunxing55](http://image.chaindesk.cn/gin_yunxing55.png/mark) 用户虽然没有登录,但是也是可以查看的,接下来我们点击登录按钮进行登录: ![gin_yunxing56](http://image.chaindesk.cn/gin_yunxing56.png/mark) 登录后,用户就可以有删除和修改的功能了。 ## 二、分页功能 截止,我们已经已经能够显示出第一页的内容了,接下来我们添加上一页和下一页的功能。 ### 2.1 Model 首先在home\_model.go中添加一个分页的结构体对象: ~~~go type HomeFooterPageCode struct { HasPre bool HasNext bool ShowPage string PreLink string NextLink string } ~~~ 接下来添加方法: ~~~go //-----------翻页----------- //page是当前的页数 func ConfigHomeFooterPageCode(page int) HomeFooterPageCode { pageCode := HomeFooterPageCode{} //查询出总的条数 num := GetArticleRowsNum() //计算出总页数 allPageNum := (num-1)/config.NUM + 1 pageCode.ShowPage = fmt.Sprintf("%d/%d", page, allPageNum) //当前页数小于等于1,那么上一页的按钮不能点击 if page <= 1 { pageCode.HasPre = false } else { pageCode.HasPre = true } //当前页数大于等于总页数,那么下一页的按钮不能点击 if page >= allPageNum { pageCode.HasNext = false } else { pageCode.HasNext = true } pageCode.PreLink = "/?page=" + strconv.Itoa(page-1) pageCode.NextLink = "/?page=" + strconv.Itoa(page+1) return pageCode } ~~~ 这段代码需要查询出数据库中所有文章的总量,所以我们要先在article\_model.go文件中,加入查询总数据量的方法: ~~~go //------翻页------ //存储表的行数,只有自己可以更改,当文章新增或者删除时需要更新这个值 var artcileRowsNum = 0 //只有首次获取行数的时候采取统计表里的行数 func GetArticleRowsNum() int { if artcileRowsNum == 0 { artcileRowsNum = QueryArticleRowNum() } return artcileRowsNum } //查询文章的总条数 func QueryArticleRowNum() int { row := database.QueryRowDB("select count(id) from article") num := 0 row.Scan(&num) return num } ~~~ 我们还要考虑一个问题,就是当新增或删除文章的时候,数据总量会发生改变,所以还要修改增加文章的方法: 先新增一个方法用于设置总页数: ~~~go //设置页数 func SetArticleRowsNum(){ artcileRowsNum = QueryArticleRowNum() } ~~~ 然后修改增加文章的方法: ~~~go //---------添加文章----------- func AddArticle(article Article) (int64, error) { i, err := insertArticle(article) SetArticleRowsNum() return i, err } ~~~ ### 2.2 Controller 修改home\_controller.go的Get()方法: ~~~go func (this *HomeController) Get() { ... page, _ := strconv.Atoi(c.Query("page")) if page <= 0 { page = 1 } ... homeFooterPageCode:=models.ConfigHomeFooterPageCode(page) c.HTML(http.StatusOK, "home.html", gin.H{"IsLogin": islogin, "Content": html,"HasFooter":true,"PageCode":homeFooterPageCode}) ... } ~~~ ### 2.3 View 修改home.html页面: ~~~html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> <link href="../static/css/blogsheet.css" rel="stylesheet"> </head> <body> {{template "block/nav.html" .}} <div id="main"> {{.Content}} {{if .HasFooter}} <div id="home-footer"> <a {{if .PageCode.HasPre}}href="{{.PageCode.PreLink}}" {{else}} class="disable" {{end}}>上一页</a> <span>{{.PageCode.ShowPage}}页</span> <a {{if .PageCode.HasNext}}href="{{.PageCode.NextLink}}" {{else}} class="disable" {{end}}>下一页</a> </div> {{end}} </div> </body> </html> ~~~ 增添上一页,下一页的链接。 ### 2.4 运行 首先我们再向数据库中插入5条数据: ![gin_db12](http://image.chaindesk.cn/gin_db12.png/mark) 然后修改配置文件,每页显示5条。 ![gin_yunxing57](http://image.chaindesk.cn/gin_yunxing57.png/mark) 接下来,我们新增加一篇文章,点击写博客: ![web10_yunxing25](http://image.chaindesk.cn/web10_yunxing25.png/mark) 在添加标签的时候,通过&区分多个标签。然后点击提交按钮。 ![gin_yunxing65](http://image.chaindesk.cn/gin_yunxing65.png/mark) 最后一页显示为我们刚刚增加的一篇文章,截止到现在我们可以很完美的显示页码了。