V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kzyuan
V2EX  ›  Java

Quartz 定时邮件发送多个备份文件 - 黑壳网

  •  
  •   kzyuan ·
    ykz200 · 2017-07-27 17:34:04 +08:00 · 2646 次点击
    这是一个创建于 2708 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文由黑壳网发布
    本文来源Quartz 定时邮件发送备份文件 - 黑壳网 http://www.bhusk.com/articles/2017/07/27/1501146724360.html

    壳叔搞笑一刻

    熊孩子也有自己的梦想

    正文

    之前由于黑壳网的博客数据库,一直没有做定期备份的处理,虽然现在不一定会出问题,但起码数据备份意识上还是要有的。

    之前有考虑过用七牛云等第三方服务,但是最后由于种种原因,暂时不考虑用第三方服务。 所以自己手写了一个定时备份程序,简单的思路↓

    到达指定时间,将数据库备份文件发送利用邮箱,发送至指定邮箱,达到定期备份的目的。

    特别提示:如果文件对安全性要求很高的话,不推荐

    程序采用 Java 语言和maven 强大的依赖体系+流行的 spring,为什么要用 Java,只是写着好玩不要太较真了。

    项目代码

    pom.xml 文件 Quartz 的包是整个项目不可缺少的

     <properties>
            <!-- Spring 的版本 -->
            <springframework.version>4.0.6.RELEASE</springframework.version>
            <!-- Quartz 的版本 -->
            <quartz.version>2.2.1</quartz.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.0.1</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/javax.mail/mail -->
            <dependency>
                <groupId>javax.mail</groupId>
                <artifactId>mail</artifactId>
                <version>1.4</version>
            </dependency>
    
            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz</artifactId>
                <version>${quartz.version}</version>
            </dependency>
    
            <!-- spring -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${springframework.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
                <version>${springframework.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${springframework.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${springframework.version}</version>
            </dependency>
        </dependencies>
    
    

    MyJob.java 继承 QuartzJobBean 然后 Override 有钻研精神的可以一点一点扒代码看 QuartzJobBean。

    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    
    import java.util.Date;
    
    /**
     * kzyuan Job 参考
     * @description black husk
     * @description http://www.bhusk.com
     */
    public class MyJob extends QuartzJobBean {
    
        private static Logger logger = LoggerFactory.getLogger(DatabaseBackupJob.class);
    
        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    
            System.out.println("执行时间:"+new Date());
        }
    }
    

    application.xml 可以理解为 quartz 配置文件 注释很齐全

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
        <!-- 定义任务 bean -->
        <bean name="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
            <!-- 指定具体的 job 类 -->
            <property name="jobClass" value="com.bhusk.quartz.Job.MyJob"/>
            <!-- 指定 job 的名称 -->
            <property name="name" value="myJob"/>
            <!-- 指定 job 的分组 -->
            <property name="group" value="jobs"/>
            <!-- 必须设置为 true,如果为 false,当没有活动的触发器与之关联时会在调度器中删除该任务  -->
            <property name="durability" value="true"/>
            <!-- 指定 spring 容器的 key,如果不设定在 job 中的 jobmap 中是获取不到 spring 容器的 -->
            <property name="applicationContextJobDataKey" value="applicationContext"/>
        </bean>
    
        <!-- 定义触发器 -->
        <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
            <property name="jobDetail" ref="myJobDetail"/>
            <!--执行时间 -->
            <property name="cronExpression" value="0 0 3 * * ?"/>
        </bean>
    
        <!-- 定义触发器 -->
         <!--演示:一个 job 可以有多个 trigger ; -->
        <!--<bean id="cronTrigger2" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">-->
        <!--<property name="jobDetail" ref="myJobDetail2" />-->
        <!--每一分钟执行一次-->
        <!--    <property name="cronExpression" value="0 0 3 * * ?"/> -->
         <!--</bean>-->
    
        <!-- 定义调度器 -->
        <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <ref bean="cronTrigger"/>
         <!--		  <ref bean="cronTrigger2"/> -->
                </list>
            </property>
        </bean>
    
    </beans>
    
    
    

    JavaMail 发送邮件工具类 java 实现邮件的发送, 抄送及多附件 这个工具类来源网络,具体精准位置也不清楚了

    import javax.activation.DataHandler;
    import javax.activation.FileDataSource;
    import javax.mail.BodyPart;
    import javax.mail.Message;
    import javax.mail.MessagingException;
    import javax.mail.Multipart;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeBodyPart;
    import javax.mail.internet.MimeMessage;
    import javax.mail.internet.MimeMultipart;
    import javax.mail.internet.MimeUtility;
    import java.io.UnsupportedEncodingException;
    import java.util.Properties;
    
    /**
     * 邮件管理器
     * java 实现邮件的发送, 抄送及多附件
     */
    public class EmailManager {
    
        public static String username = "[email protected]"; // 服务邮箱(from 邮箱)
        public static String password = ""; // 邮箱密码
        public static String senderNick = "黑壳网的壳叔";   // 发件人昵称
    
        private Properties props; // 系统属性
        private Session session; // 邮件会话对象
        private MimeMessage mimeMsg; // MIME 邮件对象
        private Multipart mp;   // Multipart 对象,邮件内容,标题,附件等内容均添加到其中后再生成 MimeMessage 对象
    
        private static EmailManager instance = null;
    
        public EmailManager() {
            props = System.getProperties();
            props.put("mail.smtp.auth", "true");
            props.put("mail.transport.protocol", "smtp");
            props.put("mail.smtp.host", "smtp.163.com");
            props.put("mail.smtp.port", "25");
            props.put("username", username);
            props.put("password", password);
            // 建立会话
            session = Session.getDefaultInstance(props);
            session.setDebug(false);
        }
    
        public static EmailManager getInstance() {
            if (instance == null) {
                instance = new EmailManager();
            }
            return instance;
        }
    
        /**
         * 发送邮件
         *
         * @param from     发件人
         * @param to       收件人
         * @param copyto   抄送
         * @param subject  主题
         * @param content  内容
         * @param fileList 附件列表
         * @return
         */
        public boolean sendMail(String from, String[] to, String[] copyto, String subject, String content, String[] fileList) {
            boolean success = true;
            try {
                mimeMsg = new MimeMessage(session);
                mp = new MimeMultipart();
    
                // 自定义发件人昵称
                String nick = "";
                try {
                    nick = javax.mail.internet.MimeUtility.encodeText(senderNick);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                // 设置发件人
    //          mimeMsg.setFrom(new InternetAddress(from));
                mimeMsg.setFrom(new InternetAddress(from, nick));
                // 设置收件人
                if (to != null && to.length > 0) {
                    String toListStr = getMailList(to);
                    mimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toListStr));
                }
                // 设置抄送人
                if (copyto != null && copyto.length > 0) {
                    String ccListStr = getMailList(copyto);
                    mimeMsg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccListStr));
                }
                // 设置主题
                mimeMsg.setSubject(subject);
                // 设置正文
                BodyPart bp = new MimeBodyPart();
                bp.setContent(content, "text/html;charset=utf-8");
                mp.addBodyPart(bp);
                // 设置附件
                if (fileList != null && fileList.length > 0) {
                    for (int i = 0; i < fileList.length; i++) {
                        bp = new MimeBodyPart();
                        FileDataSource fds = new FileDataSource(fileList[i]);
                        bp.setDataHandler(new DataHandler(fds));
                        bp.setFileName(MimeUtility.encodeText(fds.getName(), "UTF-8", "B"));
                        mp.addBodyPart(bp);
                    }
                }
                mimeMsg.setContent(mp);
                mimeMsg.saveChanges();
                // 发送邮件
                if (props.get("mail.smtp.auth").equals("true")) {
                    Transport transport = session.getTransport("smtp");
                    transport.connect((String) props.get("mail.smtp.host"), (String) props.get("username"), (String) props.get("password"));
    //              transport.sendMessage(mimeMsg, mimeMsg.getRecipients(Message.RecipientType.TO));
    //              transport.sendMessage(mimeMsg, mimeMsg.getRecipients(Message.RecipientType.CC));
                    transport.sendMessage(mimeMsg, mimeMsg.getAllRecipients());
                    transport.close();
                } else {
                    Transport.send(mimeMsg);
                }
                System.out.println("邮件发送成功");
            } catch (MessagingException e) {
                e.printStackTrace();
                success = false;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                success = false;
            }
            return success;
        }
    
        /**
         * 发送邮件
         *
         * @param from     发件人
         * @param to       收件人, 多个 Email 以英文逗号分隔
         * @param cc       抄送, 多个 Email 以英文逗号分隔
         * @param subject  主题
         * @param content  内容
         * @param fileList 附件列表
         * @return
         */
        public boolean sendMail(String from, String to, String cc, String subject, String content, String[] fileList) {
            boolean success = true;
            try {
                mimeMsg = new MimeMessage(session);
                mp = new MimeMultipart();
    
                // 自定义发件人昵称
                String nick = "";
                try {
                    nick = javax.mail.internet.MimeUtility.encodeText(senderNick);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                // 设置发件人
    //          mimeMsg.setFrom(new InternetAddress(from));
                mimeMsg.setFrom(new InternetAddress(from, nick));
                // 设置收件人
                if (to != null && to.length() > 0) {
                    mimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
                }
                // 设置抄送人
                if (cc != null && cc.length() > 0) {
                    mimeMsg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
                }
                // 设置主题
                mimeMsg.setSubject(subject);
                // 设置正文
                BodyPart bp = new MimeBodyPart();
                bp.setContent(content, "text/html;charset=utf-8");
                mp.addBodyPart(bp);
                // 设置附件
                if (fileList != null && fileList.length > 0) {
                    for (int i = 0; i < fileList.length; i++) {
                        bp = new MimeBodyPart();
                        FileDataSource fds = new FileDataSource(fileList[i]);
                        bp.setDataHandler(new DataHandler(fds));
                        bp.setFileName(MimeUtility.encodeText(fds.getName(), "UTF-8", "B"));
                        mp.addBodyPart(bp);
                    }
                }
                mimeMsg.setContent(mp);
                mimeMsg.saveChanges();
                // 发送邮件
                if (props.get("mail.smtp.auth").equals("true")) {
                    Transport transport = session.getTransport("smtp");
                    transport.connect((String) props.get("mail.smtp.host"), (String) props.get("username"), (String) props.get("password"));
                    transport.sendMessage(mimeMsg, mimeMsg.getAllRecipients());
                    transport.close();
                } else {
                    Transport.send(mimeMsg);
                }
                System.out.println("邮件发送成功");
            } catch (MessagingException e) {
                e.printStackTrace();
                success = false;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                success = false;
            }
            return success;
        }
    
        public String getMailList(String[] mailArray) {
            StringBuffer toList = new StringBuffer();
            int length = mailArray.length;
            if (mailArray != null && length < 2) {
                toList.append(mailArray[0]);
            } else {
                for (int i = 0; i < length; i++) {
                    toList.append(mailArray[i]);
                    if (i != (length - 1)) {
                        toList.append(",");
                    }
    
                }
            }
            return toList.toString();
        }
    
        public static void main(String[] args) {
            String from = username;
            String[] to = {"[email protected]", "[email protected]"};
            String[] copyto = {"[email protected]"};
            String subject = "黑壳网数据库备份";
            String content = "没有数据就没有一切,数据库备份就是一种防范灾难于未然的强力手段,没有了数据,应用再花哨也是镜中花水中月。";
            String[] fileList = new String[2];
            fileList[0] = "~/solo_h2/db.mv.db";
            fileList[1] = "~/solo_h2/db.trace.db";
    
            EmailManager.getInstance().sendMail(from, to, copyto, subject, content, fileList);
        }
    }
    
    

    参考项目 GitHub

    参考项目 GitHub:https://github.com/ykz200/Quartz_DatabaseBackup

    junbaor
        1
    junbaor  
       2017-07-28 10:27:19 +08:00
    既然引用 spring 了,一个 @Scheduled 注解就搞定了,没必要配置繁琐的 Quartz
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6023 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:06 · PVG 10:06 · LAX 18:06 · JFK 21:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.