数据生成PDF定时批量发送到目标邮箱

1.邮箱参数

复制代码
@Configuration
@Data
public class EmailUtils {
    @Value("${email.from}")
    private String from;

    @Value("${email.fromKey}")
    private String fromKey;

    @Value("${email.fromHost}")
    private String fromHost;

    @Value("${email.fromPort}")
    private String fromPort;
}

2.发送邮件

复制代码
  String fromEmail, smtpHost, smtpPort, authCode;
        fromEmail = emailUtils.getFrom();
        authCode = emailUtils.getFromKey();
        smtpHost = emailUtils.getFromHost();
        smtpPort = emailUtils.getFromPort();
        // 生成 PDF
        PDFGenerator pdfGenerator = new PDFGenerator();
        List<String[]> businessData = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime lastSaturdayStart = now.minusDays(7)
                .withHour(0)
                .withMinute(0)
                .withSecond(0);
        // 计算前1天(本周五)的23:59:59
        LocalDateTime thisFridayEnd = now.minusDays(1)
                .withHour(23)
                .withMinute(59)
                .withSecond(59);
        // 输出结果
        String startTime = lastSaturdayStart.format(formatter);
        String endTime = thisFridayEnd.format(formatter);
        // 假设的业务数据
        List<String[]> clientData = new ArrayList<>();
        List<SysDept> deptList = deptMapper.selectSubsidiaryList();
        for (SysDept sysDept : deptList) {
            List<Long> userList = wechatUserMapper.selectSubsidiaryUserId(sysDept.getDeptId());
            if (userList.size() == 0) {
                clientData.add(new String[]{sysDept.getDeptName(), "0", "0", "0", "0"});
                businessData.add(new String[]{sysDept.getDeptName(), "0", "0", "0", "0"});
                continue;
            }
            //客户、实验校
            ClientWeekVO clientWeek = clientMapper.selectWeekInfo(userList, startTime, endTime);
            ClientWeekVO schoolWeek = schoolMapper.selectWeekInfo(userList, startTime, endTime);
            List<Long> clientList = clientMapper.selectClientUser(userList);
            clientData.add(new String[]{sysDept.getDeptName(), clientWeek.getAllCount(), clientWeek.getWeekCount(), schoolWeek.getAllCount(), schoolWeek.getWeekCount()});
            if (clientList.size() == 0) {
                businessData.add(new String[]{sysDept.getDeptName(), "0", "0", "0", "0"});
                continue;
            }
            //回款、订单
            ClientWeekVO returnedWeek = returnedMapper.selectWeekInfo(clientList, startTime, endTime);
            if (!Objects.isNull(returnedWeek)) {
                if (returnedWeek.getWeekCount() == null) {
                    returnedWeek.setWeekCount("0");
                }
                if (returnedWeek.getAllCount() == null) {
                    returnedWeek.setAllCount("0");
                }
            }
            if (Objects.isNull(returnedWeek)) {
                returnedWeek = new ClientWeekVO();
                returnedWeek.setWeekCount("0");
                returnedWeek.setAllCount("0");
            }
            ClientWeekVO orderWeek = ordersMapper.selectWeekInfo(clientList, startTime, endTime);
            if (!Objects.isNull(orderWeek)) {
                if (orderWeek.getWeekCount() == null) {
                    orderWeek.setWeekCount("0");
                }
                if (orderWeek.getAllCount() == null) {
                    orderWeek.setAllCount("0");
                }
            }
            if (Objects.isNull(orderWeek)) {
                orderWeek = new ClientWeekVO();
                orderWeek.setWeekCount("0");
                orderWeek.setAllCount("0");
            }
            businessData.add(new String[]{sysDept.getDeptName(), orderWeek.getAllCount(), orderWeek.getWeekCount(), returnedWeek.getAllCount(), returnedWeek.getWeekCount()});
        }
        String pdfPath = pdfGenerator.generateBusinessReport(businessData, clientData, startTime, endTime);
        String subject = "业务周报";
        // 设置多个收件人
        LambdaQueryWrapper<Email> wrapper = new LambdaQueryWrapper<>();
        List<Email> emailLists = emailMapper.selectList(wrapper);
        List<String> emailList = new ArrayList<>();
        for (Email email : emailLists) {
            emailList.add(email.getEmailAddress());
        }
        // 配置邮件服务器属性
        Properties props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.host", smtpHost);
        props.put("mail.smtp.port", smtpPort);
        props.put("mail.smtp.ssl.enable", "true");
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        // 获取会话对象
        Session session = Session.getInstance(props, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(fromEmail, authCode);
            }
        });
        try {
            // 创建邮件消息
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(fromEmail));
            message.setSubject(subject);
            try {
                InternetAddress[] recipientAddresses = emailList.stream()
                        .map(email -> {
                            try {
                                return new InternetAddress(email);
                            } catch (AddressException e) {
                                System.out.println("无效的邮箱地址: " + email);
                                return null;
                            }
                        })
                        .filter(Objects::nonNull)
                        .toArray(InternetAddress[]::new);
                message.setRecipients(Message.RecipientType.TO, recipientAddresses);
            } catch (Exception e) {
                System.out.println("设置收件人失败: " + e.getMessage());
                return;
            }
            // 创建邮件内容部分
            MimeBodyPart textPart = new MimeBodyPart();
            textPart.setText("请查收附件中的经营周报!");
            // 创建附件部分
            MimeBodyPart attachmentPart = new MimeBodyPart();
            attachmentPart.attachFile(pdfPath);
            // 将文本和附件组合成多重消息
            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(textPart);
            multipart.addBodyPart(attachmentPart);
            // 设置邮件内容
            message.setContent(multipart);
            // 发送邮件
            Transport.send(message);
            System.out.println("邮件发送成功,附件已附加!");
        } catch (MessagingException |
                IOException e) {
            e.printStackTrace();
            System.out.println("邮件发送失败!");
        }
    }

3.生成PDF

复制代码
package com.ruoyi.quartz.util.email;

import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.properties.HorizontalAlignment;
import com.itextpdf.layout.properties.TextAlignment;

import java.io.FileOutputStream;
import java.util.List;

/**
 * 业务数据和客户数据 PDF 生成器
 *
 * @author laoyou
 */
public class PDFGenerator {
    public String generateBusinessReport(List<String[]> businessData, List<String[]> clientData, String startTime, String endTime) {
        String pdfPath = "业务周报.pdf";
        try (PdfWriter writer = new PdfWriter(new FileOutputStream(pdfPath));
             PdfDocument pdfDoc = new PdfDocument(writer);
             Document document = new Document(pdfDoc)) {

            // 加载中文字体
            //PdfFont font = PdfFontFactory.createFont("C:\\Windows\\Fonts\\simsun.ttc,1", PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
            PdfFont font = PdfFontFactory.createFont("/usr/share/fonts/wqy-zenhei/wqy-zenhei.ttc,0", PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
            document.setFont(font);
            // 添加报告标题
            document.add(new Paragraph("业务周报").setFont(font).setBold().setFontSize(18).setTextAlignment(TextAlignment.CENTER));
            // 添加时间区间
            document.add(new Paragraph("数据时间: " + startTime + " 至 " + endTime).setFont(font).setFontSize(12).setTextAlignment(TextAlignment.CENTER));
            // 添加业务情况标题
            document.add(new Paragraph("本周各区业务情况").setFont(font).setBold().setFontSize(16).setTextAlignment(TextAlignment.CENTER));
            // 业务数据表格
            document.add(new Paragraph("业务数据").setFont(font).setBold().setFontSize(14).setTextAlignment(TextAlignment.CENTER));
            Table businessTable = new Table(new float[]{2, 2, 2, 2, 2});
            businessTable.setHorizontalAlignment(HorizontalAlignment.CENTER);
            String[] businessHeaders = {
                    "子公司/大区",
                    "订单 总金额",
                    "订单 上周增加额",
                    "回款 总金额",
                    "回款 上周增加额"
            };
            for (String header : businessHeaders) {
                businessTable.addCell(new Cell().add(new Paragraph(header).setFont(font).setBold().setTextAlignment(TextAlignment.CENTER)));
            }
            for (String[] row : businessData) {
                for (String cellData : row) {
                    businessTable.addCell(new Cell().add(new Paragraph(cellData).setFont(font).setTextAlignment(TextAlignment.CENTER)));
                }
            }
            document.add(businessTable);
            // 客户数据表格
            document.add(new Paragraph("客户数据").setFont(font).setBold().setFontSize(14).setTextAlignment(TextAlignment.CENTER));
            Table clientTable = new Table(new float[]{2, 2, 2, 2, 2});
            clientTable.setHorizontalAlignment(HorizontalAlignment.CENTER);
            String[] clientHeaders = {
                    "子公司/大区",
                    "客户 总数量",
                    "客户 上周增加数",
                    "实验校 总数量",
                    "实验校 上周增加数"
            };
            for (String header : clientHeaders) {
                clientTable.addCell(new Cell().add(new Paragraph(header).setFont(font).setBold().setTextAlignment(TextAlignment.CENTER)));
            }
            for (String[] row : clientData) {
                for (String cellData : row) {
                    clientTable.addCell(new Cell().add(new Paragraph(cellData).setFont(font).setTextAlignment(TextAlignment.CENTER)));
                }
            }
            document.add(clientTable);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("PDF 生成失败!");
        }
        return pdfPath;
    }
}

4.示例

相关推荐
雷渊5 分钟前
深入分析mybatis中#{}和${}的区别
java·后端·面试
亦是远方11 分钟前
2025华为软件精英挑战赛2600w思路分享
android·java·华为
花月C25 分钟前
Spring IOC:容器管理与依赖注入秘籍
java·开发语言·rpc
海峰教授28 分钟前
扫描仪+文档pdf编辑器+pdf格式转换器
pdf
Li_na_na0131 分钟前
解决安卓手机WebView无法直接预览PDF的问题(使用PDF.js方案)
android·pdf·uni-app·html5
ylfhpy31 分钟前
Java面试黄金宝典22
java·开发语言·算法·面试·职场和发展
风象南1 小时前
Spring Boot 实现文件秒传功能
java·spring boot·后端
橘猫云计算机设计1 小时前
基于django优秀少儿图书推荐网(源码+lw+部署文档+讲解),源码可白嫖!
java·spring boot·后端·python·小程序·django·毕业设计
黑猫Teng1 小时前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
背太阳的牧羊人1 小时前
使用 PyMuPDF(fitz)库打开 PDF 文件,并且是从内存中的字节流(BytesIO)读取 PDF 内容
数据库·pdf·文件处理·pymupdf·fitz