注:本文非基础教学类文章
首先工程用到的主要jar包
spring-batch-core-3.0.0.jar
quartz-2.1.6.jar
(一) quartz实现 实际开发过程中系统中肯定有任务管理模块,所以就按实际开发来写了
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.lang.StringUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 定时job操作service
*
* @author
* @create 2017年4月10日
*/
//@Service(version = "2.0",group = "",timeout = 3000000)
@Transactional
@SuppressWarnings("rawtypes")
public class JobService {
@Autowired
private QrtzTriggersMapper qrtzTriggersMapper;//任务DAO
@Autowired
private Scheduler scheduler;//定时器
/**
* 初始化执行调度任务
*/
@PostConstruct
public void initScheduler() {
try {
scheduler.start();
} catch (SchedulerException e) {
log.error("初始化调度任务失败:", e);
}
}
/**
* 获取job列表
*
* @param page
* @return
*/
@Override
public String loadSchedulers(Map<String,Object> map) {
Page<QrtzJobDetails> page = new Page<>(Integer.parseInt(map.get("row").toString()),
Integer.parseInt(map.get("page").toString()));
map.put("offset",page.getOffset());
map.put("pageSize",page.getPageSize());
List<QrtzJobDetails> list = schedulerJobMapper.loadSchedulers(map);
int count = schedulerJobMapper.loadSchedulerCount(map);
return JsonUtil.toJSONString(page.hold(list, count));
}
/**
* 解析jobDetail参数
*
* @param qrtzJobDetails
* @return
*/
// 将参数放入map
@SuppressWarnings("unchecked")
public Map getJobParams(QrtzJobDetails qrtzJobDetails) {
String classNamePath = null;
if (StringUtils.isEmpty(qrtzJobDetails.getJobClassPath())) {
classNamePath = "com.gomefinance.ecms.web.timer";// 任务类路径 没有选择的默认到该路径
} else {
classNamePath = qrtzJobDetails.getJobClassPath();
}
qrtzJobDetails.setJobClassName(classNamePath + "." + qrtzJobDetails.getJobClassName());
Map parameterMap = new HashMap();
String spitParamKey = "";
String spitParamValue = "";
String getParams[] = qrtzJobDetails.getParameterJson().replaceAll("\r|\n", "").split(";");
if (qrtzJobDetails.getParameterJson().length() > 0) {
for (String getParam : getParams) {
spitParamKey = getParam;
spitParamValue = getParam;
int idx = spitParamKey.indexOf(",");
spitParamKey = spitParamKey.substring(0, idx);
int idx1 = spitParamValue.indexOf(",");
spitParamValue = spitParamValue.substring(idx1 + 1, spitParamValue.length());
parameterMap.put(spitParamKey.trim(), spitParamValue.trim());
}
}
return parameterMap;
}
/**
* 新增计划
*
* @param param
* @return
*/
public String addControlTrigger(String param) {
QrtzTriggers qrtzqTriggers = JsonUtil.toAny(param,new TypeReference<QrtzTriggers>(){});
//验证时间间隔不能为空
if (",,,,,".equals(qrtzqTriggers.getTimeIntreval())) {
return JsonUtil.toJSONString(new EntityWrapperResponse(EnumSystem.FAIL, "执行计划的方式不能为空,请核对!"));
}
//查询数据库中 任务类名称不能和计划相同
QrtzJobDetails qrtzJobDetails = schedulerJobMapper.loadSchedulerByName(qrtzqTriggers.getTriggerName());
if (qrtzJobDetails != null) {
return JsonUtil.toJSONString(new EntityWrapperResponse(EnumSystem.FAIL, "计划名称不能与任务名称相同,请核对!"));
}
//一个任务相同计划执行时间只能添加一次!TODO
//计划名称不能重复
QrtzTriggersKey qrtzTriggersKey = new QrtzTriggersKey(qrtzqTriggers.getSchedName(),
qrtzqTriggers.getTriggerName(), qrtzqTriggers.getTriggerGroup());
QrtzTriggers qrtz = qrtzTriggersMapper.selectByPrimaryKey(qrtzTriggersKey);
if (qrtz != null) {
return JsonUtil.toJSONString(new EntityWrapperResponse(EnumSystem.FAIL, qrtzqTriggers.getTriggerName() + ",计划名称已经存在,请核对!"));
}
//新增计划
this.addTrigger(qrtzqTriggers);
return JsonUtil.toJSONString(new EntityWrapperResponse(EnumSystem.OK));
}
/**
* 根据JObName获取job
* @param jobName
* @return
*/
@Override
public QrtzJobDetails loadSchedulerByJobName(String jobName) {
return schedulerJobMapper.loadSchedulerByName(jobName);
}
/**
* 根据jobName获取计划列表
* @param map
* @return
*/
@Override
public String loadTrigger(Map<String,Object> map) {
Page<QrtzTriggers> page = new Page<>(Integer.parseInt(map.get("row").toString()),
Integer.parseInt(map.get("page").toString()));
map.put("offset",page.getOffset());
map.put("pageSize",page.getPageSize());
List<QrtzTriggers> list = qrtzTriggersMapper.selectByJobName(page.getOffset(),page.getPageSize(),String.valueOf(map.get("jobName")));
int count = qrtzTriggersMapper.selectCountByJobName(String.valueOf(map.get("jobName")));
return JsonUtil.toJSONString(page.hold(list,count));
}
@SuppressWarnings("unchecked")
public void addTrigger(QrtzTriggers qrtzqTriggers) {
try {
if (this.scheduler == null) {
return;
}
String schedJobGroup = qrtzqTriggers.getJobGroup();//任务分组,后期维护到数据字典中。
String schedTriggerGroup = qrtzqTriggers.getTriggerName();//触发器分组,后期维护到数据字典中。
JobKey jobKey = new JobKey(qrtzqTriggers.getJobName(), schedJobGroup);
TriggerBuilder tb = TriggerBuilder.newTrigger();
tb.withIdentity(qrtzqTriggers.getTriggerName(), schedTriggerGroup);
// 构建triggerBuilder
setTrigBuilder(qrtzqTriggers, tb);
tb.forJob(jobKey);
Trigger trig = tb.build();
this.scheduler.start();
this.scheduler.scheduleJob(trig);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("后台有错,错误【:" + e.getMessage() + "】,请检查!");
}
}
/***
* 设置触发器触发时间*
*
* @param qrtzqTriggers
* @param tb
* @throws ParseException
*/
private void setTrigBuilder(QrtzTriggers qrtzqTriggers, TriggerBuilder<Trigger> tb) throws ParseException {
int type = Integer.parseInt(qrtzqTriggers.getTriggerType());
String value[] = qrtzqTriggers.getTimeIntreval().split(",");
switch (type) {
case 1:
//执行一次次
excuteOnce(tb, value);
break;
case 2:
//每天某分钟执行
everyDayMinute(tb, value);
//this.addTrigger(qrtzqTriggers,Integer.parseInt(value[1]));
break;
case 3:
//每天某小时某分执行
everyDayHourMinue(tb, value);
break;
case 4:
//某周某小时某分执行
everyWeekHM(tb, value);
break;
case 5:
everyDayHM(tb, value);
break;
case 6: {
//cron表达式
char[] chars = qrtzqTriggers.getTimeIntreval().toCharArray();
String expression = "";
int k = 0;
for (int i = 0; i < chars.length; i++) {
if (k >= 5) {
expression += chars[i];
}
if (chars[i] == ',') {
k++;
}
}
try {
cronScheduler(tb, expression);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("cron表达式验证错误。");
}
}
}
}
/***
* 执行一次*
* @param tb
* @param value
*/
private void excuteOnce(TriggerBuilder<Trigger> tb, String[] value) {
Date date = DateUtils.convertString(value[0]);
tb.startAt(date);
tb.withDescription("执行一次,执行时间:" + DateUtils.getFormatedDate(date, "yyyy-MM-dd HH:mm:ss"));
}
/***
* 每天某分钟执行*
* @param tb
* @param value
*/
@SuppressWarnings("unchecked")
private void everyDayMinute(TriggerBuilder<Trigger> tb, String[] value) {
int minute = Integer.parseInt(value[1]);
ScheduleBuilder sb = CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInMinutes(minute);
tb.startNow();
tb.withSchedule(sb);
tb.withDescription("每:" + minute + "分钟执行!");
}
/***
* 每天某小时某分执行 *
* @param tb
* @param value
*/
@SuppressWarnings({"unchecked"})
private void everyWeekHM(TriggerBuilder<Trigger> tb, String[] value) throws BusinessException {
StringBuffer aryBuString = new StringBuffer();
@SuppressWarnings("unused")
String week = getValues(value, aryBuString);
//获得周
String getweek = getWeek(aryBuString);
//获得小时
String gethour = getHour(aryBuString);
String[] aryTime1 = gethour.split(":");
String h1 = aryTime1[0];
String m1 = aryTime1[1];
String cronExperssion = "0 " + m1 + " " + h1 + " ? * " + getweek;
ScheduleBuilder sb4 = null;
try {
sb4 = CronScheduleBuilder.cronSchedule(cronExperssion);
} catch (Exception e) {
log.error("CronScheduleBuilder.cronSchedule error", e);
throw new BusinessException(e.getMessage());
}
tb.startNow();
tb.withSchedule(sb4);
StringBuffer weekName = new StringBuffer();
for (int i = 0; i < getweek.split(",").length; i++) {
weekName.append(DateUtils.getWeek(Integer.parseInt(getweek.split(",")[i])) + ",");
}
String getWeekName = weekName.substring(0, weekName.length() - 1).toString();
tb.withDescription("每周:" + getWeekName + "," + h1 + ":" + m1 + "执行!");
}
/***
* 获得传入参数*
*
* @param value
* @param aryBuString
* @return
*/
private String getValues(String[] value, StringBuffer aryBuString) {
String week = "";
int aryLength = value.length;
for (int i = 0; i < aryLength; i++) {
week = value[i].toString();
if (!week.isEmpty()) {
aryBuString.append(value[i] + ",").toString();
}
}
return week;
}
/***
* 获得周*
*
* @param aryBuString
* @return
*/
private String getWeek(StringBuffer aryBuString) {
String getweek = aryBuString.toString();
getweek = getweek.substring(0, getweek.length() - 1);
int idx = getweek.lastIndexOf(",");
getweek = getweek.substring(0, idx);
return getweek;
}
/***
* 获得天*
*
* @param aryBuString
* @return
*/
private String getDays(StringBuffer aryBuString) {
String getDays = aryBuString.toString();
getDays = getDays.substring(0, getDays.length() - 1);
int idx = getDays.lastIndexOf(",");
getDays = getDays.substring(0, idx);
return getDays;
}
/***
* 获得小时*
*
* @param aryBuString
* @return
*/
private String getHour(StringBuffer aryBuString) {
String gethour = aryBuString.toString();
gethour = gethour.substring(0, gethour.length() - 1);
int idx1 = gethour.lastIndexOf(",");
gethour = gethour.substring(idx1 + 1, gethour.length());
return gethour;
}
/***
* 每天某小时某分执行*
*
* @param tb
* @param value
*/
@SuppressWarnings("unchecked")
private void everyDayHourMinue(TriggerBuilder<Trigger> tb, String[] value) {
String[] aryTime = value[2].split(":");
int hour = Integer.parseInt(aryTime[0]);
int m = Integer.parseInt(aryTime[1]);
ScheduleBuilder sb1 = CronScheduleBuilder.dailyAtHourAndMinute(hour, m);
tb.startNow();
tb.withSchedule(sb1);
tb.withDescription("每天:" + hour + ":" + m + "执行!");
}
@SuppressWarnings({"unchecked"})
private void everyDayHM(TriggerBuilder<Trigger> tb, String[] value) {
StringBuffer aryBuString = new StringBuffer();
@SuppressWarnings("unused")
String week = getValues(value, aryBuString);
//获得天
String getday = getDays(aryBuString);
//获得小时
String gethour = getHour(aryBuString);
String[] aryTime2 = gethour.split(":");
String h2 = aryTime2[0];
String m2 = aryTime2[1];
String cronExperssion1 = "0 " + m2 + " " + h2 + " " + getday + " * ?";
ScheduleBuilder sb5 = null;
try {
sb5 = CronScheduleBuilder.cronSchedule(cronExperssion1);
} catch (Exception e) {
log.error("CronScheduleBuilder.cronSchedule error", e);
}
tb.startNow();
tb.withSchedule(sb5);
String dayName = DateUtils.getDay(getday);
tb.withDescription("每月:" + dayName + "," + h2 + ":" + m2 + "执行!");
}
/***
* cron表达式*
*
* @param tb
* @param expression
*/
@SuppressWarnings({"unchecked"})
private void cronScheduler(TriggerBuilder<Trigger> tb, String expression) {
ScheduleBuilder sb6 = null;
try {
sb6 = CronScheduleBuilder.cronSchedule(expression);
} catch (Exception e) {
e.printStackTrace();
}
tb.startNow();
tb.withSchedule(sb6);
tb.withDescription("CronTrigger表达式:" + expression);
}
}
(二)实际的jod
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.stereotype.Component;
@Component
public class TestTimer extends QuartzScheduleBaseTimer {
private static final Logger logger = LoggerFactory.getLogger(AccountExportTimer.class);
@Override
public JobExecution doJob(JobDataMap dataMap, JobExecutionContext context)
throws Exception {
//实现
}
public CommonService getCommonService(){
return (CommonService)SpringContextHolder.getBean("commonService");
}
public Job getAccountExportJob(){
return (Job)SpringContextHolder.getBean("exportJob");
}
}
(三)spring batch
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
/**
* @ClassName:AccountExportJob
* @author:
* @Description:
* @date:2017年7月24日 下午4:46:23
*/
@Configuration
@EnableBatchProcessing
@EnableAutoConfiguration
public class TestJob {
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Autowired
private JobStepListener listener;
@Autowired
private JobListener jobListener;
/**
* 读数据
*
* @return
*/
@SuppressWarnings("rawtypes")
@Bean
public ItemReader testReader() {
return new testReader();
}
// 3.写数据
@SuppressWarnings("rawtypes")
@Bean
public ItemWriter testWriter() {
return new testWriter();
}
@Bean
public Job exportJob(JobBuilderFactory jobs, @Qualifier("testStep") Step testStep) {
return jobs.get("testJob")
.incrementer(new RunIdIncrementer())
.listener(jobListener)
.flow(accountExportStep)
.end()
.build();
}
@SuppressWarnings("unchecked")
@Bean
public Step testStep(StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("testStep")
.listener(listener)
.chunk(200)
.reader(testReader())
.writer(testWriter())
.faultTolerant()
.taskExecutor(new SimpleAsyncTaskExecutor())//设置并发方式执行
.throttleLimit(10)//并发任务数为 10,默认为4
.build();
}
@Bean
public JobExecutionListener listener() {
return new JobExecutionListenerSupport();
}
}
*********************************reader***************************************8
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
public class TestReader extends MyBatisPagingItemReader<AccountEntry> implements
StepExecutionListener {
private static final Logger logger = LoggerFactory.getLogger(AccountExportReader.class);
private StepExecution stepExecution;
@Autowired
private AccountEntryDataMapper accountEntryDataMapper;
public AccountExportReader() {
super();
super.setQueryId("1000");
setPageSize(10000);
}
@Autowired
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
// TODO Auto-generated method stub
return null;
}
@Override
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
@Override
protected void doReadPage() {
}
}
******************************************writer***********************************
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @ClassName:AccountExportWriter
* @author:
* @Description:
* @date:2017年7月24日 下午3:45:49
*/
public class TestWriter implements ItemWriter, StepExecutionListener {
private StepExecution stepExecution;
@Autowired
private AccountExportMapper accountExportMapper;
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
// TODO Auto-generated method stub
return null;
}
@Override
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
}