Spring+Quartz制作定时祝福短信
** 近些天接触了Spring和Quartz,且有朋友过几天要过生日,于是萌生了制作定时祝福短信的想法,在制作过程中遇到了很多的问题,最后幸运得以解决,这篇文章便是用来记录项目制作过程以及我在项目制作过程中遇到的一些bug和自己的心路历程,以后我也会通过文章来分享自己学习java过程中的一些感悟**。
1)申请腾讯云(或阿里云)短信服务功能,并拥有合适的祝福短信模板
2)准备开发工具idea
3)准备jar包(本次没有使用Maven,在这里因为jar包不全走了不少坑)
commons-codec-1.11.jar
commons-logging-1.1.1.jar
httpclient-4.5.3.jar
httpcore-4.4.6.jar
httpmime-4.5.3.jar
json-20170516.jar
log4j-1.2.16.jar
qcloudsms-1.0.6.jar
quartz-2.2.2.jar
quartz-jobs-2.2.2.jar
slf4j-api-1.7.7.jar
slf4j-log4j12-1.7.7.jar
spring-aop-4.3.9.RELEASE.jar
spring-beans-4.3.9.RELEASE.jar
spring-context-4.3.9.RELEASE.jar
spring-context-support-4.3.9.RELEASE.jar
spring-core-4.3.9.RELEASE.jar
spring-expression-4.3.9.RELEASE.jar
spring-tx-4.3.9.RELEASE.jar
4)准备记事本,要盖房子先打地基,在制作功能之前写好流程以及记录一闪而过的想法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd"
default-lazy-init="true">
<!--获取message.properties文件中的内容 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:message.properties</value>
</list>
</property>
</bean>
<!--搭建Job实体类-->
<bean id="scheduleJobEntity" class="com.phone.entity.Job">
<property name="jobid" value="job1"></property>
<property name="jobName" value="生日短信"></property>
<property name="cronExpression" value="${cronExpression}"></property>
</bean>
<!-- 搭建job,需要搭建1.任务类 2.任务属性 -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.phone.Job.Planjob"></property>
<property name="jobDataAsMap">
<map>
<entry key="scheduleJob">
<ref bean="scheduleJobEntity"></ref>
</entry>
</map>
</property>
</bean>
<!--搭建触发器,包括1.触发时间 2.job -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="cronExpression" value="#{scheduleJobEntity.cronExpression}"></property>
<property name="jobDetail" ref="jobDetail"></property>
</bean>
<!--搭建调度器 -->
<bean id="ScheduleFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" scope="prototype">
<property name="triggers">
<list>
<ref bean="cronTrigger"></ref>
</list>
</property>
</bean>
<bean id="PhoneService" class="com.phone.serviceImpl.phoneServiceImpl">
<property name="PhoneDao" ref="phoneDao"></property>
</bean>
<bean id="phoneDao" class="com.phone.DaoImpl.phoneDaoImpl">
</bean>
</beans>
代码如下(示例):
将cronExpression放在message.properties文件中传入applicationContext.xml文件,目的是后面通过IO流对cronExpression进行修改
cronExpression=40 54 15 27 3 ? *
yanzhengma.txt文件内容
MyName=ww
age=20
FriendName=ww
phoneNumber=111111111
``
package com.phone.entity;
public class Sms2 {
//用于设置短信验证码所需的各个参数
String phoneNumber;
String FriendName;
String age;
String MyName;
public Sms2() {
}
public Sms2(String phoneNumber, String friendName, String age, String myName) {
this.phoneNumber = phoneNumber;
FriendName = friendName;
this.age = age;
MyName = myName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getFriendName() {
return FriendName;
}
public void setFriendName(String friendName) {
FriendName = friendName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getMyName() {
return MyName;
}
public void setMyName(String myName) {
MyName = myName;
}
}
package com.phone.entity;
/**
* Description
* User:
* Date:
* Time:
*/
public class Job {
private String jobid;
private String jobName;
private String cronExpression;
public Job(String jobid, String jobName, String cronExpression) {
this.jobid = jobid;
this.jobName = jobName;
this.cronExpression = cronExpression;
}
public Job() {
}
public String getJobid() {
return jobid;
}
public void setJobid(String jobid) {
this.jobid = jobid;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
}
package com.phone.Dao;
import com.phone.entity.Sms2;
public interface phoneDao {
//发送短信
boolean SendPhoneMessage(Sms2 phoneMessage);
//输入信息
void inMessage();
//定时任务
void Send();
}
package com.phone.DaoImpl;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.phone.Dao.phoneDao;
import com.phone.entity.Sms2;
import org.quartz.impl.StdScheduler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.phone.entity.Job;
import java.io.*;
import java.util.Properties;
import java.util.Scanner;
public class phoneDaoImpl implements phoneDao {
static String str;
public boolean SendPhoneMessage(Sms2 sms) {
int appid = xxxxx;
String appkey = "xxxxxxxxxxxxxxxxx";
//验证码模板id
int templateId = xxxxx;
String smsSign = "xxxxxxx";
try {
String[] params = new String[]{
sms.getFriendName(),sms.getAge(),sms.getMyName()};
SmsSingleSender sender = new SmsSingleSender(appid, appkey);
SmsSingleSenderResult result = sender.sendWithParam("86",sms.getPhoneNumber(),templateId,params,smsSign,"","");
if (result.result == 0) {
return true;
} else {
return false;
}
//"86",手机号,templateId,params,smsSign,"",""
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public void inMessage(){
//在这里完成输入电话号码,名字等操作
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您好友的手机号:");
String phoneNumber = scanner.next();
System.out.println("请输入您将要生日的好友的名字:");
String FriendName = scanner.next();
System.out.println("请输入您好友的生日年龄:");
String age = scanner.next();
System.out.println("请输入您的名字");
String MyName = scanner.next();
try{
Properties properties2 = new Properties();
Writer writer = new FileWriter("UserMessage.txt");
properties2.setProperty("phoneNumber",phoneNumber);
properties2.setProperty("FriendName",FriendName);
properties2.setProperty("age",age);
properties2.setProperty("MyName",MyName);
properties2.store(writer,null);
writer.close();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("请输入定时发送消息的月份(1-12):");
String month = scanner.next();
while(Integer.valueOf(month)<1||Integer.valueOf(month)>12){
month = scanner.next();
}
System.out.println("请输入定时发送消息的日子(1-31):");
String day = scanner.next();
while(Integer.valueOf(day)<0||Integer.valueOf(day)>59){
day = scanner.next();
}
System.out.println("请输入定时发送消息的小时(0-23):");
String hour = scanner.next();
while(Integer.valueOf(hour)<0||Integer.valueOf(hour)>59){
hour = scanner.next();
}
System.out.println("请输入定时发送消息的分钟(0-59):");
String m = scanner.next();
while(Integer.valueOf(m)<0||Integer.valueOf(m)>59){
m = scanner.next();
}
System.out.println("请输入定时发送消息的秒数(0-59):");
String s = scanner.next();
while(Integer.valueOf(s)<0||Integer.valueOf(s)>59){
s = scanner.next();
}
str = s+" "+m+" "+hour+" "+day+" "+month+" "+"? *";
Properties properties = new Properties();
try{
Writer writer = new FileWriter("src/message.properties");
properties.setProperty("cronExpression",str);
properties.store(writer,null);
System.out.println(str);
writer.close();
Properties prop = new Properties();
Reader rd = new FileReader("src/message.properties");
prop.load(rd);
String cron = prop.getProperty("cronExpression");
System.out.println(cron);
rd.close();
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void Send() {
try{
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Job job=(Job)context.getBean("scheduleJobEntity");
job.setCronExpression(str);
StdScheduler schedule = (StdScheduler)context.getBean("ScheduleFactoryBean");
schedule.start();
}catch (Exception e){
e.printStackTrace();
}
}
}
package com.phone.service;
import com.phone.entity.Sms2;
public interface phoneService {
//发送短信
boolean SendPhoneMessage(Sms2 phoneMessage);
//输入信息并执行定时任务
void InMessageAndSend();
}
package com.phone.serviceImpl;
import com.phone.Dao.phoneDao;
import com.phone.entity.Sms2;
import com.phone.service.phoneService;
public class phoneServiceImpl implements phoneService {
phoneDao PhoneDao;
public void setPhoneDao(phoneDao PhoneDao) {
this.PhoneDao = PhoneDao;
}
@Override
public boolean SendPhoneMessage(Sms2 phonemessage) {
return PhoneDao.SendPhoneMessage(phonemessage);
}
@Override
public void InMessageAndSend() {
//该方法用于保证事物的原子性
//1.输入信息
PhoneDao.inMessage();
//2.执行定时任务
PhoneDao.Send();
}
}
执行发送短信任务
package com.phone.Job;
import com.phone.entity.Sms2;
import com.phone.service.phoneService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.*;
import java.util.Properties;
public class Planjob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
phoneService PhoneService = (phoneService)context.getBean("PhoneService");
//获取UserMessage.txt中的数据
BufferedReader outputStream = new BufferedReader(new FileReader("UserMessage.txt"));
Sms2 sms = new Sms2();
Properties prop = new Properties();
Reader rd = new FileReader("UserMessage.txt");
prop.load(rd);
String phoneNumber = prop.getProperty("phoneNumber");//通过键获得值
String FriendName = prop.getProperty("FriendName");
String age = prop.getProperty("age");
String MyName = prop.getProperty("MyName");
sms.setPhoneNumber(phoneNumber);
sms.setFriendName(FriendName);
sms.setAge(age);
sms.setMyName(MyName);
System.out.println(sms);
System.out.println(PhoneService);
PhoneService.SendPhoneMessage(sms);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.phone.Test;
import com.phone.service.phoneService;
import org.quartz.SchedulerException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) throws SchedulerException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
phoneService PhoneService = (phoneService)context.getBean("PhoneService");
PhoneService.InMessageAndSend();
}
}
解决:
引入json-20170516.jar,如果是Maven就不会出现这样的问题,Maven会自动引入相关依赖,在第一次引入jar的时候我只引入了qcloudsms-1.0.6.jar,因为jar包不全引发了很多问题
**
解决:
这里的问题因为没有报错曾让我迷茫,检查了代码和腾讯云的相关数据信息之后发现也没有错误,我意识到可能还是jar包问题,通过查阅资料,我发现在最初引入jar时少引入了 commons-codec-1.11.jar,httpclient-4.5.3.jar,httpcore-4.4.6.jar,httpmime-4.5.3.jar,所以还是Maven好啊
**
最初创建applicationContext.xml文件时在src下直接创建,message.properties文件也创建在src下,所以通过classpath:message.properties可以直接获取到,而使用字符流读取文件路径时Writer writer = new FileWriter(“message.properties”);,它去项目路径下寻找,发现找不到message.properties文件,于是又创建了一个message.properties文件,导致文件数据读写错误
解决:
修改为Writer writer = new FileWriter(“src/message.properties”);
原本思路,通过${cronExpression}动态传入message.properties文件中的cronExpression,用户输入的年月日等信息通过字符串拼接为cron表达式写入message.properties以此完成动态设置定时任务时间
<bean id="scheduleJobEntity" class="com.phone.entity.Job">
<property name="jobid" value="job1"></property>
<property name="jobName" value="生日短信"></property>
<property name="cronExpression" value="${cronExpression}"></property>
</bean>
message.properties
cronExpression=40 54 15 27 3 ? *
实现时发现,定时任务所遵循的cron表达式总是上次通过用户键盘输入获取的cron表达式,而不是本次通过用户键盘输入获取的cron表达式,而通过测试发现本次用户键盘输入获取的cron表达式已经被成功写入到message.properties中。
解决:
先注入job实体类,便于以后获取cronExpression相关信息,在开启定时任务时,重新获取cronExpression信息并对其进行更新
<bean id="scheduleJobEntity" class="com.phone.entity.Job">
<property name="jobid" value="job1"></property>
<property name="jobName" value="生日短信"></property>
<property name="cronExpression" value="${cronExpression}"></property>
</bean>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Job job=(Job)context.getBean("scheduleJobEntity");
job.setCronExpression(str);
StdScheduler schedule = (StdScheduler)context.getBean("ScheduleFactoryBean");
schedule.start();
做完这个功能感受到了自己对于Spring知识了解的不够以及对quartz的运用之不熟练,且某些地方代码过于冗余,通过此次功能制作,我真切的感受到了Maven的好处,并且我会将写项目前用记事本记录想法的好习惯保持下去。
在以后的学习路程中我会继续加强对于Spring体系的学习理解,如果以后有想做的功能我也会抓住机会利用所学知识实现。感谢您看到了这里,敬请指正。