1、延时队列操作类 RedisDelayQueue
import com.eshore.zhyl.common.util.JsonUtil;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author cp
* rediss 延时队列操作类
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class RedisDelayQueue {
private final RedissonClient redissonClient;
private Map<String, RBlockingQueue<String>> blockingQueueMap = Maps.newHashMap();
private Map<String, RDelayedQueue<String>> delayedQueueMap = Maps.newHashMap();
/**
* 销毁队列
*/
void destroyQueue(String queueName) {
RDelayedQueue<String> delayedQueue = delayedQueueMap.get(queueName);
if (delayedQueue != null) {
delayedQueue.destroy();
}
}
/**
* 获取阻塞队列
*
* @param queueName 队列名称
* @return 队列
*/
RBlockingQueue<String> getBlockingQueue(String queueName) {
return blockingQueueMap.computeIfAbsent(queueName, k -> redissonClient.getBlockingQueue(queueName));
}
/**
* 获取延时队列
*
* @param queueName 队列名称
* @return 队列
*/
RDelayedQueue<String> getDelayQueue(String queueName) {
return delayedQueueMap.computeIfAbsent(queueName, k -> {
RBlockingQueue<String> blockingQueue = blockingQueueMap.computeIfAbsent(queueName,
t -> redissonClient.getBlockingQueue(queueName));
return redissonClient.getDelayedQueue(blockingQueue);
});
}
/**
* 向添加队列数据
*
* @param queueName 队列名称
* @param t DTO传输类
* @param delay 时间数量
* @param timeUnit 时间单位
*/
public <T> void addQueue(String queueName, T t, long delay, TimeUnit timeUnit) {
if (t == null) {
return;
}
RDelayedQueue<String> delayedQueue = getDelayQueue(queueName);
log.info("任务入队列,延时时间:{}({}), queueName:{}, task:{}", delay, timeUnit.name(), queueName, t);
// 指定时间以后以后将消息发送到指定队列
delayedQueue.offer(JsonUtil.toJson(t), delay, timeUnit);
}
/**
* 移除队列数据(返回被移除的队列数据)
*
* @param queueName 队列名称
* @param t DTO传输类
* @param <T> 泛型
*/
public <T extends BaseTask> List<T> removeQueueByIdentity(String queueName, T t, Class<T> classType) {
RDelayedQueue<String> delayedQueue = getDelayQueue(queueName);
log.info("任务移除队列,queueName:{}, taskId:{}", queueName, t.taskIdentity());
List<String> dataList = delayedQueue.stream().filter(data -> {
T k = JsonUtil.fromJson(data, classType);
if (k == null) {
return false;
}
if (k.taskIdentity().equals(t.taskIdentity())) {
log.info("匹配到需要删除的队列数据:{}", data);
return true;
}
return false;
}).collect(Collectors.toList());
log.info("任务ID:{}匹配到删除的记录数:{}", t.taskIdentity(), dataList.size());
delayedQueue.removeAllAsync(dataList);
return dataList.stream().map(data -> JsonUtil.fromJson(data, classType)).collect(Collectors.toList());
}
}
2、延时队列任务初始化
import com.eshore.zhyl.admin.service.impl.sys.SysUserUnlockHandler;
import com.eshore.zhyl.common.constant.RedisPrefixEnum;
import com.eshore.zhyl.common.delay.RedisDelayEngine;
import com.eshore.zhyl.common.delay.RedisDelayQueue;
import com.eshore.zhyl.common.dto.UserHandleDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* 延时队列任务初始化
*
* @author cp
*/
@Configuration
@Slf4j
public class RedisDelayConfig {
@Resource
private RedisDelayQueue redisDelayQueue;
//延时队列之后的操作
@Resource
private SysUserUnlockHandler sysUserUnlockHandler;
/**
* 取消用户锁定 延时队列
* @return
*/
@Bean(value = "userUnlockDelayEngine", destroyMethod = "destroy")
public RedisDelayEngine<UserHandleDTO> userUnlockDelayEngine() {
RedisDelayEngine<UserHandleDTO> redisDelayEngine = new RedisDelayEngine<>(redisDelayQueue,
RedisPrefixEnum.USER_UNLOCK.toString(), sysUserUnlockHandler, UserHandleDTO.class);
redisDelayEngine.setTryTimes(1);
return redisDelayEngine;
}
3、延时队列之后的操作
import com.eshore.zhyl.common.constant.Constants;
import com.eshore.zhyl.common.delay.DelayTaskListener;
import com.eshore.zhyl.common.dto.UserHandleDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* 延时队列触发用户解锁
* @author cp
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class SysUserUnlockHandler implements DelayTaskListener<UserHandleDTO> {
private final SysUserMapper sysUserMapper;
// private RedisDelayQueue redisDelayQueue;
@Override
public void invoke(UserHandleDTO userHandleDTO) {
System.out.println(" test ");
}
}
4、具体的调用
redisTemplate.delete(Constants.LOGIN_ERROR + sysUserForm.getUsername());
//5次登录失败,锁定账户,加入延时队列
UserHandleDTO userHandleDTO = UserHandleDTO.builder()
.username(sysUserForm.getUsername())
.build();
log.info("[用户登录失败账户锁定-解锁] 放入加锁账号到延时队列,data:{} , 延时:{}min", userHandleDTO, DELAY_TIME);
redisDelayQueue.addQueue(RedisPrefixEnum.USER_UNLOCK.toString(),
userHandleDTO,
DELAY_TIME,
TimeUnit.MINUTES);
throw new ApiException( "账户已锁定,请5分钟之后再试");