mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-07-18 04:55:06 +08:00
1. 完成 Job 的 CRUD 功能
This commit is contained in:
@ -28,4 +28,8 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
|
||||
return selectList(new QueryWrapper<>());
|
||||
}
|
||||
|
||||
default T selectOne(String field, Object value) {
|
||||
return selectOne(new QueryWrapper<T>().eq(field, value));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,12 @@ import org.quartz.*;
|
||||
/**
|
||||
* {@link org.quartz.Scheduler} 的管理器,负责创建任务
|
||||
*
|
||||
* 考虑到实现的简洁性,我们使用 jobHandlerName 作为唯一标识,即:
|
||||
* 1. Job 的 {@link JobDetail#getKey()}
|
||||
* 2. Trigger 的 {@link Trigger#getKey()}
|
||||
*
|
||||
* 另外,jobHandlerName 对应到 Spring Bean 的名字,直接调用
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class SchedulerManager {
|
||||
@ -17,6 +23,15 @@ public class SchedulerManager {
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加 Job 到 Quartz 中
|
||||
*
|
||||
* @param jobId 任务编号
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @param jobHandlerParam 任务处理器的参数
|
||||
* @param cronExpression CRON 表达式
|
||||
* @throws SchedulerException 添加异常
|
||||
*/
|
||||
public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression)
|
||||
throws SchedulerException {
|
||||
// 创建 JobDetail 对象
|
||||
@ -30,6 +45,14 @@ public class SchedulerManager {
|
||||
scheduler.scheduleJob(jobDetail, trigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 Job 到 Quartz
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @param jobHandlerParam 任务处理器的参数
|
||||
* @param cronExpression CRON 表达式
|
||||
* @throws SchedulerException 更新异常
|
||||
*/
|
||||
public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression)
|
||||
throws SchedulerException {
|
||||
// 创建新 Trigger 对象
|
||||
@ -38,19 +61,45 @@ public class SchedulerManager {
|
||||
scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除 Quartz 中的 Job
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @throws SchedulerException 删除异常
|
||||
*/
|
||||
public void deleteJob(String jobHandlerName) throws SchedulerException {
|
||||
scheduler.deleteJob(new JobKey(jobHandlerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停 Quartz 中的 Job
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @throws SchedulerException 暂停异常
|
||||
*/
|
||||
public void pauseJob(String jobHandlerName) throws SchedulerException {
|
||||
scheduler.pauseJob(new JobKey(jobHandlerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 Quartz 中的 Job
|
||||
*
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @throws SchedulerException 启动异常
|
||||
*/
|
||||
public void resumeJob(String jobHandlerName) throws SchedulerException {
|
||||
scheduler.resumeJob(new JobKey(jobHandlerName));
|
||||
scheduler.resumeTrigger(new TriggerKey(jobHandlerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即触发一次 Quartz 中的 Job
|
||||
*
|
||||
* @param jobId 任务编号
|
||||
* @param jobHandlerName 任务处理器的名字
|
||||
* @param jobHandlerParam 任务处理器的参数
|
||||
* @throws SchedulerException 触发异常
|
||||
*/
|
||||
public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam)
|
||||
throws SchedulerException {
|
||||
JobDataMap data = new JobDataMap();
|
||||
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.dashboard.framework.quartz.core.util;
|
||||
|
||||
import org.quartz.CronExpression;
|
||||
|
||||
/**
|
||||
* Quartz Cron 表达式的工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class CronUtils {
|
||||
|
||||
/**
|
||||
* 校验 CRON 表达式是否有效
|
||||
*
|
||||
* @param cronExpression CRON 表达式
|
||||
* @return 是否有效
|
||||
*/
|
||||
public static boolean isValid(String cronExpression) {
|
||||
return CronExpression.isValidExpression(cronExpression);
|
||||
}
|
||||
|
||||
}
|
@ -10,7 +10,9 @@ import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobDO;
|
||||
import cn.iocoder.dashboard.modules.infra.service.job.InfJobService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -37,30 +39,55 @@ public class InfJobController {
|
||||
@PostMapping("/create")
|
||||
@ApiOperation("创建定时任务")
|
||||
@PreAuthorize("@ss.hasPermission('infra:job:create')")
|
||||
public CommonResult<Long> createJob(@Valid @RequestBody InfJobCreateReqVO createReqVO) {
|
||||
public CommonResult<Long> createJob(@Valid @RequestBody InfJobCreateReqVO createReqVO)
|
||||
throws SchedulerException {
|
||||
return success(jobService.createJob(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@ApiOperation("更新定时任务")
|
||||
@PreAuthorize("@ss.hasPermission('infra:job:update')")
|
||||
public CommonResult<Boolean> updateJob(@Valid @RequestBody InfJobUpdateReqVO updateReqVO) {
|
||||
public CommonResult<Boolean> updateJob(@Valid @RequestBody InfJobUpdateReqVO updateReqVO)
|
||||
throws SchedulerException {
|
||||
jobService.updateJob(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@ApiOperation("更新定时任务的状态")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class),
|
||||
@ApiImplicitParam(name = "status", value = "状态", required = true, example = "1", dataTypeClass = Integer.class),
|
||||
})
|
||||
@PreAuthorize("@ss.hasPermission('infra:job:update')")
|
||||
public CommonResult<Boolean> updateJobStatus(@RequestParam(value = "id") Long id, @RequestParam("status") Integer status)
|
||||
throws SchedulerException {
|
||||
jobService.updateJobStatus(id, status);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@ApiOperation("删除定时任务")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true)
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('infra:job:delete')")
|
||||
public CommonResult<Boolean> deleteJob(@RequestParam("id") Long id) {
|
||||
public CommonResult<Boolean> deleteJob(@RequestParam("id") Long id)
|
||||
throws SchedulerException {
|
||||
jobService.deleteJob(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/trigger")
|
||||
@ApiOperation("触发定时任务")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('infra:job:trigger')")
|
||||
public CommonResult<Boolean> triggerJob(@RequestParam("id") Long id) throws SchedulerException {
|
||||
jobService.triggerJob(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@ApiOperation("获得定时任务")
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
|
||||
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
|
||||
@PreAuthorize("@ss.hasPermission('infra:job:query')")
|
||||
public CommonResult<InfJobRespVO> getJob(@RequestParam("id") Long id) {
|
||||
InfJobDO job = jobService.getJob(id);
|
||||
|
@ -2,13 +2,9 @@ package cn.iocoder.dashboard.modules.infra.dal.dataobject.job;
|
||||
|
||||
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.dashboard.modules.infra.enums.job.InfJobStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -21,6 +17,9 @@ import java.util.Date;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class InfJobDO extends BaseDO {
|
||||
|
||||
/**
|
||||
@ -45,7 +44,6 @@ public class InfJobDO extends BaseDO {
|
||||
/**
|
||||
* 处理器的参数
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.IGNORED)
|
||||
private String handlerParam;
|
||||
|
||||
// ========== 时间相关字段 ==========
|
||||
|
@ -18,6 +18,10 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface InfJobMapper extends BaseMapperX<InfJobDO> {
|
||||
|
||||
default InfJobDO selectByHandlerName(String handlerName) {
|
||||
return selectOne("handler_name", handlerName);
|
||||
}
|
||||
|
||||
default PageResult<InfJobDO> selectPage(InfJobPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new QueryWrapperX<InfJobDO>()
|
||||
.likeIfPresent("name", reqVO.getName())
|
||||
|
@ -17,5 +17,10 @@ public interface InfErrorCodeConstants {
|
||||
|
||||
// ========== 定时任务 1001001000 ==========
|
||||
ErrorCode JOB_NOT_EXISTS = new ErrorCode(1001001000, "定时任务不存在");
|
||||
ErrorCode JOB_HANDLER_EXISTS = new ErrorCode(1001001001, "定时任务的处理器已经存在");
|
||||
ErrorCode JOB_CHANGE_STATUS_INVALID = new ErrorCode(1001001002, "只允许修改为开启或者关闭状态");
|
||||
ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1001001003, "定时任务已经处于该状态,无需修改");
|
||||
ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1001001004, "只有开启状态的任务,才可以修改");
|
||||
ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1001001005, "CRON 表达式不正确");
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobExportReqV
|
||||
import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobPageReqVO;
|
||||
import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobUpdateReqVO;
|
||||
import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobDO;
|
||||
import org.quartz.SchedulerException;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
@ -24,21 +25,36 @@ public interface InfJobService {
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createJob(@Valid InfJobCreateReqVO createReqVO);
|
||||
Long createJob(@Valid InfJobCreateReqVO createReqVO) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* 更新定时任务
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateJob(@Valid InfJobUpdateReqVO updateReqVO);
|
||||
void updateJob(@Valid InfJobUpdateReqVO updateReqVO) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* 更新定时任务的状态
|
||||
*
|
||||
* @param id 任务编号
|
||||
* @param status 状态
|
||||
*/
|
||||
void updateJobStatus(Long id, Integer status) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* 触发定时任务
|
||||
*
|
||||
* @param id 任务编号
|
||||
*/
|
||||
void triggerJob(Long id) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* 删除定时任务
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deleteJob(Long id);
|
||||
void deleteJob(Long id) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* 获得定时任务
|
||||
|
@ -1,7 +1,8 @@
|
||||
package cn.iocoder.dashboard.modules.infra.service.job.impl;
|
||||
|
||||
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||
import cn.iocoder.dashboard.framework.quartz.core.scheduler.SchedulerManager;
|
||||
import cn.iocoder.dashboard.framework.quartz.core.util.CronUtils;
|
||||
import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobCreateReqVO;
|
||||
import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobExportReqVO;
|
||||
import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobPageReqVO;
|
||||
@ -9,15 +10,20 @@ import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobUpdateReqV
|
||||
import cn.iocoder.dashboard.modules.infra.convert.job.InfJobConvert;
|
||||
import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobDO;
|
||||
import cn.iocoder.dashboard.modules.infra.dal.mysql.job.InfJobMapper;
|
||||
import cn.iocoder.dashboard.modules.infra.enums.job.InfJobStatusEnum;
|
||||
import cn.iocoder.dashboard.modules.infra.service.job.InfJobService;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.JOB_NOT_EXISTS;
|
||||
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*;
|
||||
import static cn.iocoder.dashboard.util.collection.CollectionUtils.containsAny;
|
||||
|
||||
/**
|
||||
* 定时任务 Service 实现类
|
||||
@ -31,41 +37,109 @@ public class InfJobServiceImpl implements InfJobService {
|
||||
@Resource
|
||||
private InfJobMapper jobMapper;
|
||||
|
||||
@Resource
|
||||
private SchedulerManager schedulerManager;
|
||||
|
||||
@Override
|
||||
public Long createJob(InfJobCreateReqVO createReqVO) {
|
||||
@Transactional
|
||||
public Long createJob(InfJobCreateReqVO createReqVO) throws SchedulerException {
|
||||
validateCronExpression(createReqVO.getCronExpression());
|
||||
// 校验唯一性
|
||||
if (jobMapper.selectByHandlerName(createReqVO.getHandlerName()) != null) {
|
||||
throw exception(JOB_HANDLER_EXISTS);
|
||||
}
|
||||
// 插入
|
||||
InfJobDO job = InfJobConvert.INSTANCE.convert(createReqVO);
|
||||
if (job.getMonitorTimeout() == null) {
|
||||
job.setMonitorTimeout(0);
|
||||
}
|
||||
job.setStatus(InfJobStatusEnum.INIT.getStatus());
|
||||
fillJobMonitorTimeoutEmpty(job);
|
||||
jobMapper.insert(job);
|
||||
|
||||
// 添加 Job 到 Quartz 中
|
||||
schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression());
|
||||
// 更新
|
||||
InfJobDO updateObj = InfJobDO.builder().id(job.getId()).status(InfJobStatusEnum.NORMAL.getStatus()).build();
|
||||
jobMapper.updateById(updateObj);
|
||||
|
||||
// 返回
|
||||
return job.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateJob(InfJobUpdateReqVO updateReqVO) {
|
||||
@Transactional
|
||||
public void updateJob(InfJobUpdateReqVO updateReqVO) throws SchedulerException {
|
||||
validateCronExpression(updateReqVO.getCronExpression());
|
||||
// 校验存在
|
||||
this.validateJobExists(updateReqVO.getId());
|
||||
InfJobDO job = this.validateJobExists(updateReqVO.getId());
|
||||
// 只有开启状态,才可以修改.原因是,如果出暂停状态,修改 Quartz Job 时,会导致任务又开始执行
|
||||
if (!job.getStatus().equals(InfJobStatusEnum.NORMAL.getStatus())) {
|
||||
throw exception(JOB_UPDATE_ONLY_NORMAL_STATUS);
|
||||
}
|
||||
// 更新
|
||||
InfJobDO updateObj = InfJobConvert.INSTANCE.convert(updateReqVO);
|
||||
if (updateObj.getMonitorTimeout() == null) {
|
||||
updateObj.setMonitorTimeout(0);
|
||||
}
|
||||
fillJobMonitorTimeoutEmpty(updateObj);
|
||||
jobMapper.updateById(updateObj);
|
||||
|
||||
// 更新 Job 到 Quartz 中
|
||||
schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteJob(Long id) {
|
||||
@Transactional
|
||||
public void updateJobStatus(Long id, Integer status) throws SchedulerException {
|
||||
// 校验 status
|
||||
if (!containsAny(status, InfJobStatusEnum.NORMAL.getStatus(), InfJobStatusEnum.STOP.getStatus())) {
|
||||
throw exception(JOB_CHANGE_STATUS_INVALID);
|
||||
}
|
||||
// 校验存在
|
||||
this.validateJobExists(id);
|
||||
// 更新
|
||||
jobMapper.deleteById(id);
|
||||
InfJobDO job = this.validateJobExists(id);
|
||||
// 校验是否已经为当前状态
|
||||
if (job.getStatus().equals(status)) {
|
||||
throw exception(JOB_CHANGE_STATUS_EQUALS);
|
||||
}
|
||||
// 更新 Job 状态
|
||||
InfJobDO updateObj = InfJobDO.builder().id(id).status(status).build();
|
||||
jobMapper.updateById(updateObj);
|
||||
|
||||
// 更新状态 Job 到 Quartz 中
|
||||
if (InfJobStatusEnum.NORMAL.getStatus().equals(status)) { // 开启
|
||||
schedulerManager.resumeJob(job.getHandlerName());
|
||||
} else { // 暂停
|
||||
schedulerManager.pauseJob(job.getHandlerName());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateJobExists(Long id) {
|
||||
if (jobMapper.selectById(id) == null) {
|
||||
throw ServiceExceptionUtil.exception(JOB_NOT_EXISTS);
|
||||
@Override
|
||||
public void triggerJob(Long id) throws SchedulerException {
|
||||
// 校验存在
|
||||
InfJobDO job = this.validateJobExists(id);
|
||||
|
||||
// 触发 Quartz 中的 Job
|
||||
schedulerManager.triggerJob(job.getId(), job.getHandlerName(), job.getHandlerParam());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteJob(Long id) throws SchedulerException {
|
||||
// 校验存在
|
||||
InfJobDO job = this.validateJobExists(id);
|
||||
// 更新
|
||||
jobMapper.deleteById(id);
|
||||
|
||||
// 删除 Job 到 Quartz 中
|
||||
schedulerManager.deleteJob(job.getHandlerName());
|
||||
}
|
||||
|
||||
private InfJobDO validateJobExists(Long id) {
|
||||
InfJobDO job = jobMapper.selectById(id);
|
||||
if (job == null) {
|
||||
throw exception(JOB_NOT_EXISTS);
|
||||
}
|
||||
return job;
|
||||
}
|
||||
|
||||
private void validateCronExpression(String cronExpression) {
|
||||
if (CronUtils.isValid(cronExpression)) {
|
||||
throw exception(JOB_CRON_EXPRESSION_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,4 +163,10 @@ public class InfJobServiceImpl implements InfJobService {
|
||||
return jobMapper.selectList(exportReqVO);
|
||||
}
|
||||
|
||||
private static void fillJobMonitorTimeoutEmpty(InfJobDO job) {
|
||||
if (job.getMonitorTimeout() == null) {
|
||||
job.setMonitorTimeout(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class CollectionUtils {
|
||||
|
||||
public static boolean containsAny(Object source, Object... targets) {
|
||||
return Arrays.asList(targets).contains(source);
|
||||
}
|
||||
|
||||
public static boolean isAnyEmpty(Collection<?>... collections) {
|
||||
return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
|
||||
}
|
||||
|
Reference in New Issue
Block a user