springboot添加邮件发送及文件压缩功能

转载请注明出处https://www.cnblogs.com/funnyzpc/p/9190233.html

  这次本来只讲讲邮件发送功能的,惮于内容比较贫乏,故加了点儿文件压缩的功能讲解。

  首先邮件发送,邮件功能在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; 
  
 @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; 
  
     /** 
      *      发送简单邮件 
      * @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; 
         } 
     } 

以上压缩方法自带密码压缩功能,可以压缩单文件也可以压缩目录文件,相对于原生的实现,一下子清爽了许多,这里唯一需要说明的是,压缩的目标文件在压缩前一定不能穿件,否则会报错!另外对于解压缩一定要注意文件编码和判断文件是否存在。

  OK,本章的功能已尽数分享,希望各位在开发功能的时候能避免这其中的

发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

PostgreSQL>窗口函数的用法详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。