使用hutool+scheduled定時發送excel報表文件

定時發送報表統計是公司前段時間的一個小需求,謹此記錄一下。

一、hutool郵件工具-MailUtil

hutool就不過多解釋了,感謝這個開源項目的貢獻者,讓平時開發省了不少力,用了才發現之前自己封裝的小工具類挺雞肋...

官網:https://hutool.cn/

官方介紹:

Hutool是一個小而全的Java工具類庫,通過靜態方法封裝,降低相關API的學習成本,提高工作效率,使Java擁有函數式語言般的優雅,讓Java語言也可以“甜甜的”。

沒用過的可以有時間看看,很nice。

這裏把hutool的郵件工具-MailUtil的使用拿過來說明一下。

1.引入依賴

Hutool對所有第三方都是可選依賴,因此在使用MailUtil時需要自行引入第三方依賴。

<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

2.郵件服務器配置

在classpath(在標準Maven項目中爲src/main/resources)的config目錄下新建mail.setting文件,最小配置內容如下,在此配置下,smtp服務器和用戶名都將通過from參數識別:

# 發件人(必須正確,否則發送失敗)
from = [email protected]
# 密碼(注意,某些郵箱需要爲SMTP服務單獨設置密碼,詳情查看相關幫助)
pass = q1w2e3

but,有時候一些非標準郵箱服務器(例如企業郵箱服務器)的smtp地址等信息並不與發件人後綴一致,端口也可能不同,此時Hutool可以提供完整的配置文件:

完整配置

# 郵件服務器的SMTP地址,可選,默認爲smtp.<發件人郵箱後綴>
host = smtp.yeah.net
# 郵件服務器的SMTP端口,可選,默認25
port = 25
# 發件人(必須正確,否則發送失敗)
from = [email protected]
# 用戶名,默認爲發件人郵箱前綴
user = hutool
# 密碼(注意,某些郵箱需要爲SMTP服務單獨設置授權碼,詳情查看相關幫助)
pass = q1w2e3

注意:郵件服務器必須支持並打開SMTP協議,詳細請查看相關幫助說明 配置文件的樣例中提供的是我專門爲測試郵件功能註冊的yeah.net郵箱,帳號密碼公開,供Hutool用戶測試使用。

3.發送郵件 

  • 發送普通文本郵件,最後一個參數可選是否添加多個附件:
MailUtil.send("[email protected]", "測試", "郵件來自Hutool測試", false);
  • 發送HTML格式的郵件並附帶附件,最後一個參數可選是否添加多個附件:
MailUtil.send("[email protected]", "測試", "<h1>郵件來自Hutool測試</h1>", true, FileUtil.file("d:/aaa.xml"));
  • 羣發郵件,可選HTML或普通文本,可選多個附件:
ArrayList<String> tos = CollUtil.newArrayList(
    "[email protected]", 
    "[email protected]", 
    "[email protected]", 
    "[email protected]");

MailUtil.send(tos, "測試", "郵件來自Hutool羣發測試", false);

ps:羣發的話可以將目標郵件地址寫到yml文件裏,用“,”隔開,hutool會自動截取。

send方法源碼:

//send()發送方法 
public static void send(String to, String subject, String content, boolean isHtml, File... files) {
        send((Collection)splitAddress(to), subject, content, isHtml, files);
    }

//splitAddress(),判斷是否是字符串並截取
private static List<String> splitAddress(String addresses) {
        if(StrUtil.isBlank(addresses)) {
            return null;
        } else {
            Object result;
            if(StrUtil.contains(addresses, ',')) {
                result = StrUtil.splitTrim(addresses, ',');
            } else if(StrUtil.contains(addresses, ';')) {
                result = StrUtil.splitTrim(addresses, ';');
            } else {
                result = CollUtil.newArrayList(new String[]{addresses});
            }

            return (List)result;
        }
    }

發送郵件非常簡單,只需一個方法即可搞定其中按照參數順序說明如下:

  1. tos: 對方的郵箱地址,可以是單個,也可以是多個(Collection表示)
  2. subject:標題
  3. content:郵件正文,可以是文本,也可以是HTML內容
  4. isHtml: 是否爲HTML,如果是,那參數3識別爲HTML內容
  5. files: 可選:附件,可以爲多個或沒有,將File對象加在最後一個可變參數中即可

其他說明

  • 自定義郵件服務器

除了使用配置文件定義全局賬號以外,MailUtil.send方法同時提供重載方法可以傳入一個MailAccount對象,這個對象爲一個普通Bean,記錄了郵件服務器信息。
 

MailAccount account = new MailAccount();
account.setHost("smtp.yeah.net");
account.setPort("25");
account.setAuth(true);
account.setFrom("[email protected]");
account.setUser("hutool");
account.setPass("q1w2e3");

MailUtil.send(account, CollUtil.newArrayList("[email protected]"), "測試", "郵件來自Hutool測試", false);
  • 使用SSL加密方式發送郵件 在使用QQ或Gmail郵箱時,需要強制開啓SSL支持,此時我們只需修改配置文件即可:
# 發件人(必須正確,否則發送失敗),“小磊”可以任意變更,<>內的地址必須唯一,以下方式也對
# from = [email protected]
from = 小磊<[email protected]>
# 密碼(注意,某些郵箱需要爲SMTP服務單獨設置密碼,詳情查看相關幫助)
pass = q1w2e3
# 使用SSL安全連接
sslEnable = true

在原先極簡配置下只需加入sslEnable即可完成SSL連接,當然,這是最簡單的配置,很多參數根據已有參數已設置爲默認。

完整的配置文件如下:

# 郵件服務器的SMTP地址
host = smtp.yeah.net
# 郵件服務器的SMTP端口
port = 465
# 發件人(必須正確,否則發送失敗)
from = [email protected]
# 用戶名(注意:如果使用foxmail郵箱,此處user爲qq號)
user = hutool
# 密碼(注意,某些郵箱需要爲SMTP服務單獨設置密碼,詳情查看相關幫助)
pass = q1w2e3
#使用 STARTTLS安全連接,STARTTLS是對純文本通信協議的擴展。
starttlsEnable = true

# 使用SSL安全連接
sslEnable = true
# 指定實現javax.net.SocketFactory接口的類的名稱,這個類將被用於創建SMTP的套接字
socketFactoryClass = javax.net.ssl.SSLSocketFactory
# 如果設置爲true,未能創建一個套接字使用指定的套接字工廠類將導致使用java.net.Socket創建的套接字類, 默認值爲true
socketFactoryFallback = true
# 指定的端口連接到在使用指定的套接字工廠。如果沒有設置,將使用默認端口456
socketFactoryPort = 465

# SMTP超時時長,單位毫秒,缺省值不超時
timeout = 0
# Socket連接超時值,單位毫秒,缺省值不超時
connectionTimeout = 0
  • 針對QQ郵箱和Foxmail郵箱的說明

(1) QQ郵箱中SMTP密碼是單獨生成的授權碼,而非你的QQ密碼,至於怎麼生成,見騰訊的幫助說明:http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256

使用幫助引導生成授權碼後,配置如下即可:

pass = 你生成的授權碼

(2) Foxmail郵箱本質上也是QQ郵箱的一種別名,你可以在你的QQ郵箱中設置一個foxmail郵箱,不過配置上有所區別。在Hutool中user屬性默認提取你郵箱@前面的部分,但是foxmail郵箱是無效的,需要單獨配置爲與之綁定的qq號碼或者[email protected]XXXX。即:

host = smtp.qq.com
from = [email protected]
user = foxmail郵箱對應的QQ號碼或者qq郵箱@前面部分
...

 二、Scheduled定時任務

定時任務使用的是Spring自帶的Scheduled,使用起來非常方便,在定義的定時方法上加上@Scheduled註解即可,也不過多闡述。

1.新建mail.setting配置文件,並按hutool文檔說明加上自己的配置

2.引入依賴

<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>4.6.3</version>
</dependency>

3.yml配置文件加上目標郵件地址,以及用於環境控制配置的參數配置

yml文件追加:

report:
  env: dev
  mailAddress: 地址1,地址2,地址3...

4.新建定時任務:

@Component
@Slf4j
public class ReportSendMailScheduled {

    //定義一個郵件發送接口方便定時任務調用
    @Autowired
    private SendReportMailServiceImpl sendReportMailService;

   //開發環境
    @Value("${report.env}")
    private String env;

    //每天一點鐘執行一次
    @Scheduled(cron = "0 0 1 * * ?")
    public void sendMail(){
        //生產環境下才發送
        if (env.equals("prod")){
            sendReportMailService.sendReportMail();
        }
    }

}

5.郵件發送服務接口

public interface ISendReportMailService {

   public void sendReportMail(ReportSendMailDto reportSendMailDto);

}

6.郵件發送服務實現類

public class SendReportMailServiceImpl implements ISendReportMailService {

    //注入yml配置的目標郵件地址
    @Value("${report.mailAddress}")
    private String mailAddress;

    @Autowired
    private ReportUserInfoMapper reportUserInfoMapper;

    public void sendReportMail(ReportSendMailDto reportSendMailDto) {
        log.info("====報表郵件開始=====");
        File file = new File(StrUtil.format("截止{}報表統計.xlsx", DateUtil.getDay()));
        try {
            //用戶統計(這是案例,具體看自己業務需要哪些數據,總之查詢出來寫進excel)
            List<ReportUserStatisticsVO> reportUserStatisticsVOS = reportUserInfoMapper.selectReportUserStatistics(reportSendMailDto);
            //默認是第一個sheet
            ExcelWriter writer = ExcelUtil.getBigWriter(file, "用戶數");
            writer.addHeaderAlias("statisticsDate", "日期");
            writer.addHeaderAlias("registeredUsers", "註冊用戶");
            writer.addHeaderAlias("passengerAuthenticationUser", "乘客認證用戶");
            writer.addHeaderAlias("driverAuthenticationUser", "車主認證用戶");
            writer.write(reportUserStatisticsVOS, true);

            //乘客需求匹配量(爲了演示寫入多個sheet)
            List<ReportMatchingOfPassengerDemandVO> reportMatchingOfPassengerDemandVOS = reportMasterRouteManageMapper.searchMatchingOfPassengerDemand(reportSendMailDto);
            //寫完一個sheet可以再次追加sheet
            writer.setSheet("乘客需求匹配量");
            writer.addHeaderAlias("statisticsDate", "日期");
            writer.addHeaderAlias("passengerMatchingTotal", "乘客出行需求發佈總量");
            writer.addHeaderAlias("passengerMatchingSuccess", "乘客出行需求發佈匹配成功量");
            writer.addHeaderAlias("passengerMatchingFail", "乘客出行需求發佈未匹配成功量");
            writer.write(reportMatchingOfPassengerDemandVOS, true);
            //關閉寫入流
            writer.close();
            //這裏示範的是無內容僅有附件的郵件發送
            MailUtil.send(mailAddress, "報表統計", "", false, file);
            log.info("====報表郵件結束===");
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            //發送完就刪除生產的excel文件,否則文件會一直追加在項目目錄裏
            file.delete();
        }
    }
}

代碼有詳細註釋解釋。

至此,記錄完成~

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章