🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。
🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。
🎉欢迎 👍点赞✍评论⭐收藏
🔎 SpringBoot 领域知识 🔎
链接 | 专栏 |
---|---|
SpringBoot 专业知识学习一 | SpringBoot专栏 |
SpringBoot 专业知识学习二 | SpringBoot专栏 |
SpringBoot 专业知识学习三 | SpringBoot专栏 |
SpringBoot 专业知识学习四 | SpringBoot专栏 |
SpringBoot 专业知识学习五 | SpringBoot专栏 |
SpringBoot 专业知识学习六 | SpringBoot专栏 |
SpringBoot 专业知识学习七 | SpringBoot专栏 |
SpringBoot 专业知识学习八 | SpringBoot专栏 |
SpringBoot 专业知识学习九 | SpringBoot专栏 |
SpringBoot 专业知识学习十 | SpringBoot专栏 |
本文将详细介绍如何在 Spring Boot 中实现定时任务,并涵盖了控制层、服务层、数据访问层、XML和YAML配置的使用方式。我们将从数据库创建表开始,一步一步地实现这些功能,并提供注意事项。最后,我们将总结整个过程。
在 Spring Boot 中实现定时任务功能
1. 创建数据库表
为了实现定时任务的功能,首先需要创建一个数据库表。我们可以创建一个名为 task
的表,包含以下四个字段:
- id:自增ID
- name :定时任务的名称
- description :定时任务描述
- dueDate :定时任务结束执行的时间
- completed:定时任务是否完成
创建执行定时任务的数据库表可以按照以下 SQL 语句来进行:
CREATE TABLE `task` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`description` varchar(255) DEFAULT NULL,`dueDate` datetime DEFAULT NULL,`completed` boolean DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
该表包含了 id
、name
、description
、 dueDate
和 completed
五个字段。其中,id
为自增主键,name
表示定时任务的名称,description
表示定时任务描述,dueDate
表示定时任务结束执行的时间,completed
表示定时任务是否完成。可以根据实际需求修改表结构。
2. 添加依赖
在 pom.xml
文件中添加定时任务依赖 spring-boot-starter-quartz
:
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>demo</artifactId><version>1.0.0</version><properties><java.version>11</java.version><spring.boot.version>2.6.1</spring.boot.version></properties><dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${spring.boot.version}</version></dependency><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.boot.version}</version></dependency><!-- Spring Boot Starter Data JPA --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId><version>${spring.boot.version}</version></dependency><!-- Spring Boot Starter Quartz --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId><version>${spring.boot.version}</version></dependency><!-- MySQL Connector --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><!-- Other dependencies --><!-- ... --></dependencies><build><plugins><!-- Maven Compiler Plugin --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin></plugins></build></project>
这样我们就可以使用 Quartz 框架来实现定时任务。
3. 创建定时任务实体类和 DAO 层
3.1 首先创建一个Task实体类,用于表示定时任务的属性。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;@Entity
public class Task {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String description;private LocalDateTime dueDate;private boolean completed;// 构造函数、Getter 和 Setter 方法public Task() {}public Task(String name, String description, LocalDateTime dueDate) {this.name = name;this.description = description;this.dueDate = dueDate;this.completed = false;}// Getter 和 Setter 方法省略...// 其他属性和方法省略...
}
在这个示例中,Task
实体类有以下属性:
id
:任务的唯一标识符,使用自动生成的递增值。name
:任务的名称。description
:任务的描述。dueDate
:任务的截止日期。completed
:任务是否已完成的标志。
注意,在这个示例中,使用了 Java 8 的 LocalDateTime
类型来表示日期和时间。您可以根据具体需求选择适合的日期时间类型。
请根据您的具体需求修改属性、构造函数和方法。接下来,您可以创建一个与数据库进行交互的 DAO 层。
3.2 创建一个 TaskDao 接口
定义对定时任务的基本增删改查方法,如 addTask
、deleteTask
、updateTask
、findTaskById
等。
import java.time.LocalDateTime;
import java.util.List;public interface TaskDao {void addTask(Task task);void deleteTask(long taskId);void updateTask(long taskId, String name, String description, LocalDateTime dueDate, boolean completed);Task findTaskById(long taskId);List<Task> findTasks();
}
在这个示例中,TaskDao
定义了如下基本操作:
addTask
:添加一个新的任务。deleteTask
:删除指定的任务。updateTask
:更新任务的名称、描述、截止日期和完成状态。findTaskById
:根据任务 ID 查找任务。findTasks
:获取当前所有的任务列表。
可以根据具体需求添加、修改或删除方法。但是,通常来说,一个 DAO 接口需要定义基本的 CRUD 操作,即增加、删除、更新、查询。我们建议您采用命名规范,例如按照方法名构造 SQL 语句,或者使用注解进行映射。另外,为了管理和维护代码,我们建议您将实现代码放在另外的类中,例如命名为 TaskDaoImpl
。
4. 创建 Service 层
4.1 在 TaskService
类中实现定时任务的操作方法,包括添加、删除、修改和查询方法等。
4.2 在方法中,可以通过调用 TaskDao
中的方法来完成对数据库的操作,如创建新任务、删除任务、修改任务等。
4.3 可以使用 @Autowired
注解将 TaskDao
注入到 TaskService
中,方便调用。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.time.LocalDateTime;
import java.util.List;@Service
public class TaskService {private final TaskDao taskDao;@Autowiredpublic TaskService(TaskDao taskDao) {this.taskDao = taskDao;}public void addTask(String name, String description, LocalDateTime dueDate) {Task task = new Task(name, description, dueDate);taskDao.addTask(task);}public void deleteTask(long taskId) {taskDao.deleteTask(taskId);}public void updateTask(long taskId, String name, String description, LocalDateTime dueDate, boolean completed) {Task existingTask = taskDao.findTaskById(taskId);if (existingTask != null) {existingTask.setName(name);existingTask.setDescription(description);existingTask.setDueDate(dueDate);existingTask.setCompleted(completed);taskDao.updateTask(existingTask);} else {throw new IllegalArgumentException("Task not found with ID: " + taskId);}}public Task findTaskById(long taskId) {return taskDao.findTaskById(taskId);}public List<Task> findTasks() {return taskDao.findTasks();}
}
在这个示例中,TaskService
类使用了依赖注入将 TaskDao
对象注入进来,并实现了以下操作方法:
addTask
:创建一个新的任务,并调用TaskDao
的addTask
方法将其添加到数据库中。deleteTask
:删除指定 ID 的任务,并调用TaskDao
的deleteTask
方法进行删除操作。updateTask
:根据指定 ID 更新任务的属性,并调用TaskDao
的updateTask
方法进行更新操作。findTaskById
:根据指定 ID 查找并返回任务对象。findTasks
:获取当前所有的任务列表。
请根据您的具体需求修改代码,并确保将适当的错误处理和验证逻辑添加到每个方法中。此外,确保适当地处理依赖注入,以使 TaskDao
正确地注入到 TaskService
类中。
请注意,在这个示例中,使用了 Spring 的 @Service
和 @Autowired
注解来实现依赖注入和服务的声明。如果您没有使用 Spring 或其他类似的框架,您可以手动创建和管理相关对象的实例。
5. 创建 Controller 层
5.1 在 TaskController
类中定义定时任务的 API 接口,使用 RESTful 风格。
5.2 可以使用 @Autowired
注解将 TaskService
注入到 TaskController
中,方便调用 TaskService
中的方法。
5.3 实现增删改查等控制器方法,通过 HTTP 请求来调用相应的方法。
当您在 Controller 层中创建的时候,可以考虑如下代码示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.time.LocalDateTime;
import java.util.List;@RestController
@RequestMapping("/tasks")
public class TaskController {private final TaskService taskService;@Autowiredpublic TaskController(TaskService taskService) {this.taskService = taskService;}@PostMappingpublic ResponseEntity<Task> addTask(@RequestBody TaskRequest taskRequest) {taskService.addTask(taskRequest.getName(), taskRequest.getDescription(), taskRequest.getDueDate());return new ResponseEntity<>(HttpStatus.CREATED);}@DeleteMapping("/{taskId}")public ResponseEntity<Task> deleteTask(@PathVariable long taskId) {taskService.deleteTask(taskId);return new ResponseEntity<>(HttpStatus.NO_CONTENT);}@PutMapping("/{taskId}")public ResponseEntity<Task> updateTask(@PathVariable long taskId, @RequestBody TaskRequest taskRequest) {taskService.updateTask(taskId, taskRequest.getName(), taskRequest.getDescription(), taskRequest.getDueDate(), taskRequest.isCompleted());return new ResponseEntity<>(HttpStatus.OK);}@GetMapping("/{taskId}")public ResponseEntity<Task> findTaskById(@PathVariable long taskId) {Task task = taskService.findTaskById(taskId);if (task != null) {return new ResponseEntity<>(task, HttpStatus.OK);} else {return new ResponseEntity<>(HttpStatus.NOT_FOUND);}}@GetMappingpublic ResponseEntity<List<Task>> findTasks() {List<Task> tasks = taskService.findTasks();return new ResponseEntity<>(tasks, HttpStatus.OK);}
}
在这个示例中,TaskController
类使用了 Spring 的 MVC 注解来定义不同的 HTTP 请求处理方法:
@RestController
:声明这是一个 RESTful 控制器。@RequestMapping("/tasks")
:指定该控制器处理的 URL 前缀。@PostMapping
:处理 HTTP POST 请求,并调用addTask
方法创建任务。@DeleteMapping("/{taskId}")
:处理 HTTP DELETE 请求,并调用deleteTask
方法删除指定 ID 的任务。@PutMapping("/{taskId}")
:处理 HTTP PUT 请求,并调用updateTask
方法更新指定 ID 的任务。@GetMapping("/{taskId}")
:处理 HTTP GET 请求,并调用findTaskById
方法获取指定 ID 的任务。@GetMapping
:处理 HTTP GET 请求,并调用findTasks
方法获取所有任务列表。
请根据您的具体需求修改代码,并确保将适当的错误处理和验证逻辑添加到每个方法中。此外,确保适当地处理依赖注入,以使 TaskService
正确地注入到 TaskController
类中。
在这个示例中,TaskRequest
是一个用于接收客户端请求的数据传输对象(DTO),根据您的需求,您可以根据实际情况创建适合自己的 DTO 类来接收和传递数据。
请注意,在这个示例中,使用了 Spring 的注解来简化了 RESTful API 的开发,如果您不使用 Spring 框架,可以根据自己所用框架的要求来编写 Controller 层的代码。
6. 创建定时任务工具类
创建一个 QuartzUtil
工具类,用于创建定时任务实例。
使用 JobBuilder
、TriggerBuilder
等工具类,设置定时任务的属性,如任务名称、任务组名、任务类、触发器类型、触发器名称、触发器组名等。
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;public class QuartzUtil {private static Scheduler scheduler;static {try {scheduler = new StdSchedulerFactory().getScheduler();scheduler.start();} catch (SchedulerException e) {e.printStackTrace();}}public static void addJob(String jobId, String jobGroup, String triggerId, String triggerGroup, Class<? extends Job> jobClass, String cronExpression) throws SchedulerException {JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobId, jobGroup).build();Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerId, triggerGroup).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).build();scheduler.scheduleJob(jobDetail, trigger);}public static void deleteJob(String jobId, String jobGroup) throws SchedulerException {JobKey jobKey = new JobKey(jobId, jobGroup);scheduler.deleteJob(jobKey);}public static void pauseJob(String jobId, String jobGroup) throws SchedulerException {JobKey jobKey = new JobKey(jobId, jobGroup);scheduler.pauseJob(jobKey);}public static void resumeJob(String jobId, String jobGroup) throws SchedulerException {JobKey jobKey = new JobKey(jobId, jobGroup);scheduler.resumeJob(jobKey);}public static void shutdown() throws SchedulerException {scheduler.shutdown();}}
使用示例:
public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("执行定时任务...");}}public class Main {public static void main(String[] args) {try {// 添加一个每分钟执行一次的定时任务QuartzUtil.addJob("job1", "jobGroup", "trigger1", "triggerGroup", TestJob.class, "0 * * * * ?");Thread.sleep(10000);// 暂停定时任务QuartzUtil.pauseJob("job1", "jobGroup");Thread.sleep(10000);// 恢复定时任务QuartzUtil.resumeJob("job1", "jobGroup");Thread.sleep(10000);// 删除定时任务QuartzUtil.deleteJob("job1", "jobGroup");// 停止定时任务调度器QuartzUtil.shutdown();} catch (Exception e) {e.printStackTrace();}}}
需要注意的是,上述示例仅为基础示例,具体使用中还需要根据实际情况进行调整。定时任务的配置可以参考 Quartz 官方文档,这里不再赘述。
7. 创建定时任务类
7.1 创建一个 TaskJob
类,实现 Quartz
框架的 Job
接口,实现需要执行的任务逻辑。
7.2 在 TaskJob
类中,通过重写 execute
方法来实现具体的任务逻辑。
可以在 TaskJob
类中重写 execute
方法来实现具体的任务逻辑。以下是一个示例:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;public class TaskJob implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {// 获取任务参数JobDataMap dataMap = context.getJobDetail().getJobDataMap();String taskName = dataMap.getString("taskName");// 需要执行的任务逻辑System.out.println("执行任务:" + taskName);// 任务完成后的操作System.out.println("任务执行完成");}
}
在上述示例中,我们通过 JobDataMap
获取了任务的参数,例如 taskName
。在 execute
方法中可以编写任意复杂的任务逻辑,您可以根据实际需求进行相应的操作,例如发送电子邮件、生成报告等。最后,您还可以在任务执行完成后进行适当的清理操作或记录完成状态。请根据您的具体需求在 execute
方法中编写任务逻辑。
8. 配置定时任务
在 application.yml
文件中添加定时任务的配置:
spring:quartz:job-store-type: jdbcjdbc:initialize-schema: always
这样就可以从数据库中读取定时任务的配置信息,并在启动时创建相应的数据库表。
9. 测试
在启动 Spring Boot 项目后,通过浏览器访问 http://localhost:8080/task
来测试新增定时任务的功能是否生效。
10. 实现总结
通过以上步骤,我们成功地在 Spring Boot 中实现了定时任务的功能。使用 Spring Boot Starter Quartz 提供的依赖,我们可以方便地创建和管理定时任务。通过创建数据库表、编写实体类、DAO 层、Service 层和 Controller 层,我们实现了定时任务的增删改查功能。
需要注意的是,定时任务的时间格式是 cron
表达式,需要熟悉 cron
表达式的语法规则。同时,在测试时要注意定时任务是否已经失效,否则会影响测试结果。
总的来说,Spring Boot 提供了简单、便捷的方式来实现定时任务。通过合理地使用 Spring Boot 中的各个组件,我们可以快速地开发定时任务功能,并为我们的项目提供定时任务的支持。