springboot 添加邮件发送及文件压缩功能
先来一段诗
```
就这样吧
忍受折磨
然后, 躺进医院
然后, 死去
化作一抔土
从此, 这世界没有烦恼
没有病痛
没有我
也没有这个世界
```
以上是在半睡半醒中想到的, 写的不好, 读者可直接略过.
这次本来只讲讲邮件发送功能的, 惮于内容比较贫乏, 故加了点儿文件压缩的功能讲解.
首先邮件发送, 邮件功能在 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: username@hostname.com
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, 本章的功能已尽数分享, 希望各位在开发功能的时候能避免这其中的坑.
现在是 2018-07-14 22:16:12 , 各位晚安
来源: https://www.cnblogs.com/funnyzpc/p/9190233.html