From 35aea6ac34e6713334004912bed7837eafd02ace Mon Sep 17 00:00:00 2001 From: linhaojun Date: Sat, 24 Sep 2022 22:18:22 +0800 Subject: [PATCH 01/16] =?UTF-8?q?:art:=20=E4=BC=98=E5=8C=96=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E5=8F=91=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aurora-springboot/pom.xml | 4 + .../java/com/aurora/constant/CommonConst.java | 32 ++++---- .../consumer/CommentNoticeConsumer.java | 27 +++---- .../com/aurora/enums/CommentTypeEnum.java | 12 +-- .../java/com/aurora/model/dto/EmailDTO.java | 12 +++ .../service/impl/CommentServiceImpl.java | 79 ++++++++++++++----- .../java/com/aurora/utils/EmailUtils.java | 61 ++++++++++++++ .../main/java/com/aurora/utils/HTMLUtils.java | 2 +- .../src/main/resources/templates/owner.html | 55 +++++++++++++ .../src/main/resources/templates/user.html | 66 ++++++++++++++++ 10 files changed, 289 insertions(+), 61 deletions(-) create mode 100644 aurora-springboot/src/main/java/com/aurora/utils/EmailUtils.java create mode 100644 aurora-springboot/src/main/resources/templates/owner.html create mode 100644 aurora-springboot/src/main/resources/templates/user.html diff --git a/aurora-springboot/pom.xml b/aurora-springboot/pom.xml index da9e7b1..a437e7a 100644 --- a/aurora-springboot/pom.xml +++ b/aurora-springboot/pom.xml @@ -44,6 +44,10 @@ org.springframework.boot spring-boot-starter-quartz + + org.springframework.boot + spring-boot-starter-thymeleaf + com.baomidou mybatis-plus-boot-starter diff --git a/aurora-springboot/src/main/java/com/aurora/constant/CommonConst.java b/aurora-springboot/src/main/java/com/aurora/constant/CommonConst.java index 7de076c..e6aed4c 100644 --- a/aurora-springboot/src/main/java/com/aurora/constant/CommonConst.java +++ b/aurora-springboot/src/main/java/com/aurora/constant/CommonConst.java @@ -29,13 +29,11 @@ public class CommonConst { /** * 高亮标签 */ -// public static final String PRE_TAG = ""; public static final String PRE_TAG = ""; /** * 高亮标签 */ -// public static final String POST_TAG = ""; public static final String POST_TAG = ""; /** @@ -63,26 +61,11 @@ public class CommonConst { */ public static final String DEFAULT_NICKNAME = "用户"; - /** - * 浏览文章集合 - */ - public static String ARTICLE_SET = "articleSet"; - /** * 前端组件名 */ public static String COMPONENT = "Layout"; - /** - * 省 - */ - public static final String PROVINCE = "省"; - - /** - * 市 - */ - public static final String CITY = "市"; - /** * 未知的 */ @@ -109,4 +92,19 @@ public class CommonConst { */ public final static Integer TWENTY_MINUTES = 20; + /** + * 验证码 + */ + public static final String CAPTCHA = "验证码"; + + /** + * 审核提醒 + */ + public static final String CHECK_REMIND = "审核提醒"; + + /** + * 评论提醒 + */ + public static final String COMMENT_REMIND = "评论提醒"; + } diff --git a/aurora-springboot/src/main/java/com/aurora/consumer/CommentNoticeConsumer.java b/aurora-springboot/src/main/java/com/aurora/consumer/CommentNoticeConsumer.java index 3a713f9..4f49cb0 100644 --- a/aurora-springboot/src/main/java/com/aurora/consumer/CommentNoticeConsumer.java +++ b/aurora-springboot/src/main/java/com/aurora/consumer/CommentNoticeConsumer.java @@ -2,15 +2,14 @@ package com.aurora.consumer; import com.alibaba.fastjson.JSON; import com.aurora.model.dto.EmailDTO; +import com.aurora.utils.EmailUtils; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.mail.SimpleMailMessage; -import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Component; +import static com.aurora.constant.CommonConst.*; import static com.aurora.constant.MQPrefixConst.EMAIL_QUEUE; /** @@ -21,23 +20,17 @@ import static com.aurora.constant.MQPrefixConst.EMAIL_QUEUE; @RabbitListener(queues = EMAIL_QUEUE) public class CommentNoticeConsumer { - /** - * 邮箱号 - */ - @Value("${spring.mail.username}") - private String email; - @Autowired - private JavaMailSender javaMailSender; + private EmailUtils emailUtils; @RabbitHandler public void process(byte[] data) { - EmailDTO emailDTO = JSON.parseObject(new String(data), EmailDTO.class); - SimpleMailMessage message = new SimpleMailMessage(); - message.setFrom(email); - message.setTo(emailDTO.getEmail()); - message.setSubject(emailDTO.getSubject()); - message.setText(emailDTO.getContent()); - javaMailSender.send(message); + EmailDTO mailDTO = JSON.parseObject(new String(data), EmailDTO.class); + if (CAPTCHA.equals(mailDTO.getSubject()) || CHECK_REMIND.equals(mailDTO.getSubject())) { + emailUtils.sendSimpleMail(mailDTO); + } + if (COMMENT_REMIND.equals(mailDTO.getSubject())) { + emailUtils.sendHtmlMail(mailDTO); + } } } diff --git a/aurora-springboot/src/main/java/com/aurora/enums/CommentTypeEnum.java b/aurora-springboot/src/main/java/com/aurora/enums/CommentTypeEnum.java index 11d922a..da03237 100644 --- a/aurora-springboot/src/main/java/com/aurora/enums/CommentTypeEnum.java +++ b/aurora-springboot/src/main/java/com/aurora/enums/CommentTypeEnum.java @@ -12,9 +12,9 @@ import lombok.Getter; public enum CommentTypeEnum { /** - * 文章评论 + * 文章 */ - ARTICLE(1, "文章评论", "/articles/"), + ARTICLE(1, "文章", "/articles/"), /** * 留言 @@ -27,14 +27,14 @@ public enum CommentTypeEnum { ABOUT(3, "关于我", "/about/"), /** - * 友链评论 + * 友链 */ - LINK(4, "友链评论", "/friends/"), + LINK(4, "友链", "/friends/"), /** - * 说说评论 + * 说说 */ - TALK(5, "说说评论", "/talks/"); + TALK(5, "说说", "/talks/"); /** * 状态 diff --git a/aurora-springboot/src/main/java/com/aurora/model/dto/EmailDTO.java b/aurora-springboot/src/main/java/com/aurora/model/dto/EmailDTO.java index f659ed3..d04d604 100644 --- a/aurora-springboot/src/main/java/com/aurora/model/dto/EmailDTO.java +++ b/aurora-springboot/src/main/java/com/aurora/model/dto/EmailDTO.java @@ -5,6 +5,8 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.Map; + /** * @author 花未眠 * 邮件 @@ -30,4 +32,14 @@ public class EmailDTO { */ private String content; + /** + * 评论信息 + */ + private Map commentMap; + + /** + * 模板 + */ + private String template; + } diff --git a/aurora-springboot/src/main/java/com/aurora/service/impl/CommentServiceImpl.java b/aurora-springboot/src/main/java/com/aurora/service/impl/CommentServiceImpl.java index ad830a6..bd272f8 100644 --- a/aurora-springboot/src/main/java/com/aurora/service/impl/CommentServiceImpl.java +++ b/aurora-springboot/src/main/java/com/aurora/service/impl/CommentServiceImpl.java @@ -34,6 +34,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -92,8 +93,9 @@ public class CommentServiceImpl extends ServiceImpl impl .isReview(isCommentReview == TRUE ? FALSE : TRUE) .build(); commentMapper.insert(comment); + String fromNickname = UserUtils.getUserDetailsDTO().getNickname(); if (websiteConfig.getIsEmailNotice().equals(TRUE)) { - CompletableFuture.runAsync(() -> notice(comment)); + CompletableFuture.runAsync(() -> notice(comment, fromNickname)); } } @@ -215,10 +217,19 @@ public class CommentServiceImpl extends ServiceImpl impl } } - public void notice(Comment comment) { + private void notice(Comment comment, String fromNickname) { + // 评论自己不发邮件提醒 + if (comment.getUserId().equals(comment.getReplyUserId())) { + return; + } + // 博主自己发评论不发邮件提醒 + if (comment.getUserId().equals(BLOGGER_ID) && Objects.isNull(comment.getParentId())) { + return; + } // 查询回复用户邮箱号 + String title; Integer userId = BLOGGER_ID; - String id = Objects.nonNull(comment.getTopicId()) ? comment.getTopicId().toString() : ""; + String topicId = Objects.nonNull(comment.getTopicId()) ? comment.getTopicId().toString() : ""; if (Objects.nonNull(comment.getReplyUserId())) { userId = comment.getReplyUserId(); } else { @@ -232,26 +243,54 @@ public class CommentServiceImpl extends ServiceImpl impl break; } } - String email = userInfoMapper.selectById(userId).getEmail(); - if (StringUtils.isNotBlank(email)) { - // 发送消息 - EmailDTO emailDTO = new EmailDTO(); - if (comment.getIsReview().equals(TRUE)) { - // 评论提醒 - emailDTO.setEmail(email); + if (Objects.requireNonNull(getCommentEnum(comment.getType())).equals(ARTICLE)) { + title = articleMapper.selectById(comment.getTopicId()).getArticleTitle(); + } else { + title = Objects.requireNonNull(getCommentEnum(comment.getType())).getDesc(); + } + UserInfo user = userInfoMapper.selectById(userId); + if (StringUtils.isNotBlank(user.getEmail())) { + EmailDTO emailDTO = getEmailDTO(comment, user, fromNickname, topicId, title, userId); + rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, "*", new Message(JSON.toJSONBytes(emailDTO), new MessageProperties())); + } + } + + private EmailDTO getEmailDTO(Comment comment, UserInfo user, String fromNickname, String topicId, String title, Integer userId) { + EmailDTO emailDTO = new EmailDTO(); + if (comment.getIsReview().equals(TRUE)) { + Map map = new HashMap<>(); + String url = websiteUrl + getCommentPath(comment.getType()) + topicId; + if (Objects.isNull(comment.getParentId())) { + emailDTO.setEmail(user.getEmail()); emailDTO.setSubject("评论提醒"); - // 获取评论路径 - String url = websiteUrl + getCommentPath(comment.getType()) + id; - emailDTO.setContent("您收到了一条新的回复,请前往" + url + "页面查看"); + emailDTO.setTemplate("owner.html"); + String createTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(comment.getCreateTime()); + map.put("time", createTime); + map.put("url", url); + map.put("title", title); + map.put("nickname", fromNickname); + map.put("content", comment.getCommentContent()); } else { - // 管理员审核提醒 - String adminEmail = userInfoMapper.selectById(BLOGGER_ID).getEmail(); - emailDTO.setEmail(adminEmail); - emailDTO.setSubject("审核提醒"); - emailDTO.setContent("您收到了一条新的回复,请前往后台管理页面审核"); + Comment parentComment = commentMapper.selectOne(new LambdaQueryWrapper().select(Comment::getCommentContent, Comment::getCreateTime).eq(Comment::getId, comment.getParentId())); + emailDTO.setEmail(user.getEmail()); + emailDTO.setSubject("评论提醒"); + emailDTO.setTemplate("user.html"); + map.put("url", url); + map.put("title", title); + String createTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(parentComment.getCreateTime()); + map.put("time", createTime); + map.put("toUser", user.getNickname()); + map.put("fromUser", fromNickname); + map.put("parentComment", parentComment.getCommentContent()); + map.put("replyComment", comment.getCommentContent()); } - System.out.println(emailDTO); - rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, "*", new Message(JSON.toJSONBytes(emailDTO), new MessageProperties())); + emailDTO.setCommentMap(map); + } else { + String adminEmail = userInfoMapper.selectById(BLOGGER_ID).getEmail(); + emailDTO.setEmail(adminEmail); + emailDTO.setSubject("审核提醒"); + emailDTO.setContent("您收到了一条新的回复,请前往后台管理页面审核"); } + return emailDTO; } } diff --git a/aurora-springboot/src/main/java/com/aurora/utils/EmailUtils.java b/aurora-springboot/src/main/java/com/aurora/utils/EmailUtils.java new file mode 100644 index 0000000..8114ec6 --- /dev/null +++ b/aurora-springboot/src/main/java/com/aurora/utils/EmailUtils.java @@ -0,0 +1,61 @@ +package com.aurora.utils; + +import com.aurora.model.dto.EmailDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +/** + * 邮件工具 + * + * @author ican + */ +@Component +public class EmailUtils { + /** + * 邮箱号 + */ + @Value("${spring.mail.username}") + private String email; + + @Autowired + private JavaMailSender javaMailSender; + + @Autowired + private TemplateEngine templateEngine; + + public void sendSimpleMail(EmailDTO emailDTO) { + SimpleMailMessage simpleMail = new SimpleMailMessage(); + simpleMail.setFrom(email); + simpleMail.setTo(emailDTO.getEmail()); + simpleMail.setSubject(emailDTO.getSubject()); + simpleMail.setText(emailDTO.getContent()); + javaMailSender.send(simpleMail); + } + + public void sendHtmlMail(EmailDTO emailDTO) { + try { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage); + Context context = new Context(); + context.setVariables(emailDTO.getCommentMap()); + String process = templateEngine.process(emailDTO.getTemplate(), context); + mimeMessageHelper.setFrom(email); + mimeMessageHelper.setTo(emailDTO.getEmail()); + mimeMessageHelper.setSubject(emailDTO.getSubject()); + mimeMessageHelper.setText(process, true); + javaMailSender.send(mimeMessage); + } catch (MessagingException e) { + e.printStackTrace(); + } + } + +} diff --git a/aurora-springboot/src/main/java/com/aurora/utils/HTMLUtils.java b/aurora-springboot/src/main/java/com/aurora/utils/HTMLUtils.java index e0521d2..0356f11 100644 --- a/aurora-springboot/src/main/java/com/aurora/utils/HTMLUtils.java +++ b/aurora-springboot/src/main/java/com/aurora/utils/HTMLUtils.java @@ -29,7 +29,7 @@ public class HTMLUtils { */ public static String filter(String source) { // 敏感词过滤 - source = sensitiveWordBs.replace(source); +// source = sensitiveWordBs.replace(source); // 保留图片标签 source = source.replaceAll("(?!<(img).*?>)<.*?>", "") .replaceAll("(onload(.*?)=)", "") diff --git a/aurora-springboot/src/main/resources/templates/owner.html b/aurora-springboot/src/main/resources/templates/owner.html new file mode 100644 index 0000000..3b50a3d --- /dev/null +++ b/aurora-springboot/src/main/resources/templates/owner.html @@ -0,0 +1,55 @@ + + + + + Title + + +
+
+

+ 您的有的新评论啦! +

+
+
+

时间:

+

同学 给您的评论如下:

+
+

+
+

+ 您可以点击查看回复的完整內容 +

+
+

什么都无法舍弃的人,什么都改变不了。——《进击的巨人》

+
+
+
+ + \ No newline at end of file diff --git a/aurora-springboot/src/main/resources/templates/user.html b/aurora-springboot/src/main/resources/templates/user.html new file mode 100644 index 0000000..14b3248 --- /dev/null +++ b/aurora-springboot/src/main/resources/templates/user.html @@ -0,0 +1,66 @@ + + + + + Title + + +
+
+

+ 您在花未眠的个人博客上的留言有新回复啦! +

+
+
+

时间:

+

同学,您曾在上发表评论:

+
+

+
+

给您的回复如下:

+
+

+
+

+ 您可以点击查看回复的完整內容 + ,欢迎再次光临花未眠的个人博客。 +

+
+

不管当下的境遇如何,提瓦特大陆的星空永远会有你的位置。——《原神》

+
+
+
+ + \ No newline at end of file From ec971206643bd56d267ab11bd5010fc9879ad0d2 Mon Sep 17 00:00:00 2001 From: linhaojun Date: Sun, 25 Sep 2022 14:58:14 +0800 Subject: [PATCH 02/16] =?UTF-8?q?:rocket:=20=E6=B7=BB=E5=8A=A0mysql?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../strategy/impl/EsSearchStrategyImpl.java | 2 +- .../impl/MySqlSearchStrategyImpl.java | 98 +++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 aurora-springboot/src/main/java/com/aurora/strategy/impl/MySqlSearchStrategyImpl.java diff --git a/aurora-springboot/src/main/java/com/aurora/strategy/impl/EsSearchStrategyImpl.java b/aurora-springboot/src/main/java/com/aurora/strategy/impl/EsSearchStrategyImpl.java index 00e7aa9..28c56f6 100644 --- a/aurora-springboot/src/main/java/com/aurora/strategy/impl/EsSearchStrategyImpl.java +++ b/aurora-springboot/src/main/java/com/aurora/strategy/impl/EsSearchStrategyImpl.java @@ -75,7 +75,7 @@ public class EsSearchStrategyImpl implements SearchStrategy { HighlightBuilder.Field contentField = new HighlightBuilder.Field("articleContent"); contentField.preTags(PRE_TAG); contentField.postTags(POST_TAG); - contentField.fragmentSize(80); + contentField.fragmentSize(50); nativeSearchQueryBuilder.withHighlightFields(titleField, contentField); // 搜索 try { diff --git a/aurora-springboot/src/main/java/com/aurora/strategy/impl/MySqlSearchStrategyImpl.java b/aurora-springboot/src/main/java/com/aurora/strategy/impl/MySqlSearchStrategyImpl.java new file mode 100644 index 0000000..383705e --- /dev/null +++ b/aurora-springboot/src/main/java/com/aurora/strategy/impl/MySqlSearchStrategyImpl.java @@ -0,0 +1,98 @@ +package com.aurora.strategy.impl; + +import com.aurora.entity.Article; +import com.aurora.mapper.ArticleMapper; +import com.aurora.model.dto.ArticleSearchDTO; +import com.aurora.strategy.SearchStrategy; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.aurora.constant.CommonConst.*; +import static com.aurora.enums.ArticleStatusEnum.PUBLIC; + + +/** + * @author 花未眠 + * mysql搜索策略 + */ +@Service("mySqlSearchStrategyImpl") +public class MySqlSearchStrategyImpl implements SearchStrategy { + + @Autowired + private ArticleMapper articleMapper; + + @Override + public List searchArticle(String keywords) { + // 判空 + if (StringUtils.isBlank(keywords)) { + return new ArrayList<>(); + } + // 搜索文章 + List
articles = articleMapper.selectList(new LambdaQueryWrapper
() + .eq(Article::getIsDelete, FALSE) + .eq(Article::getStatus, PUBLIC.getStatus()) + .and(i -> i.like(Article::getArticleTitle, keywords) + .or() + .like(Article::getArticleContent, keywords))); + // 高亮处理 + return articles.stream().map(item -> { + // 文章内容高亮 + boolean isLowerCase = true; + String articleContent = item.getArticleContent(); + int contentIndex = item.getArticleContent().indexOf(keywords.toLowerCase()); + if (contentIndex == -1) { + contentIndex = item.getArticleContent().indexOf(keywords.toUpperCase()); + if (contentIndex != -1) { + isLowerCase = false; + } + } + if (contentIndex != -1) { + // 获取关键词前面的文字 + int preIndex = contentIndex > 15 ? contentIndex - 15 : 0; + String preText = item.getArticleContent().substring(preIndex, contentIndex); + // 获取关键词到后面的文字 + int last = contentIndex + keywords.length(); + int postLength = item.getArticleContent().length() - last; + int postIndex = postLength > 35 ? last + 35 : last + postLength; + String postText = item.getArticleContent().substring(contentIndex, postIndex); + // 文章内容高亮 + if (isLowerCase) { + articleContent = (preText + postText).replaceAll(keywords.toLowerCase(), PRE_TAG + keywords.toLowerCase() + POST_TAG); + } else { + articleContent = (preText + postText).replaceAll(keywords.toUpperCase(), PRE_TAG + keywords.toUpperCase() + POST_TAG); + } + } else { + return null; + } + isLowerCase = true; + int titleIndex = item.getArticleTitle().indexOf(keywords.toLowerCase()); + if (titleIndex == -1) { + titleIndex = item.getArticleTitle().indexOf(keywords.toUpperCase()); + if (titleIndex != -1) { + isLowerCase = false; + } + } + // 文章标题高亮 + String articleTitle; + if (isLowerCase) { + articleTitle = item.getArticleTitle().replaceAll(keywords.toLowerCase(), PRE_TAG + keywords.toLowerCase() + POST_TAG); + } else { + articleTitle = item.getArticleTitle().replaceAll(keywords.toUpperCase(), PRE_TAG + keywords.toUpperCase() + POST_TAG); + } + return ArticleSearchDTO.builder() + .id(item.getId()) + .articleTitle(articleTitle) + .articleContent(articleContent) + .build(); + }).filter(Objects::nonNull) + .collect(Collectors.toList()); + } + +} From 2d783f745cb40a1f66c70171a7bc034adaa2f735 Mon Sep 17 00:00:00 2001 From: linhaojun Date: Sun, 25 Sep 2022 15:09:07 +0800 Subject: [PATCH 03/16] =?UTF-8?q?:art:=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/SearchModel.vue | 48 ++++--------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/aurora-vue/aurora-blog/src/components/SearchModel.vue b/aurora-vue/aurora-blog/src/components/SearchModel.vue index cc700b5..f5de134 100644 --- a/aurora-vue/aurora-blog/src/components/SearchModel.vue +++ b/aurora-vue/aurora-blog/src/components/SearchModel.vue @@ -43,10 +43,10 @@ ref="searchInput" class="search-input" autocomplete="off" - v-model="keyword" - @input="searchKeyword" /> + v-model="keywords" + @input="searchKeywords" />