使用Redis记录错误次数、序列号锁定和冻结时间的实现步骤示例[超详细]
使用Redis记录错误次数、序列号锁定和冻结时间的实现步骤
在本文中,我们将详细介绍如何使用Redis来记录错误次数、序列号锁定和冻结时间。通过Spring Boot和Spring Data Redis,我们能够轻松实现这些功能。
依赖
首先,确保你的项目中包含以下依赖:
- Spring Boot
- Spring Data Redis
在 pom.xml
中添加以下依赖:
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 其他依赖 -->
</dependencies>
配置
在 application.yml
中配置Redis连接:
spring:redis:host: localhostport: 6379
实现
接下来,编写服务类和控制器来实现需求。
Redis配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new StringRedisSerializer());return template;}
}
服务类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;@Service
public class ValidationService {private static final String NAME_ID_KEY = "name_id:";private static final String CARD_ERROR_KEY = "card_error:";private static final int LOCK_TIME = 5; // minutesprivate static final int MAX_ATTEMPTS = 5;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public boolean validateNameAndId(String name, String id, String correctName, String correctId) {if (name.equals(correctName) && id.equals(correctId)) {return true;}if (!name.equals(correctName)) {throw new IllegalArgumentException("姓名输入错误,请重新输入");}if (!id.equals(correctId)) {throw new IllegalArgumentException("工号输入错误,请重新输入");}return false;}public void validateCard(String serialNumber, String inputCard, String correctCard) {String cardErrorKey = CARD_ERROR_KEY + serialNumber;// 检查是否已锁定if (Boolean.TRUE.equals(redisTemplate.hasKey(cardErrorKey)) && redisTemplate.getExpire(cardErrorKey) > 0) {throw new IllegalStateException("密码错误次数过多,请稍后再试");}// 获取当前错误次数int attempts = redisTemplate.opsForValue().get(cardErrorKey) == null ? 0 : (int) redisTemplate.opsForValue().get(cardErrorKey);if (!inputCard.equals(correctCard)) {attempts++;if (attempts >= MAX_ATTEMPTS) {// 超过最大尝试次数,锁定序列号redisTemplate.opsForValue().set(cardErrorKey, attempts, LOCK_TIME, TimeUnit.MINUTES);throw new IllegalStateException("密码错误次数过多,请稍后再试");} else {// 更新错误次数redisTemplate.opsForValue().set(cardErrorKey, attempts);throw new IllegalArgumentException(String.format("卡密已输入错误%d次,超过%d次将锁定", attempts, MAX_ATTEMPTS));}} else {// ��证成功,清除错误次数redisTemplate.delete(cardErrorKey);}}
}
控制器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api/validate")
public class ValidationController {@Autowiredprivate ValidationService validationService;@PostMapping("/name-id")public String validateNameAndId(@RequestParam String name, @RequestParam String id) {// 假设 correctName 和 correctId 是从数据库或其他地方获取的正确值String correctName = "正确的姓名";String correctId = "正确的工号";try {validationService.validateNameAndId(name, id, correctName, correctId);return "姓名和工号校验通过";} catch (IllegalArgumentException e) {return e.getMessage();}}### 控制器```java@PostMapping("/card")public String validateCard(@RequestParam String serialNumber, @RequestParam String inputCard) {// 假设 correctCard 是从数据库或其他地方获取的正确卡密String correctCard = "正确的卡密";try {validationService.validateCard(serialNumber, inputCard, correctCard);return "卡密校验通过";} catch (IllegalArgumentException e) {return e.getMessage();} catch (IllegalStateException e) {return e.getMessage();}}
}
详细解析
Redis配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new StringRedisSerializer());return template;}
}
解释:
- 配置RedisTemplate来处理Redis操作,设置键和值的序列化器为
StringRedisSerializer
以便于存储和读取字符串类型的数据。
服务类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;@Service
public class ValidationService {private static final String NAME_ID_KEY = "name_id:";private static final String CARD_ERROR_KEY = "card_error:";private static final int LOCK_TIME = 5; // minutesprivate static final int MAX_ATTEMPTS = 5;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public boolean validateNameAndId(String name, String id, String correctName, String correctId) {if (name.equals(correctName) && id.equals(correctId)) {return true;}if (!name.equals(correctName)) {throw new IllegalArgumentException("姓名输入错误,请重新输入");}if (!id.equals(correctId)) {throw new IllegalArgumentException("工号输入错误,请重新输入");}return false;}public void validateCard(String serialNumber, String inputCard, String correctCard) {String cardErrorKey = CARD_ERROR_KEY + serialNumber;// 检查是否已锁定if (Boolean.TRUE.equals(redisTemplate.hasKey(cardErrorKey)) && redisTemplate.getExpire(cardErrorKey) > 0) {throw new IllegalStateException("密码错误次数过多,请稍后再试");}// 获取当前错误次数int attempts = redisTemplate.opsForValue().get(cardErrorKey) == null ? 0 : (int) redisTemplate.opsForValue().get(cardErrorKey);if (!inputCard.equals(correctCard)) {attempts++;if (attempts >= MAX_ATTEMPTS) {// 超过最大尝试次数,锁定序列号redisTemplate.opsForValue().set(cardErrorKey, attempts, LOCK_TIME, TimeUnit.MINUTES);throw new IllegalStateException("密码错误次数过多,请稍后再试");} else {// 更新错误次数redisTemplate.opsForValue().set(cardErrorKey, attempts);throw new IllegalArgumentException(String.format("卡密已输入错误%d次,超过%d次将锁定", attempts, MAX_ATTEMPTS));}} else {// 验证成功,清除错误次数redisTemplate.delete(cardErrorKey);}}
}
解释:
validateNameAndId
方法:校验用户输入的姓名和工号是否与正确的姓名和工号匹配。如果不匹配,抛出适当的异常。validateCard
方法:校验卡密是否正确。使用Redis记录每个序列号的错误次数,并在错误次数达到最大尝试次数时锁定序列号一定时间。attempts
变量用于记录当前错误次数。如果Redis中不存在该键,则初始化为0。- 如果输入的卡密不正确,错误次数增加:
- 如果错误次数达到或超过最大尝试次数(
MAX_ATTEMPTS
),则设置锁定时间(LOCK_TIME
),并抛出IllegalStateException
。 - 否则,更新错误次数并抛出
IllegalArgumentException
,提示错误次数。
- 如果错误次数达到或超过最大尝试次数(