spring boot构建基础版web项目(三)-springboot、redis数据缓存整合

原文作者:程序猿杨鲍
转载声明:转载请注明原文地址,注意版权维护,谢谢!

写前说明

在spring+spring mvc+mybatis模式下,使用的最多的就是jedis,但是spring boot整合了redis后,依然可以使用jedis,但是同时也提供了一个RedisTemplate和StringRedisTemplate,RedisTemplate使用的序列化类是默认JdkSerializationRedisSerializer,而StringRedisTemplate使用的序列化类默认是StringRedisSerializer,因此在存储的方式上也是有所不同。简单的说就是RedisTemplate的key和value可以是任意类型的数据,但是StringRedisTemplate的key和value只能是String,如果存储其他类型,序列化和反序列化会存在问题。综合来说,如果使用spring提供的redis连接就使用RedisTemplate,兼容性更高,如果使用jedis就无所谓了,因为它默认就是支持各种数据类型的键值。
另外Redis群的搭建可以参考[Redis集群的简单搭建和实现(待提供)]。

准备工作

需要在新建立一个模块utui-common,这个模块用于存放Redis封装的工具类,在utui-dao中加入对utui-common的依赖坐标。

依赖的加入
<dependency>
	<groupId>com.springboot.utui</groupId>
	<artifactId>utui-common</artifactId>
	<version>1.0-SNAPSHOT</version>
</dependency>
模块结构
|-utui-common
	|-src
		|-main
			|-java
				|-com.springboot.utui.common
					|-utils
						|-RedisClientUtil
springboot整合集成RedisTemplate方式实现
父pom.xml

添加spring-boot-starter-redis的依赖jar

<!-- spring整合redis -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-redis</artifactId>
	<version>1.4.7.RELEASE</version>
</dependency>
application.properties
#-------------------------------- redis properties  start --------------------------------#
# redis数据库索引(默认是0)
spring.redis.datasource=0
# redis服务器地址
spring.redis.host=127.0.0.1
# redis服务端口
spring.redis.port=6379
# redis服务器密码(默认是空)
spring.redis.password=
# 连接池最大连接数(-1表示不限制)
spring.redis.pool.max-active=10
# 连接池最小空闲连接数
spring.redis.pool.max-idle=10
# 连接池最大空闲连接数
spring.redis.pool.min-idle=0
# 最大阻塞等待时间(-1表示不限制,单位:毫秒)
spring.redis.max-wait=3000
# 连接超时时间(单位:毫秒)
spring.redis.timeout=5000
# 集群节点(三主三从)
# spring.redis.cluster.nodes=127.0.0.1:6379,127.0.0.1:6380,127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384
#-------------------------------- redis properties  end --------------------------------#
RedisClientUtil.java

utui-common下添加RedisClientUtil类,用于封装Redis的一些公用方法,为了写这个封装花了挺长时间,并都测试了一遍,基本没有问题,如果项目中有使用,需要封装Redis工具类,可以直接拿去,不谢。

@Component
@Slf4j
public class RedisClientUtil {

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    /**
     * 键值对设值
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public <K, V> Boolean set(K key, V value) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            connection.set(JSON.toJSONBytes(key), JSON.toJSONBytes(value));
            return true;
        });
    }

    /**
     * 键值对设值和有效时间
     *
     * @param key   键
     * @param value 值
     * @param time  有效时间(单位:秒)
     * @return
     */
    public <K, V> Boolean setEx(K key, V value, long time) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            connection.setEx(JSON.toJSONBytes(key), time, JSON.toJSONBytes(value));
            return true;
        });
    }

    /**
     * 查询键值对
     *
     * @param key           键
     * @param typeReference 返回类型
     * @param <K>           键类型
     * @param <R>           返回类型
     * @return
     */
    public <K, R> R get(K key, TypeReference<R> typeReference) {
        byte[] redisValue = redisTemplate.execute((RedisCallback<byte[]>) connection -> connection.get(JSON.toJSONBytes(key)));
        if (redisValue == null) return null;
        return JSONObject.parseObject(new String(redisValue), typeReference);
    }

    /**
     * 存储Hash结构数据(批量)
     *
     * @param outerKey 外键
     * @param map      内键-内值
     * @return
     */
    public <O, I, V> Boolean hSetMap(O outerKey, Map<I, V> map) {
        if (map == null || map.isEmpty()) return false;
        Map<byte[], byte[]> byteMap = new HashMap<>();
        map.forEach((innerKey, innerValue) -> byteMap.put(JSON.toJSONBytes(innerKey), JSON.toJSONBytes(innerValue)));
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            connection.hMSet(JSON.toJSONBytes(outerKey), byteMap);
            return true;
        });
    }

    /**
     * 存储Hash结构数据
     *
     * @param outerKey   外键
     * @param innerKey   内键
     * @param innerValue 值
     * @return
     */
    public <O, I, V> Boolean hSet(O outerKey, I innerKey, V innerValue) {
        Map<I, V> map = new HashMap<>();
        map.put(innerKey, innerValue);
        return this.hSetMap(outerKey, map);
    }

    /**
     * 获取Hash结构Map集合,内键和内值键值对封装成Map集合
     *
     * @param outerKey       外键
     * @param innerKeyType   内键类型
     * @param innerValueType 值类型
     * @return
     */
    public <O, I, V> Map<I, V> hGetMap(O outerKey, TypeReference<I> innerKeyType, TypeReference<V> innerValueType) {
        Map<byte[], byte[]> redisMap = redisTemplate.execute
                ((RedisCallback<Map<byte[], byte[]>>) connection -> connection.hGetAll(JSON.toJSONBytes(outerKey)));
        if (redisMap == null) return null;
        Map<I, V> resultMap = new HashMap<>();
        redisMap.forEach((key, value) -> resultMap.put(JSONObject.parseObject
                (new String(key), innerKeyType), JSONObject.parseObject(new String(value), innerValueType)));
        return resultMap;
    }

    /**
     * 查询Hash结构的值
     *
     * @param outerKey      外键
     * @param innerKey      内键
     * @param typeReference 值类型
     * @return
     */
    public <O, I, V> V hGet(O outerKey, I innerKey, TypeReference<V> typeReference) {
        byte[] redisResult = redisTemplate.execute((RedisCallback<byte[]>)
                connection -> connection.hGet(JSON.toJSONBytes(outerKey), JSON.toJSONBytes(innerKey)));
        if (redisResult == null) return null;
        return JSONObject.parseObject(new String(redisResult), typeReference);

    }

    /**
     * 删除键值对
     *
     * @param keys 键
     * @return
     */
    public <K> Long del(List<K> keys) {
        if (keys == null || keys.isEmpty()) return 0L;
        byte[][] keyBytes = new byte[keys.size()][];
        int index = 0;
        for (K key : keys) {
            keyBytes[index] = JSON.toJSONBytes(key);
            index++;
        }
        return redisTemplate.execute((RedisCallback<Long>) connection -> connection.del(keyBytes));
    }

    /**
     * 删除Hash结构内键和值
     *
     * @param outerKey  外键
     * @param innerKeys 内键
     * @return
     */
    public <O, I> Long hDel(O outerKey, List<I> innerKeys) {
        if (innerKeys == null || innerKeys.isEmpty()) return 0L;
        byte[][] innerKeyBytes = new byte[innerKeys.size()][];
        int index = 0;
        for (I key : innerKeys) {
            innerKeyBytes[index] = JSON.toJSONBytes(key);
            index++;
        }
        return redisTemplate.execute((RedisCallback<Long>) connection ->
                connection.hDel(JSON.toJSONBytes(outerKey), innerKeyBytes));
    }
}

这里很方便,因为在spring和redis整合后,启动项目时,spring会自动从application.properties中读取redis的信息,并根据这些信息构建RedisTemplate和StringRedisTemplate对象,交由Spring管理。因此这里可以直接注入。

RedisClientController.java

在com.springboot.utui.web.controller包下创建一个RedisClientController类,用于测试整合结果。

@Controller
@RequestMapping("/redis")
@Slf4j
public class RedisClientController {

    @Autowired
    private RedisClientUtil redisClient;

    /**
     * 测试键值对
     */
    @RequestMapping(method = RequestMethod.GET, value = "/testKv")
    @ResponseBody
    public String testKv() {
        Boolean insertResult = redisClient.set("test-key-1", "test-value-1");
        redisClient.set("test-key-2", "test-value-2");
        redisClient.set("test-key-3", "test-value-3");
        String getResult = redisClient.get("test-key-1", new TypeReference<String>() {
        });
        return "insertResult:" + insertResult + ",getResult:" + getResult;
    }

    /**
     * 测试Hash结构
     */
    @RequestMapping(method = RequestMethod.GET, value = "/testKm")
    @ResponseBody
    public String testKm() {
        Boolean hSetResult = redisClient.hSet("test-hSet-outer", "test-hSet-innerKey", "test-hSet-innerValue");
        Map<String, String> innerMap = new HashMap<>();
        innerMap.put("test-hSetMap-innerKey-1", "test-hSetMap-innerValue-1");
        innerMap.put("test-hSetMap-innerKey-2", "test-hSetMap-innerValue-2");
        innerMap.put("test-hSetMap-innerKey-3", "test-hSetMap-innerValue-3");
        Boolean hSetMapResult = redisClient.hSetMap("test-hSetMap-outer", innerMap);
        String hGetResult = redisClient.hGet("test-hSet-outer", "test-hSet-innerKey", new TypeReference<String>() {
        });
        Map<String, String> hGetMapResult = redisClient.hGetMap("test-hSetMap-outer", new TypeReference<String>() {
        }, new TypeReference<String>() {
        });
        return "hSetResult:" + hSetResult + ",hGetResult:" + hGetResult + ",hSetMapResult:" + hSetMapResult + ",hGetMapResult:" + hGetMapResult;
    }

    /**
     * 测试删除
     */
    @RequestMapping(method = RequestMethod.GET, value = "/testDel")
    @ResponseBody
    public String testDel() {
        List<String> delList = new ArrayList<>();
        delList.add("test-key-1");
        delList.add("test-key-2");
        Long delNum = redisClient.del(delList);
        String delAfter = redisClient.get("test-key-1", new TypeReference<String>() {
        });
        List<String> hDelList = new ArrayList<>();
        hDelList.add("test-hSetMap-innerKey-1");
        hDelList.add("test-hSetMap-innerKey-2");
        Long hDelNum = redisClient.hDel("test-hSet-outer", hDelList);
        String hDelAfter = redisClient.hGet("test-hSet-outer", "test-hSetMap-innerKey-1", new TypeReference<String>() {
        });
        return "delNum:" + delNum + ",delAfter:" + delAfter + ",hDelNum:" + hDelNum + ",hDelAfter:" + hDelAfter;
    }
}
功能验证

步骤:
1. 启动项目
2. 浏览器访问:http://localhost:8080/redis/testKv,响应结果:insertResult:true,getResult:test-value-1
3. 浏览器访问:http://localhost:8080/redis/testKm,响应结果:hSetResult:true,hGetResult:test-hSet-innerValue,hSetMapResult:true,hGetMapResult:{test-hSetMap-innerKey-3=test-hSetMap-innerValue-3, test-hSetMap-innerKey-2=test-hSetMap-innerValue-2, test-hSetMap-innerKey-1=test-hSetMap-innerValue-1}
4. 浏览器访问:http://localhost:8080/redis/testDel,响应结果:delNum:2,delAfter:null,hDelNum:0,hDelAfter:null

####单机和集群
上面的操作步骤都是基于一台redis服务器来做的,如果是基于多台redis服务,也就是集群,这里只要将spring.redis.host/spring.redis.port注释掉,将spring.redis.cluster.nodes注释放开就可以了,没有其他什么操作,就是这么简单,其他代码都不需要动,上手测试即可。

springboot整合集成jedis方式实现(单机模式)
JedisPoolBootConfig.java

在com.springboot.utui.web下建立config包,创建JedisPoolBootConfig类。

@Configuration
public class JedisPoolBootConfig {
	@Value("${spring.redis.host}")
	private String redisHost;
	@Value("${spring.redis.port}")
	private int redisPort;
	@Value("${spring.redis.max-wait}")
	private Integer maxWait;
	@Value("${spring.redis.pool.max-active}")
	private Integer maxActive;
	@Value("${spring.redis.pool.max-idle}")
	private Integer maxIdle;
	@Value("${spring.redis.pool.min-idle}")
	private Integer minIdle;
	@Value("${spring.redis.timeout}")
	private int timeout;

	@Bean
	public ShardedJedisPool getShardedJedisPool() {
		//Jedis配置信息
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxTotal(maxActive);
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMinIdle(minIdle);
		jedisPoolConfig.setMaxWaitMillis(maxWait);
		JedisShardInfo shardInfo = new JedisShardInfo(redisHost, redisPort, timeout);
		List<JedisShardInfo> shardInfos = new ArrayList<>();
		shardInfos.add(shardInfo);
		return new ShardedJedisPool(jedisPoolConfig, shardInfos);
	}

	@Bean
	public JedisPool getJedisPool() {
		//Jedis配置信息
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxTotal(maxActive);
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMinIdle(minIdle);
		jedisPoolConfig.setMaxWaitMillis(maxWait);
		return new JedisPool(jedisPoolConfig, redisHost, redisPort, timeout);
	}
}

RedisClientController.java

在RedisClientController.java中导入ShardedJedisPool\JedisPool对象并添加测试方法。

@Autowired
private ShardedJedisPool shardedJedisPool;
@Autowired
private JedisPool jedisPool;
/**
 * 测试JedisShardedJedis
 */
@RequestMapping(method = RequestMethod.GET, value = "/testShardedJedis")
@ResponseBody
public String testShardedJedis() {
	ShardedJedis sharJedis = shardedJedisPool.getResource();
	sharJedis.set("sharJedis-test", "sharJedis-test-value");
	return "sharJedis:" + sharJedis.get("sharJedis-test-value");
}

/**
 * 测试JedisPool
 */
@RequestMapping(method = RequestMethod.GET, value = "/testJedisPool")
@ResponseBody
public String testJedisPool() {
	Jedis jedis = jedisPool.getResource();
	jedis.set("jedis-test", "jedis-test-value");
	return "jedis:" + jedis.get("jedis-test");
}

运行项目测试后得到相应的结果,这里ShardedJedisPool和JedisPool是两种实现单机Redis服务的方式,二者去其一即可,这里作为演示就都写出来。

springboot整合集成jedis方式实现(集群模式)
JedisClusterConfig.java

在com.springboot.utui.web.config包中创建JedisClusterConfig类。

@Configuration
public class JedisClusterConfig {
	@Value("${spring.redis.cluster.nodes}")
	private String redisNodes;
	@Value("${spring.redis.max-wait}")
	private Integer maxWait;
	@Value("${spring.redis.pool.max-idle}")
	private Integer maxIdle;
	@Value("${spring.redis.pool.min-idle}")
	private Integer minIdle;
	@Value("${spring.redis.timeout}")
	private int timeout;

	@Bean
	public JedisCluster getJedisCluster() {
		String[] cNodes = redisNodes.split(",");
		Set<HostAndPort> nodes = new HashSet<>();
		for (String cNode : cNodes) {
			String[] hp = cNode.split(":");
			nodes.add(new HostAndPort(hp[0], Integer.valueOf(hp[1])));
		}
		JedisPoolConfig poolConfig = new JedisPoolConfig();
		poolConfig.setMaxWaitMillis(maxWait);
		poolConfig.setMaxIdle(maxIdle);
		poolConfig.setMinIdle(minIdle);
		return new JedisCluster(nodes, timeout, poolConfig);
	}
}

RedisClientController.java

在RedisClientController.java中导入JedisCluster对象并添加测试方法。

@Autowired
private JedisCluster jedisCluster;
/**
 * 测试JedisCluster
 */
@RequestMapping(method = RequestMethod.GET, value = "/testJedisCluster")
@ResponseBody
public String testJedisCluster() {
	jedisCluster.set("jedisCluster-test", "jedisCluster-test-value");
	return "jedisCluster:" + jedisCluster.get("jedisCluster-test");
}

运行项目测试浏览器访问得到对应结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿洞晓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值