springboot mail+Thymeleaf模板

简介: compile 'org.springframework.boot:spring-boot-starter-thymeleaf' compile 'io.ratpack:ratpack-thymeleaf:1.

 

compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
compile 'io.ratpack:ratpack-thymeleaf:1.4.2'

 

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import ratpack.thymeleaf.internal.ThymeleafHttpServletRequestAdapter;
import ratpack.thymeleaf.internal.ThymeleafHttpServletResponseAdapter;
import ratpack.thymeleaf.internal.ThymeleafServletContextAdapter;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

/**
 * Created by hujunzheng on 17/9/8.
 */
@Service
public class MailService {

    @Autowired
    private MailProperties mailProperties;

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private TemplateEngine templateEngine;

    private static final Log log = LogFactory.getLog(MailService.class);
    /**
     * 发送邮件
     * @param userEmail
     * @param templateId
     */
    public void sendMail(String userEmail, Map<String, Object> params, int templateId) {
        sendMailMultiParams(new String[] {userEmail}, params, templateId);
    }

    public void sendMail(String userEmail, Object obj, int templateId) {
        Map<String, Object> params = objectToMap(obj);
        sendMailMultiParams(new String[] {userEmail}, params, templateId);
    }

    public void sendMail(String userEmail, String  message, String subject) {
        sendSampleMail(new String[] {userEmail}, message, subject);
    }

    public void sendMail(String[] userEmails, Map<String, Object> params, int templateId) {
        sendMailMultiParams(userEmails, params, templateId);
    }

    public void sendMail(String[] userEmails, Object obj, int templateId) {
        Map<String, Object> params = objectToMap(obj);
        sendMailMultiParams(userEmails, params, templateId);
    }

    public void sendMail(String[] userEmails, String  message, String subject) {
        sendSampleMail(userEmails, message, subject);
    }

    private Map<String, Object> objectToMap(Object obj) {
        PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(obj.getClass());
        Map<String, Object> params = new HashMap<>();
        for (PropertyDescriptor property : propertyDescriptors) {
            String key = property.getName();
            if (key.compareToIgnoreCase("class") == 0) {
                continue;
            }
            Optional<Method> getter = Optional.ofNullable(property.getReadMethod());
            try {
                Object value = getter.isPresent() ? getter.get().invoke(obj) : null;
                params.put(key, value);
            } catch (ReflectiveOperationException e) {
                e.printStackTrace();
            }
        }
        return params;
    }

    /**
     * 异步 分别发送 发送邮件
    * */
    public List<String> asynSendMails(List<ApiPortalOperator> apiPortalOperators, Object bodyParams) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<FutureTask<String>> futureTasks = new ArrayList<>();
        for (ApiPortalOperator apiPortalOperator : apiPortalOperators) {
            FutureTask<String> futureTask = new FutureTask(() -> {
                try {
                    this.sendMail(apiPortalOperator.getEmail(), bodyParams, 1);
                } catch (Exception e) {
                    return "邮件to " + apiPortalOperator.getEmail() + " 发送异常:" + e.getMessage();
                }
                return "邮件to " + apiPortalOperator.getEmail() + " 发送成功";
            });
            futureTasks.add(futureTask);
            executorService.submit(futureTask);
        }

        List<String> result = new ArrayList<>();
        for (int i=0; i<futureTasks.size(); ++i) {
            FutureTask futureTask = futureTasks.get(i);
            try {
                result.add((String) futureTask.get());
            } catch (Exception e) {
                result.add("to " + apiPortalOperators.get(i).getEmail() + " 发送失败:" + e.getMessage());
            }
        }

        return result;
    }

    /**
     * 异步 多个收件人一起 发送邮件
     * */
    public String asynSendMail(List<ApiPortalOperator> apiPortalOperators, Object bodyParams) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        String[] userEmails = apiPortalOperators.stream().map(ApiPortalOperator::getEmail).toArray(String[]::new);
        FutureTask<String> futureTask = new FutureTask(() -> {
            try {

                this.sendMail(userEmails, bodyParams, 1);
            } catch (Exception e) {
                return "邮件to " + StringUtils.join(userEmails, ',') + " 发送异常:" + e.getMessage();
            }
            return "邮件to " + StringUtils.join(userEmails, ',') + " 发送成功";
        });
        executorService.submit(futureTask);
        try {
            return futureTask.get();
        } catch (Exception e) {
            e.printStackTrace();
            return "邮件to " + StringUtils.join(userEmails, ',') + " 发送异常:" + e.getMessage();
        }
    }

    private void sendSampleMail(String[] userEmail, String msg, String subject) {
        MimeMessagePreparator preparator = new MimeMessagePreparator() {
            @Override
            public void prepare(MimeMessage mimeMessage) throws Exception {
                MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "utf-8");
                message.setTo(userEmail);
                message.setFrom(new InternetAddress(mailProperties.getFrom()));
                message.setSubject(subject);
                message.setText(msg);
            }
        };
        try {
            this.javaMailSender.send(preparator);
        } catch (Exception ex) {
            log.error("Mailing Exception! user email is: {}", userEmail, ex);
        }
        log.info("Mail sent successfully, user email is: {}", userEmail);
    }

    private String buildTemplateMessage(String templateName, Map<String, Object> messages) {
        HttpServletRequest request = new ThymeleafHttpServletRequestAdapter();
        HttpServletResponse response = new ThymeleafHttpServletResponseAdapter();
        ServletContext servletContext = new ThymeleafServletContextAdapter();
        WebContext context = new WebContext(request, response, servletContext);
        context.setVariables(messages);
        return templateEngine.process(templateName, context);
    }

    /**
     * 当发邮件时有多个不定参数时
     * @param userEmail 用户邮箱
     * @param params 发邮件的参数
     * @param templateId
     */
    private void sendMailMultiParams(String[] userEmail, Map<String, Object> params, Integer templateId) {

        String templateName = MailTemplate.getTemplateName(templateId);

        MimeMessagePreparator preparator = new MimeMessagePreparator() {
            @Override
            public void prepare(MimeMessage mimeMessage) throws Exception {
                MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "utf-8");
                message.setTo(userEmail);
                message.setFrom(new InternetAddress(mailProperties.getFrom()));
                message.setSubject(MailTemplate.getTemplateSubject(templateId));

                String content = buildTemplateMessage(templateName, params);
                System.out.println(content);
                message.setText(content, true);
            }
        };
        try {
            this.javaMailSender.send(preparator);
        } catch (Exception ex) {
            log.error("Mailing Exception! user email is: {}, template params are: {}, template_id is: {}", userEmail, params.toString(), templateId, ex);
        }
        log.info("Mail sent successfully, user email is: {}, template params: {}, template_id is: {}", userEmail, params.toString(), templateId);
    }
}

 

Thymeleaf 中有 plain context (不支持对url参数的解析)和 web context(支持对url参数的解析)

We'll have to change our code to create a web context, instead of a plain context. Change will be here: 

参考:https://github.com/ratpack/ratpack/blob/master/ratpack-thymeleaf/src/main/java/ratpack/thymeleaf/Template.java#L69-69

The IWebContext interface seems coupled to the servlet API, but after quick look at the code I don't think this will be a problem. I think we can just provide null values for things like request/session etc. that we can't provide. If that turns out to be a problem… we can look at providing implementations of those Servlet API type in so far makes sense.

 

最后附上一份简单的邮件模板文件

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>邮件提醒</title>
</head>
<body style="margin: 0; padding: 0;">
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="padding: 20px; font-size: 14px;">
    <tbody>
    <tr>
        <td><p style="margin: 0; margin-bottom: 20px;">Hi,</p></td>
    </tr>
    <tr>
        <td><p style="margin: 0; margin-bottom: 20px;">项目<span th:text="${project}"/>的API已设计完成,请到<a href="#" th:href="@{ ${apiUrl} }">API Portal</a>上review。</p></td>
    </tr>
    <tr th:each="link,status : ${links}">
        <td><p style="margin: 0;"><span th:text="${status.count}"/>. <span th:text="${link.method}"/>&nbsp;<span th:text="${link.path}"/>&nbsp;<span th:text="${link.description}"/>&nbsp;<a href="#" th:href="@{ ${link.url} }">点击查看</a></p></td>
    </tr>
    <tr>
        <td><p style="margin: 0; margin-top: 20px;">Thanks</p></td>
    </tr>
    <tr>
        <td><p style="margin: 0;"><span th:text="${user}"/></p></td>
    </tr>
    </tbody>
</table>
</body>
</html>

 

目录
相关文章
|
存储 Linux Shell
Linux绝对路径和相对路径
在 Linux 中,简单的理解一个文件的路径,指的就是该文件存放的位置。 只要我们告诉 Linux 系统某个文件存放的准确位置,那么它就可以找到这个文件。指明一个文件存放的位置,有 2 种方法,分别是使用绝对路径和相对路径。 我们知道,Linux 系统中所有的文件(目录)都被组织成以根目录“/”开始的倒置的树状结构 绝对路径一定是由根目录 / 开始写起。例如,使用绝对路径的表示方式指明 bin 文件所在的位置,该路径应写为 /usr/bin,测试代码如下: [root@localhost ~]# bin bash: bin: command not found <-- 没有找到 [
490 0
|
Java Maven
maven 工程pom依赖优化及常用命令
maven 工程pom依赖优化及常用命令
326 0
|
消息中间件 存储 缓存
不看损失大了,刨根问底,Kafka消息中间件到底会不会丢消息
不看损失大了,刨根问底,Kafka消息中间件到底会不会丢消息
1019 108
不看损失大了,刨根问底,Kafka消息中间件到底会不会丢消息
|
JSON 前端开发 Java
Validated、Valid 、Validator,他们的区别你知道几个
对于任何基本验证,我们将在方法调用中使用 JSR @Valid注释。另一方面,对于任何组验证,包括组序列,我们需要 在我们的方法调用中使用 Spring 的@Validated注释。
Validated、Valid 、Validator,他们的区别你知道几个
|
XML Java 数据格式
idea自动去除项目无用import以及注释不顶格且注释后空格设置(包括新建项目)
idea自动去除项目无用import以及注释不顶格且注释后空格设置(包括新建项目)
544 0
|
缓存 监控 Linux
Linux 日志查看命令journalctl
Journald是Linux系统中新的系统日志方式,它把日志信息写入二进制文件,它终结了文本日志。查看所有系统日志,只用一个命令即可,这个命令就是journalctl。Journald守护进程:systemd-journald,其中systemd日志服务就由此守护程序处理。
1421 0
|
网络协议 应用服务中间件 Linux
Linux iptables是什么?iptables和docker的关系?
iptables是Linux系统中用来配置防火墙的命令。iptables是工作在TCP/IP的二、三、四层,当主机收到一个数据包后,数据包先在内核空间处理,若发现目标地址是自身,则传到用户空间中交给对应的应用程序处理,若发现目标不是自身,则会将包丢弃或进行转发。
726 0
|
Web App开发 网络协议 Linux
docker(alpine+golang) 中 hosts 不生效问题解决大全
把使用 golang 开发的服务程序部署在以 alpine 为基础镜像的容器中,设置了 /etc/hosts,却没有生效,但是在终端中使用 ping 和 curl 域名都可以正常访问。出现上述问题的根本原因是 DNS 解析顺序不一致导致的,在 alpine 中,linux 系统默认跳过 hosts 配置,直接使用机器的 DNS 服务。因此,有如下三种解决方法。修改 NDS 解析顺序,先设置读 files,再设置读 dns,具体方法如下:但是方法一会存在一个问题,就是容器重启后,配置文件就消失了。因此可以使用
908 1
docker(alpine+golang) 中 hosts 不生效问题解决大全
|
区块链
ERC20代币合约开发规则详解(源码示例)
ERC20代币合约是一个遵循ERC20标准的代币合约,它实现了代币转移、代币冻结、代币解锁等功能。作为一个通用的标准,ERC20代币合约可以被广泛应用于各种去中心化交易所、钱包、ICO等场景。
BXA
|
安全 算法 Java
Spring Security添加二次认证
Spring Security是一个基于Spring框架的安全框架,用于为Java应用程序提供身份验证和授权服务。
BXA
875 0