说明
我们上节课处理了列表页,但我们还没有真正的入口页面到列表页面的跳转,比如分类列表、标签列表及搜索的入口,这节课我们就重点处理一下这里
处理描述信息中的非中英文字符
我们可以看到我们的列表页描述信息其实展示我是我们markdown
的源代码,里面有大量的符号,而这些符号与我们的主要内容基本无关,所以我们可以把这些符号删除之后再展示摘要部分的内容
匹配中文的正则:\u4E00-\u9FA5
匹配英文的正则:a-zA-Z
public String summary() {
String summary = this.content.replaceAll("[^\\u4E00-\\u9FA5a-zA-Z]", "");
return summary.substring(0, Math.min(300, summary.length()));
}
分类列表
- 模板:
categroy.html
- 路由:
/category.html
观察页面可以看到我们的分类列表需要如下信息
- 分类名称(已有)
- 分类描述(已有)
- 分类下的文章数:可以查下count
- 分类下文章的最后一次更新时间:可以查询文章列表后用updated进行排序
- 代码实现
//articleMapper
Long countByCategory(Category category);
@Query(value = "select updated from blog_article where category_id=?1 order by updated desc limit 1", nativeQuery = true)
Date lastUpdated(Integer id);
// categoryService
@Cacheable
public List<Category> show() {
return mapper.findAll().stream().peek(category -> {
category.setArticleCount(articleMapper.countByCategory(category));
category.setLastUpdated(articleMapper.lastUpdated(category.getId()));
}).collect(Collectors.toList());
}
//IndexController
@GetMapping("/category.html")
public String category(Model model) {
model.addAttribute("categories",categoryService.show());
return "category";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:replace="common::header(~{::title},~{},~{})">
<title th:text="${'分类大全 - '+@webSite.title}"></title>
</head>
<body>
<th:block th:include="common::nav"></th:block>
<div class="lw-container lw-main lw-posr">
<div class="lw-left-list">
<ol class="breadcrumb lw-crumb">
<li><a href="/">首页</a></li>
<li class="active">分类大全</li>
</ol>
<ul class="lw-category-list">
<li th:each="category:${categories}">
<a th:href="@{/category/{id}.html(id=${category.id})}">
<i class="fa fa-folder lw-mr5"></i>
<th:block th:text="${category.name}"></th:block>
<span>(Total <th:block th:text="${category.articleCount}"></th:block> Articles)</span></a>
<p th:text="${category.summary}"></p>
<p class="lw-category-update">最后更新: <th:block th:text="${category.articleCount eq 0}?'1970-01-01':${#dates.format(category.lastUpdated,'yyyy-MM-dd')}"></th:block></p>
</li>
</ul>
</div>
<div class="lw-right-list lw-md-show lw-posa">
<th:block th:include="common::right"></th:block>
</div>
</div>
<th:block th:include="common::footer"></th:block>
</body>
</html>
标签列表
- 模板:
tags.html
- 路由:
/tag.html
观察页面可以看到我们的分类列表需要如下信息
- 标签名称(已有)
- 标签下的文章数:可以查下count
- 代码实现
//tagMapper
@Query(value = "select count(1) from blog_article_tags where tags_id = ?1", nativeQuery = true)
Long articleCountByTid(Integer id);
//tagService
@Cacheable
public List<Tag> show() {
return mapper.findAll().stream().peek(tag -> tag.setArticleCount(mapper.articleCountByTid(tag.getId()))).filter(tag -> tag.getArticleCount()>0).collect(Collectors.toList());
}
//IndexController
@GetMapping("/tag.html")
public String tag(Model model) {
model.addAttribute("tagList", tagService.show());
return "tags";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:replace="common::header(~{::title},~{},~{})">
<title th:text="${'分类大全 - '+@webSite.title}"></title>
</head>
<body>
<th:block th:include="common::nav"></th:block>
<div class="lw-container lw-main lw-posr">
<div class="lw-left-list">
<ol class="breadcrumb lw-crumb">
<li><a href="/static">首页</a></li>
<li class="active">标签云</li>
</ol>
<div class="lw-tag-list">
<a th:each="tag:${tagList}" th:href="@{/tag/{id}.html(id=${tag.id})}" th:title="${tag.name}">
<th:block th:text="${tag.name}"></th:block>
<span th:text="${tag.articleCount}"></span>
</a>
</div>
</div>
<div class="lw-right-list lw-md-show lw-posa">
<th:block th:include="common::right"></th:block>
</div>
</div>
<th:block th:include="common::footer"></th:block>
</body>
</html>
搜索的入口
我们需要展示推荐关键字,这里我想的是用一个LRU做缓存展示20个最近使用的关键字,如果最近使用的关键字少于20个时我们用标签做补充
LRU:LRU中Least Recently Used
的缩写,这种算法认为最近使用过的数据是一个热门数据,下一次还有很大概率再次被使用,而最近很少被使用的数据,很大概率下次不会再使用了,当容器已经满了的时候把最近很少被使用的数据直接删除,这种算法最初是用于操作系统中的页面置换,现在也大多被使用于缓存过期策略
我们也认为最近被用户所搜索的关键字就是热门关键字,直接展示为推荐关键字
我们这里用LinkedHashSet
做一个简单的LRU缓存
package cn.kevinlu98.common;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* Author: Mr丶冷文
* Date: 2022/10/12 18:06
* Email: kevinlu98@qq.com
* Description:
*/
public class LRUCache {
private final Set<String> cache = new LinkedHashSet<>();
private final int limit;
public LRUCache(int limit) {
this.limit = limit;
}
public int size() {
return cache.size();
}
public List<String> list() {
return new ArrayList<>(cache);
}
public void add(String keyword) {
while (cache.size() >= limit) {
cache.remove(cache.stream().findFirst().orElse(null));
}
cache.remove(keyword);
cache.add(keyword);
}
}
Controller的变动
@ModelAttribute
private void indexModel(Model model) {
// todo 可以在这里定义这个controller公用的model的属性
model.addAttribute("friendlies", friendlyService.list());
model.addAttribute("tags", tagService.list(30));
model.addAttribute("navigations", navigationService.show());
model.addAttribute("hots", articleService.hotList(5));
int size = lruCache.size();
List<String> keywords = lruCache.list();
Collections.reverse(keywords);
if (size < 10) {
keywords.addAll(tagService.list(10 - size).stream().map(Tag::getName).collect(Collectors.toList()));
}
model.addAttribute("keywords", keywords);
}
@GetMapping("/search.html")
public String search(@RequestParam(required = false, defaultValue = "1") Integer pn, String keyword, Model model) {
lruCache.add(keyword);
//todo 如果这个分类不存在的时候我们要处理一下
model.addAttribute("keyword", keyword);
ArticleSearch articleSearch = ArticleSearch.indexShow(pn, 8);
articleSearch.setKeyword(keyword);
PageHelper<Article> articlePage = articleService.search(articleSearch);
model.addAttribute("articlePage", articlePage);
model.addAttribute("pageType", "search");
return "list";
}
<div class="lw-search-input lw-posr">
<form th:action="@{/search.html}" method="get">
<input required type="text" name="keyword" placeholder="请输入搜索关键字...">
<button class="lw-posa"><i class="fa fa-search lw-mr5"></i>搜索</button>
</form>
</div>
<p>推荐关键字:
<a class="lw-mr5" th:each="keyword:${keywords}" th:href="@{/search.html(keyword=${keyword})}" th:text="${keyword}" th:title="${keyword}"></a>
</p>
看看
多谢大佬分享
强强强
感谢作者!
感谢!