【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邮箱
获取生成的授权码
然后打开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 + "<[email protected]>");
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("[email protected]");
mail.setParams(params);
mail.setTemplate(MailTemplateNameEnum.LOGIN_CODE.getCode());
mail.setSubject("登录验证码");
mailSendService.sendWithHTMLTemplate(mail);
}
效果如下
但是实际情况中 我们登录的验证邮件不应该这么用,如果邮件发送失败,会导致整个流程阻塞,这时候需要我们的消息队列来解耦,【SpringBoot2.0系列09】SpringBoot之rabbitmq使用
最后源码地址如下:https://github.com/YuKongEr/SpringBoot-Study/tree/master/chapter11
欢迎大家关注一下我的个人公众号。一起交流一起学习,有问必答。
交流qq群: 558509374