实现思路:

数据库设计:评论表需要定义出当前博客id以便做关联,因为评论需要有回复功能,则需要定义当前评论有无上一级评论,需要定义出上级评论id;博主回复评论需要带有标签,所以需要定义Boolean类型判断是否为博主。

代码方面:点击评论需要获取当前博客id与自己评论数据进行插入,点击回复按钮需要获取上一条评论的id以及用户姓名作为回复,回复成功后,刷新页面,后台则是在数据库中查找出所有parentCommentId为-1的进行遍历,因为上级id为-1则证明当前评论无父节点。在通过对父节点id的遍历查询出所有对应评论的子节点。

页面展示

博客实体类

    private Long id;private String nickname;private String email;private String content;//头像private String avatar;private Date createTime;private Long blogId;  //关联博客idprivate Long parentCommentId;  //上级评论idprivate String parentNickname;//回复评论private List<Comment> replyComments = new ArrayList<>();private Comment parentComment;private boolean adminComment;  //是不是博主private DetailedBlog blog;

评论的博客表单html

<div id="comment-form" class="ui form"><!--获取当前博客id进行评论  使用隐藏域--><input type="hidden" name="blogId" th:value="${blog.id}"><input type="hidden" name="parentComment.id" value="-1"><div class="field"><textarea name="content" placeholder="请输入评论信息..."></textarea></div><div class="fields"><div class="field m-mobile-wide m-margin-bottom-small"><div class="ui left icon input"><i class="user icon"></i><input type="text" name="nickname" placeholder="姓名" th:value="${session.user}!=null ? ${session.user.nickname}"></div></div><div class="field m-mobile-wide m-margin-bottom-small"><div class="ui left icon input"><i class="mail icon"></i><input type="text" name="email" placeholder="邮箱" th:value="${session.user}!=null ? ${session.user.email}"></div></div><div class="field  m-margin-bottom-small m-mobile-wide"><button id="commentpost-btn" type="button" class="ui teal button m-mobile-wide"><i class="edit icon"></i>发布</button></div></div>

点击发布按钮触发


$('#commentpost-btn').click(function () {var boo = $('.ui.form').form('validate form');if (boo) {console.log('校验成功');postData();} else {console.log('校验失败');}});//评论表单验证$('.ui.form').form({fields: {title: {identifier: 'content',rules: [{type: 'empty',prompt: '请输入评论内容'}]},content: {identifier: 'nickname',rules: [{type: 'empty',prompt: '请输入你的大名'}]},type: {identifier: 'email',rules: [{type: 'email',prompt: '请填写正确的邮箱地址'}]}}});   

表单验证后发送请求到后端,提交成功之后清空表单

function postData() {$("#comment-container").load(/*[[@{/comments}]]*/"",{"parentComment.id" : $("[name='parentComment.id']").val(),"blogId" : $("[name='blogId']").val(),"nickname": $("[name='nickname']").val(),"email"   : $("[name='email']").val(),"content" : $("[name='content']").val()},function (responseTxt, statusTxt, xhr) {$(window).scrollTo($('#goto'),500);  //提交成功之后滚动到评论位置 clearContent();});}function clearContent() {$("[name='nickname']").val('');$("[name='email']").val('');$("[name='content']").val('');$("[name='parentComment.id']").val(-1);$("[name='content']").attr("placeholder", "请输入评论信息...");}

点击回复按钮,在评论区显示回复给哪个用户

<a class="reply" data-messageid="1" data-messagenickname="Matt" th:attr="data-messageid=${reply.id},data-messagenickname=${reply.nickname}" onclick="reply(this)">回复</a>

对应函数

 function reply(obj) {var messageId = $(obj).data('messageid');var messageNickname = $(obj).data('messagenickname');$("[name='content']").attr("placeholder", "@"+messageNickname).focus();//在回复时显示  @对应人$("[name='parentMessage.id']").val(messageId);//为隐藏域赋值$(window).scrollTo(0,500);  //滚动}

对应后端代码

@Controller
public class CommentController {@Autowiredprivate CommentService commentService;@Autowiredprivate BlogService blogService;@Value("${comment.avatar}")private String avatar;//    查询评论列表@GetMapping("/comments/{blogId}")public String comments(@PathVariable Long blogId, Model model) {List<Comment> comments = commentService.listCommentByBlogId(blogId);model.addAttribute("comments", comments);return "blog :: commentList"; //返回到blog下面的commentList片段}//    新增评论@PostMapping("/comments")public String post(Comment comment, HttpSession session,Model model) {Long blogId = comment.getBlogId();User user = (User) session.getAttribute("user");if (user != null) {comment.setAvatar(user.getAvatar());comment.setAdminComment(true);} else {//设置头像comment.setAvatar(avatar);}//页面中定义为-1 不会出现空指针if (comment.getParentComment().getId() != null) {//获取父对象设置对应关系comment.setParentCommentId(comment.getParentComment().getId());}commentService.saveComment(comment);List<Comment> comments = commentService.listCommentByBlogId(blogId);model.addAttribute("comments", comments);return "blog :: commentList";}

列表设置,前端遍历显示层级关系

 <div  class="ui bottom attached segment" th:if="${blog.commentabled}"><!--评论区域列表--><div id="comment-container"  class="ui teal segment"><div th:fragment="commentList"><div class="ui threaded comments" style="max-width: 100%;"><h3 class="ui dividing header">评论</h3><div class="comment" th:each="comment : ${comments}"><a class="avatar"><img src="https://unsplash.it/100/100?image=1005" th:src="@{${comment.avatar}}"></a><div class="content"><a class="author" ><span th:text="${comment.nickname}">Matt</span><--判断是不是博主--><div class="ui mini basic teal left pointing label m-padded-mini" th:if="${comment.adminComment}">栈主</div></a><div class="metadata"><span class="date" th:text="${#dates.format(comment.createTime,'yyyy-MM-dd HH:mm')}">Today at 5:42PM</span></div><div class="text" th:text="${comment.content}">How artistic!</div><div class="actions"><a class="reply" data-commentid="1" data-commentnickname="Matt" th:attr="data-commentid=${comment.id},data-commentnickname=${comment.nickname}" onclick="reply(this)">回复</a><a class="delete" href="#" th:href="@{/comment/{param1}/{param2}/delete(param1=${comment.blogId},param2=${comment.id})}" onclick="return confirm('确定要删除该评论吗?')" th:if="${session.user}">删除</a>       </div></div><!--子集评论--><div class="comments" th:if="${#arrays.length(comment.replyComments)}>0"><div class="comment" th:each="reply : ${comment.replyComments}"><a class="avatar"><img src="https://unsplash.it/100/100?image=1005" th:src="@{${reply.avatar}}"></a><div class="content"><a class="author" ><span th:text="${reply.nickname}">小红</span><!--若是博主 给标签--><div class="ui mini basic teal left pointing label m-padded-mini" th:if="${reply.adminComment}">栈主</div>&nbsp;<span th:text="|@ ${reply.parentNickname}|" class="m-teal">@ 小白</span></a><div class="metadata"><span class="date" th:text="${#dates.format(reply.createTime,'yyyy-MM-dd HH:mm')}">Today at 5:42PM</span></div><div class="text" th:text="${reply.content}">How artistic!</div><div class="actions"><a class="reply" data-commentid="1" data-commentnickname="Matt" th:attr="data-commentid=${reply.id},data-commentnickname=${reply.nickname}" onclick="reply(this)">回复</a><a class="delete" href="#" th:href="@{/comment/{param1}/{param2}/delete(param1=${reply.blogId},param2=${reply.id})}" onclick="return confirm('确定要删除该评论吗!')" th:if="${session.user}">删除</a></div></div></div></div></div></div></div></div>

后端实现逻辑:先获取顶级的数据,在一层一层往下找、放入集合

@Service
public class CommentServiceImpl implements CommentService {@Autowiredprivate CommentDao commentDao;@Autowiredprivate BlogDao blogDao;//存放迭代找出的所有子代的集合private List<Comment> tempReplys = new ArrayList<>();@Overridepublic List<Comment> listCommentByBlogId(Long blogId) {//查询出父节点List<Comment> comments = commentDao.findByBlogIdParentIdNull(blogId, Long.parseLong("-1"));for(Comment comment : comments){Long id = comment.getId();String parentNickname1 = comment.getNickname();List<Comment> childComments = commentDao.findByBlogIdParentIdNotNull(blogId,id);
//            查询出子评论combineChildren(blogId, childComments, parentNickname1);comment.setReplyComments(tempReplys);tempReplys = new ArrayList<>();}return comments;}private void combineChildren(Long blogId, List<Comment> childComments, String parentNickname1) {
//        判断是否有一级子评论if(childComments.size() > 0){
//                循环找出子评论的idfor(Comment childComment : childComments){String parentNickname = childComment.getNickname();childComment.setParentNickname(parentNickname1);tempReplys.add(childComment);Long childId = childComment.getId();
//                    查询出子二级评论recursively(blogId, childId, parentNickname);}}}private void recursively(Long blogId, Long childId, String parentNickname1) {
//        根据子一级评论的id找到子二级评论List<Comment> replayComments = commentDao.findByBlogIdAndReplayId(blogId,childId);if(replayComments.size() > 0){for(Comment replayComment : replayComments){String parentNickname = replayComment.getNickname();replayComment.setParentNickname(parentNickname1);Long replayId = replayComment.getId();tempReplys.add(replayComment);recursively(blogId,replayId,parentNickname);}}}//    新增评论@Overridepublic int saveComment(Comment comment) {comment.setCreateTime(new Date());int comments = commentDao.saveComment(comment);
//        文章评论计数blogDao.getCommentCountById(comment.getBlogId());return comments;}
}

总结:本章主要是简单介绍博客评论功能的实现,功能并不全面。实现逻辑:因为是博客普通用户不需要登录即可浏览,所以没有做普通用户登录功能,评论时候需要输入自己的姓名和邮箱进行评论,若为博主评论则是通过实体类定义的字段在前端做判断,若为博主则增加标签。

如何实现博客的评论和回复功能相关推荐

  1. 博客的评论与回复功能的实现

    你好呀,我是小邹. 在之前的文章中,提到了个人博客的简单回复功能的实现,今天记录一下完整的评论功能的实现. 实现思路 数据库设计:评论表需要定义出当前博客id以便做关联,因为评论需要有回复功能,则需要 ...

  2. 博客园的神回复,程序猿的奇葩神回复[连载][二]

    在上一篇(博客园的神回复,一起看看那些IT男的神回复[连载][一])中(ps: 这篇博客之所以改名是因为这次的神回复里有程序媛,所以用IT男不太合适),博客园神回复还是挺受欢迎的,上一篇博客的神回复取 ...

  3. php评论 盖楼,我努力了一下,终于把博客的评论样式改成盖楼样式了,完美

    前几天逛博客,看到的博客评论是那种回复一次,回复内容就在下面显示出来,也就是俗称的"盖楼式评论".像下面的样式: 我的博客的评论,我之前开发这个评论的时候,偷了一个懒,直接把回复评 ...

  4. Hugo项目实战-集成评论博客添加评论功能

    实践效果 Quick Start Install Hugo brew install hugo # or port install hugohugo version Create a New Site ...

  5. GitHub Page个人博客中评论功能

    最近通过fork大佬的github和jekyll模板搭了一个博客,但在使用过程中,发现博文的评论功能不能使用,这里记录下个人博客中评论功能得我使用流程及问题. 1.出现问题 首先看一下初始博客搭建好之 ...

  6. Hexo博客添加评论功能

    Hexo博客添加评论功能 实现了Hexo的评论功能 先附上官网链接valine官网 我使用的是Material-X主题,大多主题都支持,基本在官方主题文档都可以找到使用方法 1.进入官网,注册账号 需 ...

  7. jquery实现层级显示 效果图_php运用无限级分类实现评论及回复功能

    经常在各大论坛或新闻板块详情页面下边看到评论功能,当然不单单是直接发表评论内容那么简单,可以对别人的评论进行回复,别人又可以对你的回复再次评论或回复,如此反复,理论上可以说是没有休止; 从技术角度分析 ...

  8. 【博客项目】—用户删除功能(十二)

    [博客项目]-用户删除功能(十二)

  9. 【博客项目】—用户修改功能(十一)

    [博客项目]-用户修改功能(十一)

  10. 【博客项目】—用户新增功能(九)

    [博客项目]-用户新增功能(九) 此时的数据库里面已经新增了一个用户

最新文章

  1. c语言弟弟的作业,教弟弟做作业作文500字
  2. SCA与spring集成(在spring中开发SOA)
  3. DDNS 的工作原理及其在 Linux 上的实现--转
  4. SAP Netweaver gateway cache table logic
  5. Java程序员最值得学习的10大技术
  6. Java修炼之道--I/O
  7. Spark Streaming之updateStateByKey和mapWithState比较
  8. 使用Apache Ignite构建C++版本的分布式应用
  9. asp.net 抓取html内容,c# – 如何从ASP.NET获取网页的HTML内容
  10. ARM Linux启动分析----head-armv.S内幕
  11. cad道路里程桩号标注_CAD道路桩号自动编号插件
  12. 配置一台新的kubuntu
  13. C——esc按键按下与识别
  14. 服务器添加账号失败是怎么回事啊,outlook添加新账户时失败,该怎么办
  15. 步进电机基本原理、分类、基本参数、应用场景
  16. DVWA靶场系列1-环境搭建
  17. 欧美slots游戏 源码(完整)
  18. nodejs代码保护方式--加密、混淆、编译、打包成exe
  19. 个人使用ChatGLM-6B遇到的部分问题汇总
  20. 关于使用微软拼音在Hbuilder打不出顿号、的问题

热门文章

  1. 用Python讲述:地理“经纬度”数据的4种转换方法!
  2. app开发人员配置【职责】
  3. 微博分享sdk4.0 中遇到的坑以及解决办法汇总
  4. grep匹配单引号('),惰性匹配(.*?)
  5. CAD基础+常用快捷(四)
  6. Vue学习之vue-cli脚手架下载安装及配置
  7. 编程猫海龟编辑器 附使用教程
  8. PNP与NPN的区别与判断(一)
  9. 解决iPhone模拟器无法启动的方法
  10. 判断一个很大的数是否是11的倍数(2种做法)