SpringBoot實現(xiàn)excel生成并且通過郵件發(fā)送的步驟詳解
1. 開發(fā)環(huán)境
以下演示jdk選用1.8版本。springboot采用2.3.7.RELEASE版本。
excel生成通過alibaba的EasyExcel組件來實現(xiàn),采用最新的穩(wěn)定版本3.1.1
2. 思路
我們的核心實現(xiàn)分成兩步: 1、生成一個excel 2、將excel作為附件添加到郵件中進行發(fā)送
于是基于此思路,我們結合EasyExcel提供的write方法來生成excel文件,該excel文件在郵件發(fā)送完成后需要刪除;然后通過之前我們講解過的郵件發(fā)送工具類來實現(xiàn)郵件發(fā)送
3. 實操
1、書寫郵件發(fā)送工具類,其實現(xiàn)參考上述博文
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>3、實現(xiàn)easyExcel的數(shù)據(jù)監(jiān)聽類
/**
* @author benjamin_5
* @Description 數(shù)據(jù)監(jiān)聽類
* @date 2022/10/5
*/
@EqualsAndHashCode(callSuper = true)
public class DataListener<T> extends AnalysisEventListener<T> {
/**
* 緩存數(shù)據(jù)列表
*/
private final List<T> dataList = new ArrayList<>();
@Override
public void invoke(T data, AnalysisContext context) {
dataList.add(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
@Override
public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
this.invokeHeadMap(ConverterUtils.convertToStringMap(headMap,context),context);
}
public List<T> getDataList() {
return dataList;
}
}4、創(chuàng)建生成excel文件的工具類ExcelUtil
public class ExcelUtil {
/**
* 生成excel文件
* @param fileName excel文件路徑
* @param dataList 數(shù)據(jù)列表
* @param clazz 導出對象類
* @param <T>
* @return
* @throws IOException
*/
public static <T> File generateExcel(String fileName, List<T> dataList, Class<T> clazz) throws IOException {
// 生成文件
File excel = new File(fileName);
// excel寫入
EasyExcel.write(excel,clazz).sheet(0).doWrite(dataList);
return excel;
}
}5、創(chuàng)建導出數(shù)據(jù)的實體類
/**
* @author benjamin_5
* @Description
* @date 2022/10/5
*/
@Data
public class CustomerData implements Serializable {
@ExcelProperty(value = "客戶名稱")
@ColumnWidth(value = 25)
private String name;
@ExcelProperty(value = "客戶地址")
@ColumnWidth(value = 50)
private String address;
@ExcelProperty(value = "聯(lián)系電話")
private String phone;
@ExcelProperty(value = "金額")
private BigDecimal amount;
@ExcelProperty(value = "注冊日期")
@DateTimeFormat(value = "yyyy-MM-dd")
private Date createDate;
}6、實現(xiàn)excel數(shù)據(jù)生成及郵件發(fā)送的接口。為了演示方便我直接在controller中書寫了,實際工作中應該把生成并發(fā)送的方法提取到工具類或者Service層中。
這里調(diào)用的是基于spring-boot-starter-mail實現(xiàn)的郵件發(fā)送工具類
@GetMapping("generateExcelAndSend")
public void generateExcelAndSend(){
List<CustomerData> dataList = new ArrayList<>();
// 構造假數(shù)據(jù)
for (int i = 0; i < 100; i++) {
CustomerData data = new CustomerData();
data.setName("客戶"+i);
data.setAddress("貴州省貴陽市觀山湖區(qū)101號");
data.setPhone("13889999999");
data.setAmount(BigDecimal.valueOf(Math.random()*10000));
data.setCreateDate(new Date());
dataList.add(data);
}
// 獲取資源文件存放路徑,用于臨時存放生成的excel文件
String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
// 文件名:采用UUID,防止多線程同時生成導致的文件重名
String fileName = String.format("%s客戶統(tǒng)計數(shù)據(jù)-%s.xlsx",path,UUID.randomUUID());
try {
// 生成excel文件
File excel = ExcelUtil.generateExcel(fileName, dataList, CustomerData.class);
// 發(fā)送郵件
String content = "";
String toMail = "wuhanxue5@sina.com";
String ccMail = "wuhanxue5@163.com";
emailSpringUtil.sendEmail("客戶統(tǒng)計數(shù)據(jù)",content,true,"郵件提醒系統(tǒng)",
toMail,ccMail,null, Collections.singletonList(fileName));
// 郵件發(fā)送完成后刪除臨時生成的excel文件
excel.delete();
} catch (IOException e) {
logger.error(String.format("生成excel失敗,原因:%s",e));
e.printStackTrace();
} catch (MessagingException e) {
logger.error(String.format("郵件發(fā)送失敗,原因:%s",e));
e.printStackTrace();
}
}7、同時因為我們的附件名稱后面添加一個了個UUID,mime.mail中的參數(shù)splitlongparameters默認為 true,當附件名過長時,他會自動截取,就會導致我們接收到的附件格式變成.bin形式的。
要解決該問題就需要將其設置為false。于是我們創(chuàng)建一個啟動執(zhí)行類來單獨設置
@Configuration
public class EmailToLongConfig {
@PostConstruct
private void init(){
// 解決郵件附件名稱太長會自動截取,導致附件變成.bin格式問題
System.setProperty("mail.mime.splitlongparameters","false");
}
}當然我們也可以將System.setProperty("
mail.mime.splitlongparameters","false");放到郵件發(fā)送的方法中去。
8、啟動項目,瀏覽器訪問接口測試
http://localhost:8080/excel/generateExcelAndSend
可以看到上述郵件發(fā)送成功,excel附件也接收正常,查看附件內(nèi)容也正常
優(yōu)化
上述的實現(xiàn),需要先創(chuàng)建一個文件然后又刪除,不是很方便,我們可以采取直接用流輸入輸出
1、首先生成excel的方法調(diào)整為返回輸出流
public static <T> ByteArrayOutputStream generateExcel(List<T> dataList, Class<T> clazz) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// excel寫入
EasyExcel.write(out,clazz).sheet(0).doWrite(dataList);
return out;
} 2、其次發(fā)送郵件的方法調(diào)整為,直接接收輸入流
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);
// 設置附件(注意這里的fileName必須是服務器本地文件名,不能是遠程文件鏈接)
if (fileInput != null) {
helper.addAttachment(fileName, fileInput);
}
javaMailSender.send(message);
}3、主方法調(diào)整:不生成文件,而是通過流來傳輸
@GetMapping("generateExcelAndSend2")
public void generateExcelAndSend2() throws IOException {
long start = System.currentTimeMillis();
List<CustomerData> dataList = new ArrayList<>();
// 構造假數(shù)據(jù)
for (int i = 0; i < 100; i++) {
CustomerData data = new CustomerData();
data.setName("客戶"+i);
data.setAddress("貴州省貴陽市觀山湖區(qū)101號");
data.setPhone("13889999999");
data.setAmount(BigDecimal.valueOf(Math.random()*10000));
data.setCreateDate(new Date());
dataList.add(data);
}
// 獲取資源文件存放路徑,用于臨時存放生成的excel文件
String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
// 文件名:采用UUID,防止多線程同時生成導致的文件重名
String fileName = String.format("%s客戶統(tǒng)計數(shù)據(jù)-%s.xlsx",path,UUID.randomUUID());
ByteArrayOutputStream out = null;
try {
// 生成excel文件
out = ExcelUtil.generateExcel(dataList, CustomerData.class);
// 發(fā)送郵件
String content = "客戶統(tǒng)計數(shù)據(jù)如附件所示";
String toMail = "wuhanxue5@sina.com";
String ccMail = "wuhanxue5@163.com";
emailSpringUtil.sendEmail("客戶統(tǒng)計數(shù)據(jù)",content,false,"郵件提醒系統(tǒng)",
toMail,ccMail,null, fileName, new ByteArrayResource(out.toByteArray()));
} catch (IOException e) {
logger.error(String.format("生成excel失敗,原因:%s",e));
e.printStackTrace();
} catch (MessagingException e) {
logger.error(String.format("郵件發(fā)送失敗,原因:%s",e));
e.printStackTrace();
}finally {
if(out != null){
out.close();
}
long end = System.currentTimeMillis();
System.out.println("耗時:" + (end - start));
}
} 4、最終測試下來,第二種方法要比之前方法快600ms左右
郵件正文中直接顯示表格數(shù)據(jù)
有時候我們的統(tǒng)計數(shù)據(jù)不是很多,會更希望我們直接在郵件中展示表格數(shù)據(jù),而不用再單獨下載附件查看,這就需要用到HTML格式的郵件正文的實現(xiàn)
比較簡單的實現(xiàn)就是循環(huán)數(shù)據(jù)集合,通過字符串拼接生成html的字符串。因為實現(xiàn)比較簡單,這里就僅提供思路,如果有不清楚的同學可以留言提問。后續(xù)我們單獨抽離成一個組件來實現(xiàn)生成html字符串的功能
總結
excel的生成以及郵件的發(fā)送,都應該盡可能的提取為工具類,如果實現(xiàn)的功能更多的更需要提取的單獨的服務,通過pom依賴引入,更大化的實現(xiàn)方法的通用,和業(yè)務代碼與通用代碼之間的解耦。
以上就是SpringBoot實現(xiàn)excel生成并且通過郵件發(fā)送的步驟詳解的詳細內(nèi)容,更多關于SpringBoot實現(xiàn)excel生成的資料請關注腳本之家其它相關文章!
相關文章
Java實現(xiàn)數(shù)據(jù)更新和事件通知的觀察者模式
Java觀察者模式是一種行為型設計模式,用于實現(xiàn)對象間的一對多依賴關系。當一個對象的狀態(tài)發(fā)生改變時,它的所有依賴對象都會收到通知并自動更新。觀察者模式可以實現(xiàn)松耦合,增強了系統(tǒng)的可維護性和可拓展性2023-04-04

