這次本來只講講郵件發送功能的,憚於內容比較貧乏,故加了點兒文件壓縮的功能講解。
首先郵件發送,郵件功能在springboot裡面是有對應的依賴組件,這個:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
郵件功能開發在springboot裡面相當簡單,這裡我大致總結下開發內容:
A>添加依賴包
B>配置Mail基本參數(ymal或propertie裡面)
C>Service中註入JavaMailSender,調用相關方法即可
但是這裡面可能會有個問題,就是在具體服務器部署的時候服務器會封堵郵件服務端口,以及普通郵件安全問題,這裡講解的時候我會順道給出解決之道。
首先,需要在工程的pom.xml中引入郵件組件,組件的版本需對應springboot的版本(可不寫,這裡我略去):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
接下來就是在配置文件中配置郵件的基本參數:
spring: mail: host: smtp.exmail.qq.com username: [email protected] password: 密碼default-encoding: UTF-8 ssl: trust: smtp.exmail.qq.com properties: mail: smtp: auth: true #是否需要認證socketFactory: class: javax.net.ssl.SSLSocketFactory #SSL證書Socket工廠port: 465 #使用SMTP465端口
配置參數的時候一定要注意縮進,因為我給的是yaml的配置格式,若是properties配置,大致是這樣子(例子):spring.mail.host:smtp.exmail.qq.com,每一個子項都是完整的格式,一開始我是省略了properties項以下的配置(是否認真,SSL,端口),後來發現服務器將郵件的25端口封了,所以在本地可以但是在服務器就行不通了,所以需要指定郵件服務端口為465,我這裡使用的是qq郵箱,如果使用163或其他郵箱需自行查閱服務商支持的端口,至於郵件安全問題,在這裡需要聲明兩個,一個是ssl信任,以及mail的socket工廠,具體請見以上紅色部分,以上配置僅對qq郵箱有效,不保證其他郵箱也適用。
ok,配置完成,這裡就開始寫具體的實現類:
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;@Servicepublic class MailService { private static final Logger LOG = LoggerFactory.getLogger(MailService.class); @Value("${spring.mail.username}") private String SEND_USER_ADDR; @Autowired private JavaMailSender mailSender; /** * 發送簡單郵件* @param receive 收件人* @param obj 發送主題* @param content 郵件內容*/ public void sendSimpleMail(String receive,String obj,String content) { if(!StringUtils.isNotBlank(content) || !StringUtils.isNotBlank(receive)) return;//不發送空郵件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; /** * 發送html郵件多列表單的形式* @param receive 收件人* @param obj 發送主題(題目) * @param content 郵件內容*/ 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"); //解決亂碼問題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); } /** * 發送html郵件單列記錄形式* @param receive 收件人* @param obj 發送主題(題目) * @param content 郵件內容*/ 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"); //解決亂碼問題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); }}
以上我是將郵件功能封裝成一個服務類,使用的時候只需要將當前類註入然後直接調用即可,以上封裝了兩個方法:一個是簡單郵件發送,一個是帶html table的郵件,如果需要發送附件,需將附件放入到MimeMessageHelper裡面(調用addAttachment("文件名", 文件))方法即可,這裡因為無實際需求,遂就略去了,好了,郵件發送功能已經完成,這裡看下實際效果:
郵件功能實現完畢,現在我講講文件壓縮功能,壓縮功能的實現大致有四種,分別是:
A>利用java.util.zip提供的api壓縮
B>利用apache的ant包提供的api壓縮(org.apache.tools.ant.taskdefs.Zip)
C>使用zip4j提供的api壓縮(net.lingala.zip4j)
D>調用宿主機的shell命令壓縮
這裡需要特別提到三個問題:
A>普通郵件壓縮中文亂碼(不支持中文)
B>壓縮後無法解壓(解壓錯誤)
C>文件壓縮添加壓縮密碼問題
實際開發過壓縮功能,以上三點兒對於新手來說尤其的頭痛,這裡我分享下以前在開發壓縮功能中碰到的問題。
使用原生java.util包提供的壓縮,如果被壓縮文件使用到中文,則會亂碼(據說是jdk的一個bug),而且壓縮實現的代碼較為複雜(尤其是設置密碼),尤其是對於跨目錄壓縮和多文件壓縮尤其麻煩。
使用apache提供的zip工具雖避免了以上會出現的問題,但是需要提醒一點兒的是這個ant包與webLogic衝突(部署的時候會報錯)且無法實現壓縮設置密碼,如果使用的是webLogic而不是tomocat的情況下,一定要注意到這個問題。
使用java調用宿主機的shell命令也是個不錯的選擇,但是,需要編寫shell命令,同時對於部署在windows平台就不太友好了,移植比較麻煩。
最後,對於以上問題,我這裡推薦zip4j,以下也是針對zip4j的壓縮實現做講解。
先,需要引入依賴包:
<!--壓縮:支持加密壓縮--> <dependency> <groupId>net.lingala.zip4j</groupId> <artifactId>zip4j</artifactId> <version>1.3.2</version> </dependency>
再,封裝一個壓縮/解壓縮工具類以方便使用:
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;/** * 本工具類使用Zip4j來進行壓縮以及解壓縮*/public class ZipUtil { //聲明壓縮對象private static ZipParameters parameters; //解壓文件對象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); // 壓縮方式(默認方式) parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 壓縮級別(默認級別) //壓縮加密設置if (!StringUtils.isEmpty(password)) { parameters.setEncryptFiles(true);//是否設置文件加密(默認為否) parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式(此處是標準壓縮) 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("文件個數=>"+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");//設置編碼格式//用自帶的方法檢測一下zip文件是否合法,包括文件是否存在、是否為zip文件、是否被損壞等if (!ZipUtil.zipFile.isValidZipFile()) { throw new ZipException("文件不合法或不存在"); } // 跟java自帶相比,這里文件路徑會自動生成,不用判斷ZipUtil.zipFile.extractAll(unZipDir); return true; }catch(ZipException e){ return false; } }}以上壓縮方法自帶密碼壓縮功能,可以壓縮單文件也可以壓縮目錄文件,相對於原生的實現,一下子清爽了許多,這裡唯一需要說明的是,壓縮的目標文件在壓縮前一定不能穿件,否則會報錯!另外對於解壓縮一定要注意文件編碼和判斷文件是否存在。
總結
以上所述是小編給大家介紹的springboot實現添加郵件發送及壓縮功能,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!