小言_互联网的博客

【SpringBoot搭建个人博客】- 博客详情页面显示(十一)

412人阅读  评论(0)

博客地址:ONESTARの客栈

源码领取方式一:

  • 扫一扫文末二维码,关注公众号【编程日刊】,后台回复【博客】,即可领取源码

源码领取方式二:

欢迎给star以鼓励(^_−)☆


博客详情页面包括文章内容和评论部分,本文将从文章内容显示和评论功能来讲述SpringBoot搭建个人博客的详情页面显示,由于博客详情和分类功能都是独立的,这里将评论单独用一个类来编写接口,查询博客详情就直接放在首页的控制器进行处理

分析:

问:博客详情页面是包含文章内容和评论部分,要如何处理

答:在跳转博客详情页面的时候,可以返回连个model,一个是文章详情内容,一个是评论列表

问:文章详情内容如何处理,需要哪些接口?评论如何处理,又需要哪些接口?

答:文章详情内容定义getDetailedBlog博客详情接口,需要定义一个查询实体类来封装一下查询内容,并把分类信息也包含进来;评论功能则需要定义listCommentByBlogId查询评论列表接口、saveComment新增保存接口、deleteComment删除接口

一、文章内容显示

分析:

问:在博客详情页面中,文章显示格式要如何处理,文章访问数量如何处理,评论数量又该如何处理?

答:这些都在getDetailedBlog接口实现类中实现

  • 文章显示格式:使用开源的Markdown编辑器:Editor,调用工具类方法来增加扩展
  • 访问数量:在持久层接口定义方法updateViews来更新文章访问数量,点击文章后数值自增
  • 评论数量:在持久层接口定义方法getCommentCountById来根据博客id查询出评论数量

1. 博客详情实体类

博客详情除了显示博客信息外,还需要显示分类信息,所以还要创建分类名称属性,在queryvo包下创建DetailedBlog博客详情实体类,代码如下(省去get、set、toString方法):


  
  1. package com.star.queryvo;
  2. import java.util.Date;
  3. /**
  4. * @Description: 博客详情实体类
  5. * @Date: Created in 10:10 2020/6/19
  6. * @Author: ONESTAR
  7. * @QQ群: 530311074
  8. * @URL: https://onestar.newstar.net.cn/
  9. */
  10. public class DetailedBlog {
  11. //博客信息
  12. private Long id;
  13. private String firstPicture;
  14. private String flag;
  15. private String title;
  16. private String content;
  17. private Integer views;
  18. private Integer commentCount;
  19. private Date updateTime;
  20. private boolean commentabled;
  21. private boolean shareStatement;
  22. private boolean appreciation;
  23. private String nickname;
  24. private String avatar;
  25. //分类名称
  26. private String typeName;
  27. }

2. Markdown编辑器工具类

  • 添加依赖Editor相关依赖

在pom.xml中添加


  
  1. <dependency>
  2. <groupId>com.atlassian.commonmark </groupId>
  3. <artifactId>commonmark </artifactId>
  4. <version>0.10.0 </version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.atlassian.commonmark </groupId>
  8. <artifactId>commonmark-ext-heading-anchor </artifactId>
  9. <version>0.10.0 </version>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.atlassian.commonmark </groupId>
  13. <artifactId>commonmark-ext-gfm-tables </artifactId>
  14. <version>0.10.0 </version>
  15. </dependency>
  • 添加MarkdownUtils工具类

在util工具包下添加MarkdownUtils工具类:


  
  1. package com.star.util;
  2. import org.commonmark.Extension;
  3. import org.commonmark.ext.gfm.tables.TableBlock;
  4. import org.commonmark.ext.gfm.tables.TablesExtension;
  5. import org.commonmark.ext.heading.anchor.HeadingAnchorExtension;
  6. import org.commonmark.node.Link;
  7. import org.commonmark.node.Node;
  8. import org.commonmark.parser.Parser;
  9. import org.commonmark.renderer.html.AttributeProvider;
  10. import org.commonmark.renderer.html.AttributeProviderContext;
  11. import org.commonmark.renderer.html.AttributeProviderFactory;
  12. import org.commonmark.renderer.html.HtmlRenderer;
  13. import java.util.*;
  14. /**
  15. * @Description: Markdown编辑器
  16. * @Author: ONESTAR
  17. * @Date: Created in 13:24 2020/4/5
  18. * @QQ群: 530311074
  19. * @URL: https://onestar.newstar.net.cn/
  20. */
  21. public class MarkdownUtils {
  22. /**
  23. * markdown格式转换成HTML格式
  24. * @param markdown
  25. * @return
  26. */
  27. public static String markdownToHtml(String markdown) {
  28. Parser parser = Parser.builder().build();
  29. Node document = parser.parse(markdown);
  30. HtmlRenderer renderer = HtmlRenderer.builder().build();
  31. return renderer.render(document);
  32. }
  33. /**
  34. * 增加扩展[标题锚点,表格生成]
  35. * Markdown转换成HTML
  36. * @param markdown
  37. * @return
  38. */
  39. public static String markdownToHtmlExtensions(String markdown) {
  40. //h标题生成id
  41. Set<Extension> headingAnchorExtensions = Collections.singleton(HeadingAnchorExtension.create());
  42. //转换table的HTML
  43. List<Extension> tableExtension = Arrays.asList(TablesExtension.create());
  44. Parser parser = Parser.builder()
  45. .extensions(tableExtension)
  46. .build();
  47. Node document = parser.parse(markdown);
  48. HtmlRenderer renderer = HtmlRenderer.builder()
  49. .extensions(headingAnchorExtensions)
  50. .extensions(tableExtension)
  51. .attributeProviderFactory( new AttributeProviderFactory() {
  52. public AttributeProvider create(AttributeProviderContext context) {
  53. return new CustomAttributeProvider();
  54. }
  55. })
  56. .build();
  57. return renderer.render(document);
  58. }
  59. /**
  60. * 处理标签的属性
  61. */
  62. static class CustomAttributeProvider implements AttributeProvider {
  63. @Override
  64. public void setAttributes(Node node, String tagName, Map<String, String> attributes) {
  65. //改变a标签的target属性为_blank
  66. if (node instanceof Link) {
  67. attributes.put( "target", "_blank");
  68. }
  69. if (node instanceof TableBlock) {
  70. attributes.put( "class", "ui celled table");
  71. }
  72. }
  73. }
  74. public static void main(String[] args) {
  75. String table = "| hello | hi | 哈哈哈 |\n" +
  76. "| ----- | ---- | ----- |\n" +
  77. "| 斯维尔多 | 士大夫 | f啊 |\n" +
  78. "| 阿什顿发 | 非固定杆 | 撒阿什顿发 |\n" +
  79. "\n";
  80. String a = "[ONESTAR](https://onestar.newstar.net.cn/)";
  81. System.out.println(markdownToHtmlExtensions(a));
  82. }
  83. }

3. 持久层接口

文章内容显示是从首页点击文章标题或图片,然后跳转到博客详情页面的,所以这里就将代码放在博客业务这一块

在BlogDao接口中添加查询博客详情、文章访问更新、查询评论数量接口


  
  1. //查询博客详情
  2. DetailedBlog getDetailedBlog(Long id);
  3. //文章访问更新
  4. int updateViews(Long id);
  5. //根据博客id查询出评论数量
  6. int getCommentCountById(Long id);

4. mapper

根据持久层接口,编写如下SQL:查询博客详情、文章访问更新、查询评论数量,这里需要对博客详情进行封装


  
  1. <resultMap id="detailedBlog" type="com.star.queryvo.DetailedBlog">
  2. <id property="id" column="bid"/>
  3. <result property="firstPicture" column="first_picture"/>
  4. <result property="flag" column="flag"/>
  5. <result property="title" column="title"/>
  6. <result property="content" column="content"/>
  7. <result property="typeName" column="name"/>
  8. <result property="views" column="views"/>
  9. <result property="commentCount" column="comment_count"/>
  10. <result property="updateTime" column="update_time"/>
  11. <result property="commentabled" column="commentabled"/>
  12. <result property="shareStatement" column="share_statement"/>
  13. <result property="appreciation" column="appreciation"/>
  14. <result property="nickname" column="nickname"/>
  15. <result property="avatar" column="avatar"/>
  16. </resultMap>
  17. <!--博客详情查询-->
  18. <select id="getDetailedBlog" resultMap="detailedBlog">
  19. select b.id bid,b.first_picture,b.flag,b.title,b.content,b.views,b.comment_count,b.update_time,b.commentabled,b.share_statement,b.appreciation, u.nickname,u.avatar,t.name
  20. from myblog.t_blog b,myblog.t_user u, myblog.t_type t
  21. where b.user_id = u.id and b.type_id = t.id and b.id = #{id}
  22. </select>
  23. <!--文章访问自增-->
  24. <update id="updateViews" parameterType="com.star.entity.Blog">
  25. update myblog.t_blog b set b.views = b.views+1 where b.id = #{id}
  26. </update>
  27. <!--查询出文章评论数量并更新-->
  28. <update id="getCommentCountById" parameterType="com.star.entity.Blog">
  29. update myblog.t_blog b set b.comment_count = (
  30. select count(*) from myblog.t_comment c where c.blog_id = #{id} and b.id = #{id}
  31. ) WHERE b.id = #{id}
  32. </update>

5. 持久层

  • 持久层接口

在BlogService接口中添加查询博客详情方法:


  
  1. //查询博客详情
  2. DetailedBlog getDetailedBlog(Long id);
  • 接口实现

次接口实现主要是设置文章显示格式,文章访问自增和文章评论的统计,在BlogServiceImpl类中添加实现方法,如下:


  
  1. @Override
  2. public DetailedBlog getDetailedBlog(Long id) {
  3. DetailedBlog detailedBlog = blogDao.getDetailedBlog(id);
  4. if (detailedBlog == null) {
  5. throw new NotFoundException( "该博客不存在");
  6. }
  7. String content = detailedBlog.getContent();
  8. detailedBlog.setContent(MarkdownUtils.markdownToHtmlExtensions(content));
  9. //文章访问数量自增
  10. blogDao.updateViews(id);
  11. //文章评论数量更新
  12. blogDao.getCommentCountById(id);
  13. return detailedBlog;
  14. }

6. 控制器

在IndexController类中添加方法,调用业务层接口:


  
  1. //跳转博客详情页面
  2. @GetMapping("/blog/{id}")
  3. public String blog( @PathVariable Long id, Model model) {
  4. DetailedBlog detailedBlog = blogService.getDetailedBlog(id);
  5. model.addAttribute( "blog", detailedBlog);
  6. return "blog";
  7. }

二、评论功能

由于评论稍微复杂些,这里将评论单独放一个业务层

分析:

问:评论业务层需要哪些接口?

答:评论直接在前端页面上进行操作,没有后台管理,只是区分的管理员和普通用户,管理员可以对评论进行删除,因此需要查询评论列表(listCommentByBlogId)、添加保存评论(saveComment)、删除评论(deleteComment)接口

问:业务层这些接口够了,但持久层光这些够了吗?需要哪些SQL,需要哪些持久层接口呢?

答:持久层接口肯定是不够的,主要是查询评论列表的时候,需要将评论和回复加以区分,根据评论功能来看,有父评论、子评论(回复),并且父子评论在前端显示的位置有不同,这里细说一下查询:

  • 根据id为“-1”和博客id查询出所有父评论(父级评论id为‘-1’)
  • 根据父评论的id查询出一级子回复
  • 根据子回复的id循环迭代查询出所有子集回复
  • 将查询出来的子回复放到一个集合中

所以查询评论信息需要:查询父级评论(findByBlogIdParentIdNull)、查询一级回复(findByBlogIdParentIdNotNull)、查询二级回复(findByBlogIdAndReplayId)

1. 持久层接口

在dao包下创建CommentDao接口,添加如下接口:


  
  1. package com.star.dao;
  2. import com.star.entity.Comment;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import org.apache.ibatis.annotations.Param;
  5. import org.springframework.stereotype.Repository;
  6. import java.util.List;
  7. /**
  8. * @Description: 评论持久层接口
  9. * @Date: Created in 9:21 2020/6/23
  10. * @Author: ONESTAR
  11. * @QQ群: 530311074
  12. * @URL: https://onestar.newstar.net.cn/
  13. */
  14. @Mapper
  15. @Repository
  16. public interface CommentDao {
  17. //查询父级评论
  18. List<Comment> findByBlogIdParentIdNull( @Param("blogId") Long blogId, @Param("blogParentId") Long blogParentId);
  19. //查询一级回复
  20. List<Comment> findByBlogIdParentIdNotNull( @Param("blogId") Long blogId, @Param("id") Long id);
  21. //查询二级回复
  22. List<Comment> findByBlogIdAndReplayId( @Param("blogId") Long blogId, @Param("childId") Long childId);
  23. //添加一个评论
  24. int saveComment(Comment comment);
  25. //删除评论
  26. void deleteComment( Long id);
  27. }

2.mapper

在mapper目录下创建CommentDao.xml文件,添加如下:


  
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="com.star.dao.CommentDao">
  4. <!--添加评论-->
  5. <insert id="saveComment" parameterType="com.star.entity.Comment">
  6. insert into myblog.t_comment (nickname,email,content,avatar,create_time,blog_id,parent_comment_id,admin_comment)
  7. values (#{nickname},#{email},#{content},#{avatar},#{createTime},#{blogId},#{parentCommentId},#{adminComment});
  8. </insert>
  9. <!--查询父级评论-->
  10. <select id="findByBlogIdParentIdNull" resultType="com.star.entity.Comment">
  11. select *
  12. from myblog.t_comment c
  13. where c.blog_id = #{blogId} and c.parent_comment_id = #{blogParentId}
  14. order by c.create_time desc
  15. </select>
  16. <!--查询一级子评论-->
  17. <select id="findByBlogIdParentIdNotNull" resultType="com.star.entity.Comment">
  18. select *
  19. from myblog.t_comment c
  20. where c.blog_id = #{blogId} and c.parent_comment_id = #{id}
  21. order by c.create_time desc
  22. </select>
  23. <!--查询二级子评论-->
  24. <select id="findByBlogIdAndReplayId" resultType="com.star.entity.Comment">
  25. select *
  26. from myblog.t_comment c
  27. where c.blog_id = #{blogId} and c.parent_comment_id = #{childId}
  28. order by c.create_time desc
  29. </select>
  30. <!--删除评论-->
  31. <delete id="deleteComment" >
  32. delete from myblog.t_comment where id = #{id}
  33. </delete>
  34. </mapper>

讲解:

添加删除:直接使用insert和delete即可进行添加和删除

查询:

  • findByBlogIdParentIdNull:根据id为“-1”和博客id查询出所有父评论(父级评论id为‘-1’)
  • findByBlogIdParentIdNotNull:根据父评论的id查询出一级子回复
  • findByBlogIdAndReplayId:根据子回复的id循环迭代查询出所有子集回复

3. 业务层

  • 业务层接口:

在service包下创建CommentService接口,如下:


  
  1. package com.star.service;
  2. import com.star.entity.Comment;
  3. import java.util.List;
  4. /**
  5. * @Description: 评论业务层接口
  6. * @Date: Created in 10:22 2020/6/23
  7. * @Author: ONESTAR
  8. * @QQ群: 530311074
  9. * @URL: https://onestar.newstar.net.cn/
  10. */
  11. public interface CommentService {
  12. //根据博客id查询评论信息
  13. List<Comment> listCommentByBlogId(Long blogId);
  14. //添加保存评论
  15. int saveComment(Comment comment);
  16. //删除评论
  17. void deleteComment(Comment comment,Long id);
  18. }
  • 接口实现:

在Impl包下创建接口实现类:CommentServiceImpl,功能都在这个接口中实现


  
  1. package com.star.service.Impl;
  2. import com.star.dao.BlogDao;
  3. import com.star.dao.CommentDao;
  4. import com.star.entity.Comment;
  5. import com.star.service.CommentService;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.stereotype.Service;
  8. import java.util.ArrayList;
  9. import java.util.Date;
  10. import java.util.List;
  11. /**
  12. * @Description: 博客评论业务层接口实现类
  13. * @Date: Created in 10:23 2020/6/23
  14. * @Author: ONESTAR
  15. * @QQ群: 530311074
  16. * @URL: https://onestar.newstar.net.cn/
  17. */
  18. @Service
  19. public class CommentServiceImpl implements CommentService {
  20. @Autowired
  21. private CommentDao commentDao;
  22. @Autowired
  23. private BlogDao blogDao;
  24. //存放迭代找出的所有子代的集合
  25. private List<Comment> tempReplys = new ArrayList<>();
  26. /**
  27. * @Description: 查询评论
  28. * @Auther: ONESTAR
  29. * @Date: 10:42 2020/6/23
  30. * @Param: blogId:博客id
  31. * @Return: 评论消息
  32. */
  33. @Override
  34. public List<Comment> listCommentByBlogId(Long blogId) {
  35. //查询出父节点
  36. List<Comment> comments = commentDao.findByBlogIdParentIdNull(blogId, Long.parseLong( "-1"));
  37. for(Comment comment : comments){
  38. Long id = comment.getId();
  39. String parentNickname1 = comment.getNickname();
  40. List<Comment> childComments = commentDao.findByBlogIdParentIdNotNull(blogId,id);
  41. //查询出子评论
  42. combineChildren(blogId, childComments, parentNickname1);
  43. comment.setReplyComments(tempReplys);
  44. tempReplys = new ArrayList<>();
  45. }
  46. return comments;
  47. }
  48. /**
  49. * @Description: 查询出子评论
  50. * @Auther: ONESTAR
  51. * @Date: 10:43 2020/6/23
  52. * @Param: childComments:所有子评论
  53. * @Param: parentNickname1:父评论姓名
  54. * @Return:
  55. */
  56. private void combineChildren(Long blogId, List<Comment> childComments, String parentNickname1) {
  57. //判断是否有一级子评论
  58. if(childComments.size() > 0){
  59. //循环找出子评论的id
  60. for(Comment childComment : childComments){
  61. String parentNickname = childComment.getNickname();
  62. childComment.setParentNickname(parentNickname1);
  63. tempReplys.add(childComment);
  64. Long childId = childComment.getId();
  65. //查询出子二级评论
  66. recursively(blogId, childId, parentNickname);
  67. }
  68. }
  69. }
  70. /**
  71. * @Description: 循环迭代找出子集回复
  72. * @Auther: ONESTAR
  73. * @Date: 10:44 2020/6/23
  74. * @Param: chileId:子评论id
  75. * @Param: parentNickname1:子评论姓名
  76. * @Return:
  77. */
  78. private void recursively(Long blogId, Long childId, String parentNickname1) {
  79. //根据子一级评论的id找到子二级评论
  80. List<Comment> replayComments = commentDao.findByBlogIdAndReplayId(blogId,childId);
  81. if(replayComments.size() > 0){
  82. for(Comment replayComment : replayComments){
  83. String parentNickname = replayComment.getNickname();
  84. replayComment.setParentNickname(parentNickname1);
  85. Long replayId = replayComment.getId();
  86. tempReplys.add(replayComment);
  87. recursively(blogId,replayId,parentNickname);
  88. }
  89. }
  90. }
  91. //新增评论
  92. @Override
  93. public int saveComment(Comment comment) {
  94. comment.setCreateTime( new Date());
  95. int comments = commentDao.saveComment(comment);
  96. //文章评论计数
  97. blogDao.getCommentCountById(comment.getBlogId());
  98. return comments;
  99. }
  100. //删除评论
  101. @Override
  102. public void deleteComment(Comment comment,Long id) {
  103. commentDao.deleteComment(id);
  104. blogDao.getCommentCountById(comment.getBlogId());
  105. }
  106. }

4. 控制器

  • 添加图片配置 在评论中,需要显示头像,这里直接在配置文件里面进行配置,在application.yml中添加如下配置(这里直接把后面留言的显示图片也一起添加了):

  
  1. comment.avatar: /images/avatar.png
  2. message.avatar: /images/avatar.png

在controller包下创建CommentController类,如下:


  
  1. package com.star.controller;
  2. import com.star.entity.Comment;
  3. import com.star.entity.User;
  4. import com.star.queryvo.DetailedBlog;
  5. import com.star.service.BlogService;
  6. import com.star.service.CommentService;
  7. import org.springframework.beans.factory. annotation.Autowired;
  8. import org.springframework.beans.factory. annotation.Value;
  9. import org.springframework.stereotype.Controller;
  10. import org.springframework.ui.Model;
  11. import org.springframework.web.bind. annotation.GetMapping;
  12. import org.springframework.web.bind. annotation.PathVariable;
  13. import org.springframework.web.bind. annotation.PostMapping;
  14. import org.springframework.web.servlet.mvc.support.RedirectAttributes;
  15. import javax.servlet.http.HttpSession;
  16. import java.util.List;
  17. /**
  18. * @Description: 评论控制器
  19. * @Date: Created in 10:25 2020/6/23
  20. * @Author: ONESTAR
  21. * @QQ群: 530311074
  22. * @URL: https://onestar.newstar.net.cn/
  23. */
  24. @Controller
  25. public class CommentController {
  26. @Autowired
  27. private CommentService commentService;
  28. @Autowired
  29. private BlogService blogService;
  30. @Value("${comment.avatar}")
  31. private String avatar;
  32. //查询评论列表
  33. @GetMapping("/comments/{blogId}")
  34. public String comments( @PathVariable Long blogId, Model model) {
  35. List<Comment> comments = commentService.listCommentByBlogId(blogId);
  36. model.addAttribute( "comments", comments);
  37. return "blog :: commentList";
  38. }
  39. //新增评论
  40. @PostMapping("/comments")
  41. public String post(Comment comment, HttpSession session, Model model) {
  42. Long blogId = comment.getBlogId();
  43. User user = (User) session.getAttribute( "user");
  44. if (user != null) {
  45. comment.setAvatar(user.getAvatar());
  46. comment.setAdminComment( true);
  47. } else {
  48. //设置头像
  49. comment.setAvatar(avatar);
  50. }
  51. if (comment.getParentComment().getId() != null) {
  52. comment.setParentCommentId(comment.getParentComment().getId());
  53. }
  54. commentService.saveComment(comment);
  55. List<Comment> comments = commentService.listCommentByBlogId(blogId);
  56. model.addAttribute( "comments", comments);
  57. return "blog :: commentList";
  58. }
  59. //删除评论
  60. @GetMapping("/comment/{blogId}/{id}/delete")
  61. public String delete( @PathVariable Long blogId, @PathVariable Long id, Comment comment, RedirectAttributes attributes, Model model){
  62. commentService.deleteComment(comment,id);
  63. DetailedBlog detailedBlog = blogService.getDetailedBlog(blogId);
  64. List<Comment> comments = commentService.listCommentByBlogId(blogId);
  65. model.addAttribute( "blog", detailedBlog);
  66. model.addAttribute( "comments", comments);
  67. return "blog";
  68. }
  69. }

讲解:

查询评论列表:调用接口查询评论信息列表,局部刷新评论信息

新增评论:对评论进行判断,区分游客和管理员

删除评论:将博客id和评论id参数传入,判断删除的是哪一条评论,这里没有做迭代删除子评论,若删除了含有回复的评论,根据之前的查询来看,在前端回复也不会查询出来,但回复并没有删除,依然在数据库里面,删除的只是父评论

5. 前后端交互

给出部分前端代码,仅供参考,了解更多可以查看整个项目源码:https://github.com/oneStarLR/myblog-mybatis

提交评论

  • HTML

  
  1. <input type="hidden" name="blogId" th:value="${blog.id}">
  2. <input type="hidden" name="parentComment.id" value="-1">
  3. <div class="field">
  4. <textarea name="content" placeholder="请输入评论信息..."> </textarea>
  5. </div>
  6. <div class="fields">
  7. <div class="field m-mobile-wide m-margin-bottom-small">
  8. <div class="ui left icon input">
  9. <i class="user icon"> </i>
  10. <input type="text" name="nickname" placeholder="姓名" th:value="${session.user}!=null ? ${session.user.nickname}">
  11. </div>
  12. </div>
  13. <div class="field m-mobile-wide m-margin-bottom-small">
  14. <div class="ui left icon input">
  15. <i class="mail icon"> </i>
  16. <input type="text" name="email" placeholder="邮箱" th:value="${session.user}!=null ? ${session.user.email}">
  17. </div>
  18. </div>
  19. <div class="field m-margin-bottom-small m-mobile-wide">
  20. <button id="commentpost-btn" type="button" class="ui teal button m-mobile-wide"> <i class="edit icon"> </i>发布 </button>
  21. </div>
  22. </div>
  • JS

  
  1. $( '#commentpost-btn').click( function () {
  2. var boo = $( '.ui.form').form( 'validate form');
  3. if (boo) {
  4. console.log( '校验成功');
  5. postData();
  6. } else {
  7. console.log( '校验失败');
  8. }
  9. });
  10. function postData() {
  11. $( "#comment-container").load( /*[[@{/comments}]]*/ "",{
  12. "parentComment.id" : $( "[name='parentComment.id']").val(),
  13. "blogId" : $( "[name='blogId']").val(),
  14. "nickname": $( "[name='nickname']").val(),
  15. "email" : $( "[name='email']").val(),
  16. "content" : $( "[name='content']").val()
  17. }, function (responseTxt, statusTxt, xhr) {
  18. $( window).scrollTo($( '#goto'), 500);
  19. clearContent();
  20. });
  21. }

评论列表


  
  1. <div id= "comment-container" class= "ui teal segment">
  2. <div th:fragment="commentList">
  3. <div class="ui threaded comments" style="max-width: 100%;">
  4. <h3 class="ui dividing header">评论 </h3>
  5. <div class="comment" th:each="comment : ${comments}">
  6. <a class="avatar">
  7. <img src="https://unsplash.it/100/100?image=1005" th:src="@{${comment.avatar}}">
  8. </a>
  9. <div class="content">
  10. <a class="author" >
  11. <span th:text="${comment.nickname}">Matt </span>
  12. <div class="ui mini basic teal left pointing label m-padded-mini" th:if="${comment.adminComment}">栈主 </div>
  13. </a>
  14. <div class="metadata">
  15. <span class="date" th:text="${#dates.format(comment.createTime,'yyyy-MM-dd HH:mm')}">Today at 5:42PM </span>
  16. </div>
  17. <div class="text" th:text="${comment.content}">
  18. How artistic!
  19. </div>
  20. <div class="actions">
  21. <a class="reply" data-commentid="1" data-commentnickname="Matt" th:attr="data-commentid=${comment.id},data-commentnickname=${comment.nickname}" onclick="reply(this)">回复 </a>
  22. <a class="delete" href="#" th:href="@{/comment/{param1}/{param2}/delete(param1=${comment.blogId},param2=${comment.id})}" onclick="return confirm('确定要删除该评论吗?三思啊! 删了可就没了!')" th:if="${session.user}">删除 </a>
  23. <!--<a class="delete" href="#" th:href="@{/comment/{id}/delete(id=${comment.id})}" onclick="return confirm('确定要删除该评论吗?三思啊! 删了可就没了!')" th:if="${session.user}">删除</a>-->
  24. </div>
  25. </div>
  26. <!--子集评论-->
  27. <div class="comments" th:if="${#arrays.length(comment.replyComments)}>0">
  28. <div class="comment" th:each="reply : ${comment.replyComments}">
  29. <a class="avatar">
  30. <img src="https://unsplash.it/100/100?image=1005" th:src="@{${reply.avatar}}">
  31. </a>
  32. <div class="content">
  33. <a class="author" >
  34. <span th:text="${reply.nickname}">小红 </span>
  35. <div class="ui mini basic teal left pointing label m-padded-mini" th:if="${reply.adminComment}">栈主 </div>
  36. &nbsp; <span th:text="|@ ${reply.parentNickname}|" class="m-teal">@ 小白 </span>
  37. </a>
  38. <div class="metadata">
  39. <span class="date" th:text="${#dates.format(reply.createTime,'yyyy-MM-dd HH:mm')}">Today at 5:42PM </span>
  40. </div>
  41. <div class="text" th:text="${reply.content}">
  42. How artistic!
  43. </div>
  44. <div class="actions">
  45. <a class="reply" data-commentid="1" data-commentnickname="Matt" th:attr="data-commentid=${reply.id},data-commentnickname=${reply.nickname}" onclick="reply(this)">回复 </a>
  46. <a class="delete" href="#" th:href="@{/comment/{param1}/{param2}/delete(param1=${reply.blogId},param2=${reply.id})}" onclick="return confirm('确定要删除该评论吗?三思啊! 删了可就没了!')" th:if="${session.user}">删除 </a>
  47. <!--<a class="delete" href="#" th:href="@{/comment/{id}/delete(id=${reply.id})}" onclick="return confirm('确定要删除该评论吗?三思啊! 删了可就没了!')" th:if="${session.user}">删除</a>-->
  48. </div>
  49. </div>
  50. </div>
  51. </div>
  52. </div>
  53. </div>
  54. </div>
  55. </div>

三、运行访问

运行项目,访问 http://localhost:8080/, 点击一片文章,可以查看文章信息,并能进行评论,登录后可以对评论进行删除

至此,Springboot搭建个人博客详情页面显示开发完成,由于留言功能和评论功能基本一样,之前也写过一篇有关评论的博客(SpringBoot和Mybatis实现评论楼中楼功能(一张表搞定)),所以这里就不讲留言功能的开发了,还有不懂的伙伴可以问我,也可以加群讨论,下一篇就直接讲述分类、时间轴、音乐盒、友人帐、照片墙关于我页面的显示,比较简单,直接在一篇文章中讲完

【点关注,不迷路,欢迎持续关注本站】



转载:https://blog.csdn.net/One_L_Star/article/details/106924133
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场