在一个正常的博客系统中,归档页面也是必不可少的,需要将文章以年份或者月份归档起来,让文章依次展示出来。下面将说明Halo是怎么实现文章归档的。
实现思路
使用一个类来专门存储归档数据,这个类包括的属性有年份
,月份
,年份与月份对应的文章数量
,年份与月份对应的文章
。这样一列出来之后,那么问题就好解决多了,只需要写一个SQL语句查询就好了,然后再到Service层拼装好给视图层调用。
Archive实体类
@Data
public class Archive {
/**
* 年份
*/
private String year;
/**
* 月份
*/
private String month;
/**
* 对应的文章数
*/
private String count;
/**
* 对应的文章
*/
private List<Post> posts;
}
SQL语句
select year(post_date) as year,month(post_date) as month,count(*) as count from halo_post where post_status=0 and post_type='post' group by year(post_date),month(post_date) order by year desc,month desc
注意:上面的post_status字段为文章状态,因为只需要查询已经发布的文章,所以条件为0,post_type为文章类型,因为Halo里面的文章是分为博文和页面的,所以条件让他为post。
实现代码
因为Halo使用的持久层是Spring-Data-Jpa,所以我们需要在Repository里面把查询的语句写好。
PostRepository:
public interface PostRepository extends JpaRepository<Post,Long>{
/**
* 查询文章归档信息 根据年份和月份
*
* @return List<Object[]></>
*/
@Query(value = "select year(post_date) as year,month(post_date) as month,count(*) as count from halo_post where post_status=0 and post_type='post' group by year(post_date),month(post_date) order by year desc,month desc",nativeQuery = true)
List<Object[]> findPostGroupByYearAndMonth();
/**
* 根据年份和月份查询文章
*
* @param year year
* @param month month
* @return List<Post></>
*/
@Query(value = "select *,year(post_date) as year,month(post_date) as month from halo_post where post_status=0 and post_type='post' and year(post_date)=:year and month(post_date)=:month order by post_date desc",nativeQuery = true)
List<Post> findPostByYearAndMonth(@Param("year") String year,@Param("month") String month);
}
这里需要注意的是,上面的
findPostGroupByYearAndMonth
方法是用来根据年份月份归档的,也就是说查询出来有哪些年份和月份,所查询出来的字段有year
,month
,count
,那么这样的话,Archive里面的year
,month
,count
就有数据了,那么posts咋整?所以还需要一个方法来根据年份和月份查询文章,那就是下面的findPostByYearAndMonth方法。
PostService:
@Service
public class PostServiceImpl implements PostService {
@Autowired
private PostRepository postRepository;
/**
* 查询归档信息 根据年份和月份
*
* @return List
*/
@Override
public List<Archive> findPostGroupByYearAndMonth() {
//把归档数据查询出来,不包含文章数据
List<Object[]> objects = postRepository.findPostGroupByYearAndMonth();
//Archive的集合
List<Archive> archives = new ArrayList<>();
Archive archive = null;
//遍历objects集合,分别根据年份月份查询出对应的文章,保存在archive实体,最后在循环结束时将archive添加到archives集合。
for (Object[] obj : objects) {
archive = new Archive();
archive.setYear(obj[0].toString());
archive.setMonth(obj[1].toString());
archive.setCount(obj[2].toString());
archive.setPosts(this.findPostByYearAndMonth(obj[0].toString(), obj[1].toString()));
archives.add(archive);
}
return archives;
}
/**
* 根据年份和月份查询文章
*
* @param year year
* @param month month
* @return list
*/
@Override
public List<Post> findPostByYearAndMonth(String year, String month) {
return postRepository.findPostByYearAndMonth(year, month);
}
}
上面业务层的方法就已经把整个归档数据拼装好了,现在只需要在视图控制器里面调用就可以了。
archives.ftl:
最后就是需要在页面上显示了,页面接收到视图控制器发来的数据之后,将archives集合循环出来就行了。
<#list archivesLess as archives>
<div class="listing-title">${archive.year}</div>
<ul class="listing">
<#list archive.posts?sort_by("postDate")?reverse as post>
<div class="listing-item">
<div class="listing-post">
<a href="/archives/${post.postUrl}" >${post.postTitle}</a>
<div class="post-time">
<span class="date">${post.postDate?string("yyyy-MM-dd")}</span>
</div>
</div>
</div>
</#list>
</ul>
</#list>
结尾
这只是一种实现思路,事实证明这是可行的,并且在各个主题上都是可以完美显示的,我之前也有看到过有人用JDK8的steam来做,不过对steam不是很了解,如果你们有更好的实现方法的话,欢迎提出来。