parent
bd6fac2394
commit
c9c2296d60
14 changed files with 908 additions and 79 deletions
@ -0,0 +1,53 @@ |
||||
package org.jeecg.modules.cms.webmagic.task; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.jeecg.common.util.DateUtils; |
||||
import org.jeecg.modules.cms.webmagic.service.NewsPageProcessor; |
||||
import org.jeecg.modules.cms.webmagic.service.NewsPipeline; |
||||
import org.quartz.*; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import us.codecraft.webmagic.Spider; |
||||
|
||||
/** |
||||
* @Description: 同步定时任务 |
||||
* <p> |
||||
* 此处的同步是指 当定时任务的执行时间大于任务的时间间隔时 |
||||
* 会等待第一个任务执行完成才会走第二个任务 |
||||
* @author: taoyan |
||||
* @date: 2020年06月19日 |
||||
*/ |
||||
@PersistJobDataAfterExecution |
||||
@DisallowConcurrentExecution |
||||
@Slf4j |
||||
public class NewsAsyncJob implements Job { |
||||
|
||||
@Autowired |
||||
private NewsPipeline pipeline; |
||||
|
||||
@Autowired |
||||
private NewsPageProcessor pageProcessor; |
||||
|
||||
@Override |
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
||||
log.info(" NewsAsyncJob Execution key:" + jobExecutionContext.getJobDetail().getKey()); |
||||
log.info(String.format("NewsAsyncJob-开始时间:" + DateUtils.getTimestamp())); |
||||
|
||||
String urlPage1 = "http://sie.huanghuai.edu.cn/index.php/item-list-category-13151.shtml"; |
||||
// String urlPageOther = "http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-";
|
||||
// String url = "";
|
||||
try { |
||||
Spider.create(pageProcessor) |
||||
.addUrl(urlPage1) |
||||
// 抓取到的数据存数据库
|
||||
.addPipeline(pipeline) |
||||
// 开启2个线程抓取
|
||||
.thread(1) |
||||
// 异步启动爬虫
|
||||
.start(); |
||||
} catch (Exception ex) { |
||||
log.error("数据抓取异常:", ex.getMessage()); |
||||
log.error("定时抓取数据线程执行异常", ex); |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,71 +1,71 @@ |
||||
package org.jeecg.modules.cms.webmagic.task; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.jeecg.modules.cms.webmagic.service.NewsPageProcessor; |
||||
import org.jeecg.modules.cms.webmagic.service.NewsPipeline; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.scheduling.annotation.Scheduled; |
||||
import org.springframework.stereotype.Component; |
||||
import us.codecraft.webmagic.Spider; |
||||
|
||||
@Slf4j |
||||
@Component |
||||
public class NewsWebMagicTask { |
||||
|
||||
@Autowired |
||||
private NewsPipeline pipeline; |
||||
|
||||
@Autowired |
||||
private NewsPageProcessor pageProcessor; |
||||
|
||||
// 每天23点执行一次
|
||||
@Scheduled(cron = "0 0 23 * * ?") |
||||
//@Scheduled(cron = "0 40 15 * * ?")
|
||||
// 每隔1分钟执行一次
|
||||
// @Scheduled(cron = "0 */3 * * * ?")
|
||||
public void crawl() { |
||||
//第1页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151.shtml
|
||||
//第2页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-2.html
|
||||
//第3页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-3.html
|
||||
// ......
|
||||
//第65页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-65.html
|
||||
|
||||
String urlPage1 = "http://sie.huanghuai.edu.cn/index.php/item-list-category-13151.shtml"; |
||||
String urlPageOther = "http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-"; |
||||
String url = ""; |
||||
try { |
||||
Spider.create(pageProcessor) |
||||
.addUrl(urlPage1) |
||||
// 抓取到的数据存数据库
|
||||
.addPipeline(pipeline) |
||||
// 开启2个线程抓取
|
||||
.thread(3) |
||||
// 异步启动爬虫
|
||||
.start(); |
||||
} catch (Exception ex) { |
||||
log.error("数据抓取异常:", ex.getMessage()); |
||||
log.error("定时抓取数据线程执行异常", ex); |
||||
} |
||||
// for (int i = 1; i <= 9; i++) {
|
||||
// if (i == 1) {
|
||||
// url = urlPage1;
|
||||
// } else {
|
||||
// url = urlPageOther + (i + 1) + ".html";
|
||||
// }
|
||||
// log.info("the page {} url:{}", i, url);
|
||||
// try {
|
||||
// Spider.create(pageProcessor)
|
||||
// .addUrl(url)
|
||||
// // 抓取到的数据存数据库
|
||||
// .addPipeline(pipeline)
|
||||
// // 开启2个线程抓取
|
||||
// .thread(3)
|
||||
// // 异步启动爬虫
|
||||
// .start();
|
||||
// } catch (Exception ex) {
|
||||
// log.error("第[{}]页数据抓取异常:", i, ex.getMessage());
|
||||
// log.error("定时抓取数据线程执行异常", ex);
|
||||
// }
|
||||
//package org.jeecg.modules.cms.webmagic.task;
|
||||
//
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.jeecg.modules.cms.webmagic.service.NewsPageProcessor;
|
||||
//import org.jeecg.modules.cms.webmagic.service.NewsPipeline;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.scheduling.annotation.Scheduled;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import us.codecraft.webmagic.Spider;
|
||||
//
|
||||
//@Slf4j
|
||||
//@Component
|
||||
//public class NewsWebMagicTask {
|
||||
//
|
||||
// @Autowired
|
||||
// private NewsPipeline pipeline;
|
||||
//
|
||||
// @Autowired
|
||||
// private NewsPageProcessor pageProcessor;
|
||||
//
|
||||
// // 每天23点执行一次
|
||||
//// @Scheduled(cron = "0 0 23 * * ?")
|
||||
// //@Scheduled(cron = "0 40 15 * * ?")
|
||||
// // 每隔1分钟执行一次
|
||||
//// @Scheduled(cron = "0 */3 * * * ?")
|
||||
// public void crawl() {
|
||||
// //第1页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151.shtml
|
||||
// //第2页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-2.html
|
||||
// //第3页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-3.html
|
||||
// // ......
|
||||
// //第65页 http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-65.html
|
||||
//
|
||||
// String urlPage1 = "http://sie.huanghuai.edu.cn/index.php/item-list-category-13151.shtml";
|
||||
// String urlPageOther = "http://sie.huanghuai.edu.cn/index.php/item-list-category-13151-page-";
|
||||
// String url = "";
|
||||
// try {
|
||||
// Spider.create(pageProcessor)
|
||||
// .addUrl(urlPage1)
|
||||
// // 抓取到的数据存数据库
|
||||
// .addPipeline(pipeline)
|
||||
// // 开启2个线程抓取
|
||||
// .thread(1)
|
||||
// // 异步启动爬虫
|
||||
// .start();
|
||||
// } catch (Exception ex) {
|
||||
// log.error("数据抓取异常:", ex.getMessage());
|
||||
// log.error("定时抓取数据线程执行异常", ex);
|
||||
// }
|
||||
} |
||||
} |
||||
//// for (int i = 1; i <= 9; i++) {
|
||||
//// if (i == 1) {
|
||||
//// url = urlPage1;
|
||||
//// } else {
|
||||
//// url = urlPageOther + (i + 1) + ".html";
|
||||
//// }
|
||||
//// log.info("the page {} url:{}", i, url);
|
||||
//// try {
|
||||
//// Spider.create(pageProcessor)
|
||||
//// .addUrl(url)
|
||||
//// // 抓取到的数据存数据库
|
||||
//// .addPipeline(pipeline)
|
||||
//// // 开启2个线程抓取
|
||||
//// .thread(3)
|
||||
//// // 异步启动爬虫
|
||||
//// .start();
|
||||
//// } catch (Exception ex) {
|
||||
//// log.error("第[{}]页数据抓取异常:", i, ex.getMessage());
|
||||
//// log.error("定时抓取数据线程执行异常", ex);
|
||||
//// }
|
||||
//// }
|
||||
// }
|
||||
//}
|
||||
|
@ -0,0 +1,22 @@ |
||||
package org.jeecg.modules.cms.webmagic.task; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.jeecg.common.util.DateUtils; |
||||
import org.quartz.Job; |
||||
import org.quartz.JobExecutionContext; |
||||
import org.quartz.JobExecutionException; |
||||
|
||||
/** |
||||
* 示例不带参定时任务 |
||||
* |
||||
* @Author Scott |
||||
*/ |
||||
@Slf4j |
||||
public class SampleJobTest implements Job { |
||||
|
||||
@Override |
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
||||
log.info(" >>>>>>>>SampleJobTest Execution key:"+jobExecutionContext.getJobDetail().getKey()); |
||||
log.info(String.format(" 普通定时任务 SampleJobTest,时间:" + DateUtils.getTimestamp())); |
||||
} |
||||
} |
@ -0,0 +1,283 @@ |
||||
package org.jeecg.modules.quartz.controller; |
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
||||
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||
import io.swagger.annotations.Api; |
||||
import io.swagger.annotations.ApiOperation; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.apache.shiro.SecurityUtils; |
||||
import org.jeecg.common.api.vo.Result; |
||||
import org.jeecg.common.constant.CommonConstant; |
||||
import org.jeecg.common.system.query.QueryGenerator; |
||||
import org.jeecg.common.system.vo.LoginUser; |
||||
import org.jeecg.common.util.ImportExcelUtil; |
||||
import org.jeecg.modules.quartz.entity.QuartzJob; |
||||
import org.jeecg.modules.quartz.service.IQuartzJobService; |
||||
import org.jeecgframework.poi.excel.ExcelImportUtil; |
||||
import org.jeecgframework.poi.excel.def.NormalExcelConstants; |
||||
import org.jeecgframework.poi.excel.entity.ExportParams; |
||||
import org.jeecgframework.poi.excel.entity.ImportParams; |
||||
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; |
||||
import org.quartz.Scheduler; |
||||
import org.quartz.SchedulerException; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.web.bind.annotation.*; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
import org.springframework.web.multipart.MultipartHttpServletRequest; |
||||
import org.springframework.web.servlet.ModelAndView; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @Description: 定时任务在线管理 |
||||
* @Author: jeecg-boot |
||||
* @Date: 2019-01-02 |
||||
* @Version:V1.0 |
||||
*/ |
||||
@RestController |
||||
@RequestMapping("/sys/quartzJob") |
||||
@Slf4j |
||||
@Api(tags = "定时任务接口") |
||||
public class QuartzJobController { |
||||
@Autowired |
||||
private IQuartzJobService quartzJobService; |
||||
@Autowired |
||||
private Scheduler scheduler; |
||||
|
||||
/** |
||||
* 分页列表查询 |
||||
* |
||||
* @param quartzJob |
||||
* @param pageNo |
||||
* @param pageSize |
||||
* @param req |
||||
* @return |
||||
*/ |
||||
@RequestMapping(value = "/list", method = RequestMethod.GET) |
||||
public Result<?> queryPageList(QuartzJob quartzJob, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, |
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) { |
||||
QueryWrapper<QuartzJob> queryWrapper = QueryGenerator.initQueryWrapper(quartzJob, req.getParameterMap()); |
||||
Page<QuartzJob> page = new Page<QuartzJob>(pageNo, pageSize); |
||||
IPage<QuartzJob> pageList = quartzJobService.page(page, queryWrapper); |
||||
return Result.ok(pageList); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 添加定时任务 |
||||
* |
||||
* @param quartzJob |
||||
* @return |
||||
*/ |
||||
//@RequiresRoles("admin")
|
||||
@RequestMapping(value = "/add", method = RequestMethod.POST) |
||||
public Result<?> add(@RequestBody QuartzJob quartzJob) { |
||||
quartzJobService.saveAndScheduleJob(quartzJob); |
||||
return Result.ok("创建定时任务成功"); |
||||
} |
||||
|
||||
/** |
||||
* 更新定时任务 |
||||
* |
||||
* @param quartzJob |
||||
* @return |
||||
*/ |
||||
//@RequiresRoles("admin")
|
||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST}) |
||||
public Result<?> eidt(@RequestBody QuartzJob quartzJob) { |
||||
try { |
||||
quartzJobService.editAndScheduleJob(quartzJob); |
||||
} catch (SchedulerException e) { |
||||
log.error(e.getMessage(), e); |
||||
return Result.error("更新定时任务失败!"); |
||||
} |
||||
return Result.ok("更新定时任务成功!"); |
||||
} |
||||
|
||||
/** |
||||
* 通过id删除 |
||||
* |
||||
* @param id |
||||
* @return |
||||
*/ |
||||
//@RequiresRoles("admin")
|
||||
@RequestMapping(value = "/delete", method = RequestMethod.DELETE) |
||||
public Result<?> delete(@RequestParam(name = "id", required = true) String id) { |
||||
QuartzJob quartzJob = quartzJobService.getById(id); |
||||
if (quartzJob == null) { |
||||
return Result.error("未找到对应实体"); |
||||
} |
||||
quartzJobService.deleteAndStopJob(quartzJob); |
||||
return Result.ok("删除成功!"); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 批量删除 |
||||
* |
||||
* @param ids |
||||
* @return |
||||
*/ |
||||
//@RequiresRoles("admin")
|
||||
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE) |
||||
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) { |
||||
if (ids == null || "".equals(ids.trim())) { |
||||
return Result.error("参数不识别!"); |
||||
} |
||||
for (String id : Arrays.asList(ids.split(","))) { |
||||
QuartzJob job = quartzJobService.getById(id); |
||||
quartzJobService.deleteAndStopJob(job); |
||||
} |
||||
return Result.ok("删除定时任务成功!"); |
||||
} |
||||
|
||||
/** |
||||
* 暂停定时任务 |
||||
* |
||||
* @param id |
||||
* @return |
||||
*/ |
||||
//@RequiresRoles("admin")
|
||||
@GetMapping(value = "/pause") |
||||
@ApiOperation(value = "停止定时任务") |
||||
public Result<Object> pauseJob(@RequestParam(name = "id") String id) { |
||||
QuartzJob job = quartzJobService.getById(id); |
||||
if (job == null) { |
||||
return Result.error("定时任务不存在!"); |
||||
} |
||||
quartzJobService.pause(job); |
||||
return Result.ok("停止定时任务成功"); |
||||
} |
||||
|
||||
/** |
||||
* 启动定时任务 |
||||
* |
||||
* @param id |
||||
* @return |
||||
*/ |
||||
//@RequiresRoles("admin")
|
||||
@GetMapping(value = "/resume") |
||||
@ApiOperation(value = "启动定时任务") |
||||
public Result<Object> resumeJob(@RequestParam(name = "id") String id) { |
||||
QuartzJob job = quartzJobService.getById(id); |
||||
if (job == null) { |
||||
return Result.error("定时任务不存在!"); |
||||
} |
||||
quartzJobService.resumeJob(job); |
||||
//scheduler.resumeJob(JobKey.jobKey(job.getJobClassName().trim()));
|
||||
return Result.ok("启动定时任务成功"); |
||||
} |
||||
|
||||
/** |
||||
* 通过id查询 |
||||
* |
||||
* @param id |
||||
* @return |
||||
*/ |
||||
@RequestMapping(value = "/queryById", method = RequestMethod.GET) |
||||
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) { |
||||
QuartzJob quartzJob = quartzJobService.getById(id); |
||||
return Result.ok(quartzJob); |
||||
} |
||||
|
||||
/** |
||||
* 导出excel |
||||
* |
||||
* @param request |
||||
* @param quartzJob |
||||
*/ |
||||
@RequestMapping(value = "/exportXls") |
||||
public ModelAndView exportXls(HttpServletRequest request, QuartzJob quartzJob) { |
||||
// Step.1 组装查询条件
|
||||
QueryWrapper<QuartzJob> queryWrapper = QueryGenerator.initQueryWrapper(quartzJob, request.getParameterMap()); |
||||
// Step.2 AutoPoi 导出Excel
|
||||
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); |
||||
List<QuartzJob> pageList = quartzJobService.list(queryWrapper); |
||||
// 导出文件名称
|
||||
mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表"); |
||||
mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class); |
||||
//获取当前登录用户
|
||||
//update-begin---author:wangshuai ---date:20211227 for:[JTC-116]导出人写死了------------
|
||||
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); |
||||
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:" + user.getRealname(), "导出信息")); |
||||
//update-end---author:wangshuai ---date:20211227 for:[JTC-116]导出人写死了------------
|
||||
mv.addObject(NormalExcelConstants.DATA_LIST, pageList); |
||||
return mv; |
||||
} |
||||
|
||||
/** |
||||
* 通过excel导入数据 |
||||
* |
||||
* @param request |
||||
* @param response |
||||
* @return |
||||
*/ |
||||
@RequestMapping(value = "/importExcel", method = RequestMethod.POST) |
||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws IOException { |
||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; |
||||
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap(); |
||||
// 错误信息
|
||||
List<String> errorMessage = new ArrayList<>(); |
||||
int successLines = 0, errorLines = 0; |
||||
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) { |
||||
// 获取上传文件对象
|
||||
MultipartFile file = entity.getValue(); |
||||
ImportParams params = new ImportParams(); |
||||
params.setTitleRows(2); |
||||
params.setHeadRows(1); |
||||
params.setNeedSave(true); |
||||
try { |
||||
List<Object> listQuartzJobs = ExcelImportUtil.importExcel(file.getInputStream(), QuartzJob.class, params); |
||||
//add-begin-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986
|
||||
// for(QuartzJob job: listQuartzJobs){
|
||||
// job.setStatus(CommonConstant.STATUS_DISABLE);
|
||||
// }
|
||||
List<String> list = ImportExcelUtil.importDateSave(listQuartzJobs, IQuartzJobService.class, errorMessage, CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME); |
||||
//add-end-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986
|
||||
errorLines += list.size(); |
||||
successLines += (listQuartzJobs.size() - errorLines); |
||||
} catch (Exception e) { |
||||
log.error(e.getMessage(), e); |
||||
return Result.error("文件导入失败!"); |
||||
} finally { |
||||
try { |
||||
file.getInputStream().close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
return ImportExcelUtil.imporReturnRes(errorLines, successLines, errorMessage); |
||||
} |
||||
|
||||
/** |
||||
* 立即执行 |
||||
* |
||||
* @param id |
||||
* @return |
||||
*/ |
||||
//@RequiresRoles("admin")
|
||||
@GetMapping("/execute") |
||||
public Result<?> execute(@RequestParam(name = "id", required = true) String id) { |
||||
QuartzJob quartzJob = quartzJobService.getById(id); |
||||
if (quartzJob == null) { |
||||
return Result.error("未找到对应实体"); |
||||
} |
||||
try { |
||||
quartzJobService.execute(quartzJob); |
||||
} catch (Exception e) { |
||||
//e.printStackTrace();
|
||||
log.info("定时任务 立即执行失败>>" + e.getMessage()); |
||||
return Result.error("执行失败!"); |
||||
} |
||||
return Result.ok("执行成功!"); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,84 @@ |
||||
package org.jeecg.modules.quartz.entity; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
import org.jeecg.common.aspect.annotation.Dict; |
||||
import org.jeecgframework.poi.excel.annotation.Excel; |
||||
import org.springframework.format.annotation.DateTimeFormat; |
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType; |
||||
import com.baomidou.mybatisplus.annotation.TableField; |
||||
import com.baomidou.mybatisplus.annotation.TableId; |
||||
import com.baomidou.mybatisplus.annotation.TableName; |
||||
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
||||
import lombok.Data; |
||||
|
||||
/** |
||||
* @Description: 定时任务在线管理 |
||||
* @Author: jeecg-boot |
||||
* @Date: 2019-01-02 |
||||
* @Version: V1.0 |
||||
*/ |
||||
@Data |
||||
@TableName("sys_quartz_job") |
||||
public class QuartzJob implements Serializable { |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
/** |
||||
* id |
||||
*/ |
||||
@TableId(type = IdType.ASSIGN_ID) |
||||
private String id; |
||||
/** |
||||
* 创建人 |
||||
*/ |
||||
private String createBy; |
||||
/** |
||||
* 创建时间 |
||||
*/ |
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") |
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
||||
private java.util.Date createTime; |
||||
/** |
||||
* 删除状态 |
||||
*/ |
||||
private Integer delFlag; |
||||
/** |
||||
* 修改人 |
||||
*/ |
||||
private String updateBy; |
||||
/** |
||||
* 修改时间 |
||||
*/ |
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") |
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
||||
private java.util.Date updateTime; |
||||
/** |
||||
* 任务类名 |
||||
*/ |
||||
@Excel(name = "任务类名", width = 40) |
||||
private String jobClassName; |
||||
/** |
||||
* cron表达式 |
||||
*/ |
||||
@Excel(name = "cron表达式", width = 30) |
||||
private String cronExpression; |
||||
/** |
||||
* 参数 |
||||
*/ |
||||
@Excel(name = "参数", width = 15) |
||||
private String parameter; |
||||
/** |
||||
* 描述 |
||||
*/ |
||||
@Excel(name = "描述", width = 40) |
||||
private String description; |
||||
/** |
||||
* 状态 0正常 -1停止 |
||||
*/ |
||||
@Excel(name = "状态", width = 15, dicCode = "quartz_status") |
||||
@Dict(dicCode = "quartz_status") |
||||
private Integer status; |
||||
|
||||
} |
@ -0,0 +1,35 @@ |
||||
package org.jeecg.modules.quartz.job; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.jeecg.common.util.DateUtils; |
||||
import org.quartz.*; |
||||
|
||||
/** |
||||
* @Description: 同步定时任务测试 |
||||
* |
||||
* 此处的同步是指 当定时任务的执行时间大于任务的时间间隔时 |
||||
* 会等待第一个任务执行完成才会走第二个任务 |
||||
* |
||||
* |
||||
* @author: taoyan |
||||
* @date: 2020年06月19日 |
||||
*/ |
||||
@PersistJobDataAfterExecution |
||||
@DisallowConcurrentExecution |
||||
@Slf4j |
||||
public class AsyncJob implements Job { |
||||
|
||||
@Override |
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
||||
log.info(" --- 同步任务调度开始 --- "); |
||||
try { |
||||
//此处模拟任务执行时间 5秒 任务表达式配置为每秒执行一次:0/1 * * * * ? *
|
||||
Thread.sleep(5000); |
||||
} catch (InterruptedException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
//测试发现 每5秒执行一次
|
||||
log.info(" --- 执行完毕,时间:"+DateUtils.now()+"---"); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,23 @@ |
||||
package org.jeecg.modules.quartz.job; |
||||
|
||||
import org.jeecg.common.util.DateUtils; |
||||
import org.quartz.Job; |
||||
import org.quartz.JobExecutionContext; |
||||
import org.quartz.JobExecutionException; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
|
||||
/** |
||||
* 示例不带参定时任务 |
||||
* |
||||
* @Author Scott |
||||
*/ |
||||
@Slf4j |
||||
public class SampleJob implements Job { |
||||
|
||||
@Override |
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
||||
log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey()); |
||||
log.info(String.format(" Jeecg-Boot 普通定时任务 SampleJob ! 时间:" + DateUtils.getTimestamp())); |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
package org.jeecg.modules.quartz.job; |
||||
|
||||
import org.jeecg.common.util.DateUtils; |
||||
import org.quartz.Job; |
||||
import org.quartz.JobExecutionContext; |
||||
import org.quartz.JobExecutionException; |
||||
|
||||
import lombok.extern.slf4j.Slf4j; |
||||
|
||||
/** |
||||
* 示例带参定时任务 |
||||
* |
||||
* @Author Scott |
||||
*/ |
||||
@Slf4j |
||||
public class SampleParamJob implements Job { |
||||
|
||||
/** |
||||
* 若参数变量名修改 QuartzJobController中也需对应修改 |
||||
*/ |
||||
private String parameter; |
||||
|
||||
public void setParameter(String parameter) { |
||||
this.parameter = parameter; |
||||
} |
||||
|
||||
@Override |
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
||||
log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey()); |
||||
log.info( String.format("welcome %s! Jeecg-Boot 带参数定时任务 SampleParamJob ! 时间:" + DateUtils.now(), this.parameter)); |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
package org.jeecg.modules.quartz.mapper; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.apache.ibatis.annotations.Param; |
||||
import org.jeecg.modules.quartz.entity.QuartzJob; |
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
||||
/** |
||||
* @Description: 定时任务在线管理 |
||||
* @Author: jeecg-boot |
||||
* @Date: 2019-01-02 |
||||
* @Version: V1.0 |
||||
*/ |
||||
public interface QuartzJobMapper extends BaseMapper<QuartzJob> { |
||||
|
||||
/** |
||||
* 根据jobClassName查询 |
||||
* @param jobClassName 任务类名 |
||||
* @return |
||||
*/ |
||||
public List<QuartzJob> findByJobClassName(@Param("jobClassName") String jobClassName); |
||||
|
||||
} |
@ -0,0 +1,9 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
<mapper namespace="org.jeecg.modules.quartz.mapper.QuartzJobMapper"> |
||||
|
||||
<!-- 根据jobClassName查询 --> |
||||
<select id="findByJobClassName" resultType="org.jeecg.modules.quartz.entity.QuartzJob"> |
||||
select * from sys_quartz_job where job_class_name = #{jobClassName} |
||||
</select> |
||||
</mapper> |
@ -0,0 +1,67 @@ |
||||
package org.jeecg.modules.quartz.service; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.jeecg.modules.quartz.entity.QuartzJob; |
||||
import org.quartz.SchedulerException; |
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService; |
||||
|
||||
/** |
||||
* @Description: 定时任务在线管理 |
||||
* @Author: jeecg-boot |
||||
* @Date: 2019-04-28 |
||||
* @Version: V1.1 |
||||
*/ |
||||
public interface IQuartzJobService extends IService<QuartzJob> { |
||||
|
||||
/** |
||||
* 通过类名寻找定时任务 |
||||
* @param jobClassName 类名 |
||||
* @return List<QuartzJob> |
||||
*/ |
||||
List<QuartzJob> findByJobClassName(String jobClassName); |
||||
|
||||
/** |
||||
* 保存定时任务 |
||||
* @param quartzJob |
||||
* @return boolean |
||||
*/ |
||||
boolean saveAndScheduleJob(QuartzJob quartzJob); |
||||
|
||||
/** |
||||
* 编辑定时任务 |
||||
* @param quartzJob |
||||
* @return boolean |
||||
* @throws SchedulerException |
||||
*/ |
||||
boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException; |
||||
|
||||
/** |
||||
* 删除定时任务 |
||||
* @param quartzJob |
||||
* @return boolean |
||||
*/ |
||||
boolean deleteAndStopJob(QuartzJob quartzJob); |
||||
|
||||
/** |
||||
* 恢复定时任务 |
||||
* @param quartzJob |
||||
* @return |
||||
*/ |
||||
boolean resumeJob(QuartzJob quartzJob); |
||||
|
||||
/** |
||||
* 执行定时任务 |
||||
* @param quartzJob |
||||
* @throws Exception |
||||
*/ |
||||
void execute(QuartzJob quartzJob) throws Exception; |
||||
|
||||
/** |
||||
* 暂停任务 |
||||
* @param quartzJob |
||||
* @throws SchedulerException |
||||
*/ |
||||
void pause(QuartzJob quartzJob); |
||||
} |
@ -0,0 +1,183 @@ |
||||
package org.jeecg.modules.quartz.service.impl; |
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.jeecg.common.constant.CommonConstant; |
||||
import org.jeecg.common.exception.JeecgBootException; |
||||
import org.jeecg.common.util.DateUtils; |
||||
import org.jeecg.modules.quartz.entity.QuartzJob; |
||||
import org.jeecg.modules.quartz.mapper.QuartzJobMapper; |
||||
import org.jeecg.modules.quartz.service.IQuartzJobService; |
||||
import org.quartz.*; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.stereotype.Service; |
||||
import org.springframework.transaction.annotation.Transactional; |
||||
|
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* @Description: 定时任务在线管理 |
||||
* @Author: jeecg-boot |
||||
* @Date: 2019-04-28 |
||||
* @Version: V1.1 |
||||
*/ |
||||
@Slf4j |
||||
@Service |
||||
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements IQuartzJobService { |
||||
@Autowired |
||||
private QuartzJobMapper quartzJobMapper; |
||||
@Autowired |
||||
private Scheduler scheduler; |
||||
|
||||
/** |
||||
* 立即执行的任务分组 |
||||
*/ |
||||
private static final String JOB_TEST_GROUP = "test_group"; |
||||
|
||||
@Override |
||||
public List<QuartzJob> findByJobClassName(String jobClassName) { |
||||
return quartzJobMapper.findByJobClassName(jobClassName); |
||||
} |
||||
|
||||
/** |
||||
* 保存&启动定时任务 |
||||
*/ |
||||
@Override |
||||
@Transactional(rollbackFor = JeecgBootException.class) |
||||
public boolean saveAndScheduleJob(QuartzJob quartzJob) { |
||||
// DB设置修改
|
||||
quartzJob.setDelFlag(CommonConstant.DEL_FLAG_0); |
||||
boolean success = this.save(quartzJob); |
||||
if (success) { |
||||
if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) { |
||||
// 定时器添加
|
||||
this.schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); |
||||
} |
||||
} |
||||
return success; |
||||
} |
||||
|
||||
/** |
||||
* 恢复定时任务 |
||||
*/ |
||||
@Override |
||||
@Transactional(rollbackFor = JeecgBootException.class) |
||||
public boolean resumeJob(QuartzJob quartzJob) { |
||||
schedulerDelete(quartzJob.getId()); |
||||
schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); |
||||
quartzJob.setStatus(CommonConstant.STATUS_NORMAL); |
||||
return this.updateById(quartzJob); |
||||
} |
||||
|
||||
/** |
||||
* 编辑&启停定时任务 |
||||
* @throws SchedulerException |
||||
*/ |
||||
@Override |
||||
@Transactional(rollbackFor = JeecgBootException.class) |
||||
public boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException { |
||||
if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) { |
||||
schedulerDelete(quartzJob.getId()); |
||||
schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); |
||||
}else{ |
||||
scheduler.pauseJob(JobKey.jobKey(quartzJob.getId())); |
||||
} |
||||
return this.updateById(quartzJob); |
||||
} |
||||
|
||||
/** |
||||
* 删除&停止删除定时任务 |
||||
*/ |
||||
@Override |
||||
@Transactional(rollbackFor = JeecgBootException.class) |
||||
public boolean deleteAndStopJob(QuartzJob job) { |
||||
schedulerDelete(job.getId()); |
||||
boolean ok = this.removeById(job.getId()); |
||||
return ok; |
||||
} |
||||
|
||||
@Override |
||||
public void execute(QuartzJob quartzJob) throws Exception { |
||||
String jobName = quartzJob.getJobClassName().trim(); |
||||
Date startDate = new Date(); |
||||
String ymd = DateUtils.date2Str(startDate,DateUtils.yyyymmddhhmmss.get()); |
||||
String identity = jobName + ymd; |
||||
//3秒后执行 只执行一次
|
||||
// update-begin--author:sunjianlei ---- date:20210511--- for:定时任务立即执行,延迟3秒改成0.1秒-------
|
||||
startDate.setTime(startDate.getTime() + 100L); |
||||
// update-end--author:sunjianlei ---- date:20210511--- for:定时任务立即执行,延迟3秒改成0.1秒-------
|
||||
// 定义一个Trigger
|
||||
SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder.newTrigger() |
||||
.withIdentity(identity, JOB_TEST_GROUP) |
||||
.startAt(startDate) |
||||
.build(); |
||||
// 构建job信息
|
||||
JobDetail jobDetail = JobBuilder.newJob(getClass(jobName).getClass()).withIdentity(identity).usingJobData("parameter", quartzJob.getParameter()).build(); |
||||
// 将trigger和 jobDetail 加入这个调度
|
||||
scheduler.scheduleJob(jobDetail, trigger); |
||||
// 启动scheduler
|
||||
scheduler.start(); |
||||
} |
||||
|
||||
@Override |
||||
@Transactional(rollbackFor = JeecgBootException.class) |
||||
public void pause(QuartzJob quartzJob){ |
||||
schedulerDelete(quartzJob.getId()); |
||||
quartzJob.setStatus(CommonConstant.STATUS_DISABLE); |
||||
this.updateById(quartzJob); |
||||
} |
||||
|
||||
/** |
||||
* 添加定时任务 |
||||
* |
||||
* @param jobClassName |
||||
* @param cronExpression |
||||
* @param parameter |
||||
*/ |
||||
private void schedulerAdd(String id, String jobClassName, String cronExpression, String parameter) { |
||||
try { |
||||
// 启动调度器
|
||||
scheduler.start(); |
||||
|
||||
// 构建job信息
|
||||
JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(id).usingJobData("parameter", parameter).build(); |
||||
|
||||
// 表达式调度构建器(即任务执行的时间)
|
||||
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); |
||||
|
||||
// 按新的cronExpression表达式构建一个新的trigger
|
||||
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(id).withSchedule(scheduleBuilder).build(); |
||||
|
||||
scheduler.scheduleJob(jobDetail, trigger); |
||||
} catch (SchedulerException e) { |
||||
throw new JeecgBootException("创建定时任务失败", e); |
||||
} catch (RuntimeException e) { |
||||
throw new JeecgBootException(e.getMessage(), e); |
||||
}catch (Exception e) { |
||||
throw new JeecgBootException("后台找不到该类名:" + jobClassName, e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 删除定时任务 |
||||
* |
||||
* @param id |
||||
*/ |
||||
private void schedulerDelete(String id) { |
||||
try { |
||||
scheduler.pauseTrigger(TriggerKey.triggerKey(id)); |
||||
scheduler.unscheduleJob(TriggerKey.triggerKey(id)); |
||||
scheduler.deleteJob(JobKey.jobKey(id)); |
||||
} catch (Exception e) { |
||||
log.error(e.getMessage(), e); |
||||
throw new JeecgBootException("删除定时任务失败"); |
||||
} |
||||
} |
||||
|
||||
private static Job getClass(String classname) throws Exception { |
||||
Class<?> class1 = Class.forName(classname); |
||||
return (Job) class1.newInstance(); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue