需求
根据不同的生日日期,在生日当天发送一个祝福邮件,这是需要做到两个事情
- 定时,根据生日定时到每年的那一天
- 发送邮件
定时发送
要想做到定时发送,这时就需要一个定时任务调度的工具,这里使用的是Quartz
Quartz是一个定时任务调度框架,主要包含三个部分,Schedule(调度器)、
JobDetail(任务)CronTrigger(触发器)
- Scheduler
调度器主要是调度调度规则,在规则下启动任务
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
- CronTrigger
触发器中可以设置任务的触发规则
主要属性:
startNow():设置起始时间为即时启动
**withSchedule:**设置任务的执行规律和执行次数
withIntervalInSecos() :每隔多长时间执行,时间单位是秒
repeatForever():持续循环执行,直到结束
endAt: 触发器的结束时间
因为使用的是CronTrigger,所以时间表达式按照cron的规则
依次为(秒 分 时 日 月 星期 (年(可选)))
特殊符号:
**,**并列
- 区间,范围
/ 间隔,从起始点间隔多长时间
***** 任意值
**?**不确定值SimpleTrigger trigger = TriggerBuilder.newTrigger() trigger.startNow(); trigger.withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) //每秒执行一次 .repeatForever()); trigger.endAt(new Date(120,8,3,12,45,0))
- JobDetial
创建新任务要实现Job接口,重写execute方法
public class Myjob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// System.out.println("执行方法");
}
}
最后要将任务和触发器交给调度器调度
Trigger trigger = triggerBuilder.build();
//将任务交给触发器
JobDetail job =JobBuilder.newJob(Myjob.class).build();
//将触发器交给调度器
scheduler.scheduleJob(job,trigger);
//启动调度器
scheduler.start();
配置式
调度器:ScheduleFacrotyBean
任务:JobDetailFactoryBean
触发器:CronTriggerFactoryBean
<!--配置任务-->
<bean name="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="name" value="myjob"/>
<property name="group" value="mygroup"/>
<property name="jobClass" value="quartz.MyJob3"/>
</bean>
<!--配置调度规则-->
<bean name="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="cronExpression" value="* * * * * ?"/>
</bean>
<!--配置调度器-->
<bean name="" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger"></ref>
</list>
</property>
</bean>
注解式
要使用注解,首先要扫描目标文件,获取注解解析器
<context:component-scan base-package="quartz"/>
<task:annotation-driven/>
使用@Schedule注解
发送邮件
导入相关的jar包:
想要发送邮件,首先要有一个邮件平台 比如腾讯、新浪,并且要开启邮箱的授权码,获得授权码之后才能进行自动转发
public static void sendMessage() throws MessagingException {
//设置邮箱服务器类型
String host = "smtp.qq.com";
//设置第三方登录使用验证码
String auth = "xxxxxxxxx";
//设置发件人
Stirng form="xxxxx@qq.com";
//设置收件人
String to="xxxxxx@qq.com";
//获取本地系统参数
Properties properties=System.getProperties();
//设置邮件服务器地址
properties.setProperty("mail.smtp.host",host);
//告诉邮件客户端,本次请求是需要认证的
properties.put("mail.smtp.auth", "true");
//获取邮件服务器连接
Session session=Session.getDefaultInstance(properties, new Authenticator() {
@Override
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(from,auth);
}
});
//组装邮件内容
MimeMessage message = new MimeMessage(session);
//发送人
message.setFrom(new InternetAddress(from));
//接收人
message.addRecipient(MimeMessage.RecipientType.TO,new InternetAddress(to));
//邮件主题
message.setSubject(subject);
//邮件内容
message.setText(context);
//发送邮件
Transport.send(message);
System.out.println("发送成功");
}
实现
分别实现了定时任务调度和自动转发邮件之后,就可以将自动转发当做一个Job,通过CronTrigger的表达式设置生日,进行定时转发
这里采用配置式,方便对任务的分组和批量管理
将自动发送邮件作为任务
public class MyJob3 implements Job{
@Autowired
private UserDao userDao;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Calendar calendar=Calendar.getInstance();
int birth_year=calendar.get(Calendar.YEAR);
int birth_month=calendar.get(Calendar.MONTH)+1;
int birth_day=calendar.get(Calendar.DAY_OF_MONTH);
User u=new User();
u.setBirth_year(birth_year);
u.setBirth_month(birth_month);
u.setBirth_day(birth_day);
List<User> users = userDao.selectUserByBirthday(u);
for (User user : users) {
String from ="xxxxxxxx@qq.com";
String to=user.getEmail();
String subject="生日祝福";
String context="今天是您"+(birth_year-user.getBirth_year()+1)+"的生日,祝你生日快乐";
try {
SendMessage.sendMessage(from,to,subject,context);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
}
//调用SendMessage方法
public class SendMessage{
public static void sendMessage(String from,String to,String subject,String context) throws MessagingException {
//设置邮箱服务器类型
String host = "smtp.qq.com";
//设置第三方登录使用验证码
String auth = "xxxxxxxxxxx";
//获取本地系统参数
Properties properties=System.getProperties();
//设置邮件服务器地址
properties.setProperty("mail.smtp.host",host);
//告诉邮件客户端,本次请求是需要认证的
properties.put("mail.smtp.auth", "true");
//获取邮件服务器连接
Session session=Session.getDefaultInstance(properties, new Authenticator() {
@Override
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(from,auth);
}
});
//组装邮件内容
MimeMessage message = new MimeMessage(session);
//发送人
message.setFrom(new InternetAddress(from));
//接收人
message.addRecipient(MimeMessage.RecipientType.TO,new InternetAddress(to));
//邮件主题
message.setSubject(subject);
//邮件内容
message.setText(context);
//发送邮件
Transport.send(message);
System.out.println("发送成功");
}
}
配置文件
因为生日是从数据库中读取的,使用到了ssm框架进行整合
在spring配置文件中配置定时任务调度
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置任务-->
<bean name="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="name" value="myjob"/>
<property name="group" value="mygroup"/>
<property name="jobClass" value="quartz.MyJob3"/>
</bean>
<!--配置调度规则-->
<bean name="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="cronExpression" value="0 0 6 * * ?"/>
</bean>
<!--配置调度器-->
<bean name="" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger"></ref>
</list>
</property>
</bean>
<!-- 配置数据库配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${url}"/>
<property name="username" value="${jdbc.userName}"/>
<property name="password" value="${password}"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath*:Dao/*.xml"/>
</bean>
<mybatis:scan base-package="Dao"/>
</beans>
为了方便对任务调度器的管理,可以根据任务的分组和命名进行管理和批量操作,可以在Controller层,通过页面请求
对Schedule进行操作
停止
Schedule.pauseJob()
scheduler.pauseJob(JobKey.jobKey("jobName","groupName"))
重新开始
Schedule.resumeJob()
scheduler.resumeJon(JobKey.jobKey("jobName","groupName"))
删除
Schedule.deleteJob()
scheduler.deleteJob(JobKey.jobKey("jobName","groupName"))
问题:
在数据库映射数据时,数据库的生日字段使用的是data类型的存储方式,在映射的过程中可能会出现下面的错误
异常:
原因:Druid版本低,造成字段映射失败,主要是德鲁伊不支持该类型的字段映射
解决:
-
更新德鲁伊的版本,下载对应的映射包
-
或者将生日字段分开;
在设置日期是可以使用Calendar获取设置时间:
Calendar calendar=Calendar.getInstance();
//获取int型的年份
int birth_year=calendar.get(Calendar.YEAR);
//获取int型的月份(0-11)
int birth_month=calendar.get(Calendar.MONTH)+1;
//获取对应月份的日(自动区分日期)
int birth_day=calendar.get(Calendar.DAY_OF_MONTH);