springboot发送邮件,内容使用thymeleaf模板引擎排版

news2024/11/15 8:32:58

springboot发送邮件,内容使用thymeleaf模板引擎排版

      • 1、导入jar包
      • 2、yml设置
      • 3、收件人以及收件信息设置
      • 4、发邮件service
      • 5、模版页面
      • 6、controller

1、导入jar包

<!--发送邮件-->
  <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-mail</artifactId>
   </dependency>
<!--使用thymeleaf 形式-->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-thymeleaf</artifactId>
   </dependency>

2、yml设置

发件邮箱信息设置:


spring:
  mail:
    host: smtp.xx.cn
    port: 465
    username: 你的邮箱
    password: 你的密码
#    default-encoding: UTF-8
    protocol: smtp
    properties: # 配置以SSL的方式发送, 这个需要使用这种方式并且端口是465
      mail:
        smtp:
          auth: true
          ssl:
            enable: true
            socketFactory:
              class: com.sun.mail.util.MailSSLSocketFactory
              fallback: false
        debug: true

3、收件人以及收件信息设置

@Getter
@Setter
public class AcceptMailParam {
    //标题
    private String title;
    //接收人邮件地址
    private String receiveEmail[];
    //抄送人邮件地址
    private String chaoSongPersonEmail[];
    
    //附件,value 文件的绝对地址/动态模板数据
    private Map<String, Object> attachment;
	
	//thymeleaf模版引擎页面对象数据:邮件排版内存
    List<OperateDataResultInfoView> pageViewList;
}

页面对象数据展示
@Setter
@Getter
public class OperateDataResultInfoView {

    private Long id;

    /**
     * 存储当前年月,eg:202301
     */
    private Integer curMonth;
    /**
     * 库名
     */
    private String dbName;
    /**
     * 表名
     */
    private String tableName;

    /**
     * 计划生成数据量
     */
    private Long planGenDataCnt;

    /**
     * 实际生成数据量
     */
    private Long actualGenDataCnt;

    /**
     * 备注
     */
    private String remark;

    private String gmtCreate;

    private String gmtModified;

    /* *
     * 剩余待生成数据量
     */
    private Long remainToGenCnt;

    /* *
     * 生成数据成功率(实际生成数量/计划生成数量),单位%
     */
    private BigDecimal genDataSuccessRate;

/**模拟生成数据*/
    public OperateDataResultInfoView() {

        this.id = ThreadLocalRandom.current().nextLong(100L, 999L);
        this.curMonth = DateUtil.getPreMonth();
        String[] dbAndTableName = ("dbName" + id + ".tableName" + id).split("\\.");
        this.dbName = dbAndTableName[0];
        this.tableName = dbAndTableName[1];
        this.planGenDataCnt = id + ThreadLocalRandom.current().nextLong(10L, 99L);
        this.actualGenDataCnt = id;
        this.remark = null;
        this.gmtCreate = DateUtil.getNowStr();
        this.gmtModified = DateUtil.getNowStr();
        this.remainToGenCnt = (planGenDataCnt - actualGenDataCnt) >= 0 ? (planGenDataCnt - actualGenDataCnt) : 0;

        BigDecimal rate = new BigDecimal(actualGenDataCnt).divide(new BigDecimal(planGenDataCnt), 4, BigDecimal.ROUND_HALF_UP);
        this.genDataSuccessRate = rate.compareTo(new BigDecimal("1")) >= 0 ? new BigDecimal("100") : rate.multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP);
    }
}

4、发邮件service

public interface SendMailService {
    /**
     * 邮件内容排版调试
     */
    AcceptMailParam getMailContentAndSendMail(Integer curMonth);
}

/**
     * 获取指定月份的邮件【邮件内容:生成数据的结果集 信息】
     * 次月1日8点 发送
     */
    @Override
    public AcceptMailParam getMailContentAndSendMail(Integer curMonth) {
        AcceptMailParam acceptMailParam = new AcceptMailParam();
        List<OperateDataResultInfoView> pageViewList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            pageViewList.add(new OperateDataResultInfoView());
        }
        Collections.sort(pageViewList, Comparator.comparing(OperateDataResultInfoView::getId).reversed());
        acceptMailParam.setPageViewList(pageViewList);

        String[] emails = {"xxx1@qq.com"};
        String[] chaoSongPerson = {"xx2@qq.com"};
        //收件人,支持多人
        acceptMailParam.setReceiveEmail(emails);
        //抄送人,支持多人
        acceptMailParam.setChaoSongPersonEmail(chaoSongPerson);
        acceptMailParam.setTitle("统计业务表生成数据结果");

        //添加附件
        Map<String, Object> map = new HashMap<>();
        //key为邮件附件文件名称,路径改为你的服务器路径即可,可添加不同类型文件
        map.put("1-test1.zip", "/Users/gina/xx/data/test2.zip");
        map.put("2-test2.xlsx", "/Users/gina/xx/data/test1.xlsx");
        acceptMailParam.setAttachment(map);
        
        //调试邮件内容排版时,此处可注释掉。
        //this.sendTemplateMail(acceptMailParam,"/mail/list");
        return acceptMailParam;
    }

5、模版页面

在resources下,在路径templates/mail/下添加文件list.html

<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<style>
  tr.odd td {
    background-color: #f0faaa;
  }

  td.number {
    text-align: right;
  }


  table {
    width: 100%;
    border: 1px solid #000;
    border-collapse: collapse;
  }

  table > tbody > tr > td, table > thead > tr > th {
    padding: 2px 10px;
    border-left: 1px dotted #000000;
    vertical-align: top;
    line-height: 20px;
  }

  table > tbody > tr, table > thead > tr {
    border-bottom: 1px solid #000000;
  }

  table th {
    background-color: #99cc33;
  }

  table > tbody > tr > td > a, table > tbody > tr > td > a:hover {
    text-decoration: none;
    font-weight: bold;
    background-color: #352726;
    padding: 2px 10px;
    color: #f0faaa;
    margin-left: 10px;
    text-transform: uppercase;
    border: 0px;
  }

</style>
  <head>
    <title>统计业务表生成数据结果</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <h1>统计业务表生成数据结果</h1>
    <table>
      <tr>
        <th>生成月份</th>
        <th>库名</th>
        <th>表名</th>
        <th>计划生成()</th>
        <th>实际生成()</th>
        <th>成功率%</th>
        <th>未生成()</th>
        <th>创建时间</th>
        <th>更新时间</th>
        <th>备注</th>
      </tr>
      <tr th:each="o : ${pageViewList}" th:class="${o.id % 2 == 0}? 'odd'" >
        <td th:text="${o.curMonth}"   ></td>
        <td th:text="${o.dbName}" ></td>
        <td th:text="${o.tableName}" ></td>
        <td th:text="${o.planGenDataCnt}" ></td>
        <td th:text="${o.actualGenDataCnt}"></td>
        <td th:text="${o.genDataSuccessRate}"></td>
        <td th:text="${o.remainToGenCnt}"></td>
        <td th:text="${o.gmtCreate}"></td>
        <td th:text="${o.gmtModified}"></td>
        <td th:text="${o.remark}"></td>
      </tr>
    </table>
  </body>
</html>

6、controller

@Controller
@Slf4j
public class SendMailController {

    /**
     * 调试生成的页面样式,不发邮件
     * 数据处理结果集view
     */
    @Resource
    private SendMailService sendMailService;

    /** 点此可直接访问
     * http://localhost:8081/sendMail?curMonth=202311
    */
    @RequestMapping("sendMail")
    public String sendMail(Model model, @RequestParam(name = "curMonth") Integer curMonth) {
        try {
            AcceptMailParam acceptMailParam = sendMailService.getMailContentAndSendMail(curMonth);
            model.addAttribute("title", acceptMailParam.getTitle());
            model.addAttribute("pageViewList", acceptMailParam.getPageViewList());
        } catch (Exception e) {
            log.error("sendMail fail ,msg={}", e.getMessage());
        }
        return "mail/list";
    }
}

7、启动服务后,访问页面展示:
在这里插入图片描述

邮箱内容样式为:
在这里插入图片描述

有对thymeleaf感兴趣的同学可通过中文官网去了解:thymeleaf中文官网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1313116.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Axure RP结合内网穿透工具制作本地静态web页面并实现公网访问

作者简介&#xff1a; 懒大王敲代码&#xff0c;正在学习嵌入式方向有关课程stm32&#xff0c;网络编程&#xff0c;数据结构C/C等 今天给大家讲解使用Axure RP结合内网穿透工具制作本地静态web页面并实现公网访问&#xff0c;希望大家能觉得实用&#xff01; 欢迎大家点赞 &am…

订单系统设计-状态机

1. 状态机 1.1 状态机简介 状态机是有限状态自动机的简称&#xff0c;是现实事物运行规则抽象而成的一个数学模型。 有限状态机一般都有以下特点&#xff1a; 可以用状态来描述事物&#xff0c;并且任一时刻&#xff0c;事物总是处于一种状态&#xff1b;事物拥有的状态总数…

线程安全集合类

文章目录 1. ConcurrentHashMap2. LinkedBlockingQueue 阻塞队列3. ConcurrentLinkedQueue4. CopyOnWriteArrayList JDK1.7 hashmap采用数组加链表头插的方式&#xff0c;在扩容时会出现循环死链问题&#xff0c;A->B->C扩容后C->B->A AB BA出现循环死链。 1. Conc…

Dockerfile的介绍和使用

什么是dockerfile? Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。 docker build命令用于从Dockerfile构建映像。可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerf…

【Monitor, Maintenance Operation, Script code/prgramme】

Summary of M,M&O,Program JD) Monitor & M&O Symbio信必优) Job chance/opportunities on Dec 12th, 20231.1) Content 招聘JD job description:1.2) suggestions from Ms Liang/Winnie on Wechat app1.3) Java微服务是什么&#xff1f;1.3.1) [URL Java 微服务](…

yarn系统架构与安装

1.1 YARN系统架构 YARN的基本思想是将资源管理和作业调度/监视功能划分为单独的守护进程。其思想是拥有一个全局ResourceManager (RM)&#xff0c;以及每个应用程序拥有一个ApplicationMaster (AM)。应用程序可以是单个作业&#xff0c;也可以是一组作业。 一个ResourceManage…

数据结构与算法之美学习笔记:36 | AC自动机:如何用多模式串匹配实现敏感词过滤功能?

目录 前言基于单模式串和 Trie 树实现的敏感词过滤经典的多模式串匹配算法&#xff1a;AC 自动机解答开篇内容小结 前言 本节课程思维导图&#xff1a; 很多支持用户发表文本内容的网站&#xff0c;比如 BBS&#xff0c;大都会有敏感词过滤功能&#xff0c;用来过滤掉用户输入…

如何做好口译服务,同传和交传哪个服务好

随着中国经济的蓬勃发展和综合实力的不断增强&#xff0c;中国与世界各国的交流也日益频繁。口译作为对外交流的桥梁与纽带&#xff0c;需求量与日俱增&#xff0c;其重要性不言而喻。那么&#xff0c;如何做好口译服务呢&#xff1f;是同传还是交传更好呢&#xff1f; 要做好口…

rabbitmq-windows安装使用-简易后台界面-修改密码

文章目录 1.下载2.安装3.安装 RabbitMQ4.后台访问5.修改密码 1.下载 将erlang运行时和rabbitmq-windows版本&#xff0c;上传在csdn&#xff0c;下载链接。https://download.csdn.net/download/m0_67316550/88633443 2.安装 右键&#xff0c;以管理员身份运行rabbitmq。启动…

如何用Adobe Audition 检测波形的pop和卡顿

在Adobe Audition中&#xff0c;检测卡顿和pop的方法各有不同&#xff1a; 1. **检测卡顿**&#xff1a; - 使用“诊断”面板中的“删除静音”或“标记音频”选项可以帮助识别音频中的静音段落&#xff0c;这可能表明存在卡顿。 - 配置诊断设置&#xff0c;指定静音的振…

探讨前端技术的未来:创新与适应的必要性

一、引言 2023年&#xff0c;IT圈似乎被一种悲观的论调所笼罩&#xff0c;那就是“Java 已死、前端已凉”。然而&#xff0c;真相是否如此呢&#xff1f;本文将围绕这一主题&#xff0c;探讨前端的现状和未来发展趋势。 二、为什么会出现“前端已死”的言论 这一言论的出现并…

Python高级算法——线性规划(Linear Programming)

Python中的线性规划&#xff08;Linear Programming&#xff09;&#xff1a;高级算法解析 线性规划是一种数学优化方法&#xff0c;用于求解线性目标函数在线性约束条件下的最优解。它在运筹学、经济学、工程等领域得到广泛应用。本文将深入讲解Python中的线性规划&#xff0…

python 新手学习 - 简单实用的 Python 周期任务调度工具

如果你想周期性地执行某个 Python 脚本&#xff0c;最出名的选择应该是 Crontab 脚本&#xff0c;但是 Crontab 具有以下缺点&#xff1a; 1.不方便执行秒级任务。 2.当需要执行的定时任务有上百个的时候&#xff0c;Crontab 的管理就会特别不方便。 还有一个选择是 Celery&a…

如何在 JavaScript 中实现任务队列

任务队列的概念 任务队列就是存放任务的队列&#xff0c;队列中的任务都严格按照进入队列的先后顺序执行。 在前一条任务执行完毕后&#xff0c;立即执行下一条任务&#xff0c;直到任务队列清空。 任务队列的基本执行流程如下&#xff1a; 设置任务队列并发数&#xff1b; …

编程导航算法通关村——算法基础

目录 1. 时间复杂度 1.1. 时间复杂度概念 1.2. 几种常见的阶 1.2.1. 常数阶 O(1) 1.2.2. 线性阶 O(n) 1.2.3. 平方阶 (n) 1.2.4. 对数阶 O(logn) 2. 最坏情况和平均情况 3. 空间复杂度 1. 时间复杂度 1.1. 时间复杂度概念 当我们说算法的时间复杂度时&#xff0c;我们…

「完美世界」石昊被诓入至尊道场,修炼无敌道,打跑天仙书院弟子

Hello,小伙伴们&#xff0c;我是拾荒君。 《完美世界》这部国漫&#xff0c;在粉丝的翘首期盼中&#xff0c;终于迎来了第141集的更新。这一集的内容&#xff0c;对于喜欢石昊和至尊道场劫难的观众来说&#xff0c;可谓是扣人心弦&#xff0c;让人目不转睛。 在这一集中&#…

【node】使用 sdk 完成短信发送

实现效果 过程 流程比较复杂&#xff0c;加上需要实名认证&#xff0c;建议开发的时候先提前去认证号账号&#xff0c;然后申请模版也需要等认证。 源码 我看了新版的sdk用的代码有点长&#xff0c;感觉没必要&#xff0c;这边使用最简单的旧版的sdk。 https://github.com/…

【MySQL学习之基础篇】约束

文章目录 1. 概述2. 基础约束3. 外键约束3.1. 介绍3.2. 外键的添加3.3. 外键删除和更新行为 1. 概述 概念&#xff1a; 约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。     目的&#xff1a; 保证数据库中数据的正确、有效性和完整性。 分类&#x…

HHDESK个性化脚本功能

HHDESK可以把脚本配置在对话框中&#xff0c;生成按钮&#xff0c;便捷操作。 在界面下方的脚本框中&#xff0c;点击“”&#xff0c;选择新建&#xff1b; 随后在弹出框内填写名称及脚本&#xff0c;按需求选择填写参数&#xff0c;及运行过程中是否弹出参数框&#xff1b;…

Vue3-14- 【v-for】循环数组-解构的操作

说明 v-for 在遍历数组的时候&#xff0c;可以使用解构的语法&#xff0c;直接将数组中对象元素的属性解构出来&#xff0c; 从而实现直接使用对象属性值的效果。语法格式 &#xff1a; v-for"({属性名1,属性名2},索引变量名) in 数组名"具体的使用请看代码&#xf…