MailServiceImpl.java 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package com.cyksj.service.mail.impl;
  2. import cn.hutool.core.util.StrUtil;
  3. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  4. import com.cyksj.common.exception.BusinessRuntimeException;
  5. import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
  6. import com.cyksj.common.util.StringUtil;
  7. import com.cyksj.mapper.EmailConfigMapper;
  8. import com.cyksj.mapper.GoodsCoursewareFileMapper;
  9. import com.cyksj.mapper.GroupsRelationMapper;
  10. import com.cyksj.mapper.OrderDonMapper;
  11. import com.cyksj.model.entity.EmailConfig;
  12. import com.cyksj.model.entity.GoodsCoursewareFile;
  13. import com.cyksj.model.entity.GroupsRelation;
  14. import com.cyksj.model.entity.OrderDon;
  15. import com.cyksj.redis.RedisService;
  16. import com.cyksj.service.mail.MailService;
  17. import lombok.RequiredArgsConstructor;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.springframework.beans.factory.annotation.Value;
  20. import org.springframework.mail.MailException;
  21. import org.springframework.mail.SimpleMailMessage;
  22. import org.springframework.mail.javamail.JavaMailSender;
  23. import org.springframework.mail.javamail.JavaMailSenderImpl;
  24. import org.springframework.mail.javamail.MimeMessageHelper;
  25. import org.springframework.stereotype.Service;
  26. import javax.annotation.PostConstruct;
  27. import javax.mail.internet.MimeMessage;
  28. import javax.mail.internet.MimeUtility;
  29. import java.io.File;
  30. import java.util.ArrayList;
  31. import java.util.List;
  32. import java.util.Properties;
  33. import java.util.concurrent.ThreadLocalRandom;
  34. /*
  35. *项目名: netflix
  36. *文件名: MailServiceImpl
  37. *创建者: JavaZou
  38. *创建时间:2023/1/3 15:54
  39. */
  40. @Service
  41. @RequiredArgsConstructor
  42. @Slf4j
  43. public class MailServiceImpl implements MailService {
  44. @Value("${spring.mail.username}")
  45. private String from;
  46. private final JavaMailSender mailSender;
  47. private final RedisService redisService;
  48. private final GoodsCoursewareFileMapper coursewareFileMapper;
  49. private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
  50. private final GroupsRelationMapper groupsRelationMapper;
  51. private final OrderDonMapper orderDonMapper;
  52. private final EmailConfigMapper emailConfigMapper;
  53. private static List<JavaMailSenderImpl> senders;
  54. private static String IMG_HTML = "<p><img src='%s' width=200></p>";
  55. /**
  56. * 获取邮箱客户端
  57. */
  58. @PostConstruct
  59. public void init() {
  60. List<EmailConfig> emailConfigs = emailConfigMapper.selectList(null);
  61. senders = new ArrayList<>(emailConfigs.size());
  62. emailConfigs.forEach(emailConfig->{
  63. //过滤163邮箱
  64. if (emailConfig.getType() == 1) {
  65. return;
  66. }
  67. JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
  68. javaMailSender.setHost(emailConfig.getHost());
  69. javaMailSender.setProtocol(emailConfig.getProtocol());
  70. javaMailSender.setUsername(emailConfig.getUsername());
  71. javaMailSender.setPassword(emailConfig.getPassword());
  72. javaMailSender.setDefaultEncoding(emailConfig.getDefaultEncoding());
  73. Properties properties = new Properties();
  74. properties.setProperty("properties.mail.smtp.auth", "true");
  75. properties.setProperty("properties.mail.smtp.port", emailConfig.getPort().toString());
  76. properties.setProperty("properties.mail.smtp.starttls.enable", "true");
  77. properties.setProperty("properties.mail.smtp.starttls.required", "true");
  78. properties.setProperty("properties.mail.smtp.ssl.enable", "true");
  79. javaMailSender.setJavaMailProperties(properties);
  80. senders.add(javaMailSender);
  81. });
  82. }
  83. @Override
  84. public String sendLoginCodeEmailToPeople(Integer digit, String toAddress) {
  85. // 生成验证码
  86. String code = StringUtil.getRandomCodeStr(digit);
  87. if (sendLoginCodeEmailToPeople(code, toAddress)) {
  88. //删除之前的验证码缓存key
  89. String key = RedisService.key.EMAIL_CODE_KEY.getNameFormat(toAddress);
  90. redisService.del(key);
  91. //将验证码存入redis
  92. redisService.set(key, code, RedisService.key.EMAIL_CODE_KEY.getTimeout());
  93. return code;
  94. }
  95. return null;
  96. }
  97. @Override
  98. public Boolean sendLoginCodeEmailToPeople(String code, String toAddress) {
  99. String subject = "【银河录像局】登录验证码";
  100. String content = String.format("尊敬的用户,您的验证码为%s,此验证码仅用于银河录像。【银河录像局】", code);
  101. boolean flag = sendMail(toAddress, subject, content);
  102. return flag;
  103. }
  104. @Override
  105. public void sendEmailMsgToPeople(String people, String subject, String msg) {
  106. log.info("发送邮件至用户:{}开始", people);
  107. if (sendMail(people, subject, msg)) {
  108. log.info("发送成功");
  109. return;
  110. }
  111. }
  112. @Override
  113. public void sendCoursewareByGoodsId(Long goodsId, Long relationId, Long userId, String goodsTitle, String email) throws Exception {
  114. //获取当前目前下的课程文件
  115. MimeMessage msg = mailSender.createMimeMessage();
  116. MimeMessageHelper helper = new MimeMessageHelper(msg, true, "utf-8");
  117. List<GoodsCoursewareFile> coursewareFiles = coursewareFileMapper.selectList(Wrappers.lambdaQuery(GoodsCoursewareFile.class)
  118. .eq(GoodsCoursewareFile::getGoodsId, goodsId)
  119. .eq(GoodsCoursewareFile::getStatus, true));
  120. if (coursewareFiles.isEmpty()) {
  121. throw BusinessRuntimeException.getInstance("未配置对应课件,请联系客服..");
  122. }
  123. //标题
  124. StringBuilder subject = new StringBuilder();
  125. StringBuilder sb = new StringBuilder(IMG_HTML.length());
  126. coursewareFiles.forEach(file->{
  127. try {
  128. helper.addAttachment(MimeUtility.encodeText(file.getFileName(), "utf-8", "B"), new File(file.getPath()));
  129. if (StrUtil.isNotBlank(file.getImg())) {
  130. sb.append(String.format(IMG_HTML, file.getImg()));
  131. sb.append("<br/>");
  132. }
  133. if (subject.length() > 0) {
  134. subject.append(StrUtil.EMPTY);
  135. }
  136. subject.append(file.getSubject());
  137. } catch (Exception e) {
  138. }
  139. });
  140. if (sb.length() == 0) {
  141. sb.append(goodsTitle);
  142. }
  143. if (subject.length() == 0) {
  144. subject.append("银河录像局AI课程");
  145. }
  146. helper.setSubject(subject.toString());
  147. helper.setText(sb.toString(), true);
  148. helper.setTo(email);
  149. TASK_EXECUTOR.execute(() -> {
  150. try {
  151. JavaMailSenderImpl sender = getJavaEmailServer();
  152. helper.setFrom(sender.getUsername());
  153. log.info("开始给用户userId:{},relationId:{} 发送课程:{}专属课件", userId, relationId, goodsTitle);
  154. sendMsgIfFailRetry(sender, msg);
  155. } catch (Exception e) {
  156. log.info("发送课件失败,error:{}", StringUtil.getErrorText(e));
  157. groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
  158. .set(GroupsRelation::getAccount, null)
  159. .eq(GroupsRelation::getId, relationId)
  160. .and(qr -> qr.isNotNull(GroupsRelation::getAccount).or().ne(GroupsRelation::getAccount, StrUtil.EMPTY)));
  161. orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class)
  162. .set(OrderDon::getStatus, OrderDon.Status.hasPayment)
  163. .eq(OrderDon::getRelationId, relationId)
  164. .eq(OrderDon::getUserId, userId)
  165. .eq(OrderDon::getStatus, OrderDon.Status.complete));
  166. }
  167. });
  168. }
  169. private void sendMsgIfFailRetry(JavaMailSenderImpl sender, MimeMessage msg) {
  170. try {
  171. sender.send(msg);
  172. } catch (Exception e) {
  173. if (!retry(msg)) {
  174. throw BusinessRuntimeException.getInstance("暂无可用邮件服务器");
  175. }
  176. }
  177. }
  178. public Boolean retry(MimeMessage msg) {
  179. for (JavaMailSenderImpl retry : senders) {
  180. try {
  181. msg.setFrom(retry.getUsername());
  182. retry.send(msg);
  183. return true;
  184. } catch (Exception e2) {
  185. }
  186. }
  187. return false;
  188. }
  189. public JavaMailSenderImpl getJavaEmailServer() {
  190. if (senders.isEmpty()) {
  191. String key = "reEmailSenders";
  192. if (redisService.setNx(key, "reEmailSenders", 30l)) {
  193. if (senders.isEmpty()) {
  194. init();
  195. redisService.del(key);
  196. }
  197. } else {
  198. if (senders.isEmpty()) {
  199. throw BusinessRuntimeException.getInstance("系统超时,请重新获取邮箱验证码..");
  200. }
  201. }
  202. }
  203. int i = ThreadLocalRandom.current().nextInt(senders.size());
  204. return senders.get(i);
  205. }
  206. public boolean sendMail(String toAddress, String subject, String text) {
  207. SimpleMailMessage msg = new SimpleMailMessage();
  208. msg.setFrom(from);
  209. msg.setTo(toAddress);
  210. msg.setSubject(subject);
  211. msg.setText(text);
  212. try {
  213. mailSender.send(msg);
  214. } catch (MailException ex) {
  215. log.error(ex.getMessage());
  216. return false;
  217. }
  218. return true;
  219. }
  220. }