SpringBoot + Thymeleaf + emojioneArea 实现评论回复

📢 本文章按照仿牛客网里实现评论回复功能的改进。

👤 公众号:恩故事还在继续


1️⃣ 效果展示

在这里插入图片描述

✏️ 补充说明

上面的主要改变是将原来的评论框添加了表情回复功能,原来的项目是没有这项功能的,这个是我自己添加的。

2️⃣ 技术使用说明

这里基本逻辑框架还是使用的是 SpringBoot + Thymeleaf 

其次就是使用了 emoji 来支持表情回复,我使用的插件是: emojioneArea

3️⃣ 功能实现说明

实现评论的主要逻辑其实并不复杂,主要操作的就是两张数据表: comment(评论) 和 discuss-post(帖子)

我们添加一条评论主要针对的是:comment

我们添加评论之后需要修改帖子表里的字段: comment_count

然后后端逻辑写完之后就是如何一一对应前端显示了,最后单独说一下如何使用插件 emojioneArea

4️⃣ 代码实现

为了方便大家看主要逻辑,这里我把代码就放到GitHub 上去,我在这里主要说下我们需要用哪些代码:

后端模块主要包含的代码:

CommentMapper、 CommentService、 CommentController: 主要是添加评论

DiscussPostMapper、DiscussPostService:主要是实现更新评论数量

comment-mapper.xml、discusspost-mapper.xml: 实现相关的数据库操作

前端主要是使用到的是: discuss-detail.html

🔗 SpringBoot + Thymeleaf + emojioneArea 实现评论


5️⃣ emojioneArea 插件的使用

这篇文章主要还是说下怎么使用 emojioneArea 插件, 写这个功能的时候也看了网上很多文章,但是感觉大家写的残次不齐

并不是我想要的,不过我可以将一些我看到的文章推荐给大家使用。

🔗 emojionearea 官网

在这里插入图片描述
你可以选择去github下载源码,也可以直接点击下载 zip 文件,这里跳转到 github 里面有一些语法的解释,可以参考参考。

我这里也准备了一个小 demo 就是把作者之前写的那一堆提取出来了,只需要按照 拿我的那个用就可以, 给大家看一看,如下图所示:

在这里插入图片描述
顺便补充一款样式:

在这里插入图片描述

✏️ 使用说明

我把文件放到了一起,这里提供上面的两款样式给大家打包在一起了,第一款样式直接解压之后,选择:demo-mine 就行

第二款名称叫做: HTML实现@功能与emoji表情功能的输入框 

6️⃣ emojionearea 使用

  1. 导入相关的资源
<link rel="stylesheet" type="text/css" th:href="@{/emoji/css/emojionearea-2.1.3.min.css}">
<script type="text/javascript" th:src="@{/emoji/js/jquery-1.11.3.min.js}"></script>
<script type="text/javascript" src="http://cdn.bootcss.com/emojione/2.1.1/lib/js/emojione.min.js"></script>
<script type="text/javascript" th:src="@{/emoji/js/emojionearea-2.1.3.min.js}"></script>
  1. 指定函数
<script type="text/javascript">
 $(document).ready(function() {
   $("#example").emojioneArea();
 });
</script>

或者

<script type="text/javascript">
 $("#example").emojioneArea();
</script>
 
其中 example 指的是标签的 id

如果需要将图标隐藏起来可以添加这条属性:

$("#example").emojioneArea({
    autoHideFilters: true,
});
  1. 调用
  <textarea id="example">
  </textarea>

上面就是一个简单的使用,但是要应用到我们项目中需要注意的事项,如果我们输入到评论框里的是图片,我们没有对我们的数据库字段进行编码指定的话会出现下面这个错误:

Incorrect string value: '\xF0\x9F\x91\x93\xF0\x9F...' for column 'xxx' at row 1

这是因为我设置该字段默认编码是utf-8, 但是有特殊字符的话, 某些Unicode字符转成utf8可能4字节,而在MySQl5.5.3之前,utf8最长只有3字节。所以解决方法是, 修改字段的编码,比如我的字段是 content, 然后我点击数据表,找到该字段将编码设置为: utf8mb4

在这里插入图片描述

7️⃣ 代码展示

 <!-- 回帖 -->
 <div class="container mt-3">
     <!-- 回帖数量 -->
     <div class="row">
         <div class="col-8">
             <h6><b class="square"></b> <i th:text="${post.commentCount}">30</i>条回帖</h6>
         </div>
         <div class="col-4 text-right">
             <a href="#replyform" class="btn btn-primary btn-sm">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</a>
         </div>
     </div>
     <!-- 回帖列表 -->
     <ul class="list-unstyled mt-4">
         <!-- 第1条回帖 -->
         <li class="media pb-3 pt-3 mb-3 border-bottom" th:each="cvo:${comments}">
             <a href="profile.html">
                 <img th:src="${cvo.user.headerUrl}" class="align-self-start mr-4 rounded-circle user-header"
                      alt="用户头像">
             </a>
             <div class="media-body">
                 <div class="mt-0">
                     <span class="font-size-12 text-success" th:utext="${cvo.user.username}">掉脑袋切切</span>
                     <span class="badge badge-secondary float-right floor">
		<i th:text="${page.offset + cvoStat.count}">1</i>#
	</span>
                 </div>
                 <div class="mt-2" th:text="${cvo.comment.content}">
                     这开课时间是不是有点晚啊。。。
                 </div>
                 <div class="mt-4 text-muted font-size-12">
                     <span th:text="${#dates.format(cvo.comment.createTime,'yyyy-MM-dd HH:mm:ss')}">发布于 <b>2019-04-15 15:32:18</b></span>
                     <ul class="d-inline float-right">
                         <li class="d-inline ml-2"><a href="#" class="text-primary">(1)</a></li>
                         <li class="d-inline ml-2">|</li>
                         <li class="d-inline ml-2"><a href="#" class="text-primary">回复(<span
                                 th:text="${cvo.replayCount}">2</span>)</a></li>
                     </ul>
                 </div>
                 <!-- 回复列表 -->
                 <ul class="list-unstyled mt-4 bg-gray p-3 font-size-12 text-muted">
                     <!-- 第1条回复 -->
                     <li class="pb-3 pt-3 mb-3 border-bottom" th:each="rvo:${cvo.replays}">
                         <div>
			<span th:if="${rvo.target == null}">
				<b class="text-info" th:text="${rvo.user.username}">寒江雪</b>:&nbsp;&nbsp;
			</span>
                             <span th:if="${rvo.target != null}">
				<i class="text-info" th:text="${rvo.user.username}">Sissi</i> 回复
				<b class="text-info" th:utext="${rvo.target.username}">:寒江雪</b>&nbsp;&nbsp;
			</span>
                             <span th:text="${rvo.replay.content}">这个是直播时间哈,觉得晚的话可以直接看之前的完整录播的~</span>
                         </div>
                         <div class="mt-3">
                             <span th:text="${#dates.format(rvo.replay.createTime, 'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18</span>
                             <ul class="d-inline float-right">
                                 <li class="d-inline ml-2"><a href="#" class="text-primary">(1)</a></li>
                                 <li class="d-inline ml-2">|</li>
                                 <li class="d-inline ml-2"><a th:href="|#huifu-${rvoStat.count}|"
                                                              data-toggle="collapse" class="text-primary">回复</a>
                                 </li>
                             </ul>
                             <div th:id="|huifu-${rvoStat.count}|" class="mt-4 collapse">
                                 <form method="post" th:action="@{|/comment/add/${post.id}|}">
                                     <div>
                                         <input type="text" class="input-size" name="content" th:id="${#strings.randomAlphanumeric(100)}"
                                                th:placeholder="|回复${rvo.user.username}|" onfocus="addReplay(this)"/>
                                         <input type="hidden" name="entityType" value="2">
                                         <input type="hidden" name="entityId" th:value="${cvo.comment.id}">
                                         <input type="hidden" name="targetId" th:value="${rvo.user.id}">
                                     </div>
                                     <div class="text-right mt-2">
                                         <button type="submit" class="btn btn-primary btn-sm" onclick="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
                                     </div>
                                 </form>
                             </div>
                         </div>
                     </li>
                     <!-- 回复输入框 -->
                     <li class="pb-3 pt-3">
                         <form class="replyform" method="post" th:action="@{|/comment/add/${post.id}|}">
                             <div>
                                 <input type="text" class="input-size" name="content"  th:id="${cvo.comment.id}"  onfocus="addComment(this)" placeholder="请输入你的观点"/>
                                 <input type="hidden" name="entityType" value="2">
                                 <input type="hidden" name="entityId" th:value="${cvo.comment.id}">
                             </div>
                             <div class="text-right mt-2">
                                 <button type="submit" class="btn btn-primary btn-sm" onclick="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
                             </div>
                         </form>
                     </li>
                 </ul>
             </div>
         </li>
     </ul>
     <!-- 分页 -->
     <nav class="mt-5">
         <ul class="pagination justify-content-center" th:replace="index::pagination">
             <li class="page-item"><a class="page-link" href="#">首页</a></li>
             <li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>
             <li class="page-item active"><a class="page-link" href="#">1</a></li>
             <li class="page-item"><a class="page-link" href="#">2</a></li>
             <li class="page-item"><a class="page-link" href="#">3</a></li>
             <li class="page-item"><a class="page-link" href="#">4</a></li>
             <li class="page-item"><a class="page-link" href="#">5</a></li>
             <li class="page-item"><a class="page-link" href="#">下一页</a></li>
             <li class="page-item"><a class="page-link" href="#">末页</a></li>
         </ul>
     </nav>
 </div>
 <!-- 回帖输入 -->
 <div class="container mt-3">
     <form class="replyform" method="post" th:action="@{|/comment/add/${post.id}|}">
         <p class="mt-3">
             <a name="replyform"></a>
             <textarea placeholder="在这里畅所欲言你的看法吧!" name="content" id="commentId" ></textarea>
             <input type="hidden" name="entityType" value="1">
             <input type="hidden" name="entityId" th:value="${post.id}">
         </p>
         <p class="text-right">
             <button type="submit" class="btn btn-primary btn-sm">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
         </p>
     </form>
 </div>

<!-- 下面是调用的方法 -->
<script type="text/javascript">
    function addComment(e) {
        let parentId = e.getAttribute("id");
        console.log(parentId);

        $('#' + parentId).emojioneArea({
            autoHideFilters: true
        });
    }

    function addReplay(e) {
        let parentId = e.getAttribute("id");
        console.log(parentId);

        $('#' + parentId).emojioneArea({
            autoHideFilters: true
        });
    }
    
    $("#commentId").emojioneArea({
        autoHideFilters: true,
    });
</script>

❎ 这里需要解释一下

emojionearea 这个插件 你传入的 id 如果一直是 一个 那么你第二个框点击的时候是没有效果的,这个估计是没完善好或者有些地方我也不清楚。
所以我将他们的id 设置为随机数,这样多级评论就不会出现这个bug 。

🈵 资源获取

获取方式: 在文章末尾扫描我的公众号二维码, 然后后台回复: UI


8️⃣ 📞 联系 👨
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值