1、将JSch和邮件插件
添加到项目pom文件中。Maven
<!--java 通过JSch操作Linux-->
<dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version>
</dependency><!-- 邮件模板 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2、数据备份相关的配置文件
#数据库备份配置
dbBackups:windowsDir: E:\test\ #windows本机得备份目录linuxDir: projectFiles/dbFile #linux本机得备份目录linuxServe: #要传输得服务器信息user: xxxhost: xxxpassword: xxxremoteDir: /home/ubuntu/20231127 #需要给权限测试直接给了 777
3、邮件的配置文件
spring:#邮件发送mail:host: smtp.qq.com #发送邮件服务器username: xxx@qq.com #QQ邮箱password: xxxxxxxxx #客户端授权码protocol: smtp #发送邮件协议default-encoding: utf-8from: xxxxx@qq.com #与上面的username保持一致properties:mail:smtp:auth: trueport: 587 #端口号465或587display:sendmail: Javen #可以任意sendname: Spring Boot Guide Email #可以任意starttls:enable: truerequired: truessl:enable: true
4、定时任务
import com.jcraft.jsch.*;
import com.jcraft.jsch.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;import javax.mail.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;/*** 数据库备份* 支持几个常用的特殊符号:* *:表示任何时间触发任务* ,:表示指定的时间触发任务* -:表示一段时间内触发任务* /:表示从哪一个时刻开始,每隔多长时间触发一次任务。* ?:表示用于月中的天和周中的天两个子表达式,表示不指定值。** cron表达式参数具体含义:* 秒,取值范围:0-59,支持*、,、-、/。* 分,取值范围:0-59,支持*、,、-、/。* 时,取值范围:0-23,支持*、,、-、/。* 日期,取值范围:1-31,支持*、,、-、/。比秒多了?,表示如果指定的星期触发了,则配置的日期变成无效。* 月,取值范围:1-12,支持*、,、-、/。* 星期,取值范围:1~7,1代表星期天,6代表星期六,其他的以此类推。支持*、,、-、/、?。比秒多了?,表示如果指定的日期触发了,则配置的星期变成无效。** 常见cron表达式使用举例:* 0 0 0 1 * ? 每月1号零点执行* 0 0 2 * * ? 每天凌晨2点执行* 0 0 2 * * ? 每天凌晨2点执行* 0 0/5 11 * * ? 每天11点-11点55分,每隔5分钟执行一次* 0 0 18 ? * WED 每周三下午6点执行*/@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class DBBackupsTask {//读取yml配置@Autowiredprivate Environment environment;//邮件服务@Autowiredpublic EmailSendImpl emailSendImpl;//备份数据库并发送到邮箱@Scheduled(cron = "0/10 * * * * ?")private void dbEmailTask() {System.out.println("执行静态定时任务备份数据库开始时间: " + LocalDateTime.now());//通过util下的Date包实现Date date = new Date();SimpleDateFormat dateFormat= new SimpleDateFormat("yyyyMMddhhmmss");String format = dateFormat.format(date);String backupFileName = "backup_file_"+format + ".sql";try {String command = "";String fileDir = "";if(ZipUtils.isWindows()){fileDir = environment.getProperty("dbBackups.windowsDir"); // E:\test\ 文件备份位置 这里配置文件读取了command = "cmd /c mysqldump -uroot -p123456 forum_cs > " + fileDir + backupFileName;}else{fileDir = environment.getProperty("dbBackups.linuxDir"); // projectFiles/dbFile 文件备份位置 这里配置文件读取了command = "mysqldump -uroot -p123456 forum_cs > " + fileDir + backupFileName;}Process process = Runtime.getRuntime().exec(command);// 等待命令执行完成int exitCode = process.waitFor();if(exitCode != 0){System.err.println("备份数据库失败时间: exitCode="+ exitCode +" - "+ LocalDateTime.now());}//成功则将数据压缩并发送给管理员邮箱String to = "xxxxxxx@qq.com";String subject = "邮件通知";String content = "数据库备份成功! 备份时间:" + format;// 读取备份文件并压缩String filePath = fileDir + backupFileName ;String zipFilePath = fileDir;String fileName = "backup_file_" + format ;ZipUtils.fileToZip(filePath,zipFilePath,fileName);emailSendImpl.sendAttachmentsMail(to,subject,content,zipFilePath+fileName+".zip");System.out.println("执行静态定时任务备份数据库结束时间: " + LocalDateTime.now());} catch (IOException | InterruptedException | MessagingException e) {e.printStackTrace();}}//备份数据库并发送到指定的服务器地址 测试每十秒@Scheduled(cron = "0/10 * * * * ?")private void dbServerTask() {System.out.println("执行静态定时任务备份数据库开始时间: " + LocalDateTime.now());//通过util下的Date包实现Date date = new Date();SimpleDateFormat dateFormat= new SimpleDateFormat("yyyyMMddhhmmss");String format = dateFormat.format(date);String backupFileName = "backup_file_"+format + ".sql";try {String command = "";String fileDir = "";if(ZipUtils.isWindows()){fileDir = environment.getProperty("dbBackups.windowsDir"); // 文件备份位置 这里配置文件读取了command = "cmd /c mysqldump -uroot -p123456 forum_cs > " + fileDir + backupFileName;}else{fileDir = environment.getProperty("dbBackups.linuxDir"); // 文件备份位置 这里配置文件读取了command = "mysqldump -uroot -p123456 forum_cs > " + fileDir + backupFileName;}Process process = Runtime.getRuntime().exec(command);// 等待命令执行完成int exitCode = process.waitFor();if(exitCode != 0){System.err.println("备份数据库失败时间: exitCode="+ exitCode +" - "+ LocalDateTime.now());}// 读取备份文件并压缩String filePath = fileDir + backupFileName ;String zipFilePath = fileDir;String fileName = "backup_file_" + format ;ZipUtils.fileToZip(filePath,zipFilePath,fileName);//向指定服务器发送文件备份this.fileTransfer(zipFilePath + fileName + ".zip" );System.out.println("执行静态定时任务备份数据库结束时间: " + LocalDateTime.now());} catch (IOException | InterruptedException | JSchException e) {e.printStackTrace();}}/*** 向指定服务器发送文件备份* @throws IOException* @throws JSchException*/public void fileTransfer(String localFile) throws IOException, JSchException {String user = environment.getProperty("dbBackups.linuxServe.user"); //"ubuntu"; // 你的Linux用户名String host = environment.getProperty("dbBackups.linuxServe.host"); //"192.168.137.155"; // 你的Linux服务器主机名或IPint port = 22; // SSH运行的端口String password = environment.getProperty("dbBackups.linuxServe.password"); //"ubuntu"; // 你的Linux密码String remoteDir = environment.getProperty("dbBackups.linuxServe.remoteDir"); //"/home/ubuntu/20231127"; // 你在Linux服务器上的远程目录路径 需要给权限JSch jsch = new JSch();Session session = null;try {// 建立SSH会话session = jsch.getSession(user, host, port);// 连接认证session.setPassword(password);session.setConfig("StrictHostKeyChecking", "no");session.connect();// 打开一个SFTP通道Channel channel = session.openChannel("sftp");channel.connect();ChannelSftp sftp = (ChannelSftp) channel;// 进行文件传输sftp.put(new FileInputStream(localFile), remoteDir + "/" + localFile.substring(localFile.lastIndexOf("\\") + 1));// 关闭连接channel.disconnect();session.disconnect();} catch (JSchException | SftpException | IOException e) {e.printStackTrace();}}}
5、邮件发送工具类
import javax.mail.MessagingException;public interface EmailSend {/*** 发送文本邮件* @param to* @param subject* @param content*/public void sendSimpleMail(String to, String subject, String content);public void sendSimpleMail(String to, String subject, String content, String... cc);/*** 发送HTML邮件* @param to* @param subject* @param content* @throws MessagingException*/public void sendHtmlMail(String to, String subject, String content) throws MessagingException;public void sendHtmlMail(String to, String subject, String content, String... cc);/*** 发送带附件的邮件* @param to* @param subject* @param content* @param filePath* @throws MessagingException*/public void sendAttachmentsMail(String to, String subject, String content, String filePath) throws MessagingException;public void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc);/*** 发送正文中有静态资源的邮件* @param to* @param subject* @param content* @param rscPath* @param rscId* @throws MessagingException*/public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId) throws MessagingException;public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc);}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.mail.MessagingException;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import java.io.File;@Component
public class EmailSendImpl implements EmailSend {@Autowiredpublic JavaMailSender mailSender;@Value("${spring.mail.from}")public String from;/*** 发送文本邮件** @param to* @param subject* @param content*/@Overridepublic void sendSimpleMail(String to, String subject, String content) {SimpleMailMessage message = new SimpleMailMessage();message.setFrom(from);message.setTo(to);message.setSubject(subject);message.setText(content);mailSender.send(message);}@Overridepublic void sendSimpleMail(String to, String subject, String content, String... cc) {SimpleMailMessage message = new SimpleMailMessage();message.setFrom(from);message.setTo(to);message.setCc(cc);message.setSubject(subject);message.setText(content);mailSender.send(message);}/*** 发送HTML邮件* @param to* @param subject* @param content*/@Overridepublic void sendHtmlMail(String to, String subject, String content) throws MessagingException {MimeMessage message = mailSender.createMimeMessage();//true表示需要创建一个multipart messageMimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject(subject);helper.setText(content, true);mailSender.send(message);}/*** 获取邮件的正文* @return*/public String getContent(Integer number){String str = "<body style=\"text-align: center;margin-left: auto;margin-right: auto;\">\n"+ " <div id=\"welcome\" style=\"text-align: center;position: absolute;\" >\n"+" <h3>欢迎使用</h3>\n"+" <span>万千风景,不及见你一面</span>"+ " <div\n"+ " style=\"text-align: center; padding: 10px\"><a style=\"text-decoration: none;\" href=\"#\" target=\"_bank\" ><strong>最美的事就是与你一起,看遍万千风景</strong></a></div>\n"+ " <div\n" + " style=\"text-align: center; padding: 4px\">您的验证码:"+ number+"</div>\n"+ " </div>\n" + "</body>";return str;}@Overridepublic void sendHtmlMail(String to, String subject, String content, String... cc) {}/*** 发送带附件的邮件* @param to* @param subject* @param content* @param filePath*/public void sendAttachmentsMail(String to, String subject, String content, String filePath) throws MessagingException {MimeMessage message = mailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject(subject);helper.setText(content, true);FileSystemResource file = new FileSystemResource(new File(filePath));String fileName = filePath.substring(filePath.lastIndexOf(File.separator));helper.addAttachment(fileName, file);mailSender.send(message);}@Overridepublic void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc) {}/*** 发送正文中有静态资源(图片)的邮件** @param to* @param subject* @param content* @param rscPath* @param rscId*/public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId) throws MessagingException {MimeMessage message = mailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject(subject);helper.setText(content, true);FileSystemResource res = new FileSystemResource(new File(rscPath));helper.addInline(rscId, res);mailSender.send(message);}@Overridepublic void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc) {}}
6、zip压缩工具类
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;/*** zip工具类** @author cdj* @date 2018年8月24日 上午10:03:15*/
@Component
public class ZipUtils {/*** 将存放在sourceFilePath目录下的源文件,打包成fileName名称的zip文件,并存放到zipFilePath路径下** @param sourceFilePath* :待压缩的文件路径* @param zipFilePath* :压缩后存放路径* @param fileName* :压缩后文件的名称* @return*/public static boolean folderToZip(String sourceFilePath, String zipFilePath, String fileName) {boolean flag = false;File sourceFile = new File(sourceFilePath);FileInputStream fis = null;BufferedInputStream bis = null;FileOutputStream fos = null;ZipOutputStream zos = null;if (sourceFile.exists() == false) {System.out.println("待压缩的文件目录:" + sourceFilePath + "不存在.");} else {try {File zipFile = new File(zipFilePath + "/" + fileName + ".zip");if (zipFile.exists()) {System.out.println(zipFilePath + "目录下存在名字为:" + fileName + ".zip" + "打包文件.");} else {File[] sourceFiles = sourceFile.listFiles();if (null == sourceFiles || sourceFiles.length < 1) {System.out.println("待压缩的文件目录:" + sourceFilePath + "里面不存在文件,无需压缩.");} else {fos = new FileOutputStream(zipFile);zos = new ZipOutputStream(new BufferedOutputStream(fos));byte[] bufs = new byte[1024 * 10];for (int i = 0; i < sourceFiles.length; i++) {// 创建ZIP实体,并添加进压缩包ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());zos.putNextEntry(zipEntry);// 读取待压缩的文件并写进压缩包里fis = new FileInputStream(sourceFiles[i]);bis = new BufferedInputStream(fis, 1024 * 10);int read = 0;while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {zos.write(bufs, 0, read);}}flag = true;}}} catch (FileNotFoundException e) {e.printStackTrace();throw new RuntimeException(e);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);} finally {// 关闭流try {if (null != bis)bis.close();if (null != zos)zos.close();} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}}}return flag;}/*** 将sourceFilePath文件,打包成fileName名称的zip文件,并存放到zipFilePath路径下** @param sourceFilePath* :待压缩的文件路径* @param zipFilePath* :压缩后存放路径* @param fileName* :压缩后文件的名称* @return*/public static boolean fileToZip(String sourceFilePath, String zipFilePath, String fileName) {boolean flag = false;File sourceFile = new File(sourceFilePath);FileInputStream fis = null;BufferedInputStream bis = null;FileOutputStream fos = null;ZipOutputStream zos = null;if (sourceFile.exists() == false) {System.out.println("待压缩的文件:" + sourceFilePath + "不存在.");} else {try {File zipFile = new File(zipFilePath + "/" + fileName + ".zip");if (zipFile.exists()) {System.out.println(zipFilePath + "目录下存在名字为:" + fileName + ".zip" + "打包文件.");} else {fos = new FileOutputStream(zipFile);zos = new ZipOutputStream(new BufferedOutputStream(fos));byte[] bufs = new byte[1024 * 10];// 创建ZIP实体,并添加进压缩包ZipEntry zipEntry = new ZipEntry(sourceFile.getName());zos.putNextEntry(zipEntry);// 读取待压缩的文件并写进压缩包里fis = new FileInputStream(sourceFile);bis = new BufferedInputStream(fis, 1024 * 10);int read = 0;while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {zos.write(bufs, 0, read);}flag = true;}} catch (FileNotFoundException e) {e.printStackTrace();throw new RuntimeException(e);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);} finally {// 关闭流try {if (null != bis)bis.close();if (null != zos)zos.close();} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}}}return flag;}/*** 将流的内容打包成fileName名称的zip文件,并存放到zipFilePath路径下* @param fis* @param streamfilename* @param zipFilePath 压缩后存放路径* @param fileName 压缩后文件的名称* @return*/public static boolean streamToZip(InputStream fis, String streamfilename, String zipFilePath, String fileName) {boolean flag = false;BufferedInputStream bis = null;FileOutputStream fos = null;ZipOutputStream zos = null;try {File zipFile = new File(zipFilePath + "/" + fileName + ".zip");if (zipFile.exists()) {System.out.println(zipFilePath + "目录下存在名字为:" + fileName + ".zip" + "打包文件.");} else {fos = new FileOutputStream(zipFile);zos = new ZipOutputStream(new BufferedOutputStream(fos));byte[] bufs = new byte[1024 * 10];// 创建ZIP实体,并添加进压缩包ZipEntry zipEntry = new ZipEntry(streamfilename);zos.putNextEntry(zipEntry);// 读取待压缩的文件并写进压缩包里bis = new BufferedInputStream(fis, 1024 * 10);int read = 0;while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {zos.write(bufs, 0, read);}flag = true;}zos.close();} catch (FileNotFoundException e) {e.printStackTrace();throw new RuntimeException(e);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);} finally {// 关闭流try {if (null != bis)bis.close();if (null != zos)zos.close();} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}}return flag;}/*** 将流转成zip文件输出* @param inputstream* 文件流* @param streamfilename* 流文件的名称* @param fileName zip包的名称* @param response* @return*/public static boolean streamToZipStream(InputStream inputstream, String streamfilename, String fileName,HttpServletResponse response) {boolean flag = false;BufferedInputStream bis = null;FileOutputStream fos = null;ZipOutputStream zos = null;OutputStream out = null;try {out = response.getOutputStream();response.reset();response.setHeader("Content-Disposition","attachment;filename=" + new String(fileName.getBytes("GB2312"), "ISO-8859-1"));response.setContentType("application/octet-stream; charset=utf-8");response.setCharacterEncoding("UTF-8");zos = new ZipOutputStream(out);byte[] bufs = new byte[1024 * 10];// 创建ZIP实体,并添加进压缩包ZipEntry zipEntry = new ZipEntry(streamfilename);zos.putNextEntry(zipEntry);// 读取待压缩的文件并写进压缩包里bis = new BufferedInputStream(inputstream, 1024 * 10);int read = 0;while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {zos.write(bufs, 0, read);}flag = true;zos.close();} catch (FileNotFoundException e) {e.printStackTrace();throw new RuntimeException(e);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);} finally {// 关闭流try {if (null != bis)bis.close();if (null != zos)zos.close();if (null != out)out.close();} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}}return flag;}/*** 将多个流转成zip文件输出* @param listStream* 文件流实体类对象* @param fileName zip包的名称* @param response* @return*/public static boolean listStreamToZipStream(List<ZipStreamEntity> listStream, String fileName, HttpServletResponse response) {boolean flag = false;BufferedInputStream bis = null;FileOutputStream fos = null;ZipOutputStream zos = null;OutputStream out = null;try {out = response.getOutputStream();response.reset();response.setHeader("Content-Disposition","attachment;filename=" + new String(fileName.getBytes("GB2312"), "ISO-8859-1"));response.setContentType("application/octet-stream; charset=utf-8");response.setCharacterEncoding("UTF-8");zos = new ZipOutputStream(out);byte[] bufs = new byte[1024 * 10];for (ZipStreamEntity zipstream : listStream) {String streamfilename = zipstream.getName();// 创建ZIP实体,并添加进压缩包ZipEntry zipEntry = new ZipEntry(streamfilename);zos.putNextEntry(zipEntry);// 读取待压缩的文件并写进压缩包里bis = new BufferedInputStream(zipstream.getInputstream(), 1024 * 10);int read = 0;while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {zos.write(bufs, 0, read);}}flag = true;zos.close();} catch (FileNotFoundException e) {e.printStackTrace();throw new RuntimeException(e);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);} finally {// 关闭流try {if (null != bis)bis.close();if (null != zos)zos.close();if (null != out)out.close();} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}}return flag;}/*** 判断当前系统是否为windows* @return*/public static boolean isWindows() {return System.getProperties().getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1;}
}
7、zip流文件实体类
/*** zip相关 流文件实体类*/
public class ZipStreamEntity {public String name;public InputStream inputstream;public ZipStreamEntity() {super();// TODO Auto-generated constructor stub}public ZipStreamEntity(String name, InputStream inputstream) {super();this.name = name;this.inputstream = inputstream;}public String getName() {return name;}public void setName(String name) {this.name = name;}public InputStream getInputstream() {return inputstream;}public void setInputstream(InputStream inputstream) {this.inputstream = inputstream;}}