springboot實(shí)現(xiàn)添加郵件發(fā)送及壓縮功能
這次本來(lái)只講講郵件發(fā)送功能的,憚?dòng)趦?nèi)容比較貧乏,故加了點(diǎn)兒文件壓縮的功能講解。
首先郵件發(fā)送,郵件功能在springboot里面是有對(duì)應(yīng)的依賴(lài)組件,這個(gè):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-mail</artifactId> </dependency>
郵件功能開(kāi)發(fā)在springboot里面相當(dāng)簡(jiǎn)單,這里我大致總結(jié)下開(kāi)發(fā)內(nèi)容:
A>添加依賴(lài)包
B>配置Mail基本參數(shù)(ymal或propertie里面)
C>Service中注入JavaMailSender,調(diào)用相關(guān)方法即可
但是這里面可能會(huì)有個(gè)問(wèn)題,就是在具體服務(wù)器部署的時(shí)候服務(wù)器會(huì)封堵郵件服務(wù)端口,以及普通郵件安全問(wèn)題,這里講解的時(shí)候我會(huì)順道給出解決之道。
首先,需要在工程的pom.xml中引入郵件組件,組件的版本需對(duì)應(yīng)springboot的版本(可不寫(xiě),這里我略去):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
接下來(lái)就是在配置文件中配置郵件的基本參數(shù):
spring:
mail:
host: smtp.exmail.qq.com
username: username@hostname.com
password: 密碼
default-encoding: UTF-8
ssl:
trust: smtp.exmail.qq.com
properties:
mail:
smtp:
auth: true #是否需要認(rèn)證
socketFactory:
class: javax.net.ssl.SSLSocketFactory #SSL證書(shū)Socket工廠(chǎng)
port: 465 #使用SMTP465端口
配置參數(shù)的時(shí)候一定要注意縮進(jìn),因?yàn)槲医o的是yaml的配置格式,若是properties配置,大致是這樣子(例子):spring.mail.host:smtp.exmail.qq.com,每一個(gè)子項(xiàng)都是完整的格式,一開(kāi)始我是省略了properties項(xiàng)以下的配置(是否認(rèn)真,SSL,端口),后來(lái)發(fā)現(xiàn)服務(wù)器將郵件的25端口封了,所以在本地可以但是在服務(wù)器就行不通了,所以需要指定郵件服務(wù)端口為465,我這里使用的是qq郵箱,如果使用163或其他郵箱需自行查閱服務(wù)商支持的端口,至于郵件安全問(wèn)題,在這里需要聲明兩個(gè),一個(gè)是ssl信任,以及mail的socket工廠(chǎng),具體請(qǐng)見(jiàn)以上紅色部分,以上配置僅對(duì)qq郵箱有效,不保證其他郵箱也適用。
ok,配置完成,這里就開(kāi)始寫(xiě)具體的實(shí)現(xiàn)類(lèi):
import XXX.common.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class MailService {
private static final Logger LOG = LoggerFactory.getLogger(MailService.class);
@Value("${spring.mail.username}")
private String SEND_USER_ADDR;
@Autowired
private JavaMailSender mailSender;
/**
* 發(fā)送簡(jiǎn)單郵件
* @param receive 收件人
* @param obj 發(fā)送主題
* @param content 郵件內(nèi)容
*/
public void sendSimpleMail(String receive,String obj,String content) {
if(!StringUtils.isNotBlank(content) || !StringUtils.isNotBlank(receive))
return;//不發(fā)送空郵件
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(SEND_USER_ADDR);
if(receive.contains(";"))
message.setTo(receive.split(";"));
else
message.setTo(receive);
message.setSubject(obj);
message.setText(content);
try {
mailSender.send(message);
LOG.info("Simple mail send success!");
} catch (Exception e) {
LOG.error("sendSimpleMail ERROR!", e);
}
}
private StringBuilder strBuilder;
/**
* 發(fā)送html郵件 多列表單的形式
* @param receive 收件人
* @param obj 發(fā)送主題(題目)
* @param content 郵件內(nèi)容
*/
public void sendHtmlMailByList(String receive,String obj,List<Map> content){
if(content.isEmpty() || !StringUtils.isNotBlank(receive) || null==obj)
return;
MimeMessage msg = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(msg, true, "UTF-8"); //解決亂碼問(wèn)題
helper.setFrom(SEND_USER_ADDR);
if(receive.contains(";"))
helper.setTo(receive.split(";"));
else
helper.setTo(receive);
helper.setSubject(obj);
strBuilder=new StringBuilder();
strBuilder.append("<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body style=\"padding:3% 2%;\">");
strBuilder.append("<h2>This message is automatically sent to the system.</h2>");
strBuilder.append("<h2>Send Date by "+DateUtil.getDateFormat(new Date(),DateUtil.DATETIME_DEFAULT_FORMAT) +"</h2>");
strBuilder.append("<h2>The following is the details:</h2>");
strBuilder.append("<table border=\"2px solid red\" width=\"100%\">");
//頭
strBuilder.append("<thead style=\"background-color: #aea2e2;\">");
strBuilder.append("<tr>");
Object[] st=content.get(0).keySet().toArray();
for(int i=0;i<st.length;i++)
strBuilder.append("<th>"+st[i]+"</th>");
strBuilder.append("</tr>");
strBuilder.append("</thead>");
//體
strBuilder.append("<tbody>");
for(Map item:content){
strBuilder.append("<tr>");
for(Object str:st)
strBuilder.append("<td>"+item.get(str)+"</td>");
strBuilder.append("</tr>");
}
strBuilder.append("</tbody>");
strBuilder.append("</table>");
strBuilder.append("<h3 style=\"text-align:right\">Best wishes</h3>");
strBuilder.append("</body></html>");
//LOG.info(strBuilder.toString());
helper.setText(strBuilder.toString(),true);
}catch (Exception e){
LOG.error("sendHtmlMail ERROR:",e);
}
mailSender.send(msg);
}
/**
* 發(fā)送html郵件 單列記錄形式
* @param receive 收件人
* @param obj 發(fā)送主題(題目)
* @param content 郵件內(nèi)容
*/
public void sendHtmlMailByItem(String receive,String obj,List<String> content){
if(content.isEmpty() || !StringUtils.isNotBlank(receive) || null==obj)
return;
MimeMessage msg = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(msg, true, "UTF-8"); //解決亂碼問(wèn)題
helper.setFrom(SEND_USER_ADDR);
if(receive.contains(";"))
helper.setTo(receive.split(";"));
else
helper.setTo(receive);
helper.setSubject(obj);
strBuilder=new StringBuilder();
strBuilder.append("<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body style=\"padding:3% 2%;\">");
strBuilder.append("<h3>This message is automatically sent to the system.</h3>");
strBuilder.append("<h3>Send Date by "+DateUtil.getDateFormat(new Date(),DateUtil.DATETIME_DEFAULT_FORMAT) +"</h3>");
strBuilder.append("<h3>The following is the details:</h3>");
strBuilder.append("<table border=\"2px solid red\" width=\"100%\">");
//頭
strBuilder.append("<thead style=\"background-color: #aea2e2;\">");
strBuilder.append("<th>"+obj.toUpperCase()+" DETAIL</th>");
strBuilder.append("</thead>");
//體
strBuilder.append("<tbody>");
for(String item:content){
strBuilder.append("<tr><td>"+item+"</td></tr>");
}
strBuilder.append("</tbody>");
strBuilder.append("</table>");
strBuilder.append("<h3 style=\"text-align:right;font-weight:normal;\">Best wishes</h3>");
strBuilder.append("</body></html>");
LOG.info(strBuilder.toString());
helper.setText(strBuilder.toString(),true);
}catch (Exception e){
LOG.error("sendHtmlMail ERROR:",e);
}
mailSender.send(msg);
}
}
以上我是將郵件功能封裝成一個(gè)服務(wù)類(lèi),使用的時(shí)候只需要將當(dāng)前類(lèi)注入 然后直接調(diào)用即可,以上封裝了兩個(gè)方法:一個(gè)是簡(jiǎn)單郵件發(fā)送,一個(gè)是帶html table的郵件,如果需要發(fā)送附件,需將附件放入到MimeMessageHelper里面(調(diào)用addAttachment("文件名", 文件))方法即可,這里因?yàn)闊o(wú)實(shí)際需求,遂就略去了,好了,郵件發(fā)送功能已經(jīng)完成,這里看下實(shí)際效果:

郵件功能實(shí)現(xiàn)完畢,現(xiàn)在我講講文件壓縮功能,壓縮功能的實(shí)現(xiàn)大致有四種,分別是:
A>利用java.util.zip提供的api壓縮
B>利用apache的ant包提供的api壓縮(org.apache.tools.ant.taskdefs.Zip)
C>使用zip4j提供的api壓縮(net.lingala.zip4j)
D>調(diào)用宿主機(jī)的shell命令壓縮
這里需要特別提到三個(gè)問(wèn)題:
A>普通郵件壓縮中文亂碼(不支持中文)
B>壓縮后無(wú)法解壓(解壓錯(cuò)誤)
C>文件壓縮添加壓縮密碼問(wèn)題
實(shí)際開(kāi)發(fā)過(guò)壓縮功能,以上三點(diǎn)兒對(duì)于新手來(lái)說(shuō)尤其的頭痛,這里我分享下以前在開(kāi)發(fā)壓縮功能中碰到的問(wèn)題。
使用原生java.util包提供的壓縮,如果被壓縮文件使用到中文,則會(huì)亂碼(據(jù)說(shuō)是jdk的一個(gè)bug),而且壓縮實(shí)現(xiàn)的代碼較為復(fù)雜(尤其是設(shè)置密碼),尤其是對(duì)于跨目錄壓縮和多文件壓縮尤其麻煩。
使用apache提供的zip工具雖避免了以上會(huì)出現(xiàn)的問(wèn)題,但是需要提醒一點(diǎn)兒的是這個(gè)ant包與webLogic沖突(部署的時(shí)候會(huì)報(bào)錯(cuò))且無(wú)法實(shí)現(xiàn)壓縮設(shè)置密碼,如果使用的是webLogic而不是tomocat的情況下,一定要注意到這個(gè)問(wèn)題。
使用java調(diào)用宿主機(jī)的shell命令也是個(gè)不錯(cuò)的選擇,但是,需要編寫(xiě)shell命令,同時(shí)對(duì)于部署在windows平臺(tái)就不太友好了,移植比較麻煩。
最后,對(duì)于以上問(wèn)題,我這里推薦zip4j,以下也是針對(duì)zip4j的壓縮實(shí)現(xiàn)做講解。
先,需要引入依賴(lài)包:
<!--壓縮:支持加密壓縮-->
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>1.3.2</version>
</dependency>
再,封裝一個(gè)壓縮/解壓縮工具類(lèi)以方便使用:
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.springframework.util.StringUtils;
import java.io.File;
/**
* 本工具類(lèi)使用Zip4j來(lái)進(jìn)行壓縮以及解壓縮
*/
public class ZipUtil {
//聲明壓縮對(duì)象
private static ZipParameters parameters;
//解壓文件對(duì)象
private static ZipFile zipFile;
/**
*
* @param sourceFilePath 被壓縮的文件的路徑(單文件,文件夾)
* @param zipFilePath 壓縮文件路徑
* @param password 壓縮密碼
* @return 壓縮成功:true ,壓縮失敗:false
*/
public static Boolean singleFileCompress(String sourceFilePath,String zipFilePath,String password){
parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 壓縮方式(默認(rèn)方式)
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 壓縮級(jí)別(默認(rèn)級(jí)別)
//壓縮加密設(shè)置
if (!StringUtils.isEmpty(password)) {
parameters.setEncryptFiles(true);//是否設(shè)置文件加密(默認(rèn)為否)
parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式(此處是標(biāo)準(zhǔn)壓縮)
parameters.setPassword(password.toCharArray());
}
try {
ZipFile zipFile = new ZipFile(zipFilePath);
//如果是文件則直接壓縮,若是文件夾,遍歷文件全部壓縮
if(new File(sourceFilePath).isFile()) {
zipFile.setFileNameCharset("GBK");
zipFile.addFile(new File(sourceFilePath), parameters);
return true;
}
//File ff=new File(sourceFilePath);
File[] flst=new File(sourceFilePath).listFiles();
System.out.println("文件個(gè)數(shù)=>"+flst.length);
for(File f:flst){
zipFile.setFileNameCharset("GBK");
zipFile.addFile(f, parameters);
}
return true;
} catch (ZipException e) {
e.printStackTrace();
return false;
}catch (Exception id){
id.printStackTrace();
return false;
}
}
public static Boolean unZip(String zipFile,String unZipDir){
try {
ZipUtil.zipFile = new ZipFile(zipFile);
ZipUtil.zipFile.setFileNameCharset("GBK");//設(shè)置編碼格式
//用自帶的方法檢測(cè)一下zip文件是否合法,包括文件是否存在、是否為zip文件、是否被損壞等
if (!ZipUtil.zipFile.isValidZipFile()) {
throw new ZipException("文件不合法或不存在");
}
// 跟java自帶相比,這里文件路徑會(huì)自動(dòng)生成,不用判斷
ZipUtil.zipFile.extractAll(unZipDir);
return true;
}catch(ZipException e){
return false;
}
}
}
以上壓縮方法自帶密碼壓縮功能,可以壓縮單文件也可以壓縮目錄文件,相對(duì)于原生的實(shí)現(xiàn),一下子清爽了許多,這里唯一需要說(shuō)明的是,壓縮的目標(biāo)文件在壓縮前一定不能穿件,否則會(huì)報(bào)錯(cuò)!另外對(duì)于解壓縮一定要注意文件編碼和判斷文件是否存在。
總結(jié)
以上所述是小編給大家介紹的springboot實(shí)現(xiàn)添加郵件發(fā)送及壓縮功能 ,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!
相關(guān)文章
java?數(shù)組實(shí)現(xiàn)學(xué)生成績(jī)統(tǒng)計(jì)教程
這篇文章主要介紹了java?數(shù)組實(shí)現(xiàn)學(xué)生成績(jī)統(tǒng)計(jì)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot使用WebJars統(tǒng)一管理靜態(tài)資源的方法
這篇文章主要介紹了SpringBoot使用WebJars統(tǒng)一管理靜態(tài)資源的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
java中Scanner類(lèi)的簡(jiǎn)單用法分享
這篇文章主要介紹了java中Scanner類(lèi)的簡(jiǎn)單用法,有需要的朋友可以參考一下2014-01-01
使用Runtime 調(diào)用Process.waitfor導(dǎo)致的阻塞問(wèn)題
這篇文章主要介紹了使用Runtime 調(diào)用Process.waitfor導(dǎo)致的阻塞問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java實(shí)現(xiàn)ZooKeeper的zNode監(jiān)控
這篇文章主要介紹了Java實(shí)現(xiàn)ZooKeeper的zNode監(jiān)控問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-08-08
Yml轉(zhuǎn)properties文件工具類(lèi)YmlUtils的詳細(xì)過(guò)程(不用引任何插件和依賴(lài))
這篇文章主要介紹了Yml轉(zhuǎn)properties文件工具類(lèi)YmlUtils(不用引任何插件和依賴(lài)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08

