博客标题展示
声明:该项目是GitHub上的开源项目,本人已购买作者相关课程,仅供个人学习使用。
课程链接:https://www.lanqiao.cn/courses/1367
数据格式定义
这里以点击最多为例,后端返回一个 List 格式的对象,展示的数据仅仅为博客标题,即哪些博客是点击量比较高的,同理,最新发布栏目中即为哪些博客是发布时间较新的。
定义实体类
虽然好像我们只需要一个博客标题字段就可以了,但是这里通常会设计成可跳转的形式,即点击标题后会跳转到对应的博客详情页面中,因此还需要一个博客实体的 id 字段。
SimpleBlogListVo
//查询点击最多的博客列表(在博客表中查询)
@Data
public class SimpleBlogListVo implements Serializable {
private int blogId;
private String blogTitle;
}
dao层
BlogMapper
设计理念:
- 因为
点击最多
和最新发布
都是在同一张表查询,所以定义一个type
参数来实现方法复用 type=0
时按照点击量从大到小进行排序,展示条数为limit
条。type=1
时按照创建时间从进到远进行排序,展示条数为limit
条。- 注意:
@Param
里面的参数表示的是sql语句中对应的参数
//查询所有的博客,根据点击量(type=0)或者发布时间(type=1)进行排序
List<Blog> findBlogListByType(@Param("type") int type,@Param("limit") int limit);
- 查询
已发布
和未删除
的blog信息
<select id="findBlogListByType" resultType="blog" parameterType="_int">
select * from rm_blog.blog
where blog_status=1
and is_deleted=0
<if test="type!=null and type==0">
order by blog_views desc
</if>
<if test="type!=null and type==1">
order by blog_id desc
</if>
limit 0, #{limit}
</select>
service层
BlogService
//查询所有的博客,根据点击量(type=0)或者发布时间(type=1)进行排序
List<SimpleBlogListVo> getBlogListForIndexPage(int type,int limit);
BlogServiceImpl
//根据输入的种类和显示的条数查询出对应的博客信息
@Override
public List<SimpleBlogListVo> getBlogListForIndexPage(int type,int limit) {
//新建一个集合,用来存放id和标题
List<SimpleBlogListVo> simpleBlogListVoS = new ArrayList<>();
//查询博客的所有信息
List<Blog> blogs = blogMapper.findBlogListByType(type, limit);
//将键相同的属性从blog复制到vo中
if (!CollectionUtils.isEmpty(blogs)) {
for (Blog blog : blogs) {
SimpleBlogListVo simpleBlogListVo = new SimpleBlogListVo();
BeanUtils.copyProperties(blog, simpleBlogListVo);
simpleBlogListVoS.add(simpleBlogListVo);
}
}
//返回存放id,标题的blog集合
/*
simpleBlogListVOS:[SimpleBlogListVo(blogId=25, blogTitle=第111篇博客),
SimpleBlogListVo(blogId=26, blogTitle=第888篇博客),
SimpleBlogListVo(blogId=28, blogTitle=第999篇博客),
SimpleBlogListVo(blogId=31, blogTitle=从二进制到汇编)]
*/
System.out.println("simpleBlogListVoS:"+simpleBlogListVoS);
return simpleBlogListVoS;
}
controller层
@Controller
public class MyBlogController {
@Autowired
@Qualifier("blogServiceImpl")
private BlogService blogService;
@GetMapping({"/", "/index", "index.html"})
public String index(HttpServletRequest request){
request.setAttribute("newBlogs", blogService.getBlogListForIndexPage( 1,9));
request.setAttribute("hotBlogs", blogService.getBlogListForIndexPage(0,9));
request.setAttribute("pageName", "首页");
return "blog/index";
}
}
前端展示数据
<div class="aside-widget">
<header>
<h3>点击最多</h3>
</header>
<div class="body">
<ul class="clean-list">
<th:block th:if="${null != hotBlogs}">
<th:block th:each="hotBlog : ${hotBlogs}">
<li>
<a>
<th:block th:text="${hotBlog.blogTitle}"></th:block>
</a>
</li>
</th:block>
</th:block>
</ul>
</div>
</div>
<div class="aside-widget">
<header>
<h3>最新发布</h3>
</header>
<div class="body">
<ul class="clean-list">
<th:block th:if="${null != newBlogs}">
<th:block th:each="newBlog : ${newBlogs}">
<li>
<a>
<th:block th:text="${newBlog.blogTitle}"></th:block>
</a>
</li>
</th:block>
</th:block>
</ul>
</div>
</div>
博客标签展示
数据格式定义
- 一个标签名称的列表,展示的数据为标签的名称,但是这样的话数据有些单薄,所以在这个原型图的基础上又加上了每个标签对应的有多少篇文章在使用,因此这里显示的会是标签的名称和对应的博客数量两个字段。
定义实体类
这里通常也会设计成可跳转的形式,即点击标签后会跳转到对应的该标签下的博客列表中,因此还需要一个标签的主键字段。
//查询标签的id,标签的名字,标签对应文章的总量
@Data
public class BlogTagCountVo {
private Integer tagId;
private String tagName;
private Integer tagCount;
}
dao层
TagMapper
//获取所有标签数量,显示在主页上
List<BlogTagCountVo> getTagCount();
<!--获取所有标签数量,显示在主页上-->
<select id="getTagCount" resultType="BlogTagCountVo">
SELECT t_r.*,t.tag_name FROM
(SELECT r.tag_id,r.tag_count FROM
(SELECT tag_id ,COUNT(*) AS tag_count FROM
(SELECT tr.tag_id FROM blog_tag_relation tr LEFT JOIN blog b ON tr.blog_id = b.blog_id WHERE b.is_deleted=0)
trb GROUP BY tag_id) r ORDER BY tag_count DESC LIMIT 20 ) AS t_r LEFT JOIN blog_tag t ON t_r.tag_id = t.tag_id WHERE t.is_deleted=0
</select>
service层
//获取所有标签数量,显示在主页上
List<BlogTagCountVo> getBlogTagCountForIndex();
@Override
public List<BlogTagCountVo> getBlogTagCountForIndex() {
return tagMapper.getTagCount();
}
controller层
@GetMapping({"/", "/index", "index.html"})
public String index(HttpServletRequest request){
request.setAttribute("newBlogs", blogService.getBlogListForIndexPage( 1,9));
request.setAttribute("hotBlogs", blogService.getBlogListForIndexPage(0,9));
request.setAttribute("hotTags", tagService.getBlogTagCountForIndex());
request.setAttribute("pageName", "首页");
return "blog/index";
}
前端加载数据
<div class="aside-widget">
<header>
<h3>标签栏</h3>
</header>
<div class="body clearfix">
<ul class="tags">
<th:block th:if="${null != hotTags}">
<th:block th:each="hotTag : ${hotTags}">
<li>
<a>
<th:block
th:text="${hotTag.tagName}+'('+${hotTag.tagCount}+')'"
></th:block>
</a>
</li>
</th:block>
</th:block>
</ul>
</div>
</div>
博客内容页展示
数据格式
- blog图片
- blog标题
- 分类名称
- 分类图片
定义实体类
由于文章和分类需要能够点击看到详情
- 需要获取博客id和分类id
@Data
public class BlogListVo implements Serializable {
private Integer blogId;
private String blogTitle;
private String blogCoverImage;
private Integer blogCategoryId;
private String blogCategoryIcon;
private String blogCategoryName;
}
dao层
由于需要对查询出来的博客进行分页
- 查询所有的博客信息
- 查询总条数
- 使用分页工具类获取一个分页对象(包括:数据,数据总数,当前页,每页展示的条数)
传入一个PageUtil工具类
//分页功能
List<Blog> findBlogList(PageUtil pageUtil);
//查询总数
int getTotalBlogs();
<!--start是当前页,默认1。pageSize是每页显示多少条数据 PageUtil中的属性-->
<select id="findBlogList" parameterType="map" resultType="blog">
select *
from rm_blog.blog
where is_deleted=0
order by create_time desc
<if test="start!=null and pageSize!=null">
limit #{start},#{pageSize}
</if>
</select>
<select id="getTotalBlogs" resultType="int">
select count(*) from blog
where is_deleted=0
</select>
service层
//获取首页文章列表
PageResult getBlogsForIndexPage(int page);
/**
* 获取首页文章列表
*/
@Override
public PageResult getBlogsForIndexPage(int page) {
Map params = new HashMap();
params.put("page", page);
//每页6条
params.put("limit", 6);
//根据前端获取的参数创建一个map集合
//该集合包括开始索引,起始页,每页显示数据数
PageUtil pageUtil = new PageUtil(params);
//分页功能
List<Blog> blogList = blogMapper.findBlogList(pageUtil);
//获取需要的字段
List<BlogListVo> blogListVoS = this.getBlogListVosByBlogs(blogList);
//获取总数
int total = blogMapper.getTotalBlogs();
//分页工具类,根据数据列表,总数据,每页显示条数,当前页码创建一个分页工具类
PageResult pageResult =
new PageResult(blogListVoS, total, pageUtil.getPageSize(), pageUtil.getCurrentPage());
return pageResult;
}
/**
* 数据填充,私有方法,其他类不能访问
*/
private List<BlogListVo> getBlogListVosByBlogs(List<Blog> blogList) {
List<BlogListVo> blogListVoS = new ArrayList<>();
if (!CollectionUtils.isEmpty(blogList)) {
List<Integer> categoryIds = blogList.stream().map(Blog::getBlogCategoryId).collect(Collectors.toList());
Map<Integer, String> blogCategoryMap = new HashMap<>();
if (!CollectionUtils.isEmpty(categoryIds)) {
List<BlogCategory> blogCategories = categoryMapper.selectByCategoryIds(categoryIds);
if (!CollectionUtils.isEmpty(blogCategories)) {
blogCategoryMap = blogCategories.stream().collect(Collectors.toMap(BlogCategory::getCategoryId, BlogCategory::getCategoryIcon, (key1, key2) -> key2));
}
}
for (Blog blog : blogList) {
BlogListVo blogListVo = new BlogListVo();
BeanUtils.copyProperties(blog, blogListVo);
if (blogCategoryMap.containsKey(blog.getBlogCategoryId())) {
blogListVo.setBlogCategoryIcon(blogCategoryMap.get(blog.getBlogCategoryId()));
} else {
blogListVo.setBlogCategoryId(0);
blogListVo.setBlogCategoryName("默认分类");
blogListVo.setBlogCategoryIcon("/admin/dist/img/category/00.png");
}
blogListVoS.add(blogListVo);
}
}
return blogListVoS;
}
controller层
/**
* 首页(取第一页数据)
*/
@GetMapping({"/", "/index", "index.html"})
public String index(Model model) {
return this.page(model, 1);
}
/**
* 首页 分页数据
*/
@GetMapping({"/page/{pageNum}"})
public String page(Model model, @PathVariable("pageNum") int pageNum) {
PageResult blogPageResult = blogService.getBlogsForIndexPage(pageNum);
if (blogPageResult == null) {
return "error/error_404";
}
model.addAttribute("blogPageResult", blogPageResult);
model.addAttribute("newBlogs", blogService.getBlogListForIndexPage(1,6));
model.addAttribute("hotBlogs", blogService.getBlogListForIndexPage(0,6));
model.addAttribute("hotTags", tagService.getBlogTagCountForIndex());
model.addAttribute("pageName", "首页");
return "blog/index";
}
渲染后的结果