2021-6-28:开发小而美的博客(博客详情评论功能)

2021-6-28:开发小而美的博客(博客详情评论功能)


评论功能:
1. 评论信息提交与回复功能
2. 评论信息列表展示功能
3. 管理员回复评论功能

1、处理页面

在这里插入图片描述

2、设置隐含路径

在这里插入图片描述

3、表单验证

在这里插入图片描述


    //评论表单验证
    $('.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: '请填写正确的邮箱地址'
          }]
        }
      }
    });

4、设置按钮

在这里插入图片描述
在这里插入图片描述

5、发送请求

在这里插入图片描述

   $('#commentpost-btn').click(function () {
      var boo = $('.ui.form').form('validate form');
      if (boo) {
        console.log('校验成功');
        postData();
      } else {
        console.log('校验失败');
      }

    });

6、运行测试校验

如果邮箱号没输对,是评论不了的
在这里插入图片描述

7、信息提交给后台服务(发送请求)

在这里插入图片描述

function postData() {
      $("#comment-container").load(/*[[@{/comments}]]*/"",{
        "parentComment.id" : $("[name='parentComment.id']").val(),
        "blog.id" : $("[name='blog.id']").val(),
        "nickname": $("[name='nickname']").val(),
        "email"   : $("[name='email']").val(),
        "content" : $("[name='content']").val()
      },function (responseTxt, statusTxt, xhr) {
//        $(window).scrollTo($('#comment-container'),500);
        clearContent();
      });
    }

8、动态加载

在这里插入图片描述

<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>
                  </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.parentComment.nickname}|" 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>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
              <!--/*-->
              <div class="comment">
                <a class="avatar">
                  <img src="https://unsplash.it/100/100?image=1005">
                </a>
                <div class="content">
                  <a class="author">Elliot Fu</a>
                  <div class="metadata">
                    <span class="date">Yesterday at 12:30AM</span>
                  </div>
                  <div class="text">
                    <p>This has been very useful for my research. Thanks as well!</p>
                  </div>
                  <div class="actions">
                    <a class="reply">回复</a>
                  </div>
                </div>
                <div class="comments">
                  <div class="comment">
                    <a class="avatar">
                      <img src="https://unsplash.it/100/100?image=1005">
                    </a>
                    <div class="content">
                      <a class="author">Jenny Hess</a>
                      <div class="metadata">
                        <span class="date">Just now</span>
                      </div>
                      <div class="text">
                        Elliot you are always so right :)
                      </div>
                      <div class="actions">
                        <a class="reply">回复</a>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
              <div class="comment">
                <a class="avatar">
                  <img src="https://unsplash.it/100/100?image=1005">
                </a>
                <div class="content">
                  <a class="author">Joe Henderson</a>
                  <div class="metadata">
                    <span class="date">5 days ago</span>
                  </div>
                  <div class="text">
                    Dude, this is awesome. Thanks so much
                  </div>
                  <div class="actions">
                    <a class="reply">回复</a>
                  </div>
                </div>
              </div>
              <!--*/-->

            </div>
          </div>
        </div>

9、修改英文字符

在这里插入图片描述
指定宽度
在这里插入图片描述

10、恢复清除工作

在这里插入图片描述

 function clearContent() {
      $("[name='content']").val('');
      $("[name='parentComment.id']").val(-1);
      $("[name='content']").attr("placeholder", "请输入评论信息...");
    }

11、设置滚动到某处

在这里插入图片描述

   function postData() {
      $("#comment-container").load(/*[[@{/comments}]]*/"",{
        "parentComment.id" : $("[name='parentComment.id']").val(),
        "blog.id" : $("[name='blog.id']").val(),
        "nickname": $("[name='nickname']").val(),
        "email"   : $("[name='email']").val(),
        "content" : $("[name='content']").val()
      },function (responseTxt, statusTxt, xhr) {
//        $(window).scrollTo($('#comment-container'),500);
        clearContent();
      });
    }

12、点击回复事件

响应这个方法
在这里插入图片描述

在这里插入图片描述

13、点击回复方法

在这里插入图片描述

 function reply(obj) {
      var commentId = $(obj).data('commentid');
      var commentNickname = $(obj).data('commentnickname');
      $("[name='content']").attr("placeholder", "@"+commentNickname).focus();
      $("[name='parentComment.id']").val(commentId);
      $(window).scrollTo($('#comment-form'),500);
    }

14、新建CommentController类

在这里插入图片描述

package net.lhf.web;

import net.lhf.po.Comment;
import net.lhf.po.User;
import net.lhf.service.BlogService;
import net.lhf.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import javax.servlet.http.HttpSession;
/**
 * 功能:
 * 作者:李红芙
 * 日期:2021年6月23日
 */

@Controller
public class CommentController {

    @Autowired
    private CommentService commentService;

    @Autowired
    private BlogService blogService;

    @Value("${comment.avatar}")
    private String avatar;

    @GetMapping("/comments/{blogId}")
    public String comments(@PathVariable Long blogId, Model model) {
        model.addAttribute("comments", commentService.listCommentByBlogId(blogId));
        return "blog :: commentList";
    }


    @PostMapping("/comments")
    public String post(Comment comment, HttpSession session) {
        Long blogId = comment.getBlog().getId();
        comment.setBlog(blogService.getBlog(blogId));
        User user = (User) session.getAttribute("user");
        if (user != null) {
            comment.setAvatar(user.getAvatar());
            comment.setAdminComment(true);
        } else {
            comment.setAvatar(avatar);
        }
        commentService.saveComment(comment);
        return "redirect:/comments/" + blogId;
    }



}

15、新建CommentService接口

在这里插入图片描述

package net.lhf.service;

import net.lhf.po.Comment;

import java.util.List;

/**
 * 功能:
 * 作者:李红芙
 * 日期:2021年6月23日
 */
public interface CommentService {

    List<Comment> listCommentByBlogId(Long blogId);

    Comment saveComment(Comment comment);
}

16、新建CommentServiceImpl类

在这里插入图片描述

package net.lhf.service;

import net.lhf.dao.CommentRepository;
import net.lhf.po.Comment;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 功能:
 * 作者:李红芙
 * 日期:2021年6月23日
 */
@Service
public class CommentServiceImpl implements CommentService {

    @Autowired
    private CommentRepository commentRepository;

    @Override
    public List<Comment> listCommentByBlogId(Long blogId) {
        Sort sort = Sort.by("createTime");
        List<Comment> comments = commentRepository.findByBlogIdAndParentCommentNull(blogId,sort);
        return eachComment(comments);
    }

    @Transactional
    @Override
    public Comment saveComment(Comment comment) {
        Long parentCommentId = comment.getParentComment().getId();
        if (parentCommentId != -1) {
            comment.setParentComment(commentRepository.getOne(parentCommentId));
        } else {
            comment.setParentComment(null);
        }
        comment.setCreateTime(new Date());
        return commentRepository.save(comment);
    }


    /**
     * 循环每个顶级的评论节点
     * @param comments
     * @return
     */
    private List<Comment> eachComment(List<Comment> comments) {
        List<Comment> commentsView = new ArrayList<>();
        for (Comment comment : comments) {
            Comment c = new Comment();
            BeanUtils.copyProperties(comment,c);
            commentsView.add(c);
        }
        //合并评论的各层子代到第一级子代集合中
        combineChildren(commentsView);
        return commentsView;
    }

    /**
     *
     * @param comments root根节点,blog不为空的对象集合
     * @return
     */
    private void combineChildren(List<Comment> comments) {

        for (Comment comment : comments) {
            List<Comment> replys1 = comment.getReplyComments();
            for(Comment reply1 : replys1) {
                //循环迭代,找出子代,存放在tempReplys中
                recursively(reply1);
            }
            //修改顶级节点的reply集合为迭代处理后的集合
            comment.setReplyComments(tempReplys);
            //清除临时存放区
            tempReplys = new ArrayList<>();
        }
    }

    //存放迭代找出的所有子代的集合
    private List<Comment> tempReplys = new ArrayList<>();
    /**
     * 递归迭代,剥洋葱
     * @param comment 被迭代的对象
     * @return
     */
    private void recursively(Comment comment) {
        tempReplys.add(comment);//顶节点添加到临时存放集合
        if (comment.getReplyComments().size()>0) {
            List<Comment> replys = comment.getReplyComments();
            for (Comment reply : replys) {
                tempReplys.add(reply);
                if (reply.getReplyComments().size()>0) {
                    recursively(reply);
                }
            }
        }
    }
}

17、新建CommentRepository接口

在这里插入图片描述

package net.lhf.dao;

import net.lhf.po.Comment;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * 功能:
 * 作者:李红芙
 * 日期:2021年6月23日
 */
public interface CommentRepository extends JpaRepository<Comment,Long>{


    List<Comment> findByBlogIdAndParentCommentNull(Long blogId, Sort sort);
}

18、设置评论图片

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
th:attr=“data-commentid= c o m m e n t . i d , d a t a − c o m m e n t n i c k n a m e = {comment.id},data-commentnickname= comment.id,datacommentnickname={comment.nickname}”

19、查看数据库

在这里插入图片描述

20、效果图

在这里插入图片描述

20、管理员评论

想以管理员的身份评论,必须登录管理员账号,在对所想评论的博文进行刷新,然后他会自动获取管理员账号,
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值