SpringBoot整合Quartz 动态定时任务
程序员文章站
2022-05-23 10:17:12
...
最近项目需要整合定时任务来完成某种需求,记录一下自己整合的代码。
具体的前台页面是这样的
项目目录是这样的
一、首先加入Maven依赖(持久层使用JPA)
<!-- quartz 导入定时quartz 依赖-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<!-- Jpa 导入Jpa 启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
二、接下来添加配置文件
#配置JPA
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.open-in-view=true
#配置spring默认的线程池
task.pool.corePoolSize=20
task.pool.maxPoolSize=40
task.pool.keepAliveSeconds=300
task.pool.queueCapacity=50
然后在启动类添加以下配置
@Bean
public SpringContextHolder springContextHolder() {
return new SpringContextHolder();
}
@Bean
public ServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory fa = new TomcatServletWebServerFactory();
fa.addConnectorCustomizers(connector -> connector.setProperty("relaxedQueryChars", "[]{}"));
return fa;
}
三、弄完配置文件接下来我们来创建一个定时任务的各个包
首先创建config包在里面分别创建配置有关的东西
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 线程池配置属性类
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class AsyncTaskProperties {
private int corePoolSize;//
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
}
import lombok.Getter;
import org.springframework.http.HttpStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
@Getter
public class BadRequestException extends RuntimeException{
private Integer status = BAD_REQUEST.value();
public BadRequestException(String msg){
super(msg);
}
public BadRequestException(HttpStatus status, String msg){
super(msg);
this.status = status.value();
}
}
import com.*.quartz.domain.QuartzJob;
import com.*.quartz.repository.QuartzJobRepository;
import com.*.quartz.utils.QuartzManage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class JobRunner implements ApplicationRunner {
@Autowired
private QuartzJobRepository quartzJobRepository;
@Autowired
private QuartzManage quartzManage;
/**
* 项目启动时重新**启用的定时任务
* @param applicationArguments /
*/
@Override
public void run(ApplicationArguments applicationArguments){
System.out.println("##########注入定时任务##########");
List<QuartzJob> quartzJobs = quartzJobRepository.findByIsPauseIsFalse();
quartzJobs.forEach(quartzManage::addJob);
System.out.println("##########定时任务注入完成##########");
}
}
import org.springframework.data.domain.Page;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 分页工具
* @ClassName: PageUtil
*/
public class PageUtil extends cn.hutool.core.util.PageUtil {
/**
* List 分页
*/
public static List toPage(int page, int size , List list) {
int fromIndex = page * size;
int toIndex = page * size + size;
if(fromIndex > list.size()){
return new ArrayList();
} else if(toIndex >= list.size()) {
return list.subList(fromIndex,list.size());
} else {
return list.subList(fromIndex,toIndex);
}
}
/**
* Page 数据处理,预防redis反序列化报错
*/
public static Map<String,Object> toPage(Page page) {
Map<String,Object> map = new LinkedHashMap<>(2);
map.put("content",page.getContent());
map.put("totalElements",page.getTotalElements());
return map;
}
/**
* 自定义分页
*/
public static Map<String,Object> toPage(Object object, Object totalElements) {
Map<String,Object> map = new LinkedHashMap<>(2);
map.put("content",object);
map.put("totalElements",totalElements);
return map;
}
}
import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
/**
* @Description: 定时任务配置
*/
@Configuration
public class QuartzConfiguration {
/**
* 解决Job中注入Spring Bean为null的问题
*/
@Component("quartzJobFactory")
public static class QuartzJobFactory extends AdaptableJobFactory {
private final AutowireCapableBeanFactory capableBeanFactory;
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
/**
* 注入scheduler到spring
* @param quartzJobFactory /
* @return Scheduler
* @throws Exception /
*/
@Bean(name = "scheduler")
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
factoryBean.setJobFactory(quartzJobFactory);
factoryBean.afterPropertiesSet();
Scheduler scheduler=factoryBean.getScheduler();
scheduler.start();
return scheduler;
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Query {
String propName() default "";
Type type() default Type.EQUAL;
/**
* 连接查询的属性名,如User类中的dept
*/
String joinName() default "";
/**
* 默认左连接
*/
Join join() default Join.LEFT;
/**
* 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username")
*/
String blurry() default "";
enum Type {
// jie 2019/6/4 相等
EQUAL
// Dong ZhaoYang 2017/8/7 大于等于
, GREATER_THAN
// Dong ZhaoYang 2017/8/7 小于等于
, LESS_THAN
// Dong ZhaoYang 2017/8/7 中模糊查询
, INNER_LIKE
// Dong ZhaoYang 2017/8/7 左模糊查询
, LEFT_LIKE
// Dong ZhaoYang 2017/8/7 右模糊查询
, RIGHT_LIKE
// Dong ZhaoYang 2017/8/7 小于
, LESS_THAN_NQ
// jie 2019/6/4 包含
, IN
// 不等于
,NOT_EQUAL
// between
,BETWEEN
// 不为空
,NOT_NULL
}
/**
* @author Zheng Jie
* 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询
*/
enum Join {
/** jie 2019-6-4 13:18:30 左右连接 */
LEFT, RIGHT
}
}
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import javax.persistence.criteria.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@Slf4j
@SuppressWarnings({"unchecked","all"})
public class QueryHelp {
public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
if(query == null){
return cb.and(list.toArray(new Predicate[0]));
}
try {
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
for (Field field : fields) {
boolean accessible = field.isAccessible();
field.setAccessible(true);
Query q = field.getAnnotation(Query.class);
if (q != null) {
String propName = q.propName();
String joinName = q.joinName();
String blurry = q.blurry();
String attributeName = isBlank(propName) ? field.getName() : propName;
Class<?> fieldType = field.getType();
Object val = field.get(query);
if (ObjectUtil.isNull(val) || "".equals(val)) {
continue;
}
Join join = null;
// 模糊多字段
if (ObjectUtil.isNotEmpty(blurry)) {
String[] blurrys = blurry.split(",");
List<Predicate> orPredicate = new ArrayList<>();
for (String s : blurrys) {
orPredicate.add(cb.like(root.get(s)
.as(String.class), "%" + val.toString() + "%"));
}
Predicate[] p = new Predicate[orPredicate.size()];
list.add(cb.or(orPredicate.toArray(p)));
continue;
}
if (ObjectUtil.isNotEmpty(joinName)) {
String[] joinNames = joinName.split(">");
for (String name : joinNames) {
switch (q.join()) {
case LEFT:
if(ObjectUtil.isNotNull(join)){
join = join.join(name, JoinType.LEFT);
} else {
join = root.join(name, JoinType.LEFT);
}
break;
case RIGHT:
if(ObjectUtil.isNotNull(join)){
join = join.join(name, JoinType.RIGHT);
} else {
join = root.join(name, JoinType.RIGHT);
}
break;
default: break;
}
}
}
switch (q.type()) {
case EQUAL:
list.add(cb.equal(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType),val));
break;
case GREATER_THAN:
list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case LESS_THAN:
list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case LESS_THAN_NQ:
list.add(cb.lessThan(getExpression(attributeName,join,root)
.as((Class<? extends Comparable>) fieldType), (Comparable) val));
break;
case INNER_LIKE:
list.add(cb.like(getExpression(attributeName,join,root)
.as(String.class), "%" + val.toString() + "%"));
break;
case LEFT_LIKE:
list.add(cb.like(getExpression(attributeName,join,root)
.as(String.class), "%" + val.toString()));
break;
case RIGHT_LIKE:
list.add(cb.like(getExpression(attributeName,join,root)
.as(String.class), val.toString() + "%"));
break;
case IN:
if (CollUtil.isNotEmpty((Collection<Long>)val)) {
list.add(getExpression(attributeName,join,root).in((Collection<Long>) val));
}
break;
case NOT_EQUAL:
list.add(cb.notEqual(getExpression(attributeName,join,root), val));
break;
case NOT_NULL:
list.add(cb.isNotNull(getExpression(attributeName,join,root)));
break;
case BETWEEN:
List<Object> between = new ArrayList<>((List<Object>)val);
list.add(cb.between(getExpression(attributeName, join, root).as((Class<? extends Comparable>) between.get(0).getClass()),
(Comparable) between.get(0), (Comparable) between.get(1)));
break;
default: break;
}
}
field.setAccessible(accessible);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
int size = list.size();
return cb.and(list.toArray(new Predicate[size]));
}
@SuppressWarnings("unchecked")
private static <T, R> Expression<T> getExpression(String attributeName, Join join, Root<R> root) {
if (ObjectUtil.isNotEmpty(join)) {
return join.get(attributeName);
} else {
return root.get(attributeName);
}
}
private static boolean isBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
private static List<Field> getAllFields(Class clazz, List<Field> fields) {
if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
getAllFields(clazz.getSuperclass(), fields);
}
return fields;
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@Slf4j
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
}
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
private static void clearHolder() {
log.debug("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext);
applicationContext = null;
}
@Override
public void destroy(){
SpringContextHolder.clearHolder();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringContextHolder.applicationContext != null) {
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
}
SpringContextHolder.applicationContext = applicationContext;
}
}
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义线程名称
*/
@Component
public class TheadFactoryName implements ThreadFactory {
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TheadFactoryName() {
this("el-pool");
}
private TheadFactoryName(String name){
SecurityManager s = System.getSecurityManager();//调解所有访问控制决策
group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
this.namePrefix = name +POOL_NUMBER.getAndIncrement();
}
@Override
public Thread newThread(Runnable r) {
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
Thread t = new Thread(group, r,namePrefix + "-thread-"+threadNumber.getAndIncrement(),0);
if (t.isDaemon()) {//测试此线程是否是守护程序线程。
t.setDaemon(false);
}
//t.getPriority()返回此线程的优先级 Thread.NORM_PRIORITY分配给线程的默认优先级
//t.setPriority 更改此线程的优先级
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 用于获取自定义线程池
*/
public class ThreadPoolExecutorUtil {
public static ThreadPoolExecutor getPoll(){
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class);
return new ThreadPoolExecutor(
properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveSeconds(),
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(properties.getQueueCapacity()),
new TheadFactoryName()
);
}
}
import org.hibernate.exception.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 异常工具
*/
public class ThrowableUtil {
/**
* 获取堆栈信息
*/
public static String getStackTrace(Throwable throwable){
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
throwable.printStackTrace(pw);
return sw.toString();
}
}
public static void throwForeignKeyException(Throwable e, String msg){
Throwable t = e.getCause();
while ((t != null) && !(t instanceof ConstraintViolationException)) {
t = t.getCause();
}
if (t != null) {
throw new BadRequestException(msg);
}
assert false;
throw new BadRequestException("删除失败:" + t.getMessage());
}
}
import cn.hutool.core.util.ObjectUtil;
import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator;
/**
* 验证工具
*/
public class ValidationUtil{
/**
* 验证空
*/
public static void isNull(Object obj, String entity, String parameter , Object value){
if(ObjectUtil.isNull(obj)){
String msg = entity + " 不存在: "+ parameter +" is "+ value;
throw new BadRequestException(msg);
}
}
/**
* 验证是否为邮箱
*/
public static boolean isEmail(String email) {
return new EmailValidator().isValid(email, null);
}
}
接下来创建domain包
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author Zheng Jie
* @date 2019-01-07
*/
@Getter
@Setter
@Entity
@Table(name = "quartz_job")
public class QuartzJob implements Serializable {
public static final String JOB_KEY = "JOB_KEY";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@NotNull(groups = {Update.class})
private Long id;
/** 定时器名称 */
@Column(name = "job_name")
private String jobName;
/** Bean名称 */
@Column(name = "bean_name")
@NotBlank
private String beanName;
/** 方法名称 */
@Column(name = "method_name")
@NotBlank
private String methodName;
/** 参数 */
@Column(name = "params")
private String params;
/** cron表达式 */
@Column(name = "cron_expression")
@NotBlank
private String cronExpression;
/** 状态 */
@Column(name = "is_pause")
private Boolean isPause = false;
/** 备注 */
@Column(name = "remark")
@NotBlank
private String remark;
@Column(name = "create_time")
@CreationTimestamp
private Timestamp createTime;
public @interface Update {}
}
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author Zheng Jie
* @date 2019-01-07
*/
@Entity
@Data
@Table(name = "quartz_log")
public class QuartzLog implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/** 任务名称 */
@Column(name = "job_name")
private String jobName;
/** Bean名称 */
@Column(name = "baen_name")
private String beanName;
/** 方法名称 */
@Column(name = "method_name")
private String methodName;
/** 参数 */
@Column(name = "params")
private String params;
/** cron表达式 */
@Column(name = "cron_expression")
private String cronExpression;
/** 状态 */
@Column(name = "is_success")
private Boolean isSuccess;
/** 异常详细 */
@Column(name = "exception_detail",columnDefinition = "text")
private String exceptionDetail;
/** 耗时(毫秒) */
private Long time;
/** 创建日期 */
@CreationTimestamp
@Column(name = "create_time")
private Timestamp createTime;
}
接着创建repository包
import com.*.quartz.domain.QuartzJob;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
public interface QuartzJobRepository extends JpaRepository<QuartzJob,Long>, JpaSpecificationExecutor<QuartzJob> {
/**
* 查询启用的任务
* @return List
*/
List<QuartzJob> findByIsPauseIsFalse();
}
import com.vimochina.vimo.quartz.domain.QuartzLog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface QuartzLogRepository extends JpaRepository<QuartzLog,Long>, JpaSpecificationExecutor<QuartzLog> {
}
然后service包 service下dto包
import com.*.quartz.config.Query;
import lombok.Data;
import java.sql.Timestamp;
import java.util.List;
@Data
public class JobQueryCriteria {
@Query(type = Query.Type.INNER_LIKE)
private String jobName;
@Query
private Boolean isSuccess;
@Query(type = Query.Type.BETWEEN)
private List<Timestamp> createTime;
}
接口
import com.vimochina.vimo.quartz.domain.QuartzJob;
import com.vimochina.vimo.quartz.domain.QuartzLog;
import com.vimochina.vimo.quartz.service.dto.JobQueryCriteria;
import org.springframework.data.domain.Pageable;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
public interface QuartzJobService {
/**
* 分页查询
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAll(JobQueryCriteria criteria, Pageable pageable);
/**
* 查询全部
* @param criteria 条件
* @return /
*/
List<QuartzJob> queryAll(JobQueryCriteria criteria);
/**
* 分页查询日志
* @param criteria 条件
* @param pageable 分页参数
* @return /
*/
Object queryAllLog(JobQueryCriteria criteria, Pageable pageable);
/**
* 查询全部
* @param criteria 条件
* @return /
*/
List<QuartzLog> queryAllLog(JobQueryCriteria criteria);
/**
* 创建
* @param resources /
* @return /
*/
QuartzJob create(QuartzJob resources);
/**
* 编辑
* @param resources /
*/
void update(QuartzJob resources);
/**
* 删除任务
* @param ids /
*/
void delete(Set<Long> ids);
/**
* 根据ID查询
* @param id ID
* @return /
*/
QuartzJob findById(Long id);
/**
* 更改定时任务状态
* @param quartzJob /
*/
void updateIsPause(QuartzJob quartzJob);
/**
* 立即执行定时任务
* @param quartzJob /
*/
void execution(QuartzJob quartzJob);
}
实现类
import com.*.quartz.config.BadRequestException;
import com.*.quartz.config.PageUtil;
import com.*.quartz.config.QueryHelp;
import com.*.quartz.config.ValidationUtil;
import com.*.quartz.domain.QuartzJob;
import com.*.quartz.domain.QuartzLog;
import com.*.quartz.repository.QuartzJobRepository;
import com.*.repository.QuartzLogRepository;
import com.*.service.QuartzJobService;
import com.*.service.dto.JobQueryCriteria;
import com.*.quartz.utils.QuartzManage;
import org.quartz.CronExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
@Service(value = "quartzJobService")
@CacheConfig(cacheNames = "quartzJob")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class QuartzJobServiceImpl implements QuartzJobService {
@Autowired
private QuartzJobRepository quartzJobRepository;
@Autowired
private QuartzLogRepository quartzLogRepository;
@Autowired
private QuartzManage quartzManage;
@Cacheable
public Object queryAll(JobQueryCriteria criteria, Pageable pageable){
return PageUtil.toPage(quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable));
}
@Override
public Object queryAllLog(JobQueryCriteria criteria, Pageable pageable){
return com.vimochina.vimo.quartz.config.PageUtil.toPage(quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable));
}
@Override
public List<QuartzJob> queryAll(JobQueryCriteria criteria) {
return quartzJobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
}
@Override
public List<QuartzLog> queryAllLog(JobQueryCriteria criteria) {
return quartzLogRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder));
}
@Override
@Cacheable(key = "#p0")
public QuartzJob findById(Long id) {
QuartzJob quartzJob = quartzJobRepository.findById(id).orElseGet(QuartzJob::new);
ValidationUtil.isNull(quartzJob.getId(),"QuartzJob","id",id);
return quartzJob;
}
@Override
@CacheEvict(allEntries = true) //来删除缓存
@Transactional(rollbackFor = Exception.class)
public QuartzJob create(QuartzJob resources) {
if (!CronExpression.isValidExpression(resources.getCronExpression())){
throw new BadRequestException("cron表达式格式错误");
}
resources = quartzJobRepository.save(resources);
quartzManage.addJob(resources);
return resources;
}
@Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class)
public void update(QuartzJob resources) {
if (!CronExpression.isValidExpression(resources.getCronExpression())){
throw new BadRequestException("cron表达式格式错误");
}
resources = quartzJobRepository.save(resources);
quartzManage.updateJobCron(resources);
}
@Override
@CacheEvict(allEntries = true)
public void updateIsPause(QuartzJob quartzJob) {
if (quartzJob.getIsPause()) {
quartzManage.resumeJob(quartzJob);
quartzJob.setIsPause(false);
} else {
quartzManage.pauseJob(quartzJob);
quartzJob.setIsPause(true);
}
quartzJobRepository.save(quartzJob);
}
@Override
public void execution(QuartzJob quartzJob) {
quartzManage.runJobNow(quartzJob);
}
@Override
@CacheEvict(allEntries = true)
@Transactional(rollbackFor = Exception.class)
public void delete(Set<Long> ids) {
for (Long id : ids) {
if(id.equals(1L)){
throw new BadRequestException("更新访客记录不可删除,你可以在后台代码中取消该限制");
}
QuartzJob quartzJob = findById(id);
quartzManage.deleteJob(quartzJob);
quartzJobRepository.delete(quartzJob);
}
}
}
创建rest包
import com.vimochina.vimo.quartz.domain.QuartzJob;
import com.vimochina.vimo.quartz.service.QuartzJobService;
import com.vimochina.vimo.quartz.service.dto.JobQueryCriteria;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
@Slf4j
@RestController
@Api(tags = "系统:定时任务管理")
@RequestMapping("/api/jobs")
public class QuartzJobController {
private static final String ENTITY_NAME = "quartzJob";
@Autowired
private QuartzJobService quartzJobService;
@ApiOperation("查询定时任务")
@GetMapping
public ResponseEntity<Object> getJobs(JobQueryCriteria criteria, Pageable pageable){
return new ResponseEntity<>(quartzJobService.queryAll(criteria,pageable), HttpStatus.OK);
}
@ApiOperation("查询任务执行日志")
@GetMapping(value = "/logs")
public ResponseEntity<Object> getJobLogs(JobQueryCriteria criteria, Pageable pageable){
return new ResponseEntity<>(quartzJobService.queryAllLog(criteria,pageable), HttpStatus.OK);
}
@ApiOperation("新增定时任务")
@PostMapping
public ResponseEntity<Object> create(@Validated @RequestBody QuartzJob resources){
return new ResponseEntity<>(quartzJobService.create(resources),HttpStatus.CREATED);
}
@ApiOperation("修改定时任务")
@PutMapping
public ResponseEntity<Object> update(@Validated(QuartzJob.Update.class) @RequestBody QuartzJob resources){
quartzJobService.update(resources);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@ApiOperation("更改定时任务状态")
@PutMapping(value = "/{id}")
public ResponseEntity<Object> updateIsPause(@PathVariable Long id){
quartzJobService.updateIsPause(quartzJobService.findById(id));
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@ApiOperation("执行定时任务")
@PutMapping(value = "/exec/{id}")
public ResponseEntity<Object> execution(@PathVariable Long id){
quartzJobService.execution(quartzJobService.findById(id));
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@ApiOperation("删除定时任务")
@DeleteMapping
public ResponseEntity<Object> delete(@RequestBody Set<Long> ids){
quartzJobService.delete(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}
接下来创建task包里面写执行的任务
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class VisitsTask {
//这里面协执行的任务
public void task(){
log.info("执行成功");
}
}
接着创建utils包
import com.*.quartz.config.SpringContextHolder;
import com.*.quartz.config.ThreadPoolExecutorUtil;
import com.*.quartz.config.ThrowableUtil;
import com.*.quartz.domain.QuartzJob;
import com.*.quartz.domain.QuartzLog;
import com.*.quartz.repository.QuartzLogRepository;
import com.*.quartz.service.QuartzJobService;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.util.concurrent.*;
@Async
public class ExecutionJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/** 该处仅供参考 */
private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();
@Override
@SuppressWarnings("unchecked")
protected void executeInternal(JobExecutionContext context) {
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
// 获取spring bean
QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean(QuartzLogRepository.class);
QuartzJobService quartzJobService = SpringContextHolder.getBean(QuartzJobService.class);
QuartzLog log = new QuartzLog();
log.setJobName(quartzJob.getJobName());
log.setBeanName(quartzJob.getBeanName());
log.setMethodName(quartzJob.getMethodName());
log.setParams(quartzJob.getParams());
long startTime = System.currentTimeMillis();
log.setCronExpression(quartzJob.getCronExpression());
try {
// 执行任务
logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),
quartzJob.getParams());
Future<?> future = EXECUTOR.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
log.setTime(times);
// 任务状态
log.setIsSuccess(true);
logger.info("任务执行完毕,任务名称:{} 总共耗时:{} 毫秒", quartzJob.getJobName(), times);
} catch (Exception e) {
logger.error("任务执行失败,任务名称:{}" + quartzJob.getJobName(), e);
long times = System.currentTimeMillis() - startTime;
log.setTime(times);
// 任务状态 0:成功 1:失败
log.setIsSuccess(false);
log.setExceptionDetail(ThrowableUtil.getStackTrace(e));
quartzJob.setIsPause(false);
//更新状态
quartzJobService.updateIsPause(quartzJob);
} finally {
quartzLogRepository.save(log);
}
}
}
import com.*.quartz.config.BadRequestException;
import com.*.quartz.domain.QuartzJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import static org.quartz.TriggerBuilder.newTrigger;
@Slf4j
@Component
public class QuartzManage {
private static final String JOB_NAME = "TASK_";
@Resource(name = "scheduler")
private Scheduler scheduler;
public void addJob(QuartzJob quartzJob){
try {
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).withIdentity(JOB_NAME + quartzJob.getId()).build();
//通过触发器名和cron 表达式创建 Trigger
Trigger cronTrigger = newTrigger().withIdentity(JOB_NAME + quartzJob.getId()).startNow().withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression())).build();
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//重置启动时间
((CronTriggerImpl)cronTrigger).setStartTime(new Date());
//执行定时任务
scheduler.scheduleJob(jobDetail,cronTrigger);
// 暂停任务
if (quartzJob.getIsPause()) {
pauseJob(quartzJob);
}
} catch (Exception e){
log.error("创建定时任务失败", e);
throw new BadRequestException("创建定时任务失败");
}
}
/**
* 更新job cron表达式
* @param quartzJob /
*/
public void updateJobCron(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null){
addJob(quartzJob);
trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
}
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//重置启动时间
((CronTriggerImpl)trigger).setStartTime(new Date());
trigger.getJobDataMap().put(QuartzJob.JOB_KEY,quartzJob);
scheduler.rescheduleJob(triggerKey, trigger);
// 暂停任务
if (quartzJob.getIsPause()) {
pauseJob(quartzJob);
}
} catch (Exception e){
log.error("更新定时任务失败", e);
throw new BadRequestException("更新定时任务失败");
}
}
/**
* 删除一个job
* @param quartzJob /
*/
public void deleteJob(QuartzJob quartzJob){
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
scheduler.deleteJob(jobKey);
} catch (Exception e){
log.error("删除定时任务失败", e);
throw new BadRequestException("删除定时任务失败");
}
}
/**
* 恢复一个job
* @param quartzJob /
*/
public void resumeJob(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null) {
addJob(quartzJob);
}
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.resumeJob(jobKey);
} catch (Exception e){
log.error("恢复定时任务失败", e);
throw new BadRequestException("恢复定时任务失败");
}
}
/**
* 立即执行job
* @param quartzJob /
*/
public void runJobNow(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null) {
addJob(quartzJob);
}
JobDataMap dataMap = new JobDataMap();
dataMap.put(QuartzJob.JOB_KEY, quartzJob);
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.triggerJob(jobKey,dataMap);
} catch (Exception e){
log.error("定时任务执行失败", e);
throw new BadRequestException("定时任务执行失败");
}
}
/**
* 暂停一个job
* @param quartzJob /
*/
public void pauseJob(QuartzJob quartzJob){
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
} catch (Exception e){
log.error("定时任务暂停失败", e);
throw new BadRequestException("定时任务暂停失败");
}
}
}
import com.*.quartz.config.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* 执行定时任务
* @author /
*/
@Slf4j
public class QuartzRunnable implements Callable {
private Object target;
private Method method;
private String params;
QuartzRunnable(String beanName, String methodName, String params)throws NoSuchMethodException, SecurityException {
this.target = SpringContextHolder.getBean(beanName);
this.params = params;
if (StringUtils.isNotBlank(params)) {
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
} else {
this.method = target.getClass().getDeclaredMethod(methodName);
}
}
@Override
public Object call() throws Exception {
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotBlank(params)) {
method.invoke(target, params);
} else {
method.invoke(target);
}
return null;
}
}
本代码摘自某个项目的的代码,仅供自己记录学习,如有侵犯联系删除。
上一篇: java中的过滤器Filter
下一篇: javaweb过滤器
推荐阅读
-
SpringBoot 定时任务的两种实现方法(Scheduled和quartz)以及InitializingBean接口的作用
-
Springboot定时任务
-
springboot schedule 解决定时任务不执行的问题
-
springboot项目scheduled定时任务#配置文件取值#jar包动态修改
-
基于spring+quartz的分布式定时任务框架实现
-
linux定时任务访问页面代替quartz集群_html/css_WEB-ITnose
-
Spring整合Quartz实现一个简单的定时任务
-
基于Quartz定时调度任务(详解)
-
SpringBoot与Quartz集成实现分布式定时任务集群的代码实例
-
SpringBoot2 task scheduler 定时任务调度器四种方式