一、业务处理层实现
1、在ICommentService接口增加用户发表评论的方法
// 用户发表评论
public void pushComment(Comment comment);
2、实现该方法
@Autowired
private StatisticMapper statisticMapper;
// 用户发表评论
@Override
public void pushComment(Comment comment){
commentMapper.pushComment(comment);
// 更新文章评论数据量
Statistic statistic = statisticMapper.selectStatisticWithArticleId(comment.getArticleId());
statistic.setCommentsNum(statistic.getCommentsNum()+1);
statisticMapper.updateArticleCommentsWithId(statistic);
}
二、请求处理层实现
创建一个控制类CommentController,编写一个处理“/comments/publish”请求的方法。
该方法对用户评论信息进行了获取和封装,然后进行插入操作,最后根据执行结果向原页面返回状态信息。
@Controller
@RequestMapping("/comments")
public class CommentController {
private static final Logger logger = LoggerFactory.getLogger(CommentController.class);
@Autowired
private ICommentService commentServcieImpl;
// 发表评论操作
@PostMapping(value = "/publish")
@ResponseBody
public ArticleResponseData publishComment(HttpServletRequest request,@RequestParam Integer aid, @RequestParam String text) {
// 去除js脚本
text = MyUtils.cleanXSS(text);
text = EmojiParser.parseToAliases(text);
// 获取当前登录用户
User user=(User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
// 封装评论信息
Comment comments = new Comment();
comments.setArticleId(aid);
comments.setIp(request.getRemoteAddr());
comments.setCreated(new Date());
comments.setAuthor(user.getUsername());
comments.setContent(text);
try {
commentServcieImpl.pushComment(comments);
logger.info("发布评论成功,对应文章id: "+aid);
return ArticleResponseData.ok();
} catch (Exception e) {
logger.error("发布评论失败,对应文章id: "+aid +";错误描述: "+e.getMessage());
return ArticleResponseData.fail();
}
}
}
三、实现前端页面功能
在文章详情展示页面articleDetails.html中展示了文章的评论页面位置为client/comments::comments,在client文件夹下的comments.html文件进行具体的评论展示和发布实现。
comments.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:fragment="comments"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<body>
<div th:if="${article}!=null">
<div th:id="${article.id ?: 0}" class="comment-container">
<div id="comments" class="clearfix">
<div th:if="${article.allowComment}">
<span class="response">
<form name="logoutform" th:action="@{/logout}" method="post"></form>
<th:block sec:authorize="isAuthenticated()">
Hello,<a data-no-instant="" sec:authentication="name"></a>
如果你想 <a href="javascript:document.logoutform.submit();">注销</a> ?
</th:block>
<th:block sec:authorize="isAnonymous()">
用户想要评论,请先<a th:href="@{/login}" title="登录" data-no-instant="">登录</a>!
</th:block>
</span>
<div sec:authorize="isAuthenticated()">
<form id="comment-form" class="comment-form" role="form" onsubmit="return TaleComment.subComment();">
<input type="hidden" name="aid" id="aid" th:value="${article.id}"/>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<textarea name="text" id="textarea" class="form-control" placeholder="以上信息可以为空,评论不能为空哦!"
required="required" minlength="5" maxlength="2000"></textarea>
<button type="submit" class="submit" id="misubmit">提交</button>
</form>
</div>
</div>
<!-- 分页显示其他评论内容 -->
<div th:if="${comments}">
<ol class="comment-list">
<th:block th:each="comment :${comments.list}">
<li th:id="'li-comment-'+${comment.id}" class="comment-body comment-parent comment-odd">
<div th:id="'comment-'+${comment.id}">
<div class="comment-view" onclick="">
<div class="comment-header">
<!--设置人物头像和名称-->
<img class="avatar" th:src="@{/assets/img/avatars.jpg}" height="50"/>
<a class="comment-author" rel="external nofollow" th:text="${comment.author}" />
</div>
<!-- 评论内容 -->
<div class="comment-content">
<span class="comment-author-at"></span>
<p th:utext="${commons.article(comment.content)}"></p>
</div>
<!-- 评论日期 -->
<div class="comment-meta">
<time class="comment-time" th:text="${commons.dateFormat(comment.created)}"></time>
<a sec:authorize="isAuthenticated()" th:if="${comment.author}!= ${session.SPRING_SECURITY_CONTEXT.authentication.principal.username}" href="javascript:void(0)" style="color: #1b961b">
回复
</a>
</div>
</div>
</div>
</li>
</th:block>
</ol>
<!-- 进行评论分页 -->
<div class="lists-navigator clearfix">
<ol class="page-navigator">
<!-- 判断并展示上一页 -->
<th:block th:if="${comments.hasPreviousPage}">
<li class="prev"><a th:href="'?cp='+${comments.prePage}+'#comments'">上一页</a></li>
</th:block>
<!-- 判断并展示中间页 -->
<th:block th:each="navIndex : ${comments.navigatepageNums}">
<th:block th:if="${comments.pages} <= 5">
<li th:class="${comments.pageNum}==${navIndex}?'current':''">
<a th:href="'?cp='+${navIndex}+'#comments'" th:text="${navIndex}"></a>
</li>
</th:block>
<th:block th:if="${comments.pages} > 5">
<li th:if="${comments.pageNum <=3 && navIndex <= 5}" th:class="${comments.pageNum}==${navIndex}?'current':''">
<a th:href="'?cp='+${navIndex}+'#comments'" th:text="${navIndex}"></a>
</li>
<li th:if="${comments.pageNum >= comments.pages-2 && navIndex > comments.pages-5}" th:class="${comments.pageNum}==${navIndex}?'current':''">
<a th:href="'?cp='+${navIndex}+'#comments'" th:text="${navIndex}"></a>
</li>
<li th:if="${comments.pageNum >=4 && comments.pageNum <= comments.pages-3 && navIndex >= comments.pageNum-2 && navIndex <= comments.pageNum+2}" th:class="${comments.pageNum}==${navIndex}?'current':''">
<a th:href="'?cp='+${navIndex}+'#comments'" th:text="${navIndex}"></a>
</li>
</th:block>
</th:block>
<!-- 判断并展示下一页 -->
<th:block th:if="${comments.hasNextPage}">
<li class="next"><a th:href="'?cp='+${comments.nextPage}+'#comments'">下一页</a></li>
</th:block>
</ol>
</div>
</div>
</div>
</div>
</div>
</body>
<div th:replace="comm/tale_comment::tale_comment"></div>
</html>
注:
使用sec:*和th:*属性进行评论框管理控制以及评论列表获取展示。在评论发布框控制中,只有登录用户才可以查看到评论框并发布评论。在评论发布的<form>表单中特别添加了一个用于CSRF防御时进行CSRF Token认证的隐藏域“<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>”
在页面底部<div th:replace="comm/tale_comment::tale_comment"></div>的作用是将该标签替换为tale_comment.html的内容,该内容的作用是响应评论页面中的表单的οnsubmit="return TaleComment.subComment();"
tale_comment.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:fragment="tale_comment" >
<body>
<script type="text/javascript">
/*<![CDATA[*/
(function () {
window.TaleComment = {
subComment: function () {
$.ajax({
type: 'post',
url: '/comments/publish',
data: $('#comment-form').serialize(),
async: false,
dataType: 'json',
success: function (result) {
if (result && result.success) {
window.alert("评论提交成功!");
window.location.reload();
} else {
window.alert("发送失败")
if (result.msg) {
alert(result.msg);
}
}
}
});
return false;
}
};
})();
</script>
</body>
</html>
四、效果展示
启动项目进行测试,登录并进入到某个文章详情页面,在文章底部的评论框中发布评论进行效果测试。