前言
在博客系统中,侧边栏是提升用户体验的重要组件。通过在文章详情页添加热门文章和最新文章侧边栏,可以帮助读者快速发现优质内容,增加页面浏览量和用户停留时间。本文将详细介绍如何在 Spring Boot + Thymeleaf 技术栈中实现这一功能。
效果预览
![]()
功能需求分析
核心功能
- 热门文章:按浏览量排序,展示前5篇最受欢迎的文章
- 最新文章:按发布时间排序,展示前3篇最新发布的文章
- 响应式设计:PC端显示在左侧,移动端自动隐藏
- 性能优化:使用缓存和字段筛选,减少数据库查询开销
视觉设计
- 热门文章带排名标识(前三名使用特殊颜色区分)
- 显示文章浏览量
- 最新文章使用圆点标识
- 文章标题超长时自动截断并显示省略号
技术实现方案
一、数据库层优化
首先,我们需要一个高效的 SQL 查询来获取侧边栏所需的文章数据。为了避免查询文章内容等大字段,我们只查询必要字段:
<!-- ArticleMapperCustom.xml -->
<select id="findSidebarArticles" resultType="com.zou.blog.model.domain.ArticleCustom">
SELECT
id,
article_title,
article_url,
article_views,
article_newstime,
article_thumbnail
FROM mayday_article
WHERE article_status = #{status}
AND article_post = #{post}
ORDER BY article_newstime DESC
</select>
优化要点:
- 只查询必要字段(不包含 article_content 等大字段)
- 按发布时间倒序排列,便于获取最新文章
- 通过状态过滤,只查询已发布的文章
二、服务层实现
在 Service 层添加缓存注解,提高查询性能:
@Override
@Cacheable(value = ARTICLES_CACHE_NAME, key = "'sidebarArticles'+#status+#post")
public List<ArticleCustom> findSidebarArticles(int status, String post) {
return articleMapperCustom.findSidebarArticles(status, post);
}
三、控制器层逻辑
在文章详情页控制器中,获取侧边栏数据并进行排序处理:
@GetMapping(value = {"post/{articleUrl}", "post/{articleUrl}.html"})
public String post(Model model,
@PathVariable(value = "articleUrl") String articleUrl,
HttpServletRequest request) {
// ... 其他代码
// 获取侧边栏文章列表(带缓存,只查询必要字段)
List<ArticleCustom> sidebarArticles = articleService.findSidebarArticles(
ArticleStatus.PUBLISH.getStatus(),
PostType.POST_TYPE_POST.getValue()
);
// 获取热门文章(按浏览量排序,前5篇)
List<ArticleCustom> sortedHotArticles = sidebarArticles.stream()
.sorted((a1, a2) -> {
Long views1 = a1.getArticleViews() != null ? a1.getArticleViews() : 0L;
Long views2 = a2.getArticleViews() != null ? a2.getArticleViews() : 0L;
return views2.compareTo(views1); // 降序排列
})
.limit(5)
.collect(Collectors.toList());
model.addAttribute("hotArticles", sortedHotArticles);
// 获取最新文章(按创建时间排序,前3篇)
List<ArticleCustom> sortedLatestArticles = sidebarArticles.stream()
.limit(3)
.collect(Collectors.toList());
model.addAttribute("latestArticles", sortedLatestArticles);
// ... 其他代码
}
关键逻辑解析:
- 热门文章排序:使用 Stream API 按
articleViews降序排列,处理 null 值情况 - 最新文章获取:由于 SQL 已经按时间倒序排列,直接取前3条即可
- 数据复用:一次查询,两种用途,减少数据库访问次数
四、前端页面实现
HTML 结构(Thymeleaf 模板)
<!-- 页面整体容器 -->
<div class="post-page-wrapper">
<!-- PC端左侧边栏 -->
<aside class="post-sidebar-left">
<div class="sidebar-left-inner">
<!-- 热门文章区域 -->
<div class="sidebar-section hot-articles">
<h3 class="sidebar-title">
<i class="fa fa-fire"></i>
热门文章
</h3>
<ul class="sidebar-list">
<li class="sidebar-item"
th:each="hotArticle, iterStat : ${hotArticles}"
th:if="${iterStat.index < 5}">
<a th:href="@{'/post/'+${hotArticle.articleUrl}}" class="sidebar-link">
<span class="sidebar-rank"
th:class="'sidebar-rank rank-' + ${iterStat.index + 1}"
th:text="${iterStat.index + 1}"></span>
<span class="sidebar-text" th:text="${hotArticle.articleTitle}"></span>
</a>
<div class="sidebar-meta">
<i class="fa fa-eye"></i>
<span th:text="${hotArticle.articleViews != null ? hotArticle.articleViews : 0}"></span>
</div>
</li>
</ul>
</div>
<!-- 最新文章区域 -->
<div class="sidebar-section latest-articles">
<h3 class="sidebar-title">
<i class="fa fa-clock-o"></i>
最新文章
</h3>
<ul class="sidebar-list">
<li class="sidebar-item"
th:each="latestArticle, iterStat : ${latestArticles}"
th:if="${iterStat.index < 3}">
<a th:href="@{'/post/'+${latestArticle.articleUrl}}" class="sidebar-link">
<span class="sidebar-dot"></span>
<span class="sidebar-text" th:text="${latestArticle.articleTitle}"></span>
</a>
</li>
</ul>
</div>
</div>
</aside>
<!-- 文章主体区域 -->
<article class="main-content page-page">
<!-- 文章内容... -->
</article>
</div>
CSS 样式实现
/* ==================== PC端侧边栏样式(左侧固定) ==================== */
/* 页面整体容器 */
.post-page-wrapper {
display: flex;
gap: 30px;
max-width: 1400px;
margin: 0 auto;
padding: 0 20px;
position: relative;
}
/* 左侧边栏基础样式 - 默认隐藏 */
.post-sidebar-left {
display: none;
}
/* PC端显示左侧边栏 */
@media (min-width: 1024px) {
.post-sidebar-left {
display: block;
width: 260px;
flex-shrink: 0;
position: relative;
}
/* 左侧边栏内部容器 - 固定定位 */
.sidebar-left-inner {
position: sticky;
top: 100px;
max-height: calc(100vh - 120px);
overflow-y: auto;
}
}
/* 侧边栏区域样式 */
.sidebar-section {
background: #fff;
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
border: 1px solid #f0f0f0;
}
.sidebar-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0 0 16px 0;
padding-bottom: 12px;
border-bottom: 2px solid #f5f5f5;
display: flex;
align-items: center;
gap: 8px;
}
/* 排名样式 */
.sidebar-rank {
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
color: #666;
background: #f5f5f5;
flex-shrink: 0;
}
.sidebar-rank.rank-1 {
background: linear-gradient(135deg, #ff6b6b, #ee5a5a);
color: #fff;
}
.sidebar-rank.rank-2 {
background: linear-gradient(135deg, #ffa502, #ff9500);
color: #fff;
}
.sidebar-rank.rank-3 {
background: linear-gradient(135deg, #2ed573, #26d063);
color: #fff;
}
/* 文章标题文本 */
.sidebar-text {
flex: 1;
font-size: 14px;
line-height: 1.5;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
/* 最新文章圆点 */
.sidebar-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: #eb5055;
flex-shrink: 0;
margin-top: 8px;
}
关键技术点解析
1. 粘性定位(Sticky Positioning)
.sidebar-left-inner {
position: sticky;
top: 100px;
max-height: calc(100vh - 120px);
overflow-y: auto;
}
使用 position: sticky 实现侧边栏随页面滚动而固定,提升用户体验。top: 100px 确保侧边栏不会被顶部导航栏遮挡。
2. Stream API 排序
List<ArticleCustom> sortedHotArticles = sidebarArticles.stream()
.sorted((a1, a2) -> {
Long views1 = a1.getArticleViews() != null ? a1.getArticleViews() : 0L;
Long views2 = a2.getArticleViews() != null ? a2.getArticleViews() : 0L;
return views2.compareTo(views1);
})
.limit(5)
.collect(Collectors.toList());
使用 Java 8 Stream API 进行内存排序,避免多次数据库查询。同时处理 null 值,防止空指针异常。
3. 响应式设计
@media (min-width: 1024px) {
.post-sidebar-left {
display: block;
}
}
@media (max-width: 767px) {
.post-page-wrapper {
padding: 0;
width: 100%;
}
}
通过媒体查询实现响应式布局:
- PC端(≥1024px):显示侧边栏
- 平板端(768px-1023px):隐藏侧边栏
- 移动端(<767px):调整布局宽度
4. 缓存优化
@Cacheable(value = ARTICLES_CACHE_NAME, key = "'sidebarArticles'+#status+#post")
public List<ArticleCustom> findSidebarArticles(int status, String post) {
return articleMapperCustom.findSidebarArticles(status, post);
}
使用 Spring Cache 注解,将侧边栏文章列表缓存起来,减少数据库查询次数,提高页面加载速度。
效果展示
PC端效果
- 左侧显示热门文章和最新文章两个区块
- 热门文章前三名带有渐变色排名标识
- 文章标题超长时自动截断显示省略号
- 侧边栏随页面滚动保持可见
移动端效果
- 侧边栏自动隐藏,专注于文章内容阅读
- 页面宽度自适应,无水平滚动条
总结
通过本文的介绍,我们实现了一个功能完善、性能优良的博客侧边栏系统。主要技术亮点包括:
- 数据库优化:只查询必要字段,减少数据传输
- 缓存机制:使用 Spring Cache 提高查询性能
- Stream API:内存排序,减少数据库访问
- 响应式设计:适配各种屏幕尺寸
- 粘性定位:提升用户体验
这个实现方案不仅满足了功能需求,还兼顾了性能和用户体验,可以作为类似功能的参考实现。

评论区 0