当前位置:   article > 正文

springboot使用redis实现定时任务_springboot redis定时任务

springboot redis定时任务

在前一段时间写了一个使用springboot监听redis过期键的文章,这个我自己使用虚拟机测试是可以使用的,但是,当我实际使用的时候却出现了问题,代码明明没有问题,但是在键过期后他就是没有通知,我真是百思不得其解,又通过查各种资料整理了一个更完整的版本,以及实现一个简单的定时器。下面给大家展示一下,上代码!

修改配置文件

修改配置文件跟之前的文章步骤一样,这里就不赘述了,大家可以去看一下上一篇文章。文章连接:文章传送门

导入依赖
<dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4
编写消息处理类

我使用监听redis的目的就是为了能够在用户vip到期时自动发送一个邮件来提醒用户,还有就是在用户封禁时间结束时,给用户发送一个提醒邮件,来提醒用户封号时间已结束,里面的代码大家可以根据自己的需要自行编写。

还有就是我将用户的vip过期信息存到了编号为 1 的数据库,将用户封号信息存到了编号为 2 的数据库。

package com.video.utils;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.video.mapper.UserMapper;
import com.video.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;

@Slf4j
public class KeyExpiredListener extends KeyExpirationEventMessageListener {
    @Resource
    private UserMapper userMapper;

    private static final Topic KEYEVENT_EXPIRED_TOPIC1 = new PatternTopic("__keyevent@1__:expired");
    private static final Topic KEYEVENT_EXPIRED_TOPIC2 = new PatternTopic("__keyevent@2__:expired");

    public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }
    //设置监听的数据库
    @Override
    protected void doRegister(RedisMessageListenerContainer listenerContainer) {
        listenerContainer.addMessageListener(this, KEYEVENT_EXPIRED_TOPIC1);
        listenerContainer.addMessageListener(this, KEYEVENT_EXPIRED_TOPIC2);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
    	//得到数据库信息
        String channel = new String(message.getChannel(), StandardCharsets.UTF_8);
        //得到过期的键
        String key = new String(message.getBody(),StandardCharsets.UTF_8);
        //判断是否是数据库1中的键过期
        if("__keyevent@1__:expired".equals(channel)){
        	//判断是否是用户vip过期信息的键失效,若是则进行修改用户vip字段的操作
            if("vipOutTime:".equals(key.substring(0, 11))){
                int id = Integer.parseInt(key.substring(11));
                LambdaUpdateWrapper<User> userWrapper = new LambdaUpdateWrapper<>();
                userWrapper.eq(User::getId,id)
                        .set(User::getVip,0);
                int i = userMapper.update(null, userWrapper);
                if(i>0){
                    User user = userMapper.selectById(id);
                    log.info("用户昵称为:"+user.getName()+"的VIP已过期!");
                }else {
                    log.info("使用监听redis过期键修改用户vip状态出错!");
                }
            }
        }
        if("__keyevent@2__:expired".equals(channel)){
            if("userBanned:".equals(key.substring(0, 11))){
            	//封号结束,向用户邮箱发送邮件
                int id = Integer.parseInt(key.substring(11));
                User user = userMapper.selectById(id);
                String head = "封号结束通知";
                String body = "尊敬的"+user.getName()+"您好!" +
                        "您的账号封禁时间已结束,您可以继续正常使用该账号,但请规范使用账号以免再次封号!";
                int i = 0;
                try {
                    i = SendMailVerify.MailMessage(user.getEmail(), head, body);
                }catch (Exception e){
                    log.info("发送邮件出错!");
                    return;
                }
                if(i==1){
                    log.info("用户昵称为:"+user.getName()+"的账号解封通知已发送!");
                }else if(i==0){
                    log.info("用户解封邮件发送失败!");
                    return;
                }else {
                    log.info("邮件信息不完整,未能发送!");
                    return;
                }
                LambdaUpdateWrapper<User> wrapper=new LambdaUpdateWrapper<>();
                wrapper.eq(User::getId,id).set(User::getUserState,0)
                        .set(User::getCloseTime, LocalDateTime.now());
                int update = userMapper.update(null, wrapper);
                if(update>0){
                    log.info("用户昵称为:"+user.getName()+"的账号解除封禁成功!");
                }else {
                    log.info("用户昵称为:"+user.getName()+"的账号解除封禁失败!");
                }
            }
        }
        log.info("redis key 过期:pattern={},channel={},key={}",new String(pattern),channel,key);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
redis切换数据库

因为我是将不同的信息存到了redis不同的数据库,所以需要有一个redis切换数据库的操作。

第一步:导入依赖
<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4

这个jar包提供了一个选择数据库的方法,比较方便。

第二步,编写模板
package com.video.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;

@Configuration
public class JedisConfig {
    @Bean
    public Jedis getJedis1(){
        //redis端口号默认都是6379,这个端口号若是没有修改的话,不加也是可以的,大家可以自己尝试一下
        Jedis jedis=new Jedis("ip地址",redis端口号);
        //密码是必须要写的,没有密码的要先设置一个密码,不设置密码亲测是连接失败的
        jedis.auth("redis连接密码");
        //这个主要是确定redis已经连接成功了
        if(!"PONG".equals(jedis.ping())){
            return null;
        }
        //这个就是切换到了编号 1 的数据库上
        jedis.select(1);
        return jedis;
    }
    @Bean
    public Jedis getJedis2(){
    	//redis端口号默认都是6379,这个端口号若是没有修改的话,不加也是可以的,大家可以自己尝试一下
        Jedis jedis=new Jedis("ip地址",redis端口号);
        //密码是必须要写的,没有密码的要先设置一个密码,不设置密码亲测是连接失败的
        jedis.auth("redis连接密码");
        //这个主要是确定redis已经连接成功了
        if(!"PONG".equals(jedis.ping())){
            return null;
        }
        //这个就是切换到了编号 2 的数据库上
        jedis.select(2);
        return jedis;
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

这个是使用了一个数据库一个连接连接模板的思路,没有使用动态连接redis数据库,也是偷了个懒,相当于多创建了一个连接redis的对象。但是这样没有并发问题,就是数据库不需要在切换回去,这一个redis连接对象一直都是对我们设定好的数据库进行操作,不会对其他的连接造成干扰。

第三步,使用
@Resource
private JedisConfig jedisConfig;
Jedis jedis = jedisConfig.getJedis2();
  • 1
  • 2
  • 3

使用的话直接使用jedis就可以进行简单的向redis数据库中存储和删除,包括设置有过期时间的键相关的操作了。
当用户充值vip成功后,向数据库1中存入包含用户信息的、有过期时间的键,这样当这个键过期之后就会被监听redis过期键的类中的相关方法捕获,执行相关的操作,这也是使用redis实现一个简单的定时器的核心!

编写redis配置类

只需要在redis的配置类中加入下面的代码就可以了。

	@Resource
    private RedisConnectionFactory factory;
    @Bean
    public RedisMessageListenerContainer container() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(factory);
        return container;
    }
    @Bean
    public KeyExpiredListener keyExpiredListener() {
        return new KeyExpiredListener(this.container());
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

以上就是这次对于使用springboot使用监听redis过期键实现简单定时器的步骤了,关于之前的那个为什么不行,我还没有弄清楚,等弄明白之后再进行整理吧。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/728133
推荐阅读
相关标签
  

闽ICP备14008679号