springboot生成excel表格,并且通过邮件发送【保姆级教程二,代码直接用】

整个实现过程如下:

1、实际开发中,特别是在B端产品的开发中,经常会遇到导出 excel 的功能,更进阶一点的需要我们定期生成统计报表,然后通过邮箱发送给指定的人员。

2、这样的一个功能我们将其拆分出来包括三方面的知识点:定时任务框架、excel生成、邮件发送

3、今天要带大家来实现的就是excel生成并通过邮件发送

开发环境:

  • 以下演示 jdk 选用1.8版本。spring boot 采用 2.5.1 版本。
  • excel 生成通过 alibaba 的 EasyExcel 组件来实现

思路:
1、生成一个excel
2、将 excel 作为附件添加到邮件中进行发送

一、实现邮箱发送

首先需要实现邮箱发送的功能,推荐使用基于 spring-boot-starter-mail 的方法实现:直接引入依赖即可,具体的实现方法,可以查看这篇文章:java发送邮箱

二、生成 excel 表格

实现邮箱发送的功能之后,然后需要将数据生成 excel 表格,这里利用 EasyExcel 来生成 excel,具体方法如下:

1、excel 表格对应的实体类:

/**
 * 用于测试邮件发送 -- 实体类
 */
@Data
public class UserInfo {
    @ExcelProperty("姓名")
    private String userName;
    @ExcelProperty("电话号码")
    private String phone;
    @ExcelProperty("年龄")
    private Integer age;
}

2、获取数据来封装表格(这里使用假数据):

/**
 * 生成表格中的假数据
 */
public class GenerateDataUtil {
    public static List<UserInfo> generateData() {
        List<UserInfo> dataList = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            UserInfo data = new UserInfo();
            data.setUserName("客户" + i);
            data.setPhone("13889999999");
            data.setAge(18);
            dataList.add(data);
        }
        return dataList;
    }
}

3、写生成 excel 表格的工具类(利用 EasyExcel):

/**
 * excel表格生成工具
 */
public class ExcelUtil {

    /**
     * 生成excel文件
     *
     * @param fileName excel文件路径
     * @param dataList 数据列表
     * @param clazz    导出对象类
     * @param <T>
     * @return
     */
    public static <T> File generateExcel(String fileName, List<T> dataList, Class<T> clazz) {
        // 生成文件
        File file = new File(fileName);
        // 单sheet写入
        EasyExcel.write(file, clazz).sheet("XXX").doWrite(dataList);
        return file;
    }

    /**
     * 生成excel文件 -- 方法优化 -- 用流
     *
     * @param dataList 数据列表
     * @param clazz 导出对象类
     * @param <T>
     * @return
     */
    public static <T> ByteArrayOutputStream generateExcel(List<T> dataList, Class<T> clazz) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 单excel写入
        EasyExcel.write(out, clazz).sheet("XXX").doWrite(dataList);
        return out;
    }

}

三、整体实现

在把上面的准备工作做好之后,就可以实现了,这里直接基于接口调用的方法实现整个过程:

1、写接口:

@Slf4j
@RestController
@RequestMapping("/excel")
public class SendEmailController {

    @Autowired
    private SendEmailService service;


    @GetMapping("/send")
    public void generateExcelAndSend() {
        // 生成excel中的假数据
        long start = System.currentTimeMillis();
        try {
            service.generateExcelAndSend2();
        } catch (IOException e) {
            log.error(String.format("生成excel失败,原因:%s", e));
            e.printStackTrace();
        } catch (MessagingException e) {
            log.error(String.format("邮件发送失败,原因:%s", e));
            e.printStackTrace();
        } finally {
            long end = System.currentTimeMillis();
            System.out.println("耗时:" + (end - start));
        }
    }

}

2、service 层:

public interface SendEmailService {
    void generateExcelAndSend() throws MessagingException, UnsupportedEncodingException;
    void generateExcelAndSend2() throws MessagingException, IOException;
}

然后就是 service 层的实现层:

@Service
public class SendEmailServiceImpl implements SendEmailService {

    // 注入发送邮箱工具类
    @Autowired
    private SendEmailUtil sendEmailUtil;

    @Override
    public void generateExcelAndSend() throws MessagingException, UnsupportedEncodingException {
        // 调方法生成数据
        List<UserInfo> userInfos = GenerateDataUtil.generateData();
        String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
        String fileName = String.format("%s客户统计数据-%s.xlsx", path, UUID.randomUUID());

        // 生成excel文件
        File excel = ExcelUtil.generateExcel(fileName, userInfos, UserInfo.class);

        String subject = "客户统计数据";
        String content = "客户统计数据如附件所示";
        String toMail = "3088869337@qq.com";
        String ccMail = "zhangfuping123456@163.com";
        // 发送邮件
        sendEmailUtil.sendEmail(subject, content, false, "zfp", toMail, null, null, new File[]{excel});
        // 邮件发送完成后删除临时生成的excel文件
        excel.delete();
    }

    // 方法优化
    @Override
    public void generateExcelAndSend2() throws MessagingException, IOException {
        // 调方法生成数据
        List<UserInfo> userInfos = GenerateDataUtil.generateData();
        //
        String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
        String fileName = String.format("%s客户统计数据-%s.xlsx", path, UUID.randomUUID());

        // 生成excel文件
        ByteArrayOutputStream bos = ExcelUtil.generateExcel(userInfos, UserInfo.class);

        String subject = "客户统计数据";
        String content = "客户统计数据如附件所示";
        // 收信人
        String toMail = "3088869337@qq.com";
        // 抄送
        String ccMail = "zhangfuping123456@163.com";
        // 发送邮件
        sendEmailUtil.sendEmail(subject, content, false, "zfp", toMail, null, null, fileName, new ByteArrayResource(bos.toByteArray()));
        // 邮件发送完成后删除临时生成的excel文件
        bos.close();
    }
}

提示:代码中用到一个邮箱工具类,这个就是实现邮箱发送功能,具体过程可查看这篇文章: java发送邮箱

这里再次贴出代码:

/**
 * 发送邮件工具类
 */
@Component
public class SendEmailUtil {

    // 注入系统相关类
    @Autowired
    private JavaMailSender javaMailSender;
    @Autowired
    private MailProperties mailProperties;

    // 发送者邮箱
//    @Value("${spring.mail.username}")
//    private String sendMailer;

    /**
     * 邮件发送
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param fileNames            文件名(本地文件名)
     */
    public void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
                          String toMail, String ccMail, String bccMail, List<String> fileNames) throws MessagingException, UnsupportedEncodingException {
        // true 代表支持复杂的类型
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        /* 邮件发信人:两种写法:
        1. 定义成员变量获取application.yml的username属性
            @Value("${spring.mail.username}")
            private String sendMailer;
            helper.setFrom(sendMailer,发件人名称)
        2. 注入系统类的对象,然后调方法获取,获取的值也是application.yml文件中的值
            @Autowired
            private MailProperties mailProperties;
            helper.setFrom(mailProperties.getUsername(),发件人名称);
        */
        helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
        // 邮件收信人  1或多个
        helper.setTo(toMail);
        if (!ObjectUtils.isEmpty(ccMail)) {
            // 邮件抄送人
            helper.setCc(ccMail);
        }
        if (!ObjectUtils.isEmpty(bccMail)) {
            // 邮件私密抄送人
            helper.setBcc(bccMail);
        }
        // 邮件主题
        helper.setSubject(subject);
        // 邮件内容   contentIsHtml值为 true 代表支持html
        helper.setText(content, contentIsHtml);

        // 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
        if (!CollectionUtils.isEmpty(fileNames)) {
            for (String fileName : fileNames) {
                // 添加邮件附件
                FileDataSource fileDataSource = new FileDataSource(fileName);
                helper.addAttachment(fileDataSource.getName(), fileDataSource);
            }
        }
        // 发送邮件
        javaMailSender.send(mimeMessage);
    }

    /**
     * 邮件发送 -- 方法优化 -- 文件对象
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param files                文件对象
     */
    public void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
                          String toMail, String ccMail, String bccMail, File[] files) throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
        helper.setTo(toMail);
        if (!ObjectUtils.isEmpty(ccMail)) {
            helper.setCc(ccMail);
        }
        if (!ObjectUtils.isEmpty(bccMail)) {
            helper.setBcc(bccMail);
        }
        helper.setSubject(subject);
        helper.setText(content, contentIsHtml);
        // 设置附件,不能是远程文件
        if (!ObjectUtils.isEmpty(files)) {
            for (File file : files) {
                helper.addAttachment(file.getName(), file);
            }
        }
        javaMailSender.send(message);
    }


    /**
     * 邮件发送 -- 方法优化 -- 使用流
     *
     * @param subject              邮件主题
     * @param content              邮件内容
     * @param contentIsHtml        内容是否为html格式
     * @param fromMailPersonalName 发件人昵称
     * @param toMail               收件人邮箱
     * @param ccMail               抄送人邮箱
     * @param bccMail              秘密抄送人邮箱
     * @param fileName             文件名称
     * @param fileInput            文件流
     */
    public void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
                          String toMail, String ccMail, String bccMail, String fileName, InputStreamSource fileInput) throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
        helper.setTo(toMail);
        if (!ObjectUtils.isEmpty(ccMail)) {
            helper.setCc(ccMail);
        }
        if (!ObjectUtils.isEmpty(bccMail)) {
            helper.setBcc(bccMail);
        }
        helper.setSubject(subject);
        helper.setText(content, contentIsHtml);
        // 设置附件,不能是远程文件
        if (fileInput != null) {
            helper.addAttachment(fileName, fileInput);
        }
        javaMailSender.send(message);

    }
}

3、配置文件:

spring:
  # 配置发送邮件的配置信息
  mail:
    # 配置smtp服务主机地址
    host: smtp.qq.com
    # 发送者邮箱
    username: 308xxxx9337@qq.com
    # 配置密码,注意不是真正的密码,而是申请到的授权码
    password: jlpxxxxqhdecj
    # 端口号:465或587
    port: 465
    # 默认的邮件编码为UTF-8
    default-encoding: UTF-8
    # 其他参数
    properties:
      mail:
        # 配置SSL 加密工厂
        smtp:
          ssl:
            # 本地测试,先放开ssl
            enable: true
            required: true
          # 开启debug模式,这样邮件发送过程的日志会在控制台打印出来,方便排查错误
        debug: true

最后运行启动类,访问接口即可。

附录

疑问?为什么采用流:

上述的实现,需要先创建一个文件然后又删除,不是很方便,于是可以采取直接用流输入输出:

在这里插入图片描述

也就是:
1、首先生成 excel 的方法调整为返回输出流;
2、其次发送邮件的方法调整为,直接接收输入流;
3、主方法调整:不生成文件,而是通过流来传输

邮件正文中直接显示表格数据

1、有时候我们的统计数据不是很多,会更希望我们直接在邮件中展示表格数据,而不用再单独下载附件查看,这就需要用到 HTML 格式的邮件正文的实现。
2、比较简单的实现就是循环数据集合,通过字符串拼接生成 html 的字符串。因为实现比较简单,这里就仅提供思路。

提示:可以查看实现邮箱发送的文章,里面有实现的过程

总结

excel 的生成以及邮件的发送,都应该尽可能的提取为工具类,如果实现的功能更多的更需要提取的单独的服务,通过pom 依赖引入,更大化的实现方法的通用,和业务代码与通用代码之间的解耦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小学鸡!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值