diff --git a/fuintBackend/fuint-application/pom.xml b/fuintBackend/fuint-application/pom.xml index 04724c120..d6ba80849 100644 --- a/fuintBackend/fuint-application/pom.xml +++ b/fuintBackend/fuint-application/pom.xml @@ -23,6 +23,11 @@ fuint-framework 1.0.0 + + com.fuint + fuint-quartz + 1.0.0 + io.sentry sentry-logback diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/module/backendApi/controller/BackendStoreController.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/controller/BackendStoreController.java similarity index 99% rename from fuintBackend/fuint-application/src/main/java/com/fuint/module/backendApi/controller/BackendStoreController.java rename to fuintBackend/fuint-application/src/main/java/com/fuint/business/store/controller/BackendStoreController.java index 8ee51c572..1806091d4 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/module/backendApi/controller/BackendStoreController.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/controller/BackendStoreController.java @@ -1,4 +1,4 @@ -package com.fuint.module.backendApi.controller; +package com.fuint.business.store.controller; import com.fuint.common.util.Constants; import com.fuint.common.dto.AccountInfo; diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/controller/ChainStoreInfoController.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/controller/ChainStoreInfoController.java index 483b22610..0e541e974 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/controller/ChainStoreInfoController.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/controller/ChainStoreInfoController.java @@ -3,6 +3,7 @@ package com.fuint.business.store.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 com.fuint.business.store.entity.ChainStoreInfo; import com.fuint.business.store.service.ChainStoreInfoService; @@ -32,13 +33,15 @@ public class ChainStoreInfoController extends BaseController { /** * 分页查询所有数据 * - * @param page 分页对象 * @param chainStoreInfo 查询实体 * @return 所有数据 */ @GetMapping - public ResponseObject selectAll(Page page, ChainStoreInfo chainStoreInfo) { - return getSuccessResult(this.chainStoreInfoService.page(page, new QueryWrapper<>(chainStoreInfo))); + public ResponseObject selectAll(ChainStoreInfo chainStoreInfo,@RequestParam("pageNo") Integer pageNo, + @RequestParam("pageSize") Integer pageSize) { + Page page =new Page(pageNo,pageSize); + IPage res =this.chainStoreInfoService.listVo(page, chainStoreInfo); + return getSuccessResult(res); } /** diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/entity/ChainStoreInfo.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/entity/ChainStoreInfo.java index a1dc04bb9..7d78acb8d 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/entity/ChainStoreInfo.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/entity/ChainStoreInfo.java @@ -3,11 +3,14 @@ package com.fuint.business.store.entity; import java.util.Date; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.extension.activerecord.Model; +import com.fuint.repository.model.base.BaseEntity; import lombok.Data; import java.io.Serializable; +import java.util.List; /** * (ChainStoreInfo)表实体类 @@ -16,23 +19,18 @@ import java.io.Serializable; * @since 2023-10-11 13:17:02 */ @Data -public class ChainStoreInfo extends Model { +public class ChainStoreInfo extends BaseEntity { //主键 @TableId(type = IdType.AUTO) private Integer id; //连锁店名称 private String storeName; - //总店联系方式 - private String storePhone; private Long contractDeptId; - //创建时间 - private Date createTime; - //创建人 - private String createBy; - //更新时间 - private Date updateTime; - //更新人 - private String updateBy; - + @TableField(exist = false) + private String leaderName; + @TableField(exist = false) + private String leaderPhone; + @TableField(exist = false) + private List storeList; } diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/ChainStoreInfoMapper.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/ChainStoreInfoMapper.java index 75ebef240..0879d6874 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/ChainStoreInfoMapper.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/ChainStoreInfoMapper.java @@ -1,7 +1,10 @@ package com.fuint.business.store.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fuint.business.store.entity.ChainStoreInfo; +import org.apache.ibatis.annotations.Param; /** * (ChainStoreInfo)表数据库访问层 @@ -11,5 +14,6 @@ import com.fuint.business.store.entity.ChainStoreInfo; */ public interface ChainStoreInfoMapper extends BaseMapper { + IPage listVo(Page page, @Param("chainStoreInfo") ChainStoreInfo chainStoreInfo,@Param("ownDeptStr") String ownDeptStr); } diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/xml/ChainStoreInfoMapper.xml b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/xml/ChainStoreInfoMapper.xml index db07839ef..23f43c895 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/xml/ChainStoreInfoMapper.xml +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/mapper/xml/ChainStoreInfoMapper.xml @@ -3,4 +3,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + \ No newline at end of file diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/ChainStoreInfoService.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/ChainStoreInfoService.java index 9fdd76c37..fc5de1221 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/ChainStoreInfoService.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/ChainStoreInfoService.java @@ -1,5 +1,7 @@ package com.fuint.business.store.service; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.fuint.business.store.entity.ChainStoreInfo; @@ -10,6 +12,6 @@ import com.fuint.business.store.entity.ChainStoreInfo; * @since 2023-10-11 13:17:02 */ public interface ChainStoreInfoService extends IService { - + IPage listVo(Page page, ChainStoreInfo chainStoreInfo); } diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/impl/ChainStoreInfoServiceImpl.java b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/impl/ChainStoreInfoServiceImpl.java index aa8425d81..1fd9cebef 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/impl/ChainStoreInfoServiceImpl.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/business/store/service/impl/ChainStoreInfoServiceImpl.java @@ -1,11 +1,25 @@ package com.fuint.business.store.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fuint.business.store.entity.MtStore; import com.fuint.business.store.mapper.ChainStoreInfoMapper; import com.fuint.business.store.entity.ChainStoreInfo; import com.fuint.business.store.service.ChainStoreInfoService; +import com.fuint.business.store.service.StoreService; +import com.fuint.common.dto.AccountInfo; +import com.fuint.common.util.TokenUtil; +import com.fuint.repository.model.base.BaseEntity; +import com.fuint.system.dept.entity.SysDept; +import com.fuint.system.dept.service.ISysDeptService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import java.util.List; + /** * (ChainStoreInfo)表服务实现类 * @@ -15,5 +29,24 @@ import org.springframework.stereotype.Service; @Service("chainStoreInfoService") public class ChainStoreInfoServiceImpl extends ServiceImpl implements ChainStoreInfoService { + @Autowired + @Lazy + private ISysDeptService deptService; + @Autowired + private StoreService storeService; + + @Override + public IPage listVo(Page page, ChainStoreInfo chainStoreInfo) { + AccountInfo nowAccountInfo = TokenUtil.getNowAccountInfo(); + SysDept sysDept = deptService.getById(nowAccountInfo.getDeptId()); + IPage res = baseMapper.listVo(page,chainStoreInfo,sysDept.getAncestors()); + res.getRecords().forEach(it->{ + LambdaQueryWrapper queryWrapper =new LambdaQueryWrapper<>(); + queryWrapper.eq(MtStore::getChainStoreId,it.getId()).orderByDesc(BaseEntity::getCreateTime); + List list = storeService.list(queryWrapper); + it.setStoreList(list); + }); + return res; + } } diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/entity/SysDept.java b/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/entity/SysDept.java index 4b51bff85..52a1fa4ca 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/entity/SysDept.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/entity/SysDept.java @@ -49,7 +49,9 @@ public class SysDept extends BaseEntity /** 父部门名称 */ @TableField(exist = false) private String parentName; - + private String leaderName; + + private String leaderPhone; /** 子部门 */ @TableField(exist = false) private List children = new ArrayList(); diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/service/impl/SysDeptServiceImpl.java b/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/service/impl/SysDeptServiceImpl.java index 1ebf94265..8839bd80c 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/service/impl/SysDeptServiceImpl.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/system/dept/service/impl/SysDeptServiceImpl.java @@ -12,13 +12,13 @@ import com.fuint.common.constant.UserConstants; import com.fuint.common.domain.TreeSelect; import com.fuint.common.dto.AccountInfo; import com.fuint.common.util.Convert; -import com.fuint.common.util.SpringUtils; import com.fuint.common.util.StringUtils; import com.fuint.common.util.TokenUtil; import com.fuint.system.dept.entity.SysDept; import com.fuint.system.dept.mapper.SysDeptMapper; import com.fuint.system.dept.service.ISysDeptService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -37,8 +37,10 @@ public class SysDeptServiceImpl extends ServiceImpl imple { @Autowired + @Lazy private ChainStoreInfoService chainStoreService; @Autowired + @Lazy private StoreService storeService; /** @@ -196,6 +198,7 @@ public class SysDeptServiceImpl extends ServiceImpl imple } dept.setAncestors(info.getAncestors() + "," + dept.getParentId()); } + int insert = baseMapper.insert(dept); //处理店铺 if(StringUtils.isNotEmpty(dept.getDeptType())){ if (dept.getDeptType().equals("3")){ @@ -237,7 +240,7 @@ public class SysDeptServiceImpl extends ServiceImpl imple if (StringUtils.isEmpty(dept.getStatus())){ dept.setStatus("qy"); } - return baseMapper.insert(dept); + return insert; } /** diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/system/dict/util/DictUtils.java b/fuintBackend/fuint-application/src/main/java/com/fuint/system/dict/util/DictUtils.java index 5544bbeaa..041d952ad 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/system/dict/util/DictUtils.java +++ b/fuintBackend/fuint-application/src/main/java/com/fuint/system/dict/util/DictUtils.java @@ -5,7 +5,7 @@ import java.util.List; import com.alibaba.fastjson2.JSONArray; import com.fuint.common.constant.CacheConstants; import com.fuint.common.util.RedisCache; -import com.fuint.common.util.SpringUtils; +import com.fuint.utils.SpringUtils; import com.fuint.common.util.StringUtils; import com.fuint.system.dict.entity.SysDictData; diff --git a/fuintBackend/fuint-quartz/pom.xml b/fuintBackend/fuint-quartz/pom.xml new file mode 100644 index 000000000..2168d02c8 --- /dev/null +++ b/fuintBackend/fuint-quartz/pom.xml @@ -0,0 +1,82 @@ + + + + fuint + com.fuint + 1.0.0 + + 4.0.0 + + fuint-quartz + + + quartz定时任务 + + + + + + + org.quartz-scheduler + quartz + + + com.mchange + c3p0 + + + + + com.fuint + fuint-framework + 1.0.0 + compile + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.5.12 + + + + repackage + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + + + + + + src/main/java + + **/*.xml + + false + + + src/main/resources + + **/** + + false + + + + + \ No newline at end of file diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/Constants.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/Constants.java new file mode 100644 index 000000000..d389dce69 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/Constants.java @@ -0,0 +1,139 @@ +package com.fuint.quartz.common; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public class Constants +{ + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * www主域 + */ + public static final String WWW = "www."; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + public static final String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + public static final String FAIL = "1"; + + /** + * 登录成功 + */ + public static final String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + public static final String LOGOUT = "Logout"; + + /** + * 注册 + */ + public static final String REGISTER = "Register"; + + /** + * 登录失败 + */ + public static final String LOGIN_FAIL = "Error"; + + /** + * 验证码有效期(分钟) + */ + public static final Integer CAPTCHA_EXPIRATION = 2; + + /** + * 令牌 + */ + public static final String TOKEN = "token"; + + /** + * 令牌前缀 + */ + public static final String TOKEN_PREFIX = "Bearer "; + + /** + * 令牌前缀 + */ + public static final String LOGIN_USER_KEY = "login_user_key"; + + /** + * 用户ID + */ + public static final String JWT_USERID = "userid"; + + + /** + * 用户头像 + */ + public static final String JWT_AVATAR = "avatar"; + + /** + * 创建时间 + */ + public static final String JWT_CREATED = "created"; + + /** + * 用户权限 + */ + public static final String JWT_AUTHORITIES = "authorities"; + + /** + * 资源映射路径 前缀 + */ + public static final String RESOURCE_PREFIX = "/profile"; + + /** + * RMI 远程方法调用 + */ + public static final String LOOKUP_RMI = "rmi:"; + + /** + * LDAP 远程方法调用 + */ + public static final String LOOKUP_LDAP = "ldap:"; + + /** + * LDAPS 远程方法调用 + */ + public static final String LOOKUP_LDAPS = "ldaps:"; + + /** + * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) + */ + public static final String[] JOB_WHITELIST_STR = { "com.fuint" }; + + /** + * 定时任务违规的字符 + */ + public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", + "org.springframework", "org.apache", "com.fuint.common.utils.file", "com.fuint.common.config" }; + + public static final String CUSTOM_LOGIN_SMS = "000"; + +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/ScheduleConstants.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/ScheduleConstants.java new file mode 100644 index 000000000..f20a9343c --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/ScheduleConstants.java @@ -0,0 +1,50 @@ +package com.fuint.quartz.common; + +/** + * 任务调度通用常量 + * + * @author ruoyi + */ +public class ScheduleConstants +{ + public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME"; + + /** 执行目标key */ + public static final String TASK_PROPERTIES = "TASK_PROPERTIES"; + + /** 默认 */ + public static final String MISFIRE_DEFAULT = "0"; + + /** 立即触发执行 */ + public static final String MISFIRE_IGNORE_MISFIRES = "1"; + + /** 触发一次执行 */ + public static final String MISFIRE_FIRE_AND_PROCEED = "2"; + + /** 不触发立即执行 */ + public static final String MISFIRE_DO_NOTHING = "3"; + + public enum Status + { + /** + * 正常 + */ + NORMAL("0"), + /** + * 暂停 + */ + PAUSE("1"); + + private String value; + + private Status(String value) + { + this.value = value; + } + + public String getValue() + { + return value; + } + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/TaskException.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/TaskException.java new file mode 100644 index 000000000..5e9d33a7c --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/common/TaskException.java @@ -0,0 +1,34 @@ +package com.fuint.quartz.common; + +/** + * 计划策略异常 + * + * @author ruoyi + */ +public class TaskException extends Exception +{ + private static final long serialVersionUID = 1L; + + private Code code; + + public TaskException(String msg, Code code) + { + this(msg, code, null); + } + + public TaskException(String msg, Code code, Exception nestedEx) + { + super(msg, nestedEx); + this.code = code; + } + + public Code getCode() + { + return code; + } + + public enum Code + { + TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE + } +} \ No newline at end of file diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/config/ScheduleConfig.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/config/ScheduleConfig.java new file mode 100644 index 000000000..955a3f66a --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/config/ScheduleConfig.java @@ -0,0 +1,57 @@ +package com.fuint.quartz.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import javax.sql.DataSource; +import java.util.Properties; + +/** + * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效) + * + * @author ruoyi + */ +@Configuration +public class ScheduleConfig +{ + @Bean + public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) + { + SchedulerFactoryBean factory = new SchedulerFactoryBean(); + factory.setDataSource(dataSource); + + // quartz参数 + Properties prop = new Properties(); + prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler"); + prop.put("org.quartz.scheduler.instanceId", "AUTO"); + // 线程池配置 + prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); + prop.put("org.quartz.threadPool.threadCount", "20"); + prop.put("org.quartz.threadPool.threadPriority", "5"); + // JobStore配置 + prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); + // 集群配置 + prop.put("org.quartz.jobStore.isClustered", "true"); + prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); + prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); + prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); + + // sqlserver 启用 + // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); + prop.put("org.quartz.jobStore.misfireThreshold", "12000"); + prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); + factory.setQuartzProperties(prop); + + factory.setSchedulerName("RuoyiScheduler"); + // 延时启动 + factory.setStartupDelay(1); + factory.setApplicationContextSchedulerContextKey("applicationContextKey"); + // 可选,QuartzScheduler + // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 + factory.setOverwriteExistingJobs(true); + // 设置自动启动,默认为true + factory.setAutoStartup(true); + + return factory; + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/controller/SysJobController.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/controller/SysJobController.java new file mode 100644 index 000000000..120c42c97 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/controller/SysJobController.java @@ -0,0 +1,150 @@ +package com.fuint.quartz.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuint.framework.web.BaseController; +import com.fuint.framework.web.ResponseObject; +import com.fuint.quartz.common.Constants; +import com.fuint.quartz.common.TaskException; +import org.apache.commons.lang3.StringUtils; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import com.fuint.quartz.domain.SysJob; +import com.fuint.quartz.service.ISysJobService; +import com.fuint.quartz.util.CronUtils; +import com.fuint.quartz.util.ScheduleUtils; + +/** + * 调度任务信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/job") +public class SysJobController extends BaseController +{ + @Autowired + private ISysJobService jobService; + + /** + * 查询定时任务列表 + */ + @GetMapping("/list") + public ResponseObject list(SysJob sysJob,@RequestParam(name = "pageNo",defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize",defaultValue = "10") Integer pageSize) + { + Page page =new Page(pageNo,pageSize); + IPage list = jobService.selectJobList(page,sysJob); + return getSuccessResult(list); + } + + + /** + * 获取定时任务详细信息 + */ + @GetMapping(value = "/{jobId}") + public ResponseObject getInfo(@PathVariable("jobId") Long jobId) + { + return getSuccessResult(jobService.selectJobById(jobId)); + } + + /** + * 新增定时任务 + */ + @PostMapping + public ResponseObject add(@RequestBody SysJob job) throws SchedulerException, TaskException, TaskException { + if (!CronUtils.isValid(job.getCronExpression())) + { + return getFailureResult("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确"); + } + else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) + { + return getFailureResult("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS })) + { + return getFailureResult("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) + { + return getFailureResult("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) + { + return getFailureResult("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规"); + } + else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) + { + return getFailureResult("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); + } + return getSuccessResult(jobService.insertJob(job)); + } + + /** + * 修改定时任务 + */ + @PutMapping + public ResponseObject edit(@RequestBody SysJob job) throws SchedulerException, TaskException + { + if (!CronUtils.isValid(job.getCronExpression())) + { + return getFailureResult("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确"); + } + else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) + { + return getFailureResult("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS })) + { + return getFailureResult("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) + { + return getFailureResult("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用"); + } + else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) + { + return getFailureResult("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规"); + } + else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) + { + return getFailureResult("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内"); + } + return getSuccessResult(jobService.updateJob(job)); + } + + /** + * 定时任务状态修改 + */ + @PutMapping("/changeStatus") + public ResponseObject changeStatus(@RequestBody SysJob job) throws SchedulerException + { + SysJob newJob = jobService.selectJobById(job.getJobId()); + newJob.setStatus(job.getStatus()); + return getSuccessResult(jobService.changeStatus(newJob)); + } + + /** + * 定时任务立即执行一次 + */ + @PutMapping("/run") + public ResponseObject run(@RequestBody SysJob job) throws SchedulerException + { + boolean result = jobService.run(job); + return result ? getSuccessResult("ok") : getFailureResult("任务不存在或已过期!"); + } + + /** + * 删除定时任务 + */ + @DeleteMapping("/{jobIds}") + public ResponseObject remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException + { + jobService.deleteJobByIds(jobIds); + return getSuccessResult("ok"); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/controller/SysJobLogController.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/controller/SysJobLogController.java new file mode 100644 index 000000000..c7d5f926f --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/controller/SysJobLogController.java @@ -0,0 +1,68 @@ +package com.fuint.quartz.controller; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuint.framework.web.BaseController; +import com.fuint.framework.web.ResponseObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import com.fuint.quartz.domain.SysJobLog; +import com.fuint.quartz.service.ISysJobLogService; + +/** + * 调度日志操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/jobLog") +public class SysJobLogController extends BaseController +{ + @Autowired + private ISysJobLogService jobLogService; + + /** + * 查询定时任务调度日志列表 + */ + @GetMapping("/list") + public ResponseObject list(SysJobLog sysJobLog,@RequestParam(name = "pageNo",defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize",defaultValue = "10") Integer pageSize) + { + Page page =new Page(pageNo,pageSize); + IPage list = jobLogService.selectJobLogList(page,sysJobLog); + return getSuccessResult(list); + } + + + /** + * 根据调度编号获取详细信息 + */ + @GetMapping(value = "/{jobLogId}") + public ResponseObject getInfo(@PathVariable Long jobLogId) + { + return getSuccessResult(jobLogService.selectJobLogById(jobLogId)); + } + + + /** + * 删除定时任务调度日志 + */ + @DeleteMapping("/{jobLogIds}") + public ResponseObject remove(@PathVariable Long[] jobLogIds) + { + return getSuccessResult(jobLogService.deleteJobLogByIds(jobLogIds)); + } + + /** + * 清空定时任务调度日志 + */ + @DeleteMapping("/clean") + public ResponseObject clean() + { + jobLogService.cleanJobLog(); + return getSuccessResult("成功"); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/domain/SysJob.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/domain/SysJob.java new file mode 100644 index 000000000..fffa42a9f --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/domain/SysJob.java @@ -0,0 +1,165 @@ +package com.fuint.quartz.domain; + +import java.util.Date; + +import com.fuint.framework.entity.BaseEntity; +import com.fuint.quartz.common.ScheduleConstants; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.fasterxml.jackson.annotation.JsonFormat; + +import com.fuint.quartz.util.CronUtils; + +/** + * 定时任务调度表 sys_job + * + * @author ruoyi + */ +public class SysJob extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 任务ID */ + + private Long jobId; + + /** 任务名称 */ + + private String jobName; + + /** 任务组名 */ + + private String jobGroup; + + /** 调用目标字符串 */ + + private String invokeTarget; + + /** cron执行表达式 */ + + private String cronExpression; + + /** cron计划策略 */ + + private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT; + + /** 是否并发执行(0允许 1禁止) */ + + private String concurrent; + + /** 任务状态(0正常 1暂停) */ + + private String status; + + public Long getJobId() + { + return jobId; + } + + public void setJobId(Long jobId) + { + this.jobId = jobId; + } + + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + + public String getCronExpression() + { + return cronExpression; + } + + public void setCronExpression(String cronExpression) + { + this.cronExpression = cronExpression; + } + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + public Date getNextValidTime() + { + if (StringUtils.isNotEmpty(cronExpression)) + { + return CronUtils.getNextExecution(cronExpression); + } + return null; + } + + public String getMisfirePolicy() + { + return misfirePolicy; + } + + public void setMisfirePolicy(String misfirePolicy) + { + this.misfirePolicy = misfirePolicy; + } + + public String getConcurrent() + { + return concurrent; + } + + public void setConcurrent(String concurrent) + { + this.concurrent = concurrent; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("jobId", getJobId()) + .append("jobName", getJobName()) + .append("jobGroup", getJobGroup()) + .append("cronExpression", getCronExpression()) + .append("nextValidTime", getNextValidTime()) + .append("misfirePolicy", getMisfirePolicy()) + .append("concurrent", getConcurrent()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/domain/SysJobLog.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/domain/SysJobLog.java new file mode 100644 index 000000000..4308de69b --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/domain/SysJobLog.java @@ -0,0 +1,153 @@ +package com.fuint.quartz.domain; + +import java.util.Date; + +import com.fuint.framework.entity.BaseEntity; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 定时任务调度日志表 sys_job_log + * + * @author ruoyi + */ +public class SysJobLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** ID */ + private Long jobLogId; + + + private String jobName; + + /** 任务组名 */ + + private String jobGroup; + + /** 调用目标字符串 */ + + private String invokeTarget; + + /** 日志信息 */ + + private String jobMessage; + + /** 执行状态(0正常 1失败) */ + + private String status; + + /** 异常信息 */ + + private String exceptionInfo; + + /** 开始时间 */ + private Date startTime; + + /** 停止时间 */ + private Date stopTime; + + public Long getJobLogId() + { + return jobLogId; + } + + public void setJobLogId(Long jobLogId) + { + this.jobLogId = jobLogId; + } + + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + public String getJobMessage() + { + return jobMessage; + } + + public void setJobMessage(String jobMessage) + { + this.jobMessage = jobMessage; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getExceptionInfo() + { + return exceptionInfo; + } + + public void setExceptionInfo(String exceptionInfo) + { + this.exceptionInfo = exceptionInfo; + } + + public Date getStartTime() + { + return startTime; + } + + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getStopTime() + { + return stopTime; + } + + public void setStopTime(Date stopTime) + { + this.stopTime = stopTime; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("jobLogId", getJobLogId()) + .append("jobName", getJobName()) + .append("jobGroup", getJobGroup()) + .append("jobMessage", getJobMessage()) + .append("status", getStatus()) + .append("exceptionInfo", getExceptionInfo()) + .append("startTime", getStartTime()) + .append("stopTime", getStopTime()) + .toString(); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/SysJobLogMapper.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/SysJobLogMapper.java new file mode 100644 index 000000000..094f6ecf2 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/SysJobLogMapper.java @@ -0,0 +1,68 @@ +package com.fuint.quartz.mapper; + +import java.util.List; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuint.quartz.domain.SysJobLog; +import org.apache.ibatis.annotations.Param; + +/** + * 调度任务日志信息 数据层 + * + * @author ruoyi + */ +public interface SysJobLogMapper +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public IPage selectJobLogList(Page page, @Param("jobLog") SysJobLog jobLog); + + /** + * 查询所有调度任务日志 + * + * @return 调度任务日志列表 + */ + public List selectJobLogAll(); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + * @return 结果 + */ + public int insertJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的数据ID + * @return 结果 + */ + public int deleteJobLogByIds(Long[] logIds); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/SysJobMapper.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/SysJobMapper.java new file mode 100644 index 000000000..862bb146f --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/SysJobMapper.java @@ -0,0 +1,71 @@ +package com.fuint.quartz.mapper; + +import java.util.List; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuint.quartz.domain.SysJob; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * 调度任务信息 数据层 + * + * @author ruoyi + */ +public interface SysJobMapper +{ + /** + * 查询调度任务日志集合 + * + * @param job 调度信息 + * @return 操作日志集合 + */ + public IPage selectJobList(Page page, @RequestParam("job") SysJob job); + + /** + * 查询所有调度任务 + * + * @return 调度任务列表 + */ + public List selectJobAll(); + + /** + * 通过调度ID查询调度任务信息 + * + * @param jobId 调度ID + * @return 角色对象信息 + */ + public SysJob selectJobById(Long jobId); + + /** + * 通过调度ID删除调度任务信息 + * + * @param jobId 调度ID + * @return 结果 + */ + public int deleteJobById(Long jobId); + + /** + * 批量删除调度任务信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteJobByIds(Long[] ids); + + /** + * 修改调度任务信息 + * + * @param job 调度任务信息 + * @return 结果 + */ + public int updateJob(SysJob job); + + /** + * 新增调度任务信息 + * + * @param job 调度任务信息 + * @return 结果 + */ + public int insertJob(SysJob job); +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/xml/SysJobLogMapper.xml b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/xml/SysJobLogMapper.xml new file mode 100644 index 000000000..9b10eeab7 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/xml/SysJobLogMapper.xml @@ -0,0 +1,77 @@ + + + + + + + select * + from sys_job_log + + + + + + + + + + delete from sys_job_log where job_log_id = #{jobLogId} + + + + delete from sys_job_log where job_log_id in + + #{jobLogId} + + + + + truncate table sys_job_log + + + + insert into sys_job_log( + job_log_id, + job_name, + job_group, + invoke_target, + job_message, + status, + exception_info, + create_time + )values( + #{jobLogId}, + #{jobName}, + #{jobGroup}, + #{invokeTarget}, + #{jobMessage}, + #{status}, + #{exceptionInfo}, + sysdate() + ) + + + \ No newline at end of file diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/xml/SysJobMapper.xml b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/xml/SysJobMapper.xml new file mode 100644 index 000000000..55fa1a319 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/mapper/xml/SysJobMapper.xml @@ -0,0 +1,95 @@ + + + + + + select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark + from sys_job + + + + + + + + + + delete from sys_job where job_id = #{jobId} + + + + delete from sys_job where job_id in + + #{jobId} + + + + + update sys_job + + job_name = #{jobName}, + job_group = #{jobGroup}, + invoke_target = #{invokeTarget}, + cron_expression = #{cronExpression}, + misfire_policy = #{misfirePolicy}, + concurrent = #{concurrent}, + status = #{status}, + remark = #{remark}, + update_by = #{updateBy}, + update_time = sysdate() + + where job_id = #{jobId} + + + + insert into sys_job( + job_id, + job_name, + job_group, + invoke_target, + cron_expression, + misfire_policy, + concurrent, + status, + remark, + create_by, + create_time + )values( + #{jobId}, + #{jobName}, + #{jobGroup}, + #{invokeTarget}, + #{cronExpression}, + #{misfirePolicy}, + #{concurrent}, + #{status}, + #{remark}, + #{createBy}, + sysdate() + ) + + + \ No newline at end of file diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/ISysJobLogService.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/ISysJobLogService.java new file mode 100644 index 000000000..258be09d6 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/ISysJobLogService.java @@ -0,0 +1,59 @@ +package com.fuint.quartz.service; + +import java.util.List; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuint.quartz.domain.SysJobLog; + +/** + * 定时任务调度日志信息信息 服务层 + * + * @author ruoyi + */ +public interface ISysJobLogService +{ + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + public IPage selectJobLogList(Page page, SysJobLog jobLog); + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + public SysJobLog selectJobLogById(Long jobLogId); + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + */ + public void addJobLog(SysJobLog jobLog); + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的日志ID + * @return 结果 + */ + public int deleteJobLogByIds(Long[] logIds); + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + * @return 结果 + */ + public int deleteJobLogById(Long jobId); + + /** + * 清空任务日志 + */ + public void cleanJobLog(); +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/ISysJobService.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/ISysJobService.java new file mode 100644 index 000000000..f30453189 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/ISysJobService.java @@ -0,0 +1,105 @@ +package com.fuint.quartz.service; + +import java.util.List; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuint.quartz.common.TaskException; +import org.quartz.SchedulerException; +import com.fuint.quartz.domain.SysJob; + +/** + * 定时任务调度信息信息 服务层 + * + * @author ruoyi + */ +public interface ISysJobService +{ + /** + * 获取quartz调度器的计划任务 + * + * @param job 调度信息 + * @return 调度任务集合 + */ + public IPage selectJobList(Page page, SysJob job); + + /** + * 通过调度任务ID查询调度信息 + * + * @param jobId 调度任务ID + * @return 调度任务对象信息 + */ + public SysJob selectJobById(Long jobId); + + /** + * 暂停任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int pauseJob(SysJob job) throws SchedulerException; + + /** + * 恢复任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int resumeJob(SysJob job) throws SchedulerException; + + /** + * 删除任务后,所对应的trigger也将被删除 + * + * @param job 调度信息 + * @return 结果 + */ + public int deleteJob(SysJob job) throws SchedulerException; + + /** + * 批量删除调度信息 + * + * @param jobIds 需要删除的任务ID + * @return 结果 + */ + public void deleteJobByIds(Long[] jobIds) throws SchedulerException; + + /** + * 任务调度状态修改 + * + * @param job 调度信息 + * @return 结果 + */ + public int changeStatus(SysJob job) throws SchedulerException; + + /** + * 立即运行任务 + * + * @param job 调度信息 + * @return 结果 + */ + public boolean run(SysJob job) throws SchedulerException; + + /** + * 新增任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int insertJob(SysJob job) throws SchedulerException, TaskException; + + /** + * 更新任务 + * + * @param job 调度信息 + * @return 结果 + */ + public int updateJob(SysJob job) throws SchedulerException, TaskException; + + /** + * 校验cron表达式是否有效 + * + * @param cronExpression 表达式 + * @return 结果 + */ + public boolean checkCronExpressionIsValid(String cronExpression); +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/impl/SysJobLogServiceImpl.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/impl/SysJobLogServiceImpl.java new file mode 100644 index 000000000..b292c83ff --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/impl/SysJobLogServiceImpl.java @@ -0,0 +1,90 @@ +package com.fuint.quartz.service.impl; + +import java.util.List; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.fuint.quartz.domain.SysJobLog; +import com.fuint.quartz.mapper.SysJobLogMapper; +import com.fuint.quartz.service.ISysJobLogService; + +/** + * 定时任务调度日志信息 服务层 + * + * @author ruoyi + */ +@Service +public class SysJobLogServiceImpl implements ISysJobLogService +{ + @Autowired + private SysJobLogMapper jobLogMapper; + + /** + * 获取quartz调度器日志的计划任务 + * + * @param jobLog 调度日志信息 + * @return 调度任务日志集合 + */ + @Override + public IPage selectJobLogList(Page page, SysJobLog jobLog) + { + return jobLogMapper.selectJobLogList(page,jobLog); + } + + /** + * 通过调度任务日志ID查询调度信息 + * + * @param jobLogId 调度任务日志ID + * @return 调度任务日志对象信息 + */ + @Override + public SysJobLog selectJobLogById(Long jobLogId) + { + return jobLogMapper.selectJobLogById(jobLogId); + } + + /** + * 新增任务日志 + * + * @param jobLog 调度日志信息 + */ + @Override + public void addJobLog(SysJobLog jobLog) + { + jobLogMapper.insertJobLog(jobLog); + } + + /** + * 批量删除调度日志信息 + * + * @param logIds 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteJobLogByIds(Long[] logIds) + { + return jobLogMapper.deleteJobLogByIds(logIds); + } + + /** + * 删除任务日志 + * + * @param jobId 调度日志ID + */ + @Override + public int deleteJobLogById(Long jobId) + { + return jobLogMapper.deleteJobLogById(jobId); + } + + /** + * 清空任务日志 + */ + @Override + public void cleanJobLog() + { + jobLogMapper.cleanJobLog(); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/impl/SysJobServiceImpl.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/impl/SysJobServiceImpl.java new file mode 100644 index 000000000..d0adaca00 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/service/impl/SysJobServiceImpl.java @@ -0,0 +1,264 @@ +package com.fuint.quartz.service.impl; + +import java.util.List; +import javax.annotation.PostConstruct; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuint.quartz.common.ScheduleConstants; +import com.fuint.quartz.common.TaskException; +import org.quartz.JobDataMap; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.fuint.quartz.domain.SysJob; +import com.fuint.quartz.mapper.SysJobMapper; +import com.fuint.quartz.service.ISysJobService; +import com.fuint.quartz.util.CronUtils; +import com.fuint.quartz.util.ScheduleUtils; + +/** + * 定时任务调度信息 服务层 + * + * @author ruoyi + */ +@Service +public class SysJobServiceImpl implements ISysJobService +{ + @Autowired + private Scheduler scheduler; + + @Autowired + private SysJobMapper jobMapper; + + /** + * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据) + */ + @PostConstruct + public void init() throws SchedulerException, TaskException + { + scheduler.clear(); + List jobList = jobMapper.selectJobAll(); + for (SysJob job : jobList) + { + ScheduleUtils.createScheduleJob(scheduler, job); + } + } + + /** + * 获取quartz调度器的计划任务列表 + * + * @param job 调度信息 + * @return + */ + @Override + public IPage selectJobList(Page page, SysJob job) + { + return jobMapper.selectJobList(page,job); + } + + /** + * 通过调度任务ID查询调度信息 + * + * @param jobId 调度任务ID + * @return 调度任务对象信息 + */ + @Override + public SysJob selectJobById(Long jobId) + { + return jobMapper.selectJobById(jobId); + } + + /** + * 暂停任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int pauseJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 恢复任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int resumeJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + job.setStatus(ScheduleConstants.Status.NORMAL.getValue()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 删除任务后,所对应的trigger也将被删除 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteJob(SysJob job) throws SchedulerException + { + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + int rows = jobMapper.deleteJobById(jobId); + if (rows > 0) + { + scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + return rows; + } + + /** + * 批量删除调度信息 + * + * @param jobIds 需要删除的任务ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteJobByIds(Long[] jobIds) throws SchedulerException + { + for (Long jobId : jobIds) + { + SysJob job = jobMapper.selectJobById(jobId); + deleteJob(job); + } + } + + /** + * 任务调度状态修改 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int changeStatus(SysJob job) throws SchedulerException + { + int rows = 0; + String status = job.getStatus(); + if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) + { + rows = resumeJob(job); + } + else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) + { + rows = pauseJob(job); + } + return rows; + } + + /** + * 立即运行任务 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean run(SysJob job) throws SchedulerException + { + boolean result = false; + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + SysJob properties = selectJobById(job.getJobId()); + // 参数 + JobDataMap dataMap = new JobDataMap(); + dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties); + JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup); + if (scheduler.checkExists(jobKey)) + { + result = true; + scheduler.triggerJob(jobKey, dataMap); + } + return result; + } + + /** + * 新增任务 + * + * @param job 调度信息 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertJob(SysJob job) throws SchedulerException, TaskException + { + job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); + int rows = jobMapper.insertJob(job); + if (rows > 0) + { + ScheduleUtils.createScheduleJob(scheduler, job); + } + return rows; + } + + /** + * 更新任务的时间表达式 + * + * @param job 调度信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateJob(SysJob job) throws SchedulerException, TaskException + { + SysJob properties = selectJobById(job.getJobId()); + int rows = jobMapper.updateJob(job); + if (rows > 0) + { + updateSchedulerJob(job, properties.getJobGroup()); + } + return rows; + } + + /** + * 更新任务 + * + * @param job 任务对象 + * @param jobGroup 任务组名 + */ + public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException + { + Long jobId = job.getJobId(); + // 判断是否存在 + JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup); + if (scheduler.checkExists(jobKey)) + { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + scheduler.deleteJob(jobKey); + } + ScheduleUtils.createScheduleJob(scheduler, job); + } + + /** + * 校验cron表达式是否有效 + * + * @param cronExpression 表达式 + * @return 结果 + */ + @Override + public boolean checkCronExpressionIsValid(String cronExpression) + { + return CronUtils.isValid(cronExpression); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/task/RyTask.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/task/RyTask.java new file mode 100644 index 000000000..4647df494 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/task/RyTask.java @@ -0,0 +1,28 @@ +package com.fuint.quartz.task; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import org.springframework.stereotype.Component; + +/** + * 定时任务调度测试 + * + * @author ruoyi + */ +@Component("ryTask") +public class RyTask +{ + public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) + { + System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i)); + } + + public void ryParams(String params) + { + System.out.println("执行有参方法:" + params); + } + + public void ryNoParams() + { + System.out.println("执行无参方法"); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/AbstractQuartzJob.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/AbstractQuartzJob.java new file mode 100644 index 000000000..0fbeb2cdc --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/AbstractQuartzJob.java @@ -0,0 +1,106 @@ +package com.fuint.quartz.util; + +import java.util.Date; + +import com.fuint.quartz.common.Constants; +import com.fuint.quartz.common.ScheduleConstants; +import com.fuint.utils.SpringUtils; +import org.apache.commons.lang3.StringUtils; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.fuint.quartz.domain.SysJob; +import com.fuint.quartz.domain.SysJobLog; +import com.fuint.quartz.service.ISysJobLogService; + +/** + * 抽象quartz调用 + * + * @author ruoyi + */ +public abstract class AbstractQuartzJob implements Job +{ + private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class); + + /** + * 线程本地变量 + */ + private static ThreadLocal threadLocal = new ThreadLocal<>(); + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException + { + SysJob sysJob = new SysJob(); + BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES)); + try + { + before(context, sysJob); + if (sysJob != null) + { + doExecute(context, sysJob); + } + after(context, sysJob, null); + } + catch (Exception e) + { + log.error("任务执行异常 - :", e); + after(context, sysJob, e); + } + } + + /** + * 执行前 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void before(JobExecutionContext context, SysJob sysJob) + { + threadLocal.set(new Date()); + } + + /** + * 执行后 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void after(JobExecutionContext context, SysJob sysJob, Exception e) + { + Date startTime = threadLocal.get(); + threadLocal.remove(); + + final SysJobLog sysJobLog = new SysJobLog(); + sysJobLog.setJobName(sysJob.getJobName()); + sysJobLog.setJobGroup(sysJob.getJobGroup()); + sysJobLog.setInvokeTarget(sysJob.getInvokeTarget()); + sysJobLog.setStartTime(startTime); + sysJobLog.setStopTime(new Date()); + long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime(); + sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); + if (e != null) + { + sysJobLog.setStatus(Constants.FAIL); + String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000); + sysJobLog.setExceptionInfo(errorMsg); + } + else + { + sysJobLog.setStatus(Constants.SUCCESS); + } + + // 写入数据库当中 + SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog); + } + + /** + * 执行方法,由子类重载 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + * @throws Exception 执行过程中的异常 + */ + protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception; +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/BeanUtils.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/BeanUtils.java new file mode 100644 index 000000000..c5db19006 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/BeanUtils.java @@ -0,0 +1,110 @@ +package com.fuint.quartz.util; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Bean 工具类 + * + * @author ruoyi + */ +public class BeanUtils extends org.springframework.beans.BeanUtils +{ + /** Bean方法名中属性名开始的下标 */ + private static final int BEAN_METHOD_PROP_INDEX = 3; + + /** * 匹配getter方法的正则表达式 */ + private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)"); + + /** * 匹配setter方法的正则表达式 */ + private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)"); + + /** + * Bean属性复制工具方法。 + * + * @param dest 目标对象 + * @param src 源对象 + */ + public static void copyBeanProp(Object dest, Object src) + { + try + { + copyProperties(src, dest); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * 获取对象的setter方法。 + * + * @param obj 对象 + * @return 对象的setter方法列表 + */ + public static List getSetterMethods(Object obj) + { + // setter方法列表 + List setterMethods = new ArrayList(); + + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + + // 查找setter方法 + + for (Method method : methods) + { + Matcher m = SET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 1)) + { + setterMethods.add(method); + } + } + // 返回setter方法列表 + return setterMethods; + } + + /** + * 获取对象的getter方法。 + * + * @param obj 对象 + * @return 对象的getter方法列表 + */ + + public static List getGetterMethods(Object obj) + { + // getter方法列表 + List getterMethods = new ArrayList(); + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + // 查找getter方法 + for (Method method : methods) + { + Matcher m = GET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 0)) + { + getterMethods.add(method); + } + } + // 返回getter方法列表 + return getterMethods; + } + + /** + * 检查Bean方法名中的属性名是否相等。
+ * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。 + * + * @param m1 方法名1 + * @param m2 方法名2 + * @return 属性名一样返回true,否则返回false + */ + + public static boolean isMethodPropEquals(String m1, String m2) + { + return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX)); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/CronUtils.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/CronUtils.java new file mode 100644 index 000000000..83c70f926 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/CronUtils.java @@ -0,0 +1,63 @@ +package com.fuint.quartz.util; + +import java.text.ParseException; +import java.util.Date; +import org.quartz.CronExpression; + +/** + * cron表达式工具类 + * + * @author ruoyi + * + */ +public class CronUtils +{ + /** + * 返回一个布尔值代表一个给定的Cron表达式的有效性 + * + * @param cronExpression Cron表达式 + * @return boolean 表达式是否有效 + */ + public static boolean isValid(String cronExpression) + { + return CronExpression.isValidExpression(cronExpression); + } + + /** + * 返回一个字符串值,表示该消息无效Cron表达式给出有效性 + * + * @param cronExpression Cron表达式 + * @return String 无效时返回表达式错误描述,如果有效返回null + */ + public static String getInvalidMessage(String cronExpression) + { + try + { + new CronExpression(cronExpression); + return null; + } + catch (ParseException pe) + { + return pe.getMessage(); + } + } + + /** + * 返回下一个执行时间根据给定的Cron表达式 + * + * @param cronExpression Cron表达式 + * @return Date 下次Cron表达式执行时间 + */ + public static Date getNextExecution(String cronExpression) + { + try + { + CronExpression cron = new CronExpression(cronExpression); + return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); + } + catch (ParseException e) + { + throw new IllegalArgumentException(e.getMessage()); + } + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/ExceptionUtil.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/ExceptionUtil.java new file mode 100644 index 000000000..4b9582699 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/ExceptionUtil.java @@ -0,0 +1,41 @@ +package com.fuint.quartz.util; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * 错误信息处理类。 + * + * @author ruoyi + */ +public class ExceptionUtil +{ + /** + * 获取exception的详细错误信息。 + */ + public static String getExceptionMessage(Throwable e) + { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw, true)); + return sw.toString(); + } + + public static String getRootErrorMessage(Exception e) + { + Throwable root = ExceptionUtils.getRootCause(e); + root = (root == null ? e : root); + if (root == null) + { + return ""; + } + String msg = root.getMessage(); + if (msg == null) + { + return "null"; + } + return StringUtils.defaultString(msg); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/JobInvokeUtil.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/JobInvokeUtil.java new file mode 100644 index 000000000..d67ce35e2 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/JobInvokeUtil.java @@ -0,0 +1,183 @@ +package com.fuint.quartz.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import com.fuint.quartz.domain.SysJob; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; +import com.fuint.utils.SpringUtils; + +/** + * 任务执行工具 + * + * @author ruoyi + */ +public class JobInvokeUtil +{ + /** + * 执行方法 + * + * @param sysJob 系统任务 + */ + public static void invokeMethod(SysJob sysJob) throws Exception + { + String invokeTarget = sysJob.getInvokeTarget(); + String beanName = getBeanName(invokeTarget); + String methodName = getMethodName(invokeTarget); + List methodParams = getMethodParams(invokeTarget); + + if (!isValidClassName(beanName)) + { + Object bean = SpringUtils.getBean(beanName); + invokeMethod(bean, methodName, methodParams); + } + else + { + Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance(); + invokeMethod(bean, methodName, methodParams); + } + } + + /** + * 调用任务方法 + * + * @param bean 目标对象 + * @param methodName 方法名称 + * @param methodParams 方法参数 + */ + private static void invokeMethod(Object bean, String methodName, List methodParams) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException + { + if (!CollectionUtils.isEmpty(methodParams) && methodParams.size() > 0) + { + Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams)); + method.invoke(bean, getMethodParamsValue(methodParams)); + } + else + { + Method method = bean.getClass().getMethod(methodName); + method.invoke(bean); + } + } + + /** + * 校验是否为为class包名 + * + * @param invokeTarget 名称 + * @return true是 false否 + */ + public static boolean isValidClassName(String invokeTarget) + { + return StringUtils.countMatches(invokeTarget, ".") > 1; + } + + /** + * 获取bean名称 + * + * @param invokeTarget 目标字符串 + * @return bean名称 + */ + public static String getBeanName(String invokeTarget) + { + String beanName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringBeforeLast(beanName, "."); + } + + /** + * 获取bean方法 + * + * @param invokeTarget 目标字符串 + * @return method方法 + */ + public static String getMethodName(String invokeTarget) + { + String methodName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringAfterLast(methodName, "."); + } + + /** + * 获取method方法参数相关列表 + * + * @param invokeTarget 目标字符串 + * @return method方法相关参数列表 + */ + public static List getMethodParams(String invokeTarget) + { + String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); + if (StringUtils.isEmpty(methodStr)) + { + return null; + } + String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); + List classs = new LinkedList(); + for (int i = 0; i < methodParams.length; i++) + { + String str = StringUtils.trimToEmpty(methodParams[i]); + // String字符串类型,以'或"开头 + if (StringUtils.startsWithAny(str, "'", "\"")) + { + classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class }); + } + // boolean布尔类型,等于true或者false + else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) + { + classs.add(new Object[] { Boolean.valueOf(str), Boolean.class }); + } + // long长整形,以L结尾 + else if (StringUtils.endsWith(str, "L")) + { + classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class }); + } + // double浮点类型,以D结尾 + else if (StringUtils.endsWith(str, "D")) + { + classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class }); + } + // 其他类型归类为整形 + else + { + classs.add(new Object[] { Integer.valueOf(str), Integer.class }); + } + } + return classs; + } + + /** + * 获取参数类型 + * + * @param methodParams 参数相关列表 + * @return 参数类型列表 + */ + public static Class[] getMethodParamsType(List methodParams) + { + Class[] classs = new Class[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Class) os[1]; + index++; + } + return classs; + } + + /** + * 获取参数值 + * + * @param methodParams 参数相关列表 + * @return 参数值列表 + */ + public static Object[] getMethodParamsValue(List methodParams) + { + Object[] classs = new Object[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Object) os[0]; + index++; + } + return classs; + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/QuartzDisallowConcurrentExecution.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/QuartzDisallowConcurrentExecution.java new file mode 100644 index 000000000..dc588e5cb --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/QuartzDisallowConcurrentExecution.java @@ -0,0 +1,21 @@ +package com.fuint.quartz.util; + +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import com.fuint.quartz.domain.SysJob; + +/** + * 定时任务处理(禁止并发执行) + * + * @author ruoyi + * + */ +@DisallowConcurrentExecution +public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception + { + JobInvokeUtil.invokeMethod(sysJob); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/QuartzJobExecution.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/QuartzJobExecution.java new file mode 100644 index 000000000..e0daa6498 --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/QuartzJobExecution.java @@ -0,0 +1,19 @@ +package com.fuint.quartz.util; + +import org.quartz.JobExecutionContext; +import com.fuint.quartz.domain.SysJob; + +/** + * 定时任务处理(允许并发执行) + * + * @author ruoyi + * + */ +public class QuartzJobExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception + { + JobInvokeUtil.invokeMethod(sysJob); + } +} diff --git a/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/ScheduleUtils.java b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/ScheduleUtils.java new file mode 100644 index 000000000..87ec8edca --- /dev/null +++ b/fuintBackend/fuint-quartz/src/main/java/com/fuint/quartz/util/ScheduleUtils.java @@ -0,0 +1,142 @@ +package com.fuint.quartz.util; + +import com.fuint.quartz.common.Constants; +import com.fuint.quartz.common.ScheduleConstants; +import com.fuint.quartz.common.TaskException; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.quartz.CronScheduleBuilder; +import org.quartz.CronTrigger; +import org.quartz.Job; +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.TriggerBuilder; +import org.quartz.TriggerKey; +import com.fuint.quartz.common.TaskException.Code; +import com.fuint.quartz.domain.SysJob; +import com.fuint.utils.SpringUtils; + +/** + * 定时任务工具类 + * + * @author ruoyi + * + */ +public class ScheduleUtils +{ + /** + * 得到quartz任务类 + * + * @param sysJob 执行计划 + * @return 具体执行任务类 + */ + private static Class getQuartzJobClass(SysJob sysJob) + { + boolean isConcurrent = "0".equals(sysJob.getConcurrent()); + return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class; + } + + /** + * 构建任务触发对象 + */ + public static TriggerKey getTriggerKey(Long jobId, String jobGroup) + { + return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); + } + + /** + * 构建任务键对象 + */ + public static JobKey getJobKey(Long jobId, String jobGroup) + { + return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); + } + + /** + * 创建定时任务 + */ + public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException + { + Class jobClass = getQuartzJobClass(job); + // 构建job信息 + Long jobId = job.getJobId(); + String jobGroup = job.getJobGroup(); + JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build(); + + // 表达式调度构建器 + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression()); + cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder); + + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)) + .withSchedule(cronScheduleBuilder).build(); + + // 放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job); + + // 判断是否存在 + if (scheduler.checkExists(getJobKey(jobId, jobGroup))) + { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + scheduler.deleteJob(getJobKey(jobId, jobGroup)); + } + + // 判断任务是否过期 + if (ObjectUtils.isNotEmpty(CronUtils.getNextExecution(job.getCronExpression()))) + { + // 执行调度任务 + scheduler.scheduleJob(jobDetail, trigger); + } + + // 暂停任务 + if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) + { + scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + } + + /** + * 设置定时任务策略 + */ + public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) + throws TaskException + { + switch (job.getMisfirePolicy()) + { + case ScheduleConstants.MISFIRE_DEFAULT: + return cb; + case ScheduleConstants.MISFIRE_IGNORE_MISFIRES: + return cb.withMisfireHandlingInstructionIgnoreMisfires(); + case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED: + return cb.withMisfireHandlingInstructionFireAndProceed(); + case ScheduleConstants.MISFIRE_DO_NOTHING: + return cb.withMisfireHandlingInstructionDoNothing(); + default: + throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() + + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); + } + } + + /** + * 检查包名是否为白名单配置 + * + * @param invokeTarget 目标字符串 + * @return 结果 + */ + public static boolean whiteList(String invokeTarget) + { + String packageName = StringUtils.substringBefore(invokeTarget, "("); + int count = StringUtils.countMatches(packageName, "."); + if (count > 1) + { + return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR); + } + Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]); + String beanPackageName = obj.getClass().getPackage().getName(); + return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR) + && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR); + } +} diff --git a/fuintBackend/fuint-application/src/main/java/com/fuint/common/util/SpringUtils.java b/fuintBackend/fuint-utils/src/main/java/com/fuint/utils/SpringUtils.java similarity index 99% rename from fuintBackend/fuint-application/src/main/java/com/fuint/common/util/SpringUtils.java rename to fuintBackend/fuint-utils/src/main/java/com/fuint/utils/SpringUtils.java index 377000305..0c608d31d 100644 --- a/fuintBackend/fuint-application/src/main/java/com/fuint/common/util/SpringUtils.java +++ b/fuintBackend/fuint-utils/src/main/java/com/fuint/utils/SpringUtils.java @@ -1,4 +1,4 @@ -package com.fuint.common.util; +package com.fuint.utils; import org.apache.commons.lang.StringUtils; import org.springframework.aop.framework.AopContext; diff --git a/fuintBackend/pom.xml b/fuintBackend/pom.xml index be9b3d04f..74eefcb2b 100644 --- a/fuintBackend/pom.xml +++ b/fuintBackend/pom.xml @@ -14,6 +14,7 @@ fuint-repository fuint-application fuint-framework + fuint-quartz