博客功能篇:文章详情展示浏览与记录浏览量方式

上一节,我们完成了文章的发布功能和图片上传功能,但是还没有将文章展示出来。这一节我们来介绍如何展示文章和增加浏览量计数问题。

文章详情页面html代码

{% include "partial/header.html" %}
<div>
<div>
<div>
<div>
<div>
<h1>{{article.Title}}</h1>
<div>
{% if article.Category %}<span><a href="https://www.tuicool.com/?category_id={{article.CategoryId}}">{{article.Category.Title}}</a></span>{% endif %}
<span>{{stampToDate(article.CreatedTime, "2006-01-02")}}</span>
<span>{{article.Views}} 阅读</span>
</div>
<div>
{{article.ArticleData.Content|safe}}
</div>
</div>
</div>
<div>
<div>
<div>
{% if prev %}
<li>上一篇:<a href="https://www.tuicool.com/article/{{prev.Id}}">{{prev.Title}}</a></li>
{% endif %}
{% if next %}
<li>下一篇:<a href="https://www.tuicool.com/article/{{next.Id}}">{{next.Title}}</a></li>
{% endif %}
</div>
</div>
</div>
</div>
<div>
{% include "partial/author.html" %}
</div>
</div>
</div>
{% include "partial/footer.html" %}
复制代码

文章详情页面我们采用左右结构,左边显示文章标题、文章内容,上下篇文章等主要信息。右边则显示跟文章相关的最新文章、相关文章等内容。

左边显示的信息中,我们注意到显示文章分类使用的是 {{article.Category.Title}} ,这是因为我们定义文章模型的时候,article.Category 它指向的是文章分类的模型,article.Category.Title 就能访问到文章分类的名称了。

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

文章内容的输出我们使用标签 {{article.ArticleData.Content|safe}} 。这里同样地,article.ArticleData 指向的是文章内容表article_data模型,通过article.ArticleData.Content可以读取到文章的内容。这里我们使用了模板语言的|safe过滤标签,如果我们不使用safe标签的话,模板解析的时候,是为了安全,会对HTML标签和JS等语法标签进行自动转义,防止xss攻击。转义后,它就不是html了,这样不符合我们文章富文本内容输出的要求,因此这里我们需要使用safe来阻止它自动转义。

文章详情页控制器函数

文章详情页控制器我们写在controller/article.go 中。我们在article.go中添加 ArticleDetail() 函数:

func ArticleDetail(ctx iris.Context) {
id := ctx.Params().GetUintDefault("id", 0)
article, err := provider.GetArticleById(id)
if err != nil {
NotFound(ctx)
return
}
_ = article.AddViews(config.DB)
ctx.ViewData("article", article)
ctx.View("article/detail.html")
}
复制代码

这个函数,首先通过 ctx.Params().GetUintDefault() 来获取文章的id,我们根据文章id来读取文章,如果文章不存在,则使用 NotFound() 函数,输出404错误。检查完文章后,我们再使用 ctx.ViewData("article", article) 将article注入到模板中,这样模板就能使用article这个变量了。然后通过 ctx.View("article/detail.html") 来将控制器和文章详情模板关联起来。

这里我们使用了 provider.GetArticleById(id) ,这个函数是需要访问数据库读取文章内容的,因此我们将它抽离到provider目录中。我们打开provider/article.go,在里面添加 GetArticleById() 函数:

func GetArticleById(id uint) (*model.Article, error) {
var article model.Article
db := config.DB
err := db.Where("`id` = ?", id).Preload("ArticleData").First(&article).Error
if err != nil {
return nil, err
}
//加载分类
db.Where("`id` = ?", article.CategoryId).First(&article.Category)
return &article, nil
}
复制代码

这里我们从数据库根据文章id读取article信息的时候,先使用 Preload("ArticleData") 来将文章的内容表信息也关联的读进来。

我们设置article模型的时候,category不是和文章表通过外键关联,因此我们需要单独将文章分类加载进来。

增加文章访问量

上面我们在用户访问到文章详情页的时候,使用了 _ = article.AddViews(config.DB) 来增加文章的浏览量。这里为了直观,我们默认访问一次页面就当做增加一个浏览量。实际项目应用中,我们可能还需要根据用户的ip、ua来做处理,对搜索引擎的蜘蛛做区别处理,也要做访问记录等信息,而不是单纯的累加。

上面我们使用的是 article.AddViews() ,说明这是一个文章模型的内置方法,因此我们在model/article.go 中,增加 AddViews() 方法:

func (article *Article) AddViews(db *gorm.DB) error {
article.Views = article.Views + 1
db.Model(Article{}).Where("`id` = ?", article.Id).Update("views", article.Views)
return nil
}
复制代码

这里我们需要由上层传入db对象。因此db对象是在config中的,如果我们在model中直接访问config,就会导致嵌套依赖,会导致golang项目编译不通过。而我们这里更新文章浏览量使用的是Update函数,Update函数可以直接更新对应字段,而不会在更新后再次读取表信息,可以减少一次查询操作。

配置文章详情页面路由

上面文章详情页面准备好了,我们还需要添加文章路由,才能让用户访问到文章详情页面,我们在route/base.go 中的article分组下,添加 article.Get("/{id:uint}", controller.ArticleDetail) ,最终article分组的代码如下:

article := app.Party("/article", controller.Inspect)
{
article.Get("/{id:uint}", controller.ArticleDetail)
article.Get("/publish", controller.ArticlePublish)
article.Post("/publish", controller.ArticlePublishForm)
}
复制代码

这里我们使用了 {id:uint} 来获取文章id。这里我们定义id的类型为无符号整形数字。这么定义后,在文章详情控制器中可以通过 id := ctx.Params().GetUintDefault("id", 0) 来获取。

验证结果

我们重启一下项目,我们先在浏览器中访问 http://127.0.0.1:8001/article/1 来看看效果,验证下文章发布过程是否正常。如果不出意外可以看到这样的画面:

完整的项目示例代码托管在GitHub上,需要查看完整的项目代码可以到 github.com/fesiong/gob… 上查看,也可以直接fork一份来在上面做修改。

稀土掘金
我还没有学会写个人说明!
上一篇

中国首个mRNA新冠疫苗生产车间奠基 一期可年产1.2亿剂

下一篇

来就免费送:Epic游戏商店第二轮节日福利列表曝光

你也可能喜欢

评论已经被关闭。

插入图片