layui获得列表json数据_golang实战开发之博客功能篇:文章列表的读取与展示和分类筛选展示处理...

前面我们介绍了文章详情页面的展示的逻辑代码实现,这一节,我们将继续讲解文章列表的读取和展示、文章根据分类进行筛选、最新文章、热门文章等的调用处理逻辑。

首先,我们先编写文章列表页的前端代码。这里,我们文章采用类似WordPress博客的形式,直接将首页作为文章列表页面的展示。因此我们在template文件夹下创建index.html:

博客首页/文章列表html代码

{% include "partial/header.html" %}
<div class="layui-container index"><div class="layui-row layui-col-space15"><div class="layui-col-md8"><div class="layui-card"><div class="layui-card-body"><ul class="article-list">{% for item in articles %}<li class="item"><a href="/article/{{item.Id}}" class="link"><h5 class="title">{{item.Title}}</h5><div class="description">{{item.Description}}</div><div class="meta">{% if item.Category %}<span>{{item.Category.Title}}</span>{% endif %}<span>{{stampToDate(item.CreatedTime, "2006-01-02")}}</span><span>{{item.Views}} 阅读</span></div></a></li>{% endfor %}</ul></div>{% if prevPage || nextPage %}<div class="layui-card-body text-center"><div class="layui-box layui-laypage"><a href="{{prevPage}}" class="layui-laypage-prev{% if !prevPage %} layui-disabled{% endif %}">上一页</a><a href="{{nextPage}}" class="layui-laypage-next{% if !nextPage %} layui-disabled{% endif %}">下一页</a></div></div>{% endif %}</div></div><div class="layui-col-md4">{% include "partial/author.html" %}<div class="layui-card"><div class="layui-card-header">文章分类</div><div class="layui-card-body"><ul class="aside-list">{% for item in categories %}<li class="item"><a href="/?category_id={{item.Id}}" class="link"><h5 class="title">{{item.Title}}</h5></a></li>{% endfor %}</ul></div></div><div class="layui-card"><div class="layui-card-header">热门文章</div><div class="layui-card-body"><ul class="aside-list">{% for item in populars %}<li class="item"><a href="/article/{{item.Id}}" class="link"><h5 class="title">{{item.Title}}</h5><span class="extra">{{item.Views}}阅读</span></a></li>{% endfor %}</ul></div></div></div></div>
</div>
{% include "partial/footer.html" %}

列表页中,我们将页面分割成两栏,左边栏大约占2/3,右边栏大约占1/3。左边栏中为文章的列表、上下页信息。文章列表中,我们将展示包括文章标题、文章简介、文章分类、文章发布时间、文章浏览量等信息。右边栏中,用来展示分类列表、热门文章等内容。

左边显示的文章分类信息中,我们注意到显示文章分类使用的是{{item.Category.Title}},这是因为我们定义文章模型的时候,article.Category 它指向的是文章分类的模型,article.Category.Title 就能访问到文章分类的名称了。并且文章并不一定会存在分类,因此我们需要先判断分类是否存在{% if item.Category %}<span>{{item.Category.Title}}</span>{% endif %},即文章存在分类的时候,我们才输出分类信息。

同样,这里的文章发布时间,我们使用了{{stampToDate(article.CreatedTime, "2006-01-02")}}来显示。stampToDate是我们前面自定义的模板函数,它可以将时间戳按照给定的格式格式化输出。这里我们将文章发布的时间戳按照"2006-01-02"的格式来输出显示。

这里,我们还注意到,输出上下页信息的时候,先判断是否存在上下页{% if prevPage || nextPage %} ... {% endif %},只要上一页存在,或下一页存在,我们才输出上下页的标签,否则这一整块都不显示。当这一块显示的时候,如果没有上一页,则上一页按钮不可点击{% if !prevPage %} layui-disabled{% endif %},同样,没有下一页的时候,下一页按钮也不能点击{% if !nextPage %} layui-disabled{% endif %}

博客首页/文章列表控制器函数

文章博客首页/文章列表页面控制器我们写在controller/index.go index.go中修改IndexPage()函数:

func IndexPage(ctx iris.Context) {currentPage := ctx.URLParamIntDefault("page", 1)categoryId := uint(ctx.URLParamIntDefault("category_id", 0))//一页显示10条pageSize := 10//文章列表articles, total, _ := provider.GetArticleList(categoryId, "id desc", currentPage, pageSize)//读取列表的分类categories, _ := provider.GetCategories()for i, v := range articles {if v.CategoryId > 0 {for _, c := range categories {if c.Id == v.CategoryId {articles[i].Category = c}}}}//热门文章populars, _, _ := provider.GetArticleList(categoryId, "views desc", 1, 10)totalPage := math.Ceil(float64(total)/float64(pageSize))prevPage := ""nextPage := ""urlPfx := "/?"var category *model.Categoryif categoryId > 0 {urlPfx += fmt.Sprintf("category_id=%d&", categoryId)category, _ = provider.GetCategoryById(categoryId)}if currentPage > 1 {prevPage = fmt.Sprintf("%spage=%d", urlPfx, currentPage-1)}if currentPage < int(totalPage) {nextPage = fmt.Sprintf("%spage=%d", urlPfx, currentPage+1)}if currentPage == 2 {prevPage = strings.TrimRight(prevPage, "page=1")}ctx.ViewData("total", total)ctx.ViewData("articles", articles)ctx.ViewData("populars", populars)ctx.ViewData("totalPage", totalPage)ctx.ViewData("prevPage", prevPage)ctx.ViewData("nextPage", nextPage)ctx.ViewData("category", category)ctx.View("index.html")
}

在首页文章列表控制器中,我们需要从url中获取两个参数,一个是当前页面的页码currentPage := ctx.URLParamIntDefault("page", 1),另一个是当前页面的分类idcategoryId := uint(ctx.URLParamIntDefault("category_id", 0))。这里我们都是获取的int类型的数据,并且在没有获取到数据的时候,使用默认值来代替,因此我们使用了URLParamIntDefault方法。

我们每页显示10条,可以让列表页面差不多维持在2屏到2屏半左右的高度。pageSize := 10

接着就是读取根据条件读取文章列表了articles, total, _ := provider.GetArticleList(categoryId, "id desc", currentPage, pageSize)。我们在 provider/article.go 中,增加GetArticleList函数:

func GetArticleList(categoryId uint, order string, currentPage int, pageSize int) ([]*model.Article, int64, error) {var articles []*model.Articleoffset := (currentPage - 1) * pageSizevar total int64builder := config.DB.Model(model.Article{})if categoryId > 0 {builder = builder.Where("`category_id` = ?", categoryId)}if order != "" {builder = builder.Order(order)}if err := builder.Count(&total).Limit(pageSize).Offset(offset).Find(&articles).Error; err != nil {return nil, 0, err}return articles, total, nil
}

获取文章列表函数接收4个参数:

  • categoryId 是分类id,如果指定分类id,则只显示当前分类的文章列表。
  • order 是排序规则,传入order参数可以根据指定的字段规则进行排序,如id desc则表示按id倒序来显示。
  • currentPage 是当前读取的页数,这个参数一般由url参数中获取。
  • pageSize 是一页显示数量,这里我们默认显示10条。

这里面我们通过当前页码和每页显示数量来计算出mysql的offsetoffset := (currentPage - 1) * pageSize

再通过判断categoryId是否大于零来确定是否传入了分类id,如果有分类id,则添加分类id的条件builder = builder.Where("category_id= ?", categoryId)

如果传入了order排序规则,则添加order条件builder = builder.Order(order)

因为这是列表的展示,因此我们还需获取所有符合条件的文章数量,用来计算分页数量和分页展示信息var total int64

最后将文章列表、符合条件的文章数量、错误信息返回给控制器。

接着我们继续读取所有的分类,用来将分类赋值给文章列表中的文章:

categories, _ := provider.GetCategories()
for i, v := range articles {if v.CategoryId > 0 {for _, c := range categories {if c.Id == v.CategoryId {articles[i].Category = c}}}
}

同样地,我们需要获取所有分类,也需要在 provider/category.go 中添加GetCategories函数:

func GetCategories() ([]*model.Category, error) {var categories []*model.Categorydb := config.DBerr := db.Where("`status` = ?", 1).Find(&categories).Errorif err != nil {return nil, err}return categories, nil
}

我们只读取status = 1的分类,因为我们开始的时候,定义了status为1 表示正常的数据,status为0表示审核的数据,status为99表示已删除的数据。我们在处理数据的时候,不采取直接删除的方式,这么做是为了防止手误等各种意外操作,造成数据误删而没有恢复的机会。

首页列表中,我们在右边栏中,显示了热门文章。这里我们将浏览量最多的文章认为是热门文章。

populars, _, _ := provider.GetArticleList(categoryId, "views desc", 1, 10)

同样地,热门文章我们也使用GetArticleList函数来获取数据,我们只需要将排序规则views desc传入即可得到浏览量最多的文章。这里我们不需要读取分页,也不需要获取符合条件的数量,因此我们使用populars, _, _来接收数据,只保留文章列表,存入populars变量中,其他变量忽略,使用下划线_表示。

接着我们通过计算,算出是否有上一页、下一页,以及根据条件拼接上一页、下一页的连接。

prevPage := ""nextPage := ""urlPfx := "/?"var category *model.Categoryif categoryId > 0 {urlPfx += fmt.Sprintf("category_id=%d&", categoryId)category, _ = provider.GetCategoryById(categoryId)}if currentPage > 1 {prevPage = fmt.Sprintf("%spage=%d", urlPfx, currentPage-1)}if currentPage < int(totalPage) {nextPage = fmt.Sprintf("%spage=%d", urlPfx, currentPage+1)}if currentPage == 2 {prevPage = strings.TrimRight(prevPage, "page=1")}

最后,将页面需要使用的变量,都注入到view中,供前端使用,并指定前端页面模板:

ctx.ViewData("total", total)
ctx.ViewData("articles", articles)
ctx.ViewData("populars", populars)
ctx.ViewData("totalPage", totalPage)
ctx.ViewData("prevPage", prevPage)
ctx.ViewData("nextPage", nextPage)
ctx.ViewData("category", category)ctx.View("index.html")

配置首页文章列表页面路由

首页的路由,在一开始的时候,我们便已经配置过了,因此在这里我们不需要再次配置。它在route/route.go 中,我们给路由增加是否登录判断中间件:

app.Get("/", controller.Inspect, controller.IndexPage)

至此,我们的首页文章列表已经完成。我们的首页列表具有了分页功能,也能根据分类来筛选显示文章了。

验证结果

我们重启一下项目,我们先在浏览器中访问http://127.0.0.1:8001/来看看效果。如果不出意外可以看到这样的画面:

3a8b50325af6d04e7da88886345a8faf.png

教程用例源码

完整的项目示例代码托管在GitHub上,访问github.com/fesiong/goblog 可以查看完整的教程项目源代码,建议在查看教程的同时,认真对照源码,可以有效提高码代码速度和加深对博客项目的认识。建议直接fork一份来在上面做修改。欢迎点Star。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/523521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“智企云中享“,首届SAP中国云大会召开

2019 年 6 月 5 日&#xff0c;上海讯— 今日&#xff0c;首届SAP云大会在上海盛大召开。作为SAP云计算家族在中国的首秀&#xff0c;大会全面呈现了SAP云业务的战略、产品、商业场景、浸入式体验。作为体验管理领域的领导者&#xff0c;SAP以覆盖企业运营全价值链的云服务解决…

SpringBoot入门到精通_第7篇 _必知必会总结

接上一篇&#xff1a;SpringBoot入门到精通_第6篇 _必知必会

容器精华问答 | 如何进行跨机器的Container做Link ?

戳蓝字“CSDN云计算”关注我们哦&#xff01;云计算的发展日新月异&#xff0c;新技术层出不穷&#xff0c;尤其容器技术自2013年Docker容器问世以来一路高歌猛进红遍大江南北&#xff0c;与虚拟机相比&#xff0c;容器更显优势&#xff0c;有着更轻量、更快捷、占用资源更少&a…

腾讯也有“神盾局”?秀出“技术肌肉”就靠TA了……

戳蓝字“CSDN云计算”关注我们哦&#xff01;技术头条&#xff1a;干货、简洁、多维全面。更多云计算精华知识尽在眼前&#xff0c;get要点、solve难题&#xff0c;统统不在话下&#xff01;漫威的超级英雄世界中&#xff0c;“神盾局”一直凭借着不少的先进武器装备&#xff0…

大话云存储,这个“对象”可能无处不在

戳蓝字“CSDN云计算”关注我们哦&#xff01;文 | pasca来源 | 蛋蛋团&#xff08;ID&#xff1a;dandan_tuan&#xff09;大纲前言1、Who&#xff1a;谁使用对象存储2、What&#xff1a;对象存储是什么3、Why&#xff1a;为什么他们会使用对象存储4、how to do:应用场景分析5、…

振奋!中国正式进入5G元年;华为5G俄罗斯签下大单;王坚进入工程院院士第二轮评审...

戳蓝字“CSDN云计算”关注我们哦&#xff01;嗨&#xff0c;大家好&#xff0c;重磅君带来的【云重磅】特别栏目&#xff0c;如期而至&#xff0c;每周五第一时间为大家带来重磅新闻。把握技术风向标&#xff0c;了解行业应用与实践&#xff0c;就交给我重磅君吧&#xff01;重…

企业实战_01_Redis下载/安装/运行/停止

文章目录一、Redis下载&#xff1a;官方&#xff1a;https://redis.io/二、Redis安装&#xff1a;2.1. 上传redis软件服务器2.2. 解压redis2.3. 进入redis目录&#xff0c;进行redis安装2.4. 执行redis安装测试&#xff1a;2.5. 安装异常处理三、redis 启动、停止3.1. 进入src目…

关于5G,你必须知道的事儿……

戳蓝字“CSDN云计算”关注我们哦&#xff01;文 | 小枣君来源 | 鲜枣课堂什么是5G 5G&#xff0c;就是5th Generation Mobile Networks&#xff08;第五代移动通信网络&#xff09;&#xff0c;也可以称为5th Generation Wireless Systems&#xff08;第五代无线通信系统&a…

java管理员登录_idea实现管理员登录javaweb

mysql创建db_0106数据库&#xff0c;创建表添加一条数据&#xff0c;id int自增&#xff0c;密码&#xff1a;为MD5加密insert into tb_sys values(null,admin,MD5(123),"系统管理员");项目目录结构com.isoft.db包下db.properties文件mysql.drivercom.mysql.jdbc.Dri…

linux环境下redis5.0的安装配置

文章目录一、Redis介绍&#xff1a;二、安装Redis2.1. 下载 解压 进入文件夹 然后 编译2.2. 启动Redis2.2.1. 指定配置文件启动redis2.2.2. 配置redis后台启动三. 登录验证一、Redis介绍&#xff1a; Redis是当前比较热门的NOSQL系统之一&#xff0c;它是一个key-value存储系统…

漫话:如何给女朋友解释什么是编译与反编译

戳蓝字“CSDN云计算”关注我们哦&#xff01;来源 | 漫话编程某天下班后&#xff0c;我在家里进行电话面试&#xff0c;问到面试者这样一个问题&#xff1a;"你知道使用哪些办法可以反编译Java代码吗&#xff1f;"。但是面试者回答的并不好&#xff0c;所以我在面试评…

企业实战_02_Redis基础

接上一篇&#xff1a;企业实战_01_Redis下载/安装/运行/停止https://blog.csdn.net/weixin_40816738/article/details/99198062 Redis小知识&#xff1a; 向服务器发送命令 ①redis-cli连上redis服务器后&#xff0c;可以在命令行发送指令&#xff1b; ②ping&#xff0c;测试…

Python 爬取 42 年高考数据,告诉你高考为什么这么

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 徐麟责编 | 伍杏玲封图 | CSDN付费下载于东方IC对于像作者一样已经工作的“上班族”来说&#xff0c;6月7号到9号三天无疑是兴奋到飞起的&#xff0c;终于迎来了令人愉悦的端午假期&#xff1a;然而有那么一群人&#xff0c;…

windows下载、安装运行redis

https://github.com/microsoftarchive/redis/ redis的配置文件&#xff1a; redis.windows.conf

java读取excel某个单元格的值_[转载]Java读取Excel中的单元格数据

目前网上能找到的读取Excel表格中数据的两种比较好的方案&#xff1a;PageOffice好用开发效率高&#xff1b;POI免费。供大家参考&#xff0c;针对具体情况选择具体方案。1. PageOffice读取excelimport com.zhuozhengsoft.pageoffice.*;import com.zhuozhengsoft.pageoffice.ex…

【五分钟】看完一道有装逼解法的算法题

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者 | 程序员小吴来源 | 五分钟学算法题目来源于 LeetCode 上第 342 号问题&#xff1a;4 的幂。题目难度为 Easy&#xff0c;目前通过率为 45.3% 。题目描述给定一个整数 (32 位有符号整数)&#xff0c;请编写一个函数来判断它是否…

企业实战_03_Redis基础命令

接上一篇&#xff1a;企业实战_02_Redis基础 https://blog.csdn.net/weixin_40816738/article/details/99204244 先启动redis服务端&#xff0c;在启动redis客户端 说明命令info查看系统信息ping测试连通性dbsizekey数量keys *查看所有的keyselect 1切换到键空间(keyspace1)…

Docker精华问答 | Docker commit如何用?

Docker 是个划时代的开源项目&#xff0c;它彻底释放了计算虚拟化的威力&#xff0c;极大提高了应用的维护效率&#xff0c;降低了云计算应用开发的成本&#xff01;使用 Docker&#xff0c;可以让应用的部署、测试和分发都变得前所未有的高效和轻松&#xff01;1Q&#xff1a;…

java channel源码_Netty 4.0 源码分析(三):Channel和ChannelPipeline

Client和server通过Channel连接&#xff0c;然后通过ByteBuf进行传输。每个Channel有自己的Pipeline&#xff0c;Pipeline上面可以添加和定义Handler和Event。Channel类1 package io.netty.channel;2 import io.netty.buffer.ByteBuf;3 import io.netty.buffer.MessageBuf;4 im…