首页
苏兮影视
随笔记
壁纸
更多
直播
时光轴
友联
关于
统计
Search
1
软件添加id功能按钮
708 阅读
2
v2ray节点搭建
508 阅读
3
typecho非常有特色的模块
460 阅读
4
QQxml消息卡片生成源码
421 阅读
5
Linux下提权常用小命令
366 阅读
谈天说地
建站源码
经验教程
资源分享
动漫美图
登录
Search
标签搜索
java
flutter
springboot
rust
安卓
linux
vue
docker
joe
快捷键
git
fish shell
maven
redis
netty
dart
groovy
js
设计模式
rpc
尽意
累计撰写
95
篇文章
累计收到
38
条评论
首页
栏目
谈天说地
建站源码
经验教程
资源分享
动漫美图
页面
苏兮影视
随笔记
壁纸
直播
时光轴
友联
关于
统计
搜索到
7
篇与
的结果
Spring Boot 整合 Swagger3
Swagger3 基于 OpenAPI 3 标准,支持自动生成直观的交互式 API 文档页面。快速集成1. 引入依赖在 pom.xml 中添加以下依赖:<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>2. 配置 Swagger创建配置类 SwaggerConfig,定义基本的 Swagger 配置:package com.example.swaggerdemo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; @Configuration public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.OAS_30) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.example.swaggerdemo")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Swagger3 API 文档") .description("Spring Boot 整合 Swagger3 示例") .version("1.0.0") .build(); } }3. 创建测试接口新增 HelloController 用于测试:package com.example.swaggerdemo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1") public class HelloController { @GetMapping("/hello") public String sayHello() { return "Hello, Swagger3!"; } }4. 启动并访问启动项目后,在浏览器中访问以下地址:http://localhost:8080/swagger-ui/您将看到一个交互式的 API 文档页面。常见问题1. 无法访问 Swagger UI确保依赖和配置无误。检查 basePackage 是否正确。2. 修改访问路径在 application.yml 中自定义路径:spring: web: path-mapping: swagger-ui: "/custom/swagger-ui"重新访问:http://localhost:8080/custom/swagger-ui/
2024年12月05日
39 阅读
0 评论
1 点赞
2024-12-04
Spring Boot 集成 JWT 简单实现
一、JWT 简介JSON Web Token (JWT) 是一种用于客户端与服务端之间安全传递信息的轻量级协议。它通常用于:用户认证:登录成功后颁发 Token,后续请求中携带该 Token。授权管理:通过 Token 判断用户是否有权限。JWT 的组成部分:Header:描述令牌的类型和算法。Payload:包含用户信息及其他声明。Signature:由 Header、Payload 和密钥生成,用于验证 Token 的完整性。二、项目依赖在项目的 pom.xml 中引入以下依赖:<dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> </dependency> </dependencies>三、创建 JWT 配置类1. 定义 JwtProperties通过 @ConfigurationProperties 注解加载外部配置:package com.example.jwt.config; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "jwt") public class JwtProperties { private String secret; // 秘钥 private long expiration; // 过期时间(秒) public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } public long getExpiration() { return expiration; } public void setExpiration(long expiration) { this.expiration = expiration; } }2. 激活配置类package com.example.jwt.config; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(JwtProperties.class) public class JwtConfig { }3. 在 application.yml 中添加配置jwt: secret: my-secret-key expiration: 3600 # 单位:秒四、编写 JWT 工具类创建 JwtUtils,用于生成和验证 Token:package com.example.jwt.utils; import com.example.jwt.config.JwtProperties; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.stereotype.Component; import java.util.Date; @Component public class JwtUtils { private final JwtProperties jwtProperties; public JwtUtils(JwtProperties jwtProperties) { this.jwtProperties = jwtProperties; } // 生成 JWT public String generateToken(String username) { return Jwts.builder() .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getExpiration() * 1000)) .signWith(SignatureAlgorithm.HS256, jwtProperties.getSecret()) .compact(); } // 验证 JWT public Claims validateToken(String token) { try { return Jwts.parser() .setSigningKey(jwtProperties.getSecret()) .parseClaimsJws(token) .getBody(); } catch (Exception e) { return null; // Token 无效 } } }五、实现登录接口1. 控制器 AuthControllerpackage com.example.jwt.controller; import com.example.jwt.utils.JwtUtils; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/auth") public class AuthController { private final JwtUtils jwtUtils; public AuthController(JwtUtils jwtUtils) { this.jwtUtils = jwtUtils; } // 登录接口 @PostMapping("/login") public Map<String, String> login(@RequestBody Map<String, String> request) { String username = request.get("username"); // 简单验证用户(实际中应使用数据库或其他认证机制) if ("admin".equals(username)) { String token = jwtUtils.generateToken(username); Map<String, String> response = new HashMap<>(); response.put("token", token); return response; } else { throw new RuntimeException("Invalid username or password"); } } }2. 测试接口使用 curl 测试登录接口:curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{"username": "admin"}'返回结果:{ "token": "eyJhbGciOiJIUzI1NiIsInR..." }六、实现简单的认证拦截器为了验证 Token 是否有效,我们可以使用拦截器来处理请求。1. 创建拦截器 JwtInterceptorpackage com.example.jwt.interceptor; import com.example.jwt.utils.JwtUtils; import io.jsonwebtoken.Claims; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class JwtInterceptor implements HandlerInterceptor { private final JwtUtils jwtUtils; public JwtInterceptor(JwtUtils jwtUtils) { this.jwtUtils = jwtUtils; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { token = token.substring(7); // 去掉 "Bearer " Claims claims = jwtUtils.validateToken(token); if (claims != null) { // 将用户名放入请求属性中 request.setAttribute("username", claims.getSubject()); return true; } } response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("Unauthorized"); return false; } }2. 注册拦截器package com.example.jwt.config; import com.example.jwt.interceptor.JwtInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { private final JwtInterceptor jwtInterceptor; public WebConfig(JwtInterceptor jwtInterceptor) { this.jwtInterceptor = jwtInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns("/**") .excludePathPatterns("/auth/login"); // 登录接口不拦截 } }七、验证拦截功能添加受保护接口package com.example.jwt.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @GetMapping("/user/info") public String getUserInfo(@RequestAttribute("username") String username) { return "Hello, " + username; } }测试接口访问受保护接口(无 Token):curl http://localhost:8080/user/info返回结果:Unauthorized携带 Token 访问:curl http://localhost:8080/user/info \ -H "Authorization: Bearer <your-jwt-token>"返回结果:Hello, admin
2024年12月04日
11 阅读
0 评论
1 点赞
RabbitMQ 消息队列详解及 Spring Boot 实战教程
2024年11月26日
29 阅读
0 评论
3 点赞
2024-11-26
RabbitMQ 是一个高效、可靠的消息代理中间件,广泛应用于分布式系统中,用于实现微服务之间的异步通信和解耦。一、RabbitMQ 基本概念1.1 核心概念队列(Queue):存储消息的容器,消息由生产者发送到队列,消费者从队列中取出进行处理。支持点对点(P2P)模式。交换机(Exchange):负责根据路由规则将消息分发到队列。常见交换机类型:Direct、Fanout、Topic。绑定(Binding):连接交换机和队列的规则,结合路由键(Routing Key)定义消息的路由方式。消息模型:点对点模式(P2P): 一条消息只能被一个消费者消费。发布订阅模式(Pub/Sub): 一条消息可以被多个消费者消费。二、三种交换机详解2.1 Direct 交换机路由方式: 消息根据路由键(Routing Key)精准匹配到指定队列。优点: 简单、高效,适用于明确路由需求的场景。缺点: 需要为每个队列绑定具体的路由键,维护成本较高。应用场景: 点对点通知,如订单支付成功通知。2.2 Fanout 交换机路由方式: 广播消息到所有绑定队列,无需路由键。优点: 适合广播场景,无需复杂路由配置。缺点: 不支持消息过滤,容易造成资源浪费。应用场景: 全网公告或系统事件通知。2.3 Topic 交换机路由方式: 根据通配符模糊匹配路由键。* 匹配一个单词,# 匹配零个或多个单词。优点: 灵活的路由规则,支持复杂消息分发需求。缺点: 配置复杂,性能略低于其他类型交换机。应用场景: 新闻分类推送或订阅系统。三、Spring Boot 与 RabbitMQ 整合3.1 项目依赖在 pom.xml 文件中添加 RabbitMQ 依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>3.2 RabbitMQ 配置两种方式方法一:使用 application.yml 配置在 application.yml 文件中配置 RabbitMQ:spring: rabbitmq: host: localhost port: 5672 username: guest password: guest方法二:通过配置类创建连接工厂import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMQFactoryConfig { @Bean public ConnectionFactory connectionFactory() { CachingConnectionFactory factory = new CachingConnectionFactory(); factory.setHost("localhost"); factory.setPort(5672); factory.setUsername("guest"); factory.setPassword("guest"); return factory; } }3.3 交换机、队列及绑定的两种创建方式方法一:直接使用 new 创建import org.springframework.amqp.core.*; @Configuration public class RabbitMQDirectConfig { @Bean public Queue directQueue() { return new Queue("direct.queue"); } @Bean public DirectExchange directExchange() { return new DirectExchange("direct.exchange"); } @Bean public Binding bindingDirect(Queue directQueue, DirectExchange directExchange) { return BindingBuilder.bind(directQueue).to(directExchange).with("direct.key"); } }方法二:通过工厂类创建import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RabbitMQFactoryConfig { @Bean public Queue fanoutQueue() { return QueueBuilder.durable("fanout.queue").build(); } @Bean public FanoutExchange fanoutExchange() { return ExchangeBuilder.fanoutExchange("fanout.exchange").durable(true).build(); } @Bean public Binding bindingFanout(Queue fanoutQueue, FanoutExchange fanoutExchange) { return BindingBuilder.bind(fanoutQueue).to(fanoutExchange); } }3.4 消息生产者与消费者消息生产者import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.stereotype.Component; @Component public class MessageProducer { private final RabbitTemplate rabbitTemplate; public MessageProducer(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } public void sendDirectMessage(String message) { rabbitTemplate.convertAndSend("direct.exchange", "direct.key", message); } public void sendFanoutMessage(String message) { rabbitTemplate.convertAndSend("fanout.exchange", "", message); } public void sendTopicMessage(String message) { rabbitTemplate.convertAndSend("topic.exchange", "topic.test", message); } }消息消费者import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component public class MessageConsumer { @RabbitListener(queues = "direct.queue") public void receiveDirectMessage(String message) { System.out.println("Received Direct Message: " + message); } @RabbitListener(queues = "fanout.queue") public void receiveFanoutMessage(String message) { System.out.println("Received Fanout Message: " + message); } }3.5 单元测试使用 JUnit 测试消息发送功能:import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class RabbitMQTest { @Autowired private MessageProducer messageProducer; @Test public void testDirectMessage() { messageProducer.sendDirectMessage("Test Direct Exchange"); } @Test public void testFanoutMessage() { messageProducer.sendFanoutMessage("Test Fanout Exchange"); } }四、总结本文通过介绍 RabbitMQ 的核心概念,分析了三种交换机的优缺点及适用场景,并通过 Spring Boot 实现了 MQ 的完整配置与消息生产、消费功能。提供的两种实现方式(application.yml 配置和配置类方式,以及直接 new 和工厂创建方式)为不同项目需求提供了灵活选择。
Quartz 整合 Spring Boot
1. 项目初始化1.1 引入依赖首先,我们需要在 Spring Boot 项目中引入 Quartz 相关的依赖。对于 Maven 项目,编辑 pom.xml 文件,添加如下依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>对于 Gradle 项目,则添加如下依赖:implementation 'org.springframework.boot:spring-boot-starter-quartz'1.2 添加数据库支持(可选)如果我们打算让 Quartz 任务持久化(任务信息存储到数据库中),则需要添加数据库驱动。例如,使用 MySQL 数据库时,添加以下依赖:<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>这样我们就可以通过 Quartz 将任务存储在数据库中,保证任务在调度器重启后仍然存在。2. 创建 Quartz 任务2.1 创建一个简单的 Job在 Quartz 中,每个任务都由一个 Job 类来表示。Job 是 Quartz 的核心接口,它只有一个 execute() 方法,当触发器触发任务时,该方法将会被调用。我们首先创建一个简单的任务类 MyQuartzJob,该任务每次被触发时会输出 "Hello, Quartz!" 以及当前的时间。import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.stereotype.Component; @Component public class MyQuartzJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("执行任务: Hello, Quartz! 当前时间: " + System.currentTimeMillis()); } }2.2 解释Job 接口要求实现 execute(JobExecutionContext context) 方法,这个方法将在任务触发时被 Quartz 调度器调用。JobExecutionContext 提供了调度任务的上下文信息,如任务数据、触发器信息等。我们使用了 @Component 注解将该任务类注册为 Spring 的 Bean,便于在配置中注入和管理。3. 配置 Quartz 调度任务为了使任务能够被 Quartz 调度器调度,我们需要配置 JobDetail 和 Trigger。JobDetail 定义了任务的具体信息,而 Trigger 定义了任务的触发规则(如时间间隔、执行次数等)。3.1 基于时间间隔的 SimpleTrigger以下是一个配置类 QuartzConfig,它定义了一个每 5 秒触发一次的任务。import org.quartz.JobDetail; import org.quartz.Trigger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; @Configuration public class QuartzConfig { // 配置 JobDetail @Bean public JobDetailFactoryBean jobDetail() { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); factoryBean.setJobClass(MyQuartzJob.class); // 绑定 Job 类 factoryBean.setDescription("这是一个示例 Quartz Job"); factoryBean.setDurability(true); // 任务持久化 return factoryBean; } // 配置 Trigger(每 5 秒执行一次) @Bean public SimpleTriggerFactoryBean trigger(JobDetail jobDetail) { SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean(); factoryBean.setJobDetail(jobDetail); // 绑定任务 factoryBean.setRepeatInterval(5000); // 每 5 秒触发一次 factoryBean.setRepeatCount(SimpleTriggerFactoryBean.REPEAT_INDEFINITELY); // 无限重复执行 return factoryBean; } }3.2 解释JobDetailFactoryBean:用于定义 Quartz 的 JobDetail。它将指定的 Job 与任务元数据(如任务描述、持久化策略等)绑定。SimpleTriggerFactoryBean:用于配置一个简单触发器(SimpleTrigger),我们可以设置触发间隔时间(单位:毫秒)以及重复执行次数。在这个示例中,任务会每隔 5 秒重复执行一次,且无限次重复。3.3 CronTrigger 的使用如果需要更复杂的触发条件,比如按照每天某个时间点或每周的某些特定时刻触发任务,Quartz 提供了 CronTrigger。CronTrigger 允许我们通过 Cron 表达式精确地控制任务的调度时间。import org.quartz.JobDetail; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; @Configuration public class QuartzCronConfig { // 配置 JobDetail @Bean public JobDetailFactoryBean cronJobDetail() { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); factoryBean.setJobClass(MyQuartzJob.class); factoryBean.setDescription("这是一个示例 Cron Quartz Job"); factoryBean.setDurability(true); // 任务持久化 return factoryBean; } // 配置 CronTrigger(每 10 秒执行一次) @Bean public CronTriggerFactoryBean cronTrigger(JobDetail cronJobDetail) { CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); factoryBean.setJobDetail(cronJobDetail); // 绑定任务 factoryBean.setCronExpression("0/10 * * * * ?"); // 每 10 秒触发一次 return factoryBean; } }3.4 Cron 表达式解释"0/10 * * * * ?":每隔 10 秒执行一次。Cron 表达式的格式是 "秒 分 时 日 月 星期 年(可选)"。这个表达式表示每分钟的第 0 秒开始,每 10 秒触发一次任务。4. 使用 JobDataMap 传递参数在实际应用中,任务往往需要使用外部数据。Quartz 提供了 JobDataMap,用于在任务执行时传递参数。4.1 配置任务并传递参数在 JobDetailFactoryBean 中,我们可以通过 setJobDataAsMap() 方法传递参数:@Bean public JobDetailFactoryBean jobDetailWithParams() { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); factoryBean.setJobClass(MyQuartzJob.class); factoryBean.setDescription("带参数的 Quartz Job"); factoryBean.setDurability(true); // 传递参数 Map<String, Object> jobDataMap = new HashMap<>(); jobDataMap.put("param1", "参数值1"); factoryBean.setJobDataAsMap(jobDataMap); return factoryBean; }4.2 在 Job 中获取参数在 execute() 方法中,我们可以通过 JobExecutionContext 获取传递的参数:public class MyQuartzJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { String param1 = context.getMergedJobDataMap().getString("param1"); System.out.println("执行任务,参数1: " + param1); } }JobDataMap 允许我们在任务执行时携带自定义数据,并在任务中访问这些数据。对于复杂的业务逻辑,这一特性非常实用。5. 任务持久化(使用 JDBC)Quartz 支持将任务信息持久化到数据库中,这对于任务调度器重启时继续执行未完成的任务非常重要。为了使用持久化功能,我们需要配置数据库,并让 Quartz 将任务和调度信息保存到数据库中。5.1 创建数据库表首先,你需要为 Quartz 创建数据库表。Quartz 官方提供了 SQL 脚本用于创建这些表。你可以在 Quartz 文档 中找到5.2 配置 Quartz 使用数据库在 application.properties 或 application.yml 文件中,我们需要配置 Quartz 使用 JDBC 存储任务调度数据。对于 application.properties:spring.quartz.job-store-type=jdbc # 使用数据库存储 spring.quartz.jdbc.initialize-schema=always # 自动创建表,生产环境中建议使用 validate spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate # JDBC驱动代理 spring.datasource.url=jdbc:mysql://localhost:3306/quartz_db?useSSL=false&serverTimezone=UTC # 数据库连接URL spring.datasource.username=root # 数据库用户名 spring.datasource.password=your_password # 数据库密码对于 application.yml:spring: quartz: job-store-type: jdbc # 使用数据库存储 jdbc: initialize-schema: always # 自动创建表 properties: org: quartz: jobStore: driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # JDBC代理 datasource: url: jdbc:mysql://localhost:3306/quartz_db?useSSL=false&serverTimezone=UTC # 数据库URL username: root # 数据库用户名 password: your_password # 数据库密码5.3 初始化数据库Quartz 提供了内置的表结构,默认会在数据库中创建任务、触发器、锁等所需的表。配置 spring.quartz.jdbc.initialize-schema=always 可以让 Spring Boot 在启动时自动初始化这些表。你也可以手动执行 Quartz 提供的 SQL 脚本,这些脚本位于 Quartz 官方发布包的 docs/dbTables 目录下。5.4 解释job-store-type:指定 Quartz 如何存储任务信息。memory 表示将任务存储在内存中,jdbc 则表示将任务存储在数据库中。driverDelegateClass:指定数据库驱动代理类。对于 MySQL,我们使用 StdJDBCDelegate,如果使用其他数据库(如 PostgreSQL),则需要根据数据库类型选择对应的代理类。initialize-schema:控制是否在启动时自动创建 Quartz 需要的表。生产环境下应设置为 validate,以避免重复创建表。5.5 测试任务持久化当 Quartz 任务配置完成并启动时,所有的任务、触发器以及调度信息都会存储到配置的数据库中。你可以停止并重启应用程序,来验证任务的持久性。如果配置正确,任务调度器重新启动后,Quartz 将从数据库中恢复之前的任务调度信息并继续执行未完成的任务。6. 任务并发控制默认情况下,Quartz 会在多个线程中并发执行多个任务。如果你希望控制任务的并发执行,可以通过 @DisallowConcurrentExecution 注解来实现,确保同一个任务在同一时间只有一个实例在运行。6.1 禁止并发执行修改我们的 MyQuartzJob 类,添加 @DisallowConcurrentExecution 注解:import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.stereotype.Component; @DisallowConcurrentExecution // 禁止并发执行 @Component public class MyQuartzJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("执行任务: Hello, Quartz! 当前时间: " + System.currentTimeMillis()); } }6.2 解释@DisallowConcurrentExecution:Quartz 提供的注解,用于确保在同一时间内同一任务(JobDetail)只能执行一次。如果该任务正在运行,新的任务不会并发执行。7. 动态添加与删除任务在实际应用中,我们可能需要根据某些业务规则动态地添加或删除定时任务。Quartz 支持动态管理任务,可以通过 Quartz 提供的 API 来实现任务的增删改查。7.1 动态添加任务以下是一个示例,用于动态添加任务:import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class QuartzJobService { @Autowired private Scheduler scheduler; // 注入 Quartz 的 Scheduler // 动态添加任务 public void addJob(String jobName, String groupName, String cronExpression) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(MyQuartzJob.class) .withIdentity(jobName, groupName) .build(); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(jobName + "Trigger", groupName) .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); scheduler.scheduleJob(jobDetail, trigger); // 将任务和触发器注册到调度器 } }7.2 动态删除任务以下是动态删除任务的示例:public void deleteJob(String jobName, String groupName) throws SchedulerException { JobKey jobKey = JobKey.jobKey(jobName, groupName); scheduler.deleteJob(jobKey); // 删除指定的任务 }7.3 调用示例你可以通过 REST API 或者在服务启动时调用这些方法:@RestController @RequestMapping("/jobs") public class JobController { @Autowired private QuartzJobService jobService; @PostMapping("/add") public String addJob(@RequestParam String jobName, @RequestParam String groupName, @RequestParam String cronExpression) { try { jobService.addJob(jobName, groupName, cronExpression); return "任务添加成功"; } catch (SchedulerException e) { e.printStackTrace(); return "任务添加失败"; } } @DeleteMapping("/delete") public String deleteJob(@RequestParam String jobName, @RequestParam String groupName) { try { jobService.deleteJob(jobName, groupName); return "任务删除成功"; } catch (SchedulerException e) { e.printStackTrace(); return "任务删除失败"; } } }8. 总结通过本教程,你已经学会了如何将 Quartz 整合到 Spring Boot 中,并实现以下功能:创建简单的定时任务。使用 SimpleTrigger 和 CronTrigger 实现时间间隔和复杂调度的任务。通过 JobDataMap 向任务传递参数。实现任务的持久化,并将任务信息保存到数据库中。控制任务的并发执行,避免重复调度。动态添加和删除定时任务。Quartz 强大的调度功能与 Spring Boot 的简洁配置相结合,使得我们可以轻松构建复杂的任务调度系统。在实际应用中,你可以根据业务需求进行进一步的自定义和优化,构建一个高度可扩展的调度系统。
2024年10月19日
14 阅读
0 评论
2 点赞
SpringBoot配合Lombok代替@Autowired
@RequiredArgsConstructor是Lombok库提供的注解之一,它的作用是自动生成一个包含所有被标注的final字段的构造函数。 @Component @RequiredArgsConstructor public class MyController { private final MyService myService; }
2024年02月02日
65 阅读
0 评论
1 点赞
1
2