spring boot+redis 监听过期Key的操作方法

    前言:

    在订单业务中,有时候需要对订单设置有效期,有效期到了后如果还未支付,就需要修改订单状态。对于这种业务的实现,有多种不同的办法,比如:

    1、使用querytz,每次生成一个订单,就创建一个定时任务,到期后执行业务代码;

    2、rabbitMq中的延迟队列;

    3、对Redis的Key进行监控;

     1、引入依赖

    
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>

    2、修改boot的redis配置

    
    spring:
     #redis
     redis:
     database: 0
     host: 127.0.0.1
     password: redis_123456
     port: 6379

    3、在服务器中 修改redis.conf配置文件(原来notify-keyspace-events 属性是” ” 空的,我们只需要填上“Ex”就行了)

    
    notify-keyspace-events "Ex"

    4、创建一个Redis监控类,用于监控过期的key,该类需继承KeyExpirationEventMessageListener

    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.data.redis.connection.Message;
    import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
    import org.springframework.data.redis.listener.RedisMessageListenerContainer;
     
    import java.nio.charset.StandardCharsets;
     
    /**
     * @program: SpringCloud
     * @description: redis Key过期监听
     * @author: zhang yi
     * @create: 2020-03-24 14:14
     */
    public class KeyExpiredListener extends KeyExpirationEventMessageListener {
     
     public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
      super(listenerContainer);
     }
     
     @Override
     public void onMessage(Message message, byte[] pattern) {
      System.out.println("过期key:" + message.toString());
     }
    }

    5、创建Redis配置类

    
    import com.zy.rabbitmq.base.Listener.KeyExpiredListener;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.listener.RedisMessageListenerContainer;
     
    /**
     * @program: SpringCloud
     * @description: redis配置类
     * @author: zhang yi
     * @create: 2020-03-24 14:17
     */
    @Configuration
    public class RedisConfiguration {
     
     @Autowired
     private RedisConnectionFactory redisConnectionFactory;
     
     @Bean
     public RedisMessageListenerContainer redisMessageListenerContainer() {
      RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
      redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
      return redisMessageListenerContainer;
     }
     
     @Bean
     public KeyExpiredListener keyExpiredListener() {
      return new KeyExpiredListener(this.redisMessageListenerContainer());
     }
     
    }

    6、这里提供一个redis工具类,用于存储值,获取值,获取过期时间等操作。

    
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Component;
    import org.springframework.util.CollectionUtils;
     
    import javax.annotation.Resource;
    import java.util.concurrent.TimeUnit;
    /**
     * redis 工具类
     * @Author ZhangYi
     */
    @Component
    public class RedisUtil {
     
    	@Resource
    	private RedisTemplate<String, Object> redisTemplate;
     
    	/**
    	 * 指定缓存失效时间
    	 * 
    	 * @param key 键
    	 * @param time 时间(秒)
    	 * @return
    	 */
    	public boolean expire(String key, long time) {
    		try {
    			if (time > 0) {
    				redisTemplate.expire(key, time, TimeUnit.SECONDS);
    			}
    			return true;
    		} catch (Exception e) {
    			e.printStackTrace();
    			return false;
    		}
    	}
     
    	/**
    	 * 根据key 获取过期时间
    	 * 
    	 * @param key 键 不能为null
    	 * @return 时间(秒) 返回0代表为永久有效
    	 */
    	public long getExpire(String key) {
    		return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    	}
     
    	/**
    	 * 判断key是否存在
    	 * 
    	 * @param key 键
    	 * @return true 存在 false不存在
    	 */
    	public boolean hasKey(String key) {
    		try {
    			return redisTemplate.hasKey(key);
    		} catch (Exception e) {
    			e.printStackTrace();
    			return false;
    		}
    	}
     
    	/**
    	 * 删除缓存
    	 * 
    	 * @param key 可以传一个值 或多个
    	 */
    	@SuppressWarnings("unchecked")
    	public void del(String... key) {
    		if (key != null && key.length > 0) {
    			if (key.length == 1) {
    				redisTemplate.delete(key[0]);
    			} else {
    				redisTemplate.delete(CollectionUtils.arrayToList(key));
    			}
    		}
    	}
     
    	// ============================String=============================
    	/**
    	 * 普通缓存获取
    	 * 
    	 * @param key 键
    	 * @return 值
    	 */
    	public Object get(String key) {
    		return key == null ? null : redisTemplate.opsForValue().get(key);
    	}
     
    	/**
    	 * 普通缓存放入
    	 * 
    	 * @param key 键
    	 * @param value 值
    	 * @return true成功 false失败
    	 */
    	public boolean set(String key, Object value) {
    		try {
    			redisTemplate.opsForValue().set(key, value);
    			return true;
    		} catch (Exception e) {
    			e.printStackTrace();
    			return false;
    		}
     
    	}
     
    	/**
    	 * 普通缓存放入并设置时间
    	 * 
    	 * @param key 键
    	 * @param value 值
    	 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
    	 * @return true成功 false 失败
    	 */
    	public boolean set(String key, Object value, long time) {
    		try {
    			if (time > 0) {
    				redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
    			} else {
    				set(key, value);
    			}
    			return true;
    		} catch (Exception e) {
    			e.printStackTrace();
    			return false;
    		}
    	}
    }

    7、测试。(这里开放两个接口,一个set值,并设置过期时间为10秒,一个获取值和过期时间,当到达过期时间,看是否回去到过期Key)

    
    @GetMapping("/put")
     public String demo(){
      redisUtil.set("name","zhangyi",10);
      return "aaa";
     }
     
     @GetMapping("/get")
     public Map<String,Object> get(){
      Map<String,Object> m =new HashMap<>();
      m.put("time",redisUtil.getExpire("name"));
      m.put("val",redisUtil.get("name"));
      return m;
     }

    成功获取到了过期Key,这里乱码是因为boot集成的Redis存key或者value的时候,没有配置字符串序列化。没有配置的话是默认使用jdk本身的序列化的。

    到此这篇关于spring boot+redis 监听过期Key的文章就介绍到这了,更多相关spring boot+redis 监听过期Key内容请搜索lingkb以前的文章或继续浏览下面的相关文章希望大家以后多多支持lingkb!