SpringBoot + SpringTask + SpringDataJPA
業務:
用戶選擇 自動關閉
后, 可以選擇一個時間(格式為yyyy-MM-dd hh:mm),時間到后觸發定時任務,關閉或開啟系統(修改狀態)
精確到秒倒計時會出錯(未知), 所以就規定用戶不能選秒, 業務邏輯也是可以的(不太好).
核心代碼:
DynamicTaskController :
/**
* 定時任務接口
*
* @author wqkeep
* @date 2020/6/10 14:51
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/XXXXXX/task")
public class DynamicTaskController extends BaseController {
//BaseController 主要用於調用JSONResponse ,給JSONResponse 中的參數賦值,this.success(Object data)就是這樣
//JSONResponse 封裝好的返回結果,有 是否成功success,數據data,消息提示msg,狀態碼status
private final TaskServiceImpl taskServiceImpl;
/**
* 開啟報名通道定時任務
*
* @param id 系統id
* @param sysStatus 系統狀態
* @param countDownTime 倒計時時間
* @return JSONResponse 封裝好的返回結果,有 是否成功success,數據data,消息提示msg,狀態碼status
* @throws OperationException 封裝好的自定義異常信息
*/
@PostMapping("/XXXXXX/startCron")
public JSONResponse startCron(Long id, Integer sysStatus, @RequestParam("date") String countDownTime) throws OperationException {
taskServiceImpl.startCron(id, sysStatus,countDownTime);
return this.success(SysConst.SUCCESS);
}
/**
* 關閉當前線程定時任務
*
* @return JSONResponse
*/
@PostMapping("/XXXXXX/stopCron")
public JSONResponse stopCron() {
taskServiceImpl.stopCron();
return this.success(SysConst.SUCCESS);
}
/**
* TODO 定時任務存在問題
*
* 目前可以實現倒計時的功能, 但系統如果要集群就會存在問題(關閉不了當前線程, 用戶可能會修改多個不同線程的定時任務).
*
*/
}
TaskServiceImpl:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
/**
* 定時任務
*
* @author wqkeep
* @date 2020/6/10 17:31
*/
@Slf4j
@Service
@Transactional(rollbackOn = RuntimeException.class)
public class TaskServiceImpl implements TaskService {
@Autowired
private TaskRepository taskRepository; //(PO)實體類Task 對應的Repository
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private ScheduledFuture<?> future;
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
/**
* 開啟報名通道定時任務
*
* @param id 系統id
* @param sysStatus 系統狀態
* @param countDownTime 倒計時時間
* @throws OperationException 自定義異常信息
*/
public void startCron(Long id, Integer sysStatus, String countDownTime) throws OperationException {
String currentThread = Thread.currentThread().getName();
log.info("DynamicTask 報名通道定時任務開啟: 當前線程 " + currentThread);
String strDateFormat = "yyyy-MM-dd HH:mm";
SimpleDateFormat sd = new SimpleDateFormat(strDateFormat);
Date countDownDate = null;
try {
countDownDate = sd.parse(countDownTime);
} catch (Exception e) {
throw new OperationException("字符串轉換日期失敗");
}
String cron = CronDateUtils.getCron(countDownDate);
//task為自定義的定時任務實體類 我這里主要存儲cron表達式和定時任務具體時間,需要定時任務的系統名字,只有一個定時任務需求,所以寫死了(不好)
Task task = new Task();
task.setId(1L);
task.setCron(cron);
task.setName("XXXXX系統");
task.setRemark("自動開啟關閉");
task.setCountDownTime(countDownDate);
//保存 自定義的定時任務實體類task
taskRepository.save(task);
if (future != null) {
future.cancel(true);
}
future = threadPoolTaskScheduler.schedule(new Runnable() {
@SneakyThrows
@Override
public void run() {
//業務代碼, 我這里是修改系統狀態為關閉或開啟
stopCron();
log.info("DynamicTask 報名通道定時任務停止: 當前線程 " + currentThread);
}
}, new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
});
}
/**
* 關閉當前線程定時任務
*/
public void stopCron() {
if (future != null) {
future.cancel(true);
}
}
}
cron表達式和日期轉換工具類CronDateUtils :
import com.zjxf.config.exception.custom.OperationException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 定時任務cron表達式與Date之間的轉換
*
* @author wqkeep
* @date 2020/6/10 14:51
*/
public class CronDateUtils {
//自定義cron表達式格式 可以修改
private static final String CRON_DATE_FORMAT = "0/1 mm HH dd MM ?";
/***
* Date轉換為cron表達式
*
* @param date 時間
* @return cron類型的日期
*/
public static String getCron(final Date date){
SimpleDateFormat sdf = new SimpleDateFormat(CRON_DATE_FORMAT);
String formatTimeStr = "";
if (date != null) {
formatTimeStr = sdf.format(date);
}
return formatTimeStr;
}
/**
* cron表達式轉換為Date
*
* @param cron Quartz cron的類型的日期
* @return Date日期
* @throws OperationException 自定義異常信息
*/
public static Date getDate(final String cron) throws OperationException {
if(cron == null) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat(CRON_DATE_FORMAT);
Date date = null;
try {
date = sdf.parse(cron);
} catch (Exception e) {
throw new OperationException("轉換失敗");
}
return date;
}
}
參考博客:
https://blog.csdn.net/weixin_37591536/article/details/82150933