崛起於Springboot2.0.X之頁面統一操作Quartz所有定時任務何時啟動(47)
(記得來開源中國關注我喲!如果部落格被我發現有不好的地方,都會優化更新的,所以關注我呦,嘻嘻)
技術棧:Springboot2.0.X(2.1.X也可以)+ Quartz +FastMybatis (自認為比mybatis-plus更方便的框架) + Hutool + lombok
FastMybatis框架部落格:
01、
02、崛起於Springboot2.0.X之整合FastMybatis精裝版 --> my.oschina.net/mdxlcj/blog/3059687
03、
Quartz入門級框架部落格:
04、崛起於Springboot2.0.X之整合Quartz定時排程 --> my.oschina.net/mdxlcj/blog/1862472
序言:之前公司有一個需求說是可以通過一個介面來操作定時任務的時間、包括修改、啟動、關閉等功能,而不是在程式碼中寫死,那個時候從網上找了很久都沒有找到,部落格都特別初級,只能算是入門的後來就不了了之了,目前已經實現開發出這套功能,公開一下,我也希望能夠幫助更多的人在企業更加快速的實現該功能,如圖:
然後我們看一下,新增定時任務配置截圖:
這個功能也有批量暫停定時任務的功能、立即恢復、以及執行,當然還有定時任務啟動時的日誌記錄,如圖:
所以接下來就進入開發階段,由於前端頁面是用vue寫的,我就不把前端程式碼弄出來了,反而這樣會讓大家使用起來比較費力,所以我們就不用vue進行測試了,只用後段自己生成資料來測試就可以了,也能夠達到目的的。
1、pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>net.oschina.durcframework</groupId> <artifactId>fastmybatis-spring-boot-starter</artifactId> <version>1.8.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
2、application.properties
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/ss?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=root
3、mysql表結構
CREATE TABLE `schedule_job` ( `job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任務id', `bean_name` varchar(200) DEFAULT NULL COMMENT 'spring bean名稱', `method_name` varchar(100) DEFAULT NULL COMMENT '方法名', `params` varchar(2000) DEFAULT NULL COMMENT '引數', `cron_expression` varchar(100) DEFAULT NULL COMMENT 'cron表示式', `status` tinyint(4) DEFAULT NULL COMMENT '任務狀態 0:啟動 1:擱置', `remark` varchar(255) DEFAULT NULL COMMENT '備註', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`job_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='定時任務' CREATE TABLE `schedule_job_log` ( `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任務日誌id', `job_id` bigint(20) NOT NULL COMMENT '任務id', `bean_name` varchar(200) DEFAULT NULL COMMENT 'spring bean名稱', `method_name` varchar(100) DEFAULT NULL COMMENT '方法名', `params` varchar(2000) DEFAULT NULL COMMENT '引數', `status` tinyint(4) NOT NULL COMMENT '任務狀態 0:成功 1:失敗', `error` varchar(2000) DEFAULT NULL COMMENT '失敗資訊', `times` int(11) NOT NULL COMMENT '耗時(單位:毫秒)', `create_time` datetime DEFAULT NULL COMMENT '建立時間', PRIMARY KEY (`log_id`), KEY `job_id` (`job_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='定時任務日誌'
4、實體類
import lombok.Data; import javax.persistence.*; import java.io.Serializable; import java.util.Date; @Data @Table(name = "schedule_job") public class ScheduleJobEntity implements Serializable { private static final long serialVersionUID = 1L; public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY"; //任務排程引數key @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "job_id") private Long jobId; //任務id @Column(name = "bean_name") private String beanName; //spring bean名稱 @Column(name = "method_name") private String methodName; //方法名 @Column(name = "params") private String params; //引數 @Column(name = "cron_expression") private String cronExpression; //cron表示式 @Column(name = "status") private Integer status; //任務狀態 @Column(name = "remark") private String remark; //備註 @Column(name = "create_time") private Date createTime; //建立時間 }
import lombok.Data; import javax.persistence.*; import java.io.Serializable; import java.util.Date; /** * 定時執行日誌 */ @Data @Table(name = "schedule_job_log") public class ScheduleJobLogEntity implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "log_id") private Long logId; //日誌id @Column(name = "job_id") private Long jobId; //任務id @Column(name = "bean_name") private String beanName; //spring bean名稱 @Column(name = "method_name") private String methodName;//方法名 @Column(name = "params") private String params; //引數 @Column(name = "status") private Integer status; // 任務狀態 0:成功 1:失敗 @Column(name = "error") private String error; //失敗資訊 @Column(name = "times") private Integer times; //耗時(單位:毫秒) @Column(name = "create_time") private Date createTime; //建立時間 }
請求介面統一返回實體類
import lombok.AllArgsConstructor; import lombok.Data; import lombok.ToString; @Data @AllArgsConstructor @ToString public class ResultData { private boolean success; private String code; private String message; private Object data; public ResultData() { this.success = true; this.code = "200"; } }
5、Util層
這一層程式碼大家看不明白沒有關係,畢竟這些都是工具類裡面的,不是我們開發日常編碼那種,所以只需要配置一次就好啦,正常開發我們就直接跳過第五步就好了。
import org.apache.commons.lang.StringUtils; import org.quartz.JobExecutionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.quartz.QuartzJobBean; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ScheduleJob extends QuartzJobBean { private Logger logger = LoggerFactory.getLogger(getClass()); private ExecutorService service = Executors.newSingleThreadExecutor(); @Override protected void executeInternal(JobExecutionContext context) { ScheduleJobEntity scheduleJob = (ScheduleJobEntity) context.getMergedJobDataMap() .get(ScheduleJobEntity.JOB_PARAM_KEY); //獲取spring bean ScheduleJobService scheduleJobService = (ScheduleJobService) SpringContextUtils.getBean("scheduleJobService"); //資料庫儲存執行記錄 ScheduleJobLogEntity log = new ScheduleJobLogEntity(); log.setJobId(scheduleJob.getJobId()); log.setBeanName(scheduleJob.getBeanName()); log.setMethodName(scheduleJob.getMethodName()); log.setParams(scheduleJob.getParams()); log.setCreateTime(new Date()); //任務開始時間 long startTime = System.currentTimeMillis(); try { //執行任務 logger.info("任務準備執行,任務ID:" + scheduleJob.getJobId()); ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(), scheduleJob.getMethodName(), scheduleJob.getParams()); Future<?> future = service.submit(task); future.get(); //任務執行總時長 long times = System.currentTimeMillis() - startTime; log.setTimes((int) times); //任務狀態 0:成功 1:失敗 log.setStatus(0); logger.info("任務執行完畢,任務ID:" + scheduleJob.getJobId() + " 總共耗時:" + times + "毫秒"); } catch (Exception e) { logger.error("任務執行失敗,任務ID:" + scheduleJob.getJobId(), e); //任務執行總時長 long times = System.currentTimeMillis() - startTime; log.setTimes((int) times); //任務狀態 0:成功 1:失敗 log.setStatus(1); log.setError(StringUtils.substring(e.toString(), 0, 2000)); } finally { scheduleJobService.saveLog(log); } } }
import org.apache.commons.lang.StringUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; public class ScheduleRunnable implements Runnable { private Object target; private Method method; private String params; public ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException { this.target = SpringContextUtils.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 void run() { try { ReflectionUtils.makeAccessible(method); if (StringUtils.isNotBlank(params)) { method.invoke(target, params); } else { method.invoke(target); } } catch (Exception e) { throw new RuntimeException("執行定時任務失敗", e); } } }
import org.quartz.*; public class ScheduleUtils { private final static String JOB_NAME = "TASK_"; /** * 獲取觸發器key */ public static TriggerKey getTriggerKey(Long jobId) { return TriggerKey.triggerKey(JOB_NAME + jobId); } /** * 獲取jobKey */ public static JobKey getJobKey(Long jobId) { return JobKey.jobKey(JOB_NAME + jobId); } /** * 獲取表示式觸發器 */ public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) { try { return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId)); } catch (SchedulerException e) { throw new RuntimeException("獲取定時任務CronTrigger出現異常", e); } } /** * 建立定時任務 */ public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { try { //構建job資訊 JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getJobId())).build(); //表示式排程構建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) .withMisfireHandlingInstructionDoNothing(); //按新的cronExpression表示式構建一個新的trigger CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build(); //放入引數,執行時的方法可以獲取 jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJob); scheduler.scheduleJob(jobDetail, trigger); //暫停任務 if (scheduleJob.getStatus() == 1) { pauseJob(scheduler, scheduleJob.getJobId()); } } catch (SchedulerException e) { throw new RuntimeException("建立定時任務失敗", e); } } /** * 更新定時任務 */ public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) { try { TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId()); //表示式排程構建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) .withMisfireHandlingInstructionDoNothing(); CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId()); //按新的cronExpression表示式重新構建trigger trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); //引數 trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJob); scheduler.rescheduleJob(triggerKey, trigger); //暫停任務 if (scheduleJob.getStatus() == 1) { pauseJob(scheduler, scheduleJob.getJobId()); } } catch (SchedulerException e) { throw new RuntimeException("更新定時任務失敗", e); } } /** * 立即執行任務 */ public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJob) { try { //引數 JobDataMap dataMap = new JobDataMap(); dataMap.put(ScheduleJobEntity.JOB_PARAM_KEY, scheduleJob); scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap); } catch (SchedulerException e) { throw new RuntimeException("立即執行定時任務失敗", e); } } /** * 暫停任務 */ public static void pauseJob(Scheduler scheduler, Long jobId) { try { scheduler.pauseJob(getJobKey(jobId)); } catch (SchedulerException e) { throw new RuntimeException("暫停定時任務失敗", e); } } /** * 恢復任務 */ public static void resumeJob(Scheduler scheduler, Long jobId) { try { scheduler.resumeJob(getJobKey(jobId)); } catch (SchedulerException e) { throw new RuntimeException("暫停定時任務失敗", e); } } /** * 刪除定時任務 */ public static void deleteScheduleJob(Scheduler scheduler, Long jobId) { try { scheduler.deleteJob(getJobKey(jobId)); } catch (SchedulerException e) { throw new RuntimeException("刪除定時任務失敗", e); } } }
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringContextUtils implements ApplicationContextAware { public static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtils.applicationContext = applicationContext; } public static Object getBean(String name) { return applicationContext.getBean(name); } public static <T> T getBean(String name, Class<T> requiredType) { return applicationContext.getBean(name, requiredType); } public static boolean containsBean(String name) { return applicationContext.containsBean(name); } public static boolean isSingleton(String name) { return applicationContext.isSingleton(name); } public static Class<? extends Object> getType(String name) { return applicationContext.getType(name); } /** * 從靜態變數applicationContext中取得Bean, 自動轉型為所賦值物件的型別. */ public static <T> T getBean(Class<T> requiredType) { return applicationContext.getBean(requiredType); } }
import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.util.Set; public class ValidatorUtils { private static Validator validator; static { validator = Validation.buildDefaultValidatorFactory().getValidator(); } /** * 校驗物件 * * @param object 待校驗物件 * @param groups 待校驗的組 * @throws BusinessException 校驗不通過,則報BusinessException異常 */ public static void validateEntity(Object object, Class<?>... groups) throws RuntimeException { Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups); if (!constraintViolations.isEmpty()) { ConstraintViolation<Object> constraint = (ConstraintViolation<Object>) constraintViolations.iterator().next(); throw new RuntimeException(constraint.getMessage()); } } }
6、dao層
import com.gitee.fastmybatis.core.mapper.CrudMapper; import java.util.List; import java.util.Map; public interface ScheduleJobDao extends CrudMapper<ScheduleJobEntity,Integer> { int updateBatchStatus(Map<String, Object> map); List<ScheduleJobEntity> queryList(Map<String, Object> map); ScheduleJobEntity queryObject(Long jobId); int queryTotal(Map<String, Object> map); void deleteBatch(Long[] jobIds); }
import com.gitee.fastmybatis.core.mapper.CrudMapper; public interface ScheduleJobLogDao extends CrudMapper<ScheduleJobLogEntity,Long> { ScheduleJobLogEntity queryObject(Long jobId); }
7、Service層
介面
public interface ScheduleJobService { /** * 根據ID,查詢定時任務 */ ScheduleJobEntity queryObject(Long jobId); /** * 查詢定時任務列表 */ List<ScheduleJobEntity> queryList(Map<String, Object> map); /** * 查詢總數 */ int queryTotal(Map<String, Object> map); /** * 儲存定時任務 */ void save(ScheduleJobEntity scheduleJob); /** * 更新定時任務 */ void update(ScheduleJobEntity scheduleJob); /** * 批量刪除定時任務 */ void deleteBatch(Long[] jobIds); /** * 批量更新定時任務狀態 */ int updateBatch(Long[] jobIds, int status); /** * 立即執行 */ void run(Long[] jobIds); /** * 暫停執行 */ void pause(Long[] jobIds); /** * 恢復執行 */ void resume(Long[] jobIds); /** * 定時任務列表+總數 */ ResultData listJob(int pageIndex, int pageSize); /** * 日誌查詢 */ ResultData queryLogObject(Long jobId); /** * 儲存日誌記錄 */ void saveLog(ScheduleJobLogEntity log); /** * 查詢日誌記錄列表 */ ResultData listLog(int pageIndex, int pageSize); }
實現類
import com.gitee.fastmybatis.core.query.Query; import org.quartz.CronTrigger; import org.quartz.Scheduler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.PostConstruct; import java.util.HashMap; import java.util.List; import java.util.Map; @Service("scheduleJobService") public class ScheduleJobServiceImpl implements ScheduleJobService { @Autowired private Scheduler scheduler; @Autowired private ScheduleJobDao schedulerJobDao; @Autowired ScheduleJobLogDao jobLogDao; /** * 專案啟動時,初始化定時器 */ @PostConstruct public void init(){ List<ScheduleJobEntity> scheduleJobList = schedulerJobDao.queryList(new HashMap<>()); for(ScheduleJobEntity scheduleJob : scheduleJobList){ CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getJobId()); //如果不存在,則建立 if(cronTrigger == null) { ScheduleUtils.createScheduleJob(scheduler, scheduleJob); }else { ScheduleUtils.updateScheduleJob(scheduler, scheduleJob); } } } @Override public ScheduleJobEntity queryObject(Long jobId) { return schedulerJobDao.queryObject(jobId); } @Override public List<ScheduleJobEntity> queryList(Map<String, Object> map) { return schedulerJobDao.queryList(map); } @Override public int queryTotal(Map<String, Object> map) { return schedulerJobDao.queryTotal(map); } @Override @Transactional public void save(ScheduleJobEntity scheduleJob) { schedulerJobDao.save(scheduleJob); ScheduleUtils.createScheduleJob(scheduler, scheduleJob); } @Override @Transactional public void update(ScheduleJobEntity scheduleJob) { ScheduleUtils.updateScheduleJob(scheduler, scheduleJob); schedulerJobDao.update(scheduleJob); } @Override @Transactional public void deleteBatch(Long[] jobIds) { for(Long jobId : jobIds){ ScheduleUtils.deleteScheduleJob(scheduler, jobId); } //刪除資料 schedulerJobDao.deleteBatch(jobIds); } @Override public int updateBatch(Long[] jobIds, int status){ Map<String, Object> map = new HashMap<>(); map.put("list", jobIds); map.put("status", status); return schedulerJobDao.updateBatchStatus(map); } @Override @Transactional public void run(Long[] jobIds) { for(Long jobId : jobIds){ ScheduleUtils.run(scheduler, queryObject(jobId)); } } @Override @Transactional public void pause(Long[] jobIds) { for(Long jobId : jobIds){ ScheduleUtils.pauseJob(scheduler, jobId); } updateBatch(jobIds, 1); } @Override @Transactional public void resume(Long[] jobIds) { for(Long jobId : jobIds){ ScheduleUtils.resumeJob(scheduler, jobId); } updateBatch(jobIds, 0); } @Override public ResultData listJob(int pageIndex, int pageSize) { ResultData resultData = new ResultData(); //查詢列表資料 Query query = new Query(); query.page(1,10); List<ScheduleJobEntity> jobList = schedulerJobDao.list(query); long total = schedulerJobDao.getCount(query); Map<String,Object> map = new HashMap<>(); map.put("total",total); map.put("list",jobList); resultData.setData(map); return resultData; } @Override public ResultData queryLogObject(Long jobId) { ResultData resultData = new ResultData(); resultData.setData(jobLogDao.getById(jobId)); return resultData; } @Override public void saveLog(ScheduleJobLogEntity log) { jobLogDao.save(log); } @Override public ResultData listLog(int pageIndex, int pageSize) { ResultData resultData = new ResultData(); //查詢列表資料 Query query = new Query(); query.page(pageIndex,pageSize); List<ScheduleJobLogEntity> jobList = jobLogDao.list(query); long total = jobLogDao.getCount(query); Map<String,Object> map = new HashMap<>(); map.put("total",total); map.put("list",jobList); resultData.setData(map); return resultData; } }
8、Controller層
@RestController @RequestMapping("/schedule") public class ScheduleJobController { @Autowired private ScheduleJobService scheduleJobService; /** * 定時任務列表 */ @RequestMapping("/list") public ResultData list() { return scheduleJobService.listJob(1,10); } /** * 定時任務資訊 */ @RequestMapping("/info/{jobId}") public ResultData info(@PathVariable("jobId") Long jobId) { ScheduleJobEntity schedule = scheduleJobService.queryObject(jobId); ResultData resultData = new ResultData(); resultData.setData(schedule); return resultData; } /** * 儲存定時任務 @RequestBody ScheduleJobEntity scheduleJob */ @RequestMapping("/save") public ResultData save() { //先測試編寫一個臨時ScheduleJobEntity,畢竟後端頁面不會寫 ScheduleJobEntity jobEntity = createJob(); ValidatorUtils.validateEntity(jobEntity); scheduleJobService.save(jobEntity); return new ResultData(); } /** * 修改定時任務 */ @RequestMapping("/update") public ResultData update(@RequestBody ScheduleJobEntity scheduleJob) { ValidatorUtils.validateEntity(scheduleJob); scheduleJobService.update(scheduleJob); return new ResultData(); } /** * 刪除定時任務 */ @RequestMapping("/delete") public ResultData delete(@RequestBody Long[] jobIds) { scheduleJobService.deleteBatch(jobIds); return new ResultData(); } /** * 立即執行任務 */ @RequestMapping("/run") public ResultData run(@RequestBody Long[] jobIds) { scheduleJobService.run(jobIds); return new ResultData(); } /** * 暫停定時任務 */ @RequestMapping("/pause") public ResultData pause(@RequestBody Long[] jobIds) { scheduleJobService.pause(jobIds); return new ResultData(); } /** * 恢復定時任務 */ @RequestMapping("/resume") public ResultData resume(@RequestBody Long[] jobIds) { scheduleJobService.resume(jobIds); return new ResultData(); } /** * 定時任務日誌列表 */ @RequestMapping("/log/list") public ResultData listLog() { return scheduleJobService.listLog(1,10); } /** * 定時任務日誌資訊查詢 */ @RequestMapping("/log/info/{logId}") public ResultData infoLog(@PathVariable("logId") Long logId) { return scheduleJobService.queryLogObject(logId); } public static ScheduleJobEntity createJob(){ ScheduleJobEntity jobEntity = new ScheduleJobEntity(); jobEntity.setBeanName("mytask"); jobEntity.setCreateTime(new Date()); jobEntity.setMethodName("firstTask"); jobEntity.setCronExpression("0/10 * * * * ?"); jobEntity.setParams(null); jobEntity.setStatus(1); jobEntity.setRemark("測試該定時任務的執行"); return jobEntity; } }
9、定時任務
該類涉及到@Component(value = "mytask")和方法名都將被前端頁面使用,使用這兩個屬性值定位到何時執行該定時任務。
import org.springframework.stereotype.Component; /** * @Author:MuJiuTian * @Description: 頁面控制定時任務的觸發時間、開啟和關閉都要有定時任務 * @Date: Created in 下午2:06 2019/8/27 */ @Component(value = "mytask") public class MyTask { public void firstTask(){ //再這個方法中執行task業務邏輯 System.out.println("該定時任務由前臺頁面控制何時啟動"); } }
10、啟動測試
謹記,啟動類,千萬不要新增@MapperScan(),因為集成了FastMybatis框架,已經自動封裝了。如果大家不喜歡這個框架的話,也可以使用Mybatis或者流行的Mybatis-plus或者TKMybatis、EasyMybatis等等框架。
測試介面:http://localhost:8081/schedule/save,我的埠是8081的。
結果如圖已經觸發我們剛剛寫的定時任務了:
成功啦!不喜歡用FastMybatis的話用其他框架操作mysql吧,畢竟我不太喜歡用mybatis-plus,畢竟需要多寫程式碼。 &nbs