springboot整合缓存技术 (SpringCache + SpringDataRedis) (代码版) 第2版

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

application.yml

spring:
	redis:
	        database: xxx
	        host: xxx
	        port: 6379
	        password: xxxx # 密码(默认为空)
	        timeout: 6000  # 连接超时时长(毫秒)
	        pool:
	            max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
	            max-wait: -1      # 连接池最大阻塞等待时间(使用负值表示没有限制)
	            max-idle: 10      # 连接池中的最大空闲连接
	            min-idle: 5       # 连接池中的最小空闲连接

RedisConfig.java

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.core.*;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * SpringDataRedis配置
 * 
 * Redis的Value支持5种类型:  
 * String字符串,  List双向链表, Hash键值对, 
 * Set无序集合, Sorted Set有序集合
 */
@Configuration
public class RedisConfig{
    @Autowired
    private RedisConnectionFactory factory;

    @Bean(name = "redisTemplateCustomize")
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }

	// value是Hash键值对类型
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }
    
	// value是String字符串类型
    @Bean
    public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
        return redisTemplate.opsForValue();
    }
    
	// value是List双向链表类型
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }
    
	// value是Set无序集合类型
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }
    
	// value是Sorted Set有序集合类型
    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }

}

CacheConfig.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

/**
 * SpringCache配置
 */
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
    @Autowired
    RedisTemplate redisTemplate;

    @Bean
    @ConditionalOnClass(RedisTemplate.class)
    @Override
    public CacheManager cacheManager() {
        redisTemplate.setKeySerializer(new Jackson2JsonRedisSerializer<String>(String.class));
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setUsePrefix(true);
        cacheManager.setDefaultExpiration(50000);
        return cacheManager;
    }

}

RedisUtils.java

import cn.jiguang.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 */
@Component
public class RedisUtils {

    public static final Logger log = LoggerFactory.getLogger(RedisUtils.class);
    //    @Autowired
    //    @Qualifier("redisTemplateCustomize")
    //    private RedisTemplate redisTemplate;
    @Autowired
    private ValueOperations<String, String> valueOperations;
    //    @Resource(name="redisTemplate")
    //    private HashOperations<String, String, Object> hashOperations;
    //    @Resource(name="redisTemplate")
    //    private ListOperations<String, Object> listOperations;
    //    @Resource(name="redisTemplate")
    //    private SetOperations<String, Object> setOperations;
    //    @Resource(name="redisTemplate")
    //    private ZSetOperations<String, Object> zSetOperations;
    /**  默认过期时长,单位:秒 */
    public final static long DEFAULT_EXPIRE = 60 * 60 * 24L;
    /**  过期时长,2H */
    public final static long EXPIRE_TWO_HOUR = 60 * 60 * 2L;
    /**  不设置过期时长 */
    public final static long NOT_EXPIRE = -1;

    /**
     * 获取key对应的value值
     */
    public String get(String key) {
        return valueOperations.get(key);
        //return get(key, NOT_EXPIRE);
    }

    /**
     * 获取key对应的value值, 并把value转为指定类型
     */
    public <T> T get(String key, Class<T> clazz) {
        return get(key, clazz, NOT_EXPIRE);
    }

    public <T> T get(String key, Class<T> clazz, long expire) {
        String value = valueOperations.get(key);
        if(expire != NOT_EXPIRE){
            valueOperations.getOperations().expire(key, expire, TimeUnit.SECONDS);
        }
        return value == null ? null : fromJson(value, clazz);
    }

    public String get(String key, long expire) {
        String value = valueOperations.get(key);
        if(expire != NOT_EXPIRE){
            valueOperations.getOperations().expire(key, expire, TimeUnit.SECONDS);
        }
        return value;
    }

    /**
     * 往redis插入数据
     */
    public void set(String key, Object value){
        set(key, value, DEFAULT_EXPIRE);
    }

    /**
     * 设置key的过期时间
     */
    public void set(String key, Object value, long expire){
        String strdata=toJson(value);
        valueOperations.set(key, strdata);
        if(expire != NOT_EXPIRE){
            valueOperations.getOperations().expire(key, expire, TimeUnit.SECONDS);
        }
    }

    /**
     * 删除指定数据
     */
    public void delete(String key) {
        valueOperations.getOperations().delete(key);
    }

    /**
     * Object转成JSON数据
     */
    private String toJson(Object object){
        if(object instanceof Integer || object instanceof Long || object instanceof Float ||
                object instanceof Double || object instanceof Boolean || object instanceof String){
            return String.valueOf(object);
        }
        return JSON.toJSONString(object, SerializerFeature.WriteDateUseDateFormat);
    }

    /**
     * JSON数据,转成Object
     */
    private <T> T fromJson(String json, Class<T> clazz){
        return JSON.parseObject(json, clazz);
    }


    public void deleteAllKeys(String key) {
        Set<String> keys = valueOperations.getOperations().keys(key);
        valueOperations.getOperations().delete(keys);
    }

    /**
     * 加锁
     * @param key
     * @param value 当前时间+超时时间
     * @return
     */
    public boolean lock(String key, String value) {
        if(valueOperations.setIfAbsent(key, value)) {
            return true;
        }
        //currentValue=A   这两个线程的value都是B  其中一个线程拿到锁
        String currentValue = valueOperations.get(key);
        //如果锁过期
        if (!StringUtils.isEmpty(currentValue)
                && Long.parseLong(currentValue) < System.currentTimeMillis()) {
            //获取上一个锁的时间
            String oldValue = valueOperations.getAndSet(key, value);
            return !StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue);
        }
        return false;
    }

    /**
     * 解锁
     * @param key
     * @param value
     */
    public void unlock(String key, String value) {
        try {
            String currentValue = valueOperations.get(key);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                valueOperations.getOperations().delete(key);
            }
        }catch (Exception e) {
            log.error("【redis分布式锁】解锁异常, {}", e);
        }
    }

}

RedisKeys.java

/**
 * Redis所有Keys
 */
public class RedisKeys {

    public static String getSysConfigKey(String key){
        return "sys:config:" + key;
    }

    public static String getShiroSessionKey(String key){
        return "sessionid:" + key;
    }
    public static String getViewCountKey(String key) {return "viewCountKey:"+key;}
    
	// 自己自定义添加...
}

RedisShiroSessionDAO.java

import com.yymt.common.utils.RedisKeys;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

/**
 * shiro session dao
 */
@Component
public class RedisShiroSessionDAO extends EnterpriseCacheSessionDAO {
    @Autowired
    private RedisTemplate redisTemplate;

    //创建session
    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = super.doCreate(session);
        final String key = RedisKeys.getShiroSessionKey(sessionId.toString());
        setShiroSession(key, session);
        return sessionId;
    }

    //获取session
    @Override
    protected Session doReadSession(Serializable sessionId) {
        Session session = super.doReadSession(sessionId);
        if (session == null) {
            final String key = RedisKeys.getShiroSessionKey(sessionId.toString());
            session = getShiroSession(key);
        }
        return session;
    }

    //更新session
    @Override
    protected void doUpdate(Session session) {
        super.doUpdate(session);
        final String key = RedisKeys.getShiroSessionKey(session.getId().toString());
        setShiroSession(key, session);
    }

    //删除session
    @Override
    protected void doDelete(Session session) {
        super.doDelete(session);
        final String key = RedisKeys.getShiroSessionKey(session.getId().toString());
        redisTemplate.delete(key);
    }

    private Session getShiroSession(String key) {
        return (Session) redisTemplate.opsForValue().get(key);
    }

    private void setShiroSession(String key, Session session) {
        redisTemplate.opsForValue().set(key, session);
        //60分钟过期
        redisTemplate.expire(key, 60, TimeUnit.MINUTES);
    }
}

Demo1 (换脸次数每天最多30次)

@Autowired
RedisUtils redisUtils;

private void ifLimitCount(long userId) {
    String date = DateUtil.dateConvert(new Date(), "yyyy-MM-dd");
    String redisKey = date + ":" + userId;
    Integer count = ConvertUtil.parseInt(redisUtils.get(redisKey));
    if (count >= 30) {
        throw new RRException("你已超过今日换脸次数,请明日再试!");
    } else {
        redisUtils.set(redisKey, count + 1, 60 * 60 * 24);
    }
}

Demo2 ( RedisUtils.get(key, class)使用案例 )

@PostMapping("/hot")
@ApiOperation("热门搜索")
//	@Cacheable(cacheNames = "hotsearch")
public R hot() {
	String strkey= RedisKeys.getViewCountKey(parmas.toString());
	R ret=redisUtils.get(strkey,R.class);
	if(ret==null){
		List<Map<String, Object>> list = scenicService.queryHotSearchRank();
		ret=R.ok().put("data", list);
		redisUtils.set(strkey,ret,60*2);
	}
	return ret;
}

public R getWxLiveInfo(Map<String,Object> parmas){
    String strKey= RedisKeys.getLiveInfoKey(parmas.toString());
    String strdata= redisUtils.get(strKey, String.class);
    try {
        if(strdata==null){
            // 业务逻辑 ...
        }
    }catch(Exception e){
        return R.error("获取数据异常");
    }
    return R.ok().put("data", strdata);
}

CREATE TABLE `sys_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `key` varchar(50) DEFAULT NULL COMMENT 'key',
  `value` varchar(2000) DEFAULT NULL COMMENT 'value',
  `status` tinyint(4) DEFAULT '1' COMMENT '状态   0:隐藏   1:显示',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  `del_flag` tinyint(1) DEFAULT NULL COMMENT '是否删除1-是,0-否',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `key` (`key`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='系统管理-系统配置信息表';

SysConfigRedis.java

import com.yymt.common.utils.RedisKeys;
import com.yymt.common.utils.RedisUtils;
import com.yymt.entity.sys.SysConfigEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 系统配置Redis
 */
@Component
public class SysConfigRedis {
    @Autowired
    private RedisUtils redisUtils;

    public void saveOrUpdate(SysConfigEntity config) {
        if(config == null){
            return ;
        }
        String key = RedisKeys.getSysConfigKey(config.getKey());
        redisUtils.set(key, config);
    }

    public void delete(String configKey) {
        String key = RedisKeys.getSysConfigKey(configKey);
        redisUtils.delete(key);
    }

    public SysConfigEntity get(String configKey){
        String key = RedisKeys.getSysConfigKey(configKey);
        return redisUtils.get(key, SysConfigEntity.class);
    }
}

SysConfigServiceImpl.java

import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.yymt.dao.sys.SysConfigDao;
import com.yymt.entity.sys.SysConfigEntity;
import com.yymt.modules.redis.SysConfigRedis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("sysConfigService")
public class SysConfigServiceImpl extends ServiceImpl<SysConfigDao, SysConfigEntity>{
    @Autowired
    private SysConfigRedis sysConfigRedis;

    public void save(SysConfigEntity config) {
        this.insert(config);
        sysConfigRedis.saveOrUpdate(config);
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(SysConfigEntity config) {
        this.updateById(config);
        sysConfigRedis.saveOrUpdate(config);
    }
    
    @Transactional(rollbackFor = Exception.class)
    public void updateValueByKey(String key, String value) {
        baseMapper.updateValueByKey(key, value);
        sysConfigRedis.delete(key);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值