内容介绍
本专题将带你使用 axum 实现一个简洁易用的博客系统应用骨架
本章我们将开始搭建本应用的骨架,包括:依赖、`Result` 和 `AppError` 以及通用数据库操作等。模板
我们的博客分为“前台”和“后台”两部分。前台用于展示博客内容,后台用于管理博客。本章我们将编写前台和后台的基础模板以及对应的路由。分类管理
本章开始,我们将对博客的具体业务进行实现。首先,我们实现博客分类的管理功能。文章管理
本章我们将实现博客的文章管理功能。鉴权与登录
本章实现后台管理的鉴权,以及管理员的登录、注销功能。涉及的知识点有:cookie及中间件等。后台管理菜单及首页模板
目前,后台管理功能基本完成,但还有两个工作没做:清理后台管理的导航菜单以及后台管理首页的模板。网站首页
后台管理完成后,我们开始进入前台功能的开发。本章我们将完成博客首页的开发。分类文章列表
本章将实现博客的分类文章列表功能。文章详情
本章将实现博客文章的详情显示功能。存档文章列表
本章将实现存档文章列表功能。注意,本章涉及较多PostgreSQL知识,如果你对相关知识不熟悉,可以先让代码跑起来,再去了解相关知识。总结与作业
恭喜你,已经完成了本专题的学习。下面我们对本专题进行简要的总结。
网站首页
- 544258
- 2022-03-26 15:51:46
后台管理完成后,我们开始进入前台功能的开发。本章我们将完成博客首页的开发。
母模板
templates/frontend/base.html
是时候对前台母模板进行数据填充和块的定义了:
其中:
<nav class="nav d-flex justify-content-between">
{% for cat in cats %}
<a class="p-2 link-secondary" href="/category/{{cat.id}}">{{cat.name}}</a>
{%endfor%}
</nav>
用于将分类列表填充为头部导航,而
<ol class="list-unstyled mb-0">
{% for arch in archives %}
<li><a href="/archive/{{arch.dateline}}">{{arch.dateline}}</a></li>
{%endfor%}
</ol>
用于填充按月份为单位的存档。
其它块的定义之前章节已做过说明,此处略过。
首页模板
templates/frontend/index.html
{%extends "./base.html"%}
{%block category_name%}最新博文{%endblock%}
{% block content %}
{% for item in list.data %}
<article class="blog-post">
<h2 class="blog-post-title">
<a href="/topic/{{item.id}}">{{item.title}}</a>
</h2>
<p class="blog-post-meta">
<a href="https://axum.rs" target="_blank">AXUM.RS</a> 发表于 {{item.dateline()}} [<a href="/category/{{item.category_id}}">{{item.category_name}}</a>]
</p>
{{ item.summary }}
</article>
{%endfor%}
{% endblock %}
{% block paginate %}
{%include "../pagination.html"%}
{%endblock%}
其中 {% for item in list.data %}...{%endfor%}
用于填充文章列表。这个list
是一个 Paginate
分页对象。
视图类
// src/view/frontend/index.rs
#[derive(Template)]
#[template(path="frontend/index.html")]
pub struct Index {
pub list: Paginate<Vec<TopicList>>,
pub page : u32,
pub cats: Vec<Category>,
pub archives: Vec<TopicArchive>,
}
handler
// src/handler/frontend/index.rs
pub async fn index(
Extension(state):Extension<Arc<AppState>>,
Query(args):Query<Args>
)->Result<HtmlView> {
let page = args.page();
let handler_name = "frontend/index/index";
let client = get_client(&state).await.map_err(log_error(handler_name))?;
let list = topic::list(&client, page).await.map_err(log_error(handler_name))?;
let cats = category::list(&client).await.map_err(log_error(handler_name))?;
let archives = topic::archive_list(&client).await.map_err(log_error(handler_name))?;
let tmpl = Index{
list,
page,
cats,
archives,
};
render(tmpl).map_err(log_error(handler_name))
}
Args
:前台页面所需要的参数,请参见下文的“Args”部分。topic::archive_list()
:根据已发表的文章获取按月存档的日期列表。详情请见下文的“数据库操作”部分。
数据库操作
// src/db/topic.rs
pub async fn archive_list(client: &Client) -> Result<Vec<TopicArchive>> {
let sql = "SELECT
to_char(DATE_TRUNC('month',dateline), 'YYYY年MM月')
AS dateline
FROM topics
GROUP BY to_char(DATE_TRUNC('month',dateline), 'YYYY年MM月')";
super::query(client, sql, &[]).await
}
archive_list()
:调用Postgresql相关函数,根据已发表的文章获取按月存档的日期列表。单条记录的格式如2022年03月
Args
page
:可选的分页页码。
本章代码位于07/网站首页分支。