package com.cyksj.service.mail.impl; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.task.GlobalThreadPoolTaskExecutor; import com.cyksj.common.util.StringUtil; import com.cyksj.mapper.EmailConfigMapper; import com.cyksj.mapper.GoodsCoursewareFileMapper; import com.cyksj.mapper.GroupsRelationMapper; import com.cyksj.mapper.OrderDonMapper; import com.cyksj.model.entity.EmailConfig; import com.cyksj.model.entity.GoodsCoursewareFile; import com.cyksj.model.entity.GroupsRelation; import com.cyksj.model.entity.OrderDon; import com.cyksj.redis.RedisService; import com.cyksj.service.mail.MailService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.mail.MailException; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeUtility; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.ThreadLocalRandom; /* *项目名: netflix *文件名: MailServiceImpl *创建者: JavaZou *创建时间:2023/1/3 15:54 */ @Service @RequiredArgsConstructor @Slf4j public class MailServiceImpl implements MailService { @Value("${spring.mail.username}") private String from; private final JavaMailSender mailSender; private final RedisService redisService; private final GoodsCoursewareFileMapper coursewareFileMapper; private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance(); private final GroupsRelationMapper groupsRelationMapper; private final OrderDonMapper orderDonMapper; private final EmailConfigMapper emailConfigMapper; private static List senders; private static String IMG_HTML = "

"; /** * 获取邮箱客户端 */ @PostConstruct public void init() { List emailConfigs = emailConfigMapper.selectList(null); senders = new ArrayList<>(emailConfigs.size()); emailConfigs.forEach(emailConfig->{ //过滤163邮箱 if (emailConfig.getType() == 1) { return; } JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); javaMailSender.setHost(emailConfig.getHost()); javaMailSender.setProtocol(emailConfig.getProtocol()); javaMailSender.setUsername(emailConfig.getUsername()); javaMailSender.setPassword(emailConfig.getPassword()); javaMailSender.setDefaultEncoding(emailConfig.getDefaultEncoding()); Properties properties = new Properties(); properties.setProperty("properties.mail.smtp.auth", "true"); properties.setProperty("properties.mail.smtp.port", emailConfig.getPort().toString()); properties.setProperty("properties.mail.smtp.starttls.enable", "true"); properties.setProperty("properties.mail.smtp.starttls.required", "true"); properties.setProperty("properties.mail.smtp.ssl.enable", "true"); javaMailSender.setJavaMailProperties(properties); senders.add(javaMailSender); }); } @Override public String sendLoginCodeEmailToPeople(Integer digit, String toAddress) { // 生成验证码 String code = StringUtil.getRandomCodeStr(digit); if (sendLoginCodeEmailToPeople(code, toAddress)) { //删除之前的验证码缓存key String key = RedisService.key.EMAIL_CODE_KEY.getNameFormat(toAddress); redisService.del(key); //将验证码存入redis redisService.set(key, code, RedisService.key.EMAIL_CODE_KEY.getTimeout()); return code; } return null; } @Override public Boolean sendLoginCodeEmailToPeople(String code, String toAddress) { String subject = "【银河录像局】登录验证码"; String content = String.format("尊敬的用户,您的验证码为%s,此验证码仅用于银河录像。【银河录像局】", code); boolean flag = sendMail(toAddress, subject, content); return flag; } @Override public void sendEmailMsgToPeople(String people, String subject, String msg) { log.info("发送邮件至用户:{}开始", people); if (sendMail(people, subject, msg)) { log.info("发送成功"); return; } } @Override public void sendCoursewareByGoodsId(Long goodsId, Long relationId, Long userId, String goodsTitle, String email) throws Exception { //获取当前目前下的课程文件 MimeMessage msg = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(msg, true, "utf-8"); List coursewareFiles = coursewareFileMapper.selectList(Wrappers.lambdaQuery(GoodsCoursewareFile.class) .eq(GoodsCoursewareFile::getGoodsId, goodsId) .eq(GoodsCoursewareFile::getStatus, true)); if (coursewareFiles.isEmpty()) { throw BusinessRuntimeException.getInstance("未配置对应课件,请联系客服.."); } //标题 StringBuilder subject = new StringBuilder(); StringBuilder sb = new StringBuilder(IMG_HTML.length()); coursewareFiles.forEach(file->{ try { helper.addAttachment(MimeUtility.encodeText(file.getFileName(), "utf-8", "B"), new File(file.getPath())); if (StrUtil.isNotBlank(file.getImg())) { sb.append(String.format(IMG_HTML, file.getImg())); sb.append("
"); } if (subject.length() > 0) { subject.append(StrUtil.EMPTY); } subject.append(file.getSubject()); } catch (Exception e) { } }); if (sb.length() == 0) { sb.append(goodsTitle); } if (subject.length() == 0) { subject.append("银河录像局AI课程"); } helper.setSubject(subject.toString()); helper.setText(sb.toString(), true); helper.setTo(email); TASK_EXECUTOR.execute(() -> { try { JavaMailSenderImpl sender = getJavaEmailServer(); helper.setFrom(sender.getUsername()); log.info("开始给用户userId:{},relationId:{} 发送课程:{}专属课件", userId, relationId, goodsTitle); sendMsgIfFailRetry(sender, msg); } catch (Exception e) { log.info("发送课件失败,error:{}", StringUtil.getErrorText(e)); groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(GroupsRelation::getAccount, null) .eq(GroupsRelation::getId, relationId) .and(qr -> qr.isNotNull(GroupsRelation::getAccount).or().ne(GroupsRelation::getAccount, StrUtil.EMPTY))); orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class) .set(OrderDon::getStatus, OrderDon.Status.hasPayment) .eq(OrderDon::getRelationId, relationId) .eq(OrderDon::getUserId, userId) .eq(OrderDon::getStatus, OrderDon.Status.complete)); } }); } private void sendMsgIfFailRetry(JavaMailSenderImpl sender, MimeMessage msg) { try { sender.send(msg); } catch (Exception e) { if (!retry(msg)) { throw BusinessRuntimeException.getInstance("暂无可用邮件服务器"); } } } public Boolean retry(MimeMessage msg) { for (JavaMailSenderImpl retry : senders) { try { msg.setFrom(retry.getUsername()); retry.send(msg); return true; } catch (Exception e2) { } } return false; } public JavaMailSenderImpl getJavaEmailServer() { if (senders.isEmpty()) { String key = "reEmailSenders"; if (redisService.setNx(key, "reEmailSenders", 30l)) { if (senders.isEmpty()) { init(); redisService.del(key); } } else { if (senders.isEmpty()) { throw BusinessRuntimeException.getInstance("系统超时,请重新获取邮箱验证码.."); } } } int i = ThreadLocalRandom.current().nextInt(senders.size()); return senders.get(i); } public boolean sendMail(String toAddress, String subject, String text) { SimpleMailMessage msg = new SimpleMailMessage(); msg.setFrom(from); msg.setTo(toAddress); msg.setSubject(subject); msg.setText(text); try { mailSender.send(msg); } catch (MailException ex) { log.error(ex.getMessage()); return false; } return true; } }