(二十)评论回复功能及邮件提醒
说明
上节课我们完成了最基本的评论功能及展示,这节课我们来说下评论回复功能、收到评论后的给站长及被评论者的邮件通知功能
回复功能
- 给每个评论加上
data-id
的属性存储评论的id
<li class="lw-posr" th:each="comment:${commentPage.rows}">
<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 th:data-id="${comment.id}" href="javascript:void(0)"
class="lw-comment-replay">回复</a>
<a href="javascript:void(0)" class="lw-comment-cancel"
style="display: none">取消回复</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>
- 当我们点击回复按钮时将评论框移到目标评论的下方,然后清空评论框的内容并将评论框的
pid
改为目标评论的id
$('#lw-comment-list').on('click', '.lw-comment-replay', function () {
$('#lw-comment-list .lw-comment-cancel').hide()
$('#lw-comment-list .lw-comment-replay').show()
let id = $(this).data('id');
let source = $('#lw-comment-box')
// 复制一个评论框
let cloneBox = source.clone();
//删除源评论框
source.remove()
//将复制的评论框加到目标评论的下方
$(this).parent().parent().append(source)
//更改pid
$('#lw-comment-form input[name=pid]').val(id)
$(this).hide()
$(this).parent().find('.lw-comment-cancel').show()
})
- 评论完成后将评论框移加原来的位置并将评论框的
pid
变为0
且评论内容清空
function commBoxReset(){
let source = $('#lw-comment-box')
let cloneBox = source.clone();
source.remove()
$('#lw-article-box').after(source)
$('#lw-comment-form input[name=pid]').val(0)
$('#lw-comment-form textarea').val('')
$('#lw-comment-list .lw-comment-cancel').hide()
$('#lw-comment-list .lw-comment-replay').show()
}
$('#lw-comment-list').on('click', '.lw-comment-cancel', function () {
commBoxReset()
})
- 后端处理评论层级关系
//Mapper
Page<Comment> findAllByArticleAndPidOrderByCreatedDesc(Article article, Integer pid, Pageable pageable);
List<Comment> findAllByPidOrderByCreatedDesc(Integer pid);
//Service
public void save(Comment comment) {
//新评论
if (Objects.isNull(comment.getId())) {
comment.setCreated(new Date());
comment.setView(false);
if (comment.getPid() != 0) {
Comment parent = detail(comment.getPid());
comment.setContent("@"+parent.getNickname()+": "+comment.getContent());
comment.setPid(findParent(comment.getPid()));
}
}
mapper.save(comment);
}
private Integer findParent(Integer id) {
Comment comment = detail(id);
if (comment.getPid() == 0) {
return comment.getId();
}
return findParent(comment.getPid());
}
- 修改分页查询评论
Service
层的代码为其加上子评论列表
PageHelper.<Comment>builder()
.rows(page.getContent().stream().peek(x -> x.setChildren(mapper.findAllByPidOrderByCreatedDesc(x.getId()))).collect(Collectors.toList()))
.current(pageNum)
.total(page.getTotalElements())
.totalPage(page.getTotalPages())
.build();
- 页面子评论处理
<ul>
<li class="lw-posr" th:each="comment:${commentPage.rows}">
<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 th:data-id="${comment.id}" href="javascript:void(0)"
class="lw-comment-replay">回复</a>
<a href="javascript:void(0)" class="lw-comment-cancel"
style="display: none">取消回复</a>
</p>
<p class="lw-comment-info" th:text="${comment.content}"></p>
</div>
<ul th:if="${comment.children.size() > 0}">
<li class="lw-posr" th:each="child:${comment.children}">
<div class="lw-comment-avatar lw-posa">
<img th:src="${@defaultImage.avatar(child.email)}" alt="">
</div>
<div class="lw-comment-content">
<p>
<b th:text="${child.nickname}"></b>
<span th:text="${#dates.format(child.created,'yyyy-MM-dd HH:mm')}"></span>
<a th:data-id="${child.id}" href="javascript:void(0)"
class="lw-comment-replay">回复</a>
<a href="javascript:void(0)" class="lw-comment-cancel"
style="display: none">取消回复</a>
</p>
<p class="lw-comment-info" th:text="${child.content}"></p>
</div>
</li>
</ul>
</li>
</ul>
邮件提醒
准备工作
我这里以QQ邮箱为例,其它邮箱同理
- 我们先准备一个QQ邮箱且开通时长大于15天
- 开启
POP3/IMAP/SMTP/
服务并生成授权码
常见SMTP服务器地址
邮箱类型 | SMTP服务器地址 | 端口号 |
---|---|---|
QQ邮箱 | smtp.qq.com | 465或587 |
sina邮箱 | smtp.sina.cn | 465或587 |
126邮箱 | smtp.126.com | 465或994 |
aliyun邮箱 | smtp.aliyun.com | 465或994 |
163邮箱 | smtp.163.com | 465或994 |
yeah邮箱 | smtp.yeah.net | 465或994 |
SpringBootMail邮件测试
- 导入依赖
<!-- springboot 邮件mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
- 配置发件人
spring:
mail:
# 默认的邮件编码为UTF-8
default-encoding: UTF-8
# 邮箱服务器
host: smtp.qq.com
# 邮箱
username: xxx@qq.com
# 密码
password: xxxxx
# 端口
port: 587
# 其它属性,这里只开启debug输出错误信息
properties:
debug: true
- 创建一个邮件工具类
package cn.kevinlu98.common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Date;
/**
* Author: Mr丶冷文
* Date: 2022/10/14 19:44
* Email: kevinlu98@qq.com
* Description:
*/
@Slf4j
@Component
public class MailHelper {
@Value("${spring.mail.username}")
private String from;
private final JavaMailSender javaMailSender;
public MailHelper(JavaMailSender javaMailSender) {
this.javaMailSender = javaMailSender;
}
/**
* 发送邮件
*
* @param send 收件人
* @param subject 主题
* @param text 内容
*/
public void sendMail(String send, String subject, String text) {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
try {
helper.setSentDate(new Date()); //设置发件时间
helper.setFrom(from); //发件人
helper.setTo(send); //设置收件人
helper.setSubject(subject); //设置标签
helper.setText(text, true); //设置内容
javaMailSender.send(message); //发邮件
} catch (MessagingException e) {
log.error(e.getMessage(), e);
}
}
}
- 测试是否发送成功
package cn.kevinlu98.test;
import cn.kevinlu98.Application;
import cn.kevinlu98.common.MailHelper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Author: Mr丶冷文
* Date: 2022/10/14 19:49
* Email: kevinlu98@qq.com
* Description:
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MailTest {
@Autowired
private MailHelper helper;
@Test
public void testSend(){
helper.sendMail("xxx@qq.com","测试邮件","<h1>冷文学习者</h1><p>我是一个测试邮件</p>");
}
}
评论邮件提醒
- 在保存新评论时先给站长收一封邮件通知
@Async
public void sendMailToWebsite(Integer id) {
Article article = articleMapper.findById(id).orElse(null);
if (Objects.isNull(article)) return;
String content = "<p>\n" + " 你的文章 <a href=\"" + webSite.getUrl() + "/" + id + ".html\">" + article.getTitle() + "</a>收到了新评论,点些查看\n" + "</p>\n" + "<p style=\"text-align:right ;\">\n" + "时间:\n" + new Date() + "</p>";
helper.sendMail(webSite.getMail(), webSite.getTitle() + "收到新评论", content);
}
- 如果父评论不为空,则给被回复者也发一封邮件
@Async
public void sendMailToComment(Integer id, Integer cid, String replay) {
Article article = articleMapper.findById(id).orElse(null);
if (Objects.isNull(article)) return;
Comment comment = mapper.findById(cid).orElse(null);
if (Objects.isNull(comment)) return;
String content = "<p>\n" +
" 你在<a href=\"" + webSite.getUrl() + "\">" + webSite.getTitle() +
"</a>对 <a href=\"" + webSite.getUrl() + "/" + article.getId() + ".html\">" + article.getTitle() +
"</a>文章的评论收到了新回复,回复内容如下:\n" +
"</p>\n" +
"<p>\n" +
replay +
"</p>\n" +
"<p style=\"text-align:right ;\">\n" +
" 一一发件人:" + webSite.getTitle() +
"</p>\n" +
"<p style=\"text-align:right ;\">\n" +
"时间:" + new Date() +
"</p>\n" +
"<p style=\"text-align:right ;\">\n" +
" 此邮件是由" + webSite.getTitle() + "自动发送,请勿回复 \n" +
" </p>";
helper.sendMail(comment.getEmail(), webSite.getTitle() + "收到新回复", content);
}
//Service save
public void save(Comment comment) {
//新评论
if (Objects.isNull(comment.getId())) {
sendMailToWebsite(comment.getArticle().getId());
comment.setCreated(new Date());
comment.setView(false);
if (comment.getPid() != 0) {
sendMailToComment(comment.getArticle().getId(), comment.getPid(), comment.getContent());
Comment parent = detail(comment.getPid());
comment.setContent("@" + parent.getNickname() + ": " + comment.getContent());
comment.setPid(findParent(comment.getPid()));
}
}
mapper.save(comment);
}
看看
多谢大佬分享
强强强
感谢作者!
感谢!