【SpringBoot2.0系列12】SpringBoot之JavaMail发送,支持FreeMark模板渲染

前言 我们在日常生活经常会用到邮箱,比如登录验证码,找回密码验证码/链接等, 今天我就实现一个类似功能,邮件验证码登录,注重点邮件的发送,模板的选择。

依赖

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
       </dependency>
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
       </dependency>
  • freemark是用户模板渲染支持
  • mail 是用于邮件发送支持

编码实现

大家都知道邮件协议有两个 smtp:邮件发送协议 pop3:邮件接收协议 我们现在要实现的邮件发送,那么重点就要放在smtp上。 在这里我们借助第三的邮件系统的smtp服务器来。比如QQ 126等。

打开qq邮箱

image.png

获取生成的授权码

然后打开application.yml 配置smtp相关信息

spring:
  mail:
    host: smtp.qq.com  # qq  smtp服务器地址
    username: 你的邮箱
    password: 刚刚的权限码
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

然后我们还需要配置一下freemark的配置,我在之前的【SpringBoot2.0系列03】SpringBoot之使用freemark视图模板介绍过 我就不在讲了。

    freemarker:
    charset: UTF-8
    allow-request-override: false
    cache: false
    expose-request-attributes: false
    expose-session-attributes: false
    content-type: text/html
    template-loader-path: classpath:/static/template/  #模板目录
    expose-spring-macro-helpers: false
    check-template-location: true
    enabled: true

邮件实体类Mail.java

package com.yukong.mail.entity;

import java.io.Serializable;
import java.util.Map;

/**
 * @author: yukong
 * @date: 2018/12/5 17:25
 */
public class Mail implements Serializable {
    private static final long serialVersionUID = 1L;
    //接收方邮件
    private String email;

    //主题
    private String subject;
    //模板
    private String template;

    // 自定义参数
    private Map<String, Object> params;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getTemplate() {
        return template;
    }

    public void setTemplate(String template) {
        this.template = template;
    }

    public Map<String, Object> getParams() {
        return params;
    }

    public void setParams(Map<String, Object> params) {
        this.params = params;
    }
}

邮件发送实现类 MailSendService.java

package com.yukong.mail;

import com.yukong.mail.entity.Mail;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: yukong
 * @date: 2018/12/5 16:56
 */
@Service
public class MailSendService {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    @Value("${spring.mail.username}")
    private  String USERNAME = "yukong";




    /**
     * 根据模板名 获取邮件内容
     * @param templateName
     * @param params
     * @return
     */
    private String getMailTextByTemplateName(String templateName, Map<String,Object> params) throws IOException, TemplateException {
        String mailText = "";
        //通过指定模板名获取FreeMarker模板实例
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(templateName);
        //FreeMarker通过Map传递动态数据
        //注意动态数据的key和模板标签中指定的属性相匹配
        //解析模板并替换动态数据,最终code将替换模板文件中的${code}标签。
        mailText = FreeMarkerTemplateUtils.processTemplateIntoString(template, params);
        return mailText;
    }

    public boolean sendWithHTMLTemplate(Mail mail) {
        try {
            //发件人的昵称
            String nick = MimeUtility.encodeText(USERNAME);
            //发件人是谁
            InternetAddress from = new InternetAddress(nick + "<541130126@qq.com>");
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true);
            mimeMessageHelper.setTo(mail.getEmail());
            mimeMessageHelper.setFrom(from);
            mimeMessageHelper.setSubject(mail.getSubject());
            HashMap<String, Object> params = new HashMap<>();
            // 使用模板生成html邮件内容
            String result =getMailTextByTemplateName(mail.getTemplate(), mail.getParams());
            mimeMessageHelper.setText(result, true);
            javaMailSender.send(mimeMessage);
            return true;
        } catch (Exception e) {
            logger.error("发送邮件失败" + e.getMessage());
            return false;
        }
    }


}

编写模板login_code.ftl 注意它的目录是resource/static/tempalte/login_code.ftl

你好,你本次的登录验证码为${code}若非本人操作,请忽略本邮件。

如果有其他邮件,编写不同的模板即可 因为用到了模板名称渲染,所以我们根据规范,编写一个模板枚举

package com.yukong.mail;

/**
 * @author: yukong
 * @date: 2018/12/5 17:23
 */
public enum MailTemplateNameEnum {

    LOGIN_CODE("login_code.ftl", "登录验证码模板");

    String code;

    String desc;

   private MailTemplateNameEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public String getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

}

接下里就是编写测试类测试, ctrl+shift+T

 @Test
    public void sendWithHTMLTemplate() {
        Map<String, Object> params = new HashMap<>();
        // 参数
        Integer code = (int)(Math.random()*9+1)*100000;
        params.put("code", code);
        Mail mail  = new Mail();
        mail.setEmail("yukonga@vip.qq.com");
        mail.setParams(params);
        mail.setTemplate(MailTemplateNameEnum.LOGIN_CODE.getCode());
        mail.setSubject("登录验证码");
        mailSendService.sendWithHTMLTemplate(mail);
    }

效果如下

image.png

但是实际情况中 我们登录的验证邮件不应该这么用,如果邮件发送失败,会导致整个流程阻塞,这时候需要我们的消息队列来解耦,【SpringBoot2.0系列09】SpringBoot之rabbitmq使用

最后源码地址如下:https://github.com/YuKongEr/SpringBoot-Study/tree/master/chapter11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券