springboot添加邮件发送及压缩功能
springboot添加邮件发送及文件压缩功能
转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9190233.html
这次本来只讲讲邮件发送功能的,惮于内容比较贫乏,故加了点儿文件压缩的功能讲解。
首先邮件发送,邮件功能在springboot里面是有对应的依赖组件,这个:
1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-mail</artifactId>
4 </dependency>
邮件功能开发在springboot里面相当简单,这里我大致总结下开发内容:
A>添加依赖包
B>配置Mail基本参数(ymal或propertie里面)
C>Service中注入JavaMailSender,调用相关方法即可
但是这里面可能会有个问题,就是在具体服务器部署的时候服务器会封堵邮件服务端口,以及普通邮件安全问题,这里讲解的时候我会顺道给出解决之道。
首先,需要在工程的pom.xml中引入邮件组件,组件的版本需对应springboot的版本(可不写,这里我略去):
1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-mail</artifactId>
4 </dependency>
接下来就是在配置文件中配置邮件的基本参数:
1 spring:
2 mail:
3 host: smtp.exmail.qq.com
4 username: username@hostname.com
5 password: 密码
6 default-encoding: UTF-8
7 ssl:
8 trust: smtp.exmail.qq.com
9 properties:
10 mail:
11 smtp:
12 auth: true #是否需要认证
13 socketFactory:
14 class: javax.net.ssl.SSLSocketFactory #SSL证书Socket工厂
15 port: 465 #使用SMTP465端口
配置参数的时候一定要注意缩进,因为我给的是yaml的配置格式,若是properties配置,大致是这样子(例子):spring.mail.host:smtp.exmail.qq.com,每一个子项都是完整的格式,一开始我是省略了properties项以下的配置(是否认真,SSL,端口),后来发现服务器将邮件的25端口封了,所以在本地可以但是在服务器就行不通了,所以需要指定邮件服务端口为465,我这里使用的是qq邮箱,如果使用163或其他邮箱需自行查阅服务商支持的端口,至于邮件安全问题,在这里需要声明两个,一个是ssl信任,以及mail的socket工厂,具体请见以上红色部分,以上配置仅对qq邮箱有效,不保证其他邮箱也适用。
ok,配置完成,这里就开始写具体的实现类:
1 import XXX.common.util.DateUtil;
2 import org.apache.commons.lang3.StringUtils;
3 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory;
5 import org.springframework.beans.factory.annotation.Autowired;
6 import org.springframework.beans.factory.annotation.Value;
7 import org.springframework.mail.SimpleMailMessage;
8 import org.springframework.mail.javamail.JavaMailSender;
9 import org.springframework.mail.javamail.MimeMessageHelper;
10 import org.springframework.stereotype.Service;
11
12 import javax.mail.internet.MimeMessage;
13 import java.util.Date;
14 import java.util.List;
15 import java.util.Map;
16
17 @Service
18 public class MailService {
19 private static final Logger LOG = LoggerFactory.getLogger(MailService.class);
20
21 @Value("${spring.mail.username}")
22 private String SEND_USER_ADDR;
23
24 @Autowired
25 private JavaMailSender mailSender;
26
27 /**
28 * 发送简单邮件
29 * @param receive 收件人
30 * @param obj 发送主题
31 * @param content 邮件内容
32 */
33 public void sendSimpleMail(String receive,String obj,String content) {
34 if(!StringUtils.isNotBlank(content) || !StringUtils.isNotBlank(receive))
35 return;//不发送空邮件
36 SimpleMailMessage message = new SimpleMailMessage();
37 message.setFrom(SEND_USER_ADDR);
38 if(receive.contains(";"))
39 message.setTo(receive.split(";"));
40 else
41 message.setTo(receive);
42 message.setSubject(obj);
43 message.setText(content);
44 try {
45 mailSender.send(message);
46 LOG.info("Simple mail send success!");
47 } catch (Exception e) {
48 LOG.error("sendSimpleMail ERROR!", e);
49 }
50
51 }
52
53 private StringBuilder strBuilder;
54 /**
55 * 发送html邮件 多列表单的形式
56 * @param receive 收件人
57 * @param obj 发送主题(题目)
58 * @param content 邮件内容
59 */
60 public void sendHtmlMailByList(String receive,String obj,List<Map> content){
61 if(content.isEmpty() || !StringUtils.isNotBlank(receive) || null==obj)
62 return;
63 MimeMessage msg = mailSender.createMimeMessage();
64 try {
65 MimeMessageHelper helper = new MimeMessageHelper(msg, true, "UTF-8"); //解决乱码问题
66 helper.setFrom(SEND_USER_ADDR);
67 if(receive.contains(";"))
68 helper.setTo(receive.split(";"));
69 else
70 helper.setTo(receive);
71 helper.setSubject(obj);
72 strBuilder=new StringBuilder();
73 strBuilder.append("<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="padding:3% 2%;">");
74 strBuilder.append("<h2>This message is automatically sent to the system.</h2>");
75 strBuilder.append("<h2>Send Date by "+DateUtil.getDateFormat(new Date(),DateUtil.DATETIME_DEFAULT_FORMAT) +"</h2>");
76 strBuilder.append("<h2>The following is the details:</h2>");
77 strBuilder.append("<table border="2px solid red" width="100%">");
78
79 //头
80 strBuilder.append("<thead style="background-color: #aea2e2;">");
81 strBuilder.append("<tr>");
82 Object[] st=content.get(0).keySet().toArray();
83 for(int i=0;i<st.length;i++)
84 strBuilder.append("<th>"+st[i]+"</th>");
85 strBuilder.append("</tr>");
86 strBuilder.append("</thead>");
87
88 //体
89 strBuilder.append("<tbody>");
90 for(Map item:content){
91 strBuilder.append("<tr>");
92 for(Object str:st)
93 strBuilder.append("<td>"+item.get(str)+"</td>");
94 strBuilder.append("</tr>");
95 }
96 strBuilder.append("</tbody>");
97
98 strBuilder.append("</table>");
99 strBuilder.append("<h3 style="text-align:right">Best wishes</h3>");
100 strBuilder.append("</body></html>");
101 //LOG.info(strBuilder.toString());
102 helper.setText(strBuilder.toString(),true);
103 }catch (Exception e){
104 LOG.error("sendHtmlMail ERROR:",e);
105 }
106 mailSender.send(msg);
107 }
108
109
110 /**
111 * 发送html邮件 单列记录形式
112 * @param receive 收件人
113 * @param obj 发送主题(题目)
114 * @param content 邮件内容
115 */
116 public void sendHtmlMailByItem(String receive,String obj,List<String> content){
117 if(content.isEmpty() || !StringUtils.isNotBlank(receive) || null==obj)
118 return;
119 MimeMessage msg = mailSender.createMimeMessage();
120 try {
121 MimeMessageHelper helper = new MimeMessageHelper(msg, true, "UTF-8"); //解决乱码问题
122 helper.setFrom(SEND_USER_ADDR);
123 if(receive.contains(";"))
124 helper.setTo(receive.split(";"));
125 else
126 helper.setTo(receive);
127 helper.setSubject(obj);
128 strBuilder=new StringBuilder();
129 strBuilder.append("<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="padding:3% 2%;">");
130 strBuilder.append("<h3>This message is automatically sent to the system.</h3>");
131 strBuilder.append("<h3>Send Date by "+DateUtil.getDateFormat(new Date(),DateUtil.DATETIME_DEFAULT_FORMAT) +"</h3>");
132 strBuilder.append("<h3>The following is the details:</h3>");
133 strBuilder.append("<table border="2px solid red" width="100%">");
134
135 //头
136 strBuilder.append("<thead style="background-color: #aea2e2;">");
137
138 strBuilder.append("<th>"+obj.toUpperCase()+" DETAIL</th>");
139 strBuilder.append("</thead>");
140
141 //体
142 strBuilder.append("<tbody>");
143 for(String item:content){
144 strBuilder.append("<tr><td>"+item+"</td></tr>");
145 }
146 strBuilder.append("</tbody>");
147
148 strBuilder.append("</table>");
149 strBuilder.append("<h3 style="text-align:right;font-weight:normal;">Best wishes</h3>");
150 strBuilder.append("</body></html>");
151 LOG.info(strBuilder.toString());
152 helper.setText(strBuilder.toString(),true);
153 }catch (Exception e){
154 LOG.error("sendHtmlMail ERROR:",e);
155 }
156 mailSender.send(msg);
157 }
158 }
以上我是将邮件功能封装成一个服务类,使用的时候只需要将当前类注入 然后直接调用即可,以上封装了两个方法:一个是简单邮件发送,一个是带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的压缩实现做讲解。
先,需要引入依赖包:
1 <!--压缩:支持加密压缩-->
2 <dependency>
3 <groupId>net.lingala.zip4j</groupId>
4 <artifactId>zip4j</artifactId>
5 <version>1.3.2</version>
6 </dependency>
再,封装一个压缩/解压缩工具类以方便使用:
1 import net.lingala.zip4j.core.ZipFile;
2 import net.lingala.zip4j.exception.ZipException;
3 import net.lingala.zip4j.model.ZipParameters;
4 import net.lingala.zip4j.util.Zip4jConstants;
5 import org.springframework.util.StringUtils;
6
7 import java.io.File;
8
9
10 /**
11 * 本工具类使用Zip4j来进行压缩以及解压缩
12 */
13 public class ZipUtil {
14
15 //声明压缩对象
16 private static ZipParameters parameters;
17
18 //解压文件对象
19 private static ZipFile zipFile;
20
21 /**
22 *
23 * @param sourceFilePath 被压缩的文件的路径(单文件,文件夹)
24 * @param zipFilePath 压缩文件路径
25 * @param password 压缩密码
26 * @return 压缩成功:true ,压缩失败:false
27 */
28 public static Boolean singleFileCompress(String sourceFilePath,String zipFilePath,String password){
29 parameters = new ZipParameters();
30 parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式(默认方式)
31 parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 压缩级别(默认级别)
32 //压缩加密设置
33 if (!StringUtils.isEmpty(password)) {
34 parameters.setEncryptFiles(true);//是否设置文件加密(默认为否)
35 parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式(此处是标准压缩)
36 parameters.setPassword(password.toCharArray());
37 }
38 try {
39 ZipFile zipFile = new ZipFile(zipFilePath);
40 //如果是文件则直接压缩,若是文件夹,遍历文件全部压缩
41 if(new File(sourceFilePath).isFile()) {
42 zipFile.setFileNameCharset("GBK");
43 zipFile.addFile(new File(sourceFilePath), parameters);
44 return true;
45 }
46 //File ff=new File(sourceFilePath);
47 File[] flst=new File(sourceFilePath).listFiles();
48 System.out.println("文件个数=>"+flst.length);
49 for(File f:flst){
50 zipFile.setFileNameCharset("GBK");
51 zipFile.addFile(f, parameters);
52 }
53
54 return true;
55 } catch (ZipException e) {
56 e.printStackTrace();
57 return false;
58 }catch (Exception id){
59 id.printStackTrace();
60 return false;
61 }
62 }
63 public static Boolean unZip(String zipFile,String unZipDir){
64 try {
65 ZipUtil.zipFile = new ZipFile(zipFile);
66 ZipUtil.zipFile.setFileNameCharset("GBK");//设置编码格式
67 //用自带的方法检测一下zip文件是否合法,包括文件是否存在、是否为zip文件、是否被损坏等
68 if (!ZipUtil.zipFile.isValidZipFile()) {
69 throw new ZipException("文件不合法或不存在");
70 }
71 // 跟java自带相比,这里文件路径会自动生成,不用判断
72 ZipUtil.zipFile.extractAll(unZipDir);
73 return true;
74 }catch(ZipException e){
75 return false;
76 }
77 }
78 }
以上压缩方法自带密码压缩功能,可以压缩单文件也可以压缩目录文件,相对于原生的实现,一下子清爽了许多,这里唯一需要说明的是,压缩的目标文件在压缩前一定不能穿件,否则会报错!另外对于解压缩一定要注意文件编码和判断文件是否存在。
OK,本章的功能已尽数分享,希望各位在开发功能的时候能避免这其中的坑。
现在是2018-07-14 22:16:12 ,各位晚安
- 【springboot】 spring session 分布式会话共享
- 基于jfinal Template的Shiro 标签
- 基于Spring Cloud 少量配置完成单点登录开发
- Spring 必知概念(一)
- 如何在EHAB(EntLib)中定义”细粒度”异常策略?
- MVC、MVP以及Model2[下篇]
- Dora.Interception: 一个为.NET Core度身定制的AOP框架
- 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]
- 关于Expression Tree和IL Emit的所谓的"性能差别"
- 采用一个自创的"验证框架"实现对数据实体的验证[扩展篇]
- 采用一个自创的"验证框架"实现对数据实体的验证[改进篇]
- Flash XSS检测脚本的简单实现
- 采用一个自创的"验证框架"实现对数据实体的验证[设计篇]
- 采用一个自创的"验证框架"实现对数据实体的验证[编程篇]
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释