内容介绍
本专题将带你使用 axum 实现一个简洁易用的博客系统应用骨架
本章我们将开始搭建本应用的骨架,包括:依赖、`Result` 和 `AppError` 以及通用数据库操作等。模板
我们的博客分为“前台”和“后台”两部分。前台用于展示博客内容,后台用于管理博客。本章我们将编写前台和后台的基础模板以及对应的路由。分类管理
本章开始,我们将对博客的具体业务进行实现。首先,我们实现博客分类的管理功能。文章管理
本章我们将实现博客的文章管理功能。鉴权与登录
本章实现后台管理的鉴权,以及管理员的登录、注销功能。涉及的知识点有:cookie及中间件等。后台管理菜单及首页模板
目前,后台管理功能基本完成,但还有两个工作没做:清理后台管理的导航菜单以及后台管理首页的模板。网站首页
后台管理完成后,我们开始进入前台功能的开发。本章我们将完成博客首页的开发。分类文章列表
本章将实现博客的分类文章列表功能。文章详情
本章将实现博客文章的详情显示功能。存档文章列表
本章将实现存档文章列表功能。注意,本章涉及较多PostgreSQL知识,如果你对相关知识不熟悉,可以先让代码跑起来,再去了解相关知识。总结与作业
恭喜你,已经完成了本专题的学习。下面我们对本专题进行简要的总结。
文章详情
- 543811
- 2022-03-26 16:21:46
本章将实现博客文章的详情显示功能。
数据库视图
CREATE VIEW v_topic_cat_detail AS
SELECT t.id, title, html, hit, dateline,category_id,t.is_del,
c.name AS category_name
FROM
topics AS t
INNER JOIN categories AS c
ON t.category_id=c.id
WHERE c.is_del = false
;
该视图和v_topic_cat_list
唯一不同的地方在于,它要的是topics
的html
字段。
数据模型
// src/model.rs
#[derive(PostgresMapper, Serialize)]
#[pg_mapper(table="v_topic_cat_detail")]
pub struct TopicDetail{
pub id:i64,
pub title: String,
pub category_id:i32,
pub html:String,
pub hit:i32,
pub dateline:time::SystemTime,
pub is_del:bool,
pub category_name:String,
}
impl TopicDetail {
pub fn dateline(&self) ->String {
dateline(self.dateline.clone())
}
}
fn dateline(dt:time::SystemTime) -> String {
let ts = dt.duration_since(time::UNIX_EPOCH).unwrap_or(time::Duration::from_secs(0)).as_secs() as i64;
Local.timestamp(ts, 0).format("%Y/%m/%d %H:%M:%S").to_string()
}
这里新增了 dateline()
函数,用于将时间以字符串的形式显示。为了代码重用,TopicList::dateline()
也重构为调用该函数
// src/model.rs
impl TopicList {
pub fn dateline(&self) ->String {
dateline(self.dateline.clone())
}
}
模板
视图类
文章详情的视图类位于src/view/frontend/topic.rs,请自行查看。
handler
topic::detail()
用于通过id获取文章详情。
数据库操作
pub async fn detail(client: &Client, id: i64) -> Result<TopicDetail> {
super::execute(client, "UPDATE topics SET hit=hit+1 WHERE id=$1", &[&id]).await ?;
let sql = "SELECT id,title,category_id,html,hit,dateline,is_del,category_name FROM v_topic_cat_detail WHERE is_del=false and id=$1 LIMIT 1";
super::query_row(client, sql, &[&id]).await
}
首先,使文章的浏览次数加1,然后返回文章的数据。
原因在于,我们需要返回的数据来自于视图,如果:
另外,此处不需要用事务,因为如果UPDATE
出错,那么整个函数都退出了(返回值是Err(AppError)
)——除非你把SELECT
写在UPDATE
前面。
路由
本章代码位于09/文章详情分支。