说明
经过前面的学习,我们博客的功能是越来越完善了,这节课我们来说下评论功能的实现
我们希望我们的评论完成之后页面不进行刷,只刷新评论部分,然后评论的翻页也是如此
普通评论实现
定义评论接口
- 路由:
/comment
- 方式:
POST
- 参数:
Comment
对象 - 返回:公共返回对象
- 路由:
//Service
@PostMapping("/comment")
public void save(Comment comment) {
//新评论
if (Objects.isNull(comment.getId())) {
comment.setCreated(new Date());
comment.setView(false);
}
mapper.save(comment);
}
//Controller
@PostMapping("/comment")
@ResponseBody
public Result<String> comment(Comment comment) {
if (StringUtils.equals(comment.getEmail(), webSite.getMail())) {
return Result.error(ResultEnum.RESULT_MAIL_FAIL);
}
commentService.save(comment);
return Result.success();
}
- 完善评论表单的
name
属性
<form id="lw-comment-form">
<input type="hidden" name="article.id" th:value="${article.id}">
<input type="hidden" name="pid" value="0">
<div class="col-md-12 lw-p0" style="padding-right: 10px;">
<textarea required name="content" placeholder="请输入你的评论..."></textarea>
</div>
<div class="col-md-4 col-xs-12 lw-comment-input lw-posr">
<input name="nickname" required type="text" placeholder="请输入昵称...">
<i class="fa fa-user lw-comment-input lw-posa"></i>
</div>
<div class="col-md-4 col-xs-12 lw-comment-input lw-posr">
<input name="email" required type="email" placeholder="请输入电子邮件...">
<i class="fa fa-envelope lw-posa"></i>
</div>
<div class="col-md-4 col-xs-12 lw-comment-input lw-posr">
<input name="url" type="url" placeholder="请输入主页地址...">
<i class="fa fa-link fa-link lw-posa"></i>
</div>
<div class="col-md-12 col-xs-12 lw-comment-input lw-posr" style="text-align: right">
<button class="lw-comment-submit" type="submit">提交按钮</button>
</div>
</form>
- 拦截表单提交改为
Ajax
提交表单
$('#lw-comment-form').on('submit', function () {
let data = $(this).serialize();
$.ajax({
url: '/comment',
method: 'POST',
data: data,
dataType: 'json',
success: res => {
if (res.code === 200) {
layer.msg('评论成功', {icon: 1})
// todo 局部刷新评论列表
} else {
layer.msg(res.message, {icon: 2})
}
}
})
return false;
})
局部刷新展示
我们其实可以写个获取评论列表的接口返回一个JSON
数据,然后前端把这个JSON
拼接到一段HTML
代码再展示出来,这过这样太麻烦了,我们可以直接利用Thymeleaf
返回一个fragment
,然后得用Jquery
的load
方法将其加载到对应容器中
- 在获取文章详情时也获取文章下的第一页评论
//Mapper
Page<Comment> findAllByArticleOrderByCreatedDesc(Article article, Pageable pageable);
//Service
public PageHelper<Comment> list(Integer id, int pageNum) {
Page<Comment> page = mapper.findAllByArticleOrderByCreatedDesc(Article.builder().id(id).build(), PageRequest.of(pageNum - 1, 5));
return PageHelper.<Comment>builder()
.rows(page.getContent())
.current(pageNum)
.total(page.getTotalElements())
.totalPage(page.getTotalPages())
.build();
}
//Controller
@GetMapping("/{id}.html")
public String detail(@PathVariable Integer id, Model model, HttpServletRequest request, HttpServletResponse response) {
Article article = articleService.detail(id);
if (Objects.isNull(CookieUtil.getCookie(request, Article.VIEW_PREFIX + id))) {
articleService.viewArticle(id);
CookieUtil.setCookie(response, Article.VIEW_PREFIX + id, "true");
}
//todo 当文章不存在时的处理
model.addAttribute("article", article);
PageHelper<Comment> commentPage = commentService.list(id, 1);
model.addAttribute("commentPage", commentPage);
return "detail";
}
- 如果评论是QQ邮箱,我们直接取QQ头像(https://q1.qlogo.cn/g?b=qq&nk=1628048198&s=100)做为评论者的头像,反之随机头像
public String avatar(String mail) {
Pattern pattern = Pattern.compile("(\\d{5,10})@qq.com");
Matcher matcher = pattern.matcher(mail);
if (matcher.find()) {
String qq = matcher.group(1);
return String.format("https://q1.qlogo.cn/g?b=qq&nk=%s&s=100", qq);
}
return avatars.get((int) (Math.random() * avatars.size()));
}
- 将页面的评论列表改为
fragment
并做渲染
<div id="lw-comment-list">
<th:block th:fragment="comments">
<div class="lw-comment-list">
<ul th:each="comment:${commentPage.rows}">
<li class="lw-posr">
<div class="lw-comment-avatar lw-posa">
<img th:src="${@defaultImage.avatar(comment.email)}" alt="">
</div>
<div class="lw-comment-content">
<p><b th:text="${comment.nickname}"></b> <span
th:text="${#dates.format(comment.created,'yyyy-MM-dd HH:mm')}"></span> <a
href="">回复</a></p>
<p class="lw-comment-info" th:text="${comment.content}"></p>
</div>
<ul>
<li class="lw-posr">
<div class="lw-comment-avatar lw-posa">
<img src="https://q1.qlogo.cn/g?b=qq&nk=1518228633&s=100" alt="">
</div>
<div class="lw-comment-content">
<p><b>VOODOO</b> <span>2022-09-28 19:53</span> <a href="">回复</a></p>
<p class="lw-comment-info">
@xpboy
<br>
谢谢</p>
</div>
</li>
</ul>
</li>
</ul>
</div>
<ul th:if="${commentPage.totalPage>1}" id="lw-page-list" class="lw-pagenation">
<li th:if="${commentPage.current != 1}"><a href="javascript:void(0)" data-page="1">首页</a></li>
<li th:each="num:${#numbers.sequence((commentPage.current < 3?1: commentPage.current -2) ,(commentPage.current < commentPage.totalPage -2?commentPage.current+2: commentPage.totalPage))}">
<a th:class="${commentPage.current eq num}?'lw-active':''"
href="javascript:void(0)"
th:data-page="${num}"
th:text="${num}"></a>
</li>
<li th:if="${commentPage.current != commentPage.totalPage}">
<a href="javascript:void(0)" th:data-page="${commentPage.totalPage}">尾页</a>
</li>
<li th:text="${'共 '+ commentPage.totalPage +' 页'}"></li>
</ul>
</th:block>
</div>
- 在分页及评论成功时调用
load
方法请求评论区域的数据并加载到容器
@GetMapping("/comment/{id}")
public String comments(@PathVariable Integer id, @RequestParam(required = false, defaultValue = "1") Integer pn, Model model) {
pn = Math.max(1, pn);
PageHelper<Comment> commentPage = commentService.list(id, pn);
model.addAttribute("commentPage", commentPage);
return "detail::comments";
}
//评论成功
$('#lw-comment-list').load('/comment/' + articleId)
//分页
$('#lw-comment-list').on('click', '#lw-page-list a', function () {
let page = $(this).data('page')
$('#lw-comment-list').load(`/comment/${articleId}?pn=${page}`)
})
丘丘人 游客 2023-02-23 14:07 回复
支持
4 游客 2023-05-04 19:35 回复
@丘丘人
1
MGS浪疯 游客 2023-02-02 00:26 回复
支持
腹肌没有五花腩要不要 游客 2023-01-04 08:56 回复
顶一下
jzl 游客 2022-10-29 16:28 回复
支持
遇见你真好 游客 2022-10-27 21:45 回复
看看
小丑 游客 2022-10-22 01:13 回复
来看看