springboot备份mysql后发送邮件并删除备份文件,支持win和Linux
首先加入springboot的邮箱依赖
<!--邮箱依赖--> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
邮件实体类
1 package com.xiaostudy.shiro_test1.entity; 2 3 import java.io.File; 4 5 /** 6 * Created with IntelliJ IDEA. 7 * User: xiaostudy 8 * Date: 2019/7/23 9 * Time: 21:28 10 * Description: No Description 11 */ 12 public class MailEntity { 13 /** 14 * 主题 15 */ 16 private String subject; 17 /** 18 * 内容 19 */ 20 private String content; 21 /** 22 * 邮箱 23 */ 24 private String toAccount; 25 /** 26 * 附件 27 */ 28 private File attachmentFile; 29 /** 30 * 附件文件名 31 */ 32 private String attachmentFileName; 33 34 public String getSubject() { 35 return subject; 36 } 37 38 public void setSubject(String subject) { 39 this.subject = subject; 40 } 41 42 public String getContent() { 43 return content; 44 } 45 46 public void setContent(String content) { 47 this.content = content; 48 } 49 50 public String getToAccount() { 51 return toAccount; 52 } 53 54 public void setToAccount(String toAccount) { 55 this.toAccount = toAccount; 56 } 57 58 public File getAttachmentFile() { 59 return attachmentFile; 60 } 61 62 public void setAttachmentFile(File attachmentFile) { 63 this.attachmentFile = attachmentFile; 64 } 65 66 public String getAttachmentFileName() { 67 return attachmentFileName; 68 } 69 70 public void setAttachmentFileName(String attachmentFileName) { 71 this.attachmentFileName = attachmentFileName; 72 } 73 }
spring获取bean工具类【不是service和controller层的不能注入bean】
1 package com.xiaostudy.shiro_test1.utils; 2 3 import org.springframework.beans.BeansException; 4 import org.springframework.beans.factory.NoSuchBeanDefinitionException; 5 import org.springframework.context.ApplicationContext; 6 import org.springframework.context.ApplicationContextAware; 7 import org.springframework.stereotype.Component; 8 9 import java.util.Map; 10 11 /** 12 * Spring Context 工具类:可以在其他地方通过静态方法获取Spring配置的Bean 13 * 14 */ 15 @Component 16 public class SpringContextUtils implements ApplicationContextAware { 17 private static ApplicationContext applicationContext; 18 19 @Override 20 public void setApplicationContext(ApplicationContext applicationContext) 21 throws BeansException { 22 if (SpringContextUtils.applicationContext == null) { 23 SpringContextUtils.applicationContext = applicationContext; 24 } 25 } 26 27 public static ApplicationContext getApplicationContext() { 28 return applicationContext; 29 } 30 31 public static Object getBean(String name) { 32 return applicationContext.getBean(name); 33 } 34 35 /** 36 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. 37 */ 38 public static <T> T getBean(Class<T> requiredType) { 39 // assertContextInjected(); 40 if(null == applicationContext) { 41 return null; 42 } 43 return applicationContext.getBean(requiredType); 44 } 45 46 /** 47 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. 48 */ 49 public static <T> Map<String, T> getBeanOfMap(Class<T> requiredType) { 50 // assertContextInjected(); 51 if(null == applicationContext) { 52 return null; 53 } 54 return applicationContext.getBeansOfType(requiredType); 55 } 56 57 /** 58 * 检查ApplicationContext不为空. 59 */ 60 /*private static void assertContextInjected() { 61 Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder."); 62 }*/ 63 64 /*** 65 * 类似于getBean(String name)只是在参数中提供了需要返回到的类型。 66 * 67 * @param name 68 * @param requiredType 69 * @return 70 * @throws BeansException 71 */ 72 public static <T> T getBean(String name, Class<T> requiredType) { 73 return applicationContext.getBean(name, requiredType); 74 } 75 76 /** 77 * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true 78 * 79 * @param name 80 * @return boolean 81 */ 82 public static boolean containsBean(String name) { 83 return applicationContext.containsBean(name); 84 } 85 86 /** 87 * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 88 * 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) 89 * 90 * @param name 91 * @return boolean 92 * @throws NoSuchBeanDefinitionException 93 */ 94 public static boolean isSingleton(String name) { 95 return applicationContext.isSingleton(name); 96 } 97 98 public static Class<? extends Object> getType(String name) { 99 return applicationContext.getType(name); 100 } 101 102 /** 103 * 获取Spring装配的bean的名称 104 */ 105 public static String[] getBeanNameAll() { 106 return applicationContext.getBeanDefinitionNames(); 107 } 108 109 /*** 110 * 类似于获取同类型的BEAN 111 * @param <T> 112 * @param requiredType 113 * @return 114 * @throws BeansException 115 */ 116 public static <T> Map<String, T> getBeansOfType(Class<T> requiredType) { 117 return applicationContext.getBeansOfType(requiredType); 118 } 119 }
发邮件工具类
1 package com.xiaostudy.shiro_test1.utils; 2 3 import com.xiaostudy.shiro_test1.entity.MailEntity; 4 //import org.jasypt.encryption.StringEncryptor; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.boot.autoconfigure.mail.MailProperties; 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.Component; 11 12 import javax.mail.MessagingException; 13 import javax.mail.internet.MimeMessage; 14 15 /** 16 * Created with IntelliJ IDEA. 17 * User: xiaostudy 18 * Date: 2019/7/23 19 * Time: 21:25 20 * Description: No Description 21 */ 22 @Component 23 public class MailUtils { 24 25 /** 26 * 发送邮件,里面有判断是否发文件 27 */ 28 public static void sendMail(MailEntity mailEntity) { 29 if(null != mailEntity) { 30 if(null != mailEntity.getAttachmentFile() && mailEntity.getAttachmentFile().exists()) { 31 if(null == mailEntity.getAttachmentFileName()) { 32 mailEntity.setAttachmentFileName(mailEntity.getAttachmentFile().getName()); 33 } 34 sendMailAttachment(mailEntity); 35 } else { 36 sendSimpleMail(mailEntity); 37 } 38 } 39 } 40 41 /** 42 * 发送邮件,这里只发内容,不发文件 43 */ 44 public static void sendSimpleMail(MailEntity mailEntity) { 45 SimpleMailMessage mimeMessage = new SimpleMailMessage(); 46 mimeMessage.setFrom(SpringContextUtils.getBean(MailProperties.class).getUsername()); 47 mimeMessage.setTo(mailEntity.getToAccount()); 48 mimeMessage.setSubject(mailEntity.getSubject()); 49 mimeMessage.setText(mailEntity.getContent()); 50 SpringContextUtils.getBean(JavaMailSender.class).send(mimeMessage); 51 } 52 53 /** 54 * 发送邮件-附件邮件 55 * 56 * @param mailEntity 57 */ 58 public static boolean sendMailAttachment(MailEntity mailEntity) { 59 JavaMailSender javaMailSender = SpringContextUtils.getBean(JavaMailSender.class); 60 try { 61 MimeMessage mimeMessage = javaMailSender.createMimeMessage(); 62 MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); 63 helper.setFrom(SpringContextUtils.getBean(MailProperties.class).getUsername()); 64 helper.setTo(mailEntity.getToAccount()); 65 helper.setSubject(mailEntity.getSubject()); 66 helper.setText(mailEntity.getContent(), true); 67 // 增加附件名称和附件 68 helper.addAttachment(mailEntity.getAttachmentFileName(), mailEntity.getAttachmentFile()); 69 javaMailSender.send(mimeMessage); 70 return true; 71 } catch (MessagingException e) { 72 e.printStackTrace(); 73 return false; 74 } 75 } 76 }
删除备份文件线程类
1 package com.xiaostudy.shiro_test1.thread; 2 3 import com.xiaostudy.shiro_test1.entity.LoginLogEntity; 4 import com.xiaostudy.shiro_test1.service.LoginLogService; 5 import com.xiaostudy.shiro_test1.utils.DateUtils; 6 import com.xiaostudy.shiro_test1.utils.IpUtil; 7 import com.xiaostudy.shiro_test1.utils.MakeMD5; 8 import com.xiaostudy.shiro_test1.utils.ShiroUtils; 9 10 import java.io.File; 11 12 /** 13 * Created with IntelliJ IDEA. 14 * User: xiaostudy 15 * Date: 2019/7/22 16 * Time: 0:05 17 * Description: No Description 18 */ 19 public class RemoveBackupSqlFileThread implements Runnable { 20 21 private String filePath; 22 private Long start; 23 24 public RemoveBackupSqlFileThread(String filePath) { 25 this.filePath = filePath; 26 this.start = System.currentTimeMillis(); 27 } 28 29 @Override 30 public void run() { 31 try { 32 // 前让线程睡1分钟,保证邮件已经发送 33 Thread.sleep(1000 * 60); 34 } catch (InterruptedException e) { 35 e.printStackTrace(); 36 } 37 File file = new File(filePath); 38 // 30分钟内,每1分钟删除备份文件,删除文件就结束线程 39 while (System.currentTimeMillis() - this.start < 1000 * 60 * 30) { 40 if(null != file && file.exists() && file.isFile() && file.delete()) { 41 break; 42 } 43 try { 44 Thread.sleep(1000 * 60); 45 } catch (InterruptedException e) { 46 e.printStackTrace(); 47 } 48 } 49 } 50 }
1、在win下备份mysql并发送邮件
在spirng:后加,如下图
mail: host: smtp.mxhichina.com #阿里云发送服务器地址 port: 25 #端口号 username: 邮箱地址 #发送人地址 password: 密码 #密码
配置my.ini【因为java运行备份mysql的命令,不能直接用密码】
在最后添加
[client] host=localhost user=用户名 password=密码
这里说明一下这个my.ini文件,有些是在安装mysql的目录下,有些不是在安装目录下,可以用工具Everything搜一下
备份的命令是
"D:/Program Files/MySQL/MySQL Server 5.7/bin/mysqldump.exe" --defaults-extra-file="D:/ProgramData/MySQL/MySQL Server 5.7/my.ini" -B 数据库名称>C:/temp/20190725.sql
上面为什么要用双引号呢,主要是文件夹名称有空格,cmd识别不了,加双引号就好了。
备份数据,发送邮件,删除备份文件
@GetMapping("backup") @ResponseBody public Map backup(){ String thisDateTime = DateUtils.getDateTime("yyyyMMdd_HHmmss"); String filePath; String shell; String[] cmd; // 通过获取系统名称是否包含windows来判断是win还是Linux if(System.getProperties().getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1) { filePath = "C:/temp/myLog_" + thisDateTime + ".sql"; shell = "\"D:/Program Files/MySQL/MySQL Server 5.7/bin/mysqldump.exe\" --defaults-extra-file=\"D:/ProgramData/MySQL/MySQL Server 5.7/my.ini\" -B my_log>" + filePath; // java运行cmd命令要多加cmd空格/c空格 shell = "cmd /c " + shell; } else { filePath = "/home/backup/myLog_" + thisDateTime + ".sql"; shell = "/usr/local/mysql/bin/mysqldump --defaults-extra-file=/usr/local/mysql/my.cnf -B my_log>" + filePath; } System.out.println("shell:" + shell); Runtime runTime = Runtime.getRuntime(); if (runTime == null) { System.err.println("Create runtime false!"); } try { if(System.getProperties().getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1) { runTime.exec(shell); } else { runTime.exec(new String[]{"/bin/sh", "-c", shell}); } } catch (IOException e) { e.printStackTrace(); } MailEntity mailEntity = new MailEntity(); // 对方邮箱地址 mailEntity.setToAccount("手机号@163.com"); mailEntity.setSubject("备份mysql"); mailEntity.setContent("备份mysql的my_log数据库"); File file = null; long thisTime = System.currentTimeMillis(); // 这里是处理备份的sql文件是否写入完成,这里是10秒 while (System.currentTimeMillis() - thisTime < 10*1000) { file = new File(filePath); if(file.exists() && file.isFile()) { break; } else { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } mailEntity.setAttachmentFile(file); MailUtils.sendMail(mailEntity); // 删除备份文件 new Thread(new RemoveBackupSqlFileThread(filePath)).start(); Map map = new HashMap(); map.put("code", "0"); map.put("msg", "已发送至邮箱"); return map; }
注:如果win备份mysql文件大小为0,那么可以考虑用new String[]{"cmd", "/c", shell}。参考下面Linux运行命令方法
2、Linux下备份mysql并发送邮件
配置my.cnf文件
vi my.cnf打开文件【按i进入编辑状态,按Esc退出编辑,按:wq保存退出查看文件】
[client] host=内网ip user=用户名 password=密码
springboot的配置,阿里云服务器封了25端口,要用465端口
1 mail: 2 default-encoding: UTF-8 3 host: smtp.mxhichina.com #阿里云发送服务器地址 4 # port: 25 #端口号 5 username: 邮箱地址 #发送人地址 6 password: 密码 #密码 7 properties: 8 mail: 9 smtp: 10 starttls: 11 enable: true 12 required: true 13 auth: true 14 socketFactory: 15 class: javax.net.ssl.SSLSocketFactory 16 port: 465
备份数据,发送邮件,删除备份文件
1 @GetMapping("backup") 2 @ResponseBody 3 public Map backup(){ 4 String thisDateTime = DateUtils.getDateTime("yyyyMMdd_HHmmss"); 5 String filePath; 6 String shell; 7 // 通过获取系统名称是否包含windows来判断是win还是Linux 8 if(System.getProperties().getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1) { 9 filePath = "C:/temp/myLog_" + thisDateTime + ".sql"; 10 shell = "\"D:/Program Files/MySQL/MySQL Server 5.7/bin/mysqldump.exe\" --defaults-extra-file=\"D:/ProgramData/MySQL/MySQL Server 5.7/my.ini\" -B my_log>" + filePath; 11 shell = "cmd /c " + shell; 12 } else { 13 filePath = "/home/backup/myLog_" + thisDateTime + ".sql"; 14 shell = "/usr/local/mysql/bin/mysqldump --defaults-extra-file=/usr/local/mysql/my.cnf -B my_log>" + filePath; 15 } 16 Runtime runTime = Runtime.getRuntime(); 17 Map map = new HashMap(); 18 if (null != runTime) { 19 try { 20 if(System.getProperties().getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1) { 21 runTime.exec(shell); 22 } else { 23 // linux运行shell命令要加 24 runTime.exec(new String[]{"/bin/sh", "-c", shell}); 25 } 26 } catch (IOException e) { 27 e.printStackTrace(); 28 } 29 MailEntity mailEntity = new MailEntity(); 30 mailEntity.setToAccount("对方邮箱地址"); 31 mailEntity.setSubject("备份mysql"); 32 mailEntity.setContent("备份mysql的my_log数据库"); 33 File file = null; 34 long thisTime = System.currentTimeMillis(); 35 while (System.currentTimeMillis() - thisTime < 10*1000) { 36 file = new File(filePath); 37 if(file.exists() && file.isFile()) { 38 break; 39 } else { 40 try { 41 Thread.sleep(200); 42 } catch (InterruptedException e) { 43 e.printStackTrace(); 44 } 45 } 46 } 47 mailEntity.setAttachmentFile(file); 48 MailUtils.sendMail(mailEntity); 49 // 删除备份文件 50 new Thread(new RemoveBackupSqlFileThread(filePath)).start(); 51 map.put("code", "0"); 52 map.put("msg", "已发送至邮箱"); 53 } else { 54 map.put("code", "1"); 55 map.put("msg", "获取Runtime为null,不能运行命令"); 56 } 57 return map; 58 }
后面测试定时备份数据和发送邮件