参考自: https://www.cnblogs.com/zeng1994/p/03303c805731afc9aa9c60dbbd32a323.html
1、maven依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7.RELEASE</version> <relativePath/> </parent> <groupId>com.example</groupId> <artifactId>test-redis</artifactId> <version>0.0.1-SNAPSHOT</version> <name>test-redis</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <kotlin.version>1.2.71</kotlin.version> </properties> <dependencies> <!--<dependency>--> <!--<groupId>org.springframework.boot</groupId>--> <!--<artifactId>spring-boot-starter</artifactId>--> <!--</dependency>--> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-reflect</artifactId> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-test-junit5 --> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-test-junit5</artifactId> <version>1.2.70</version> <scope>test</scope> </dependency> </dependencies> <build> <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory> <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <configuration> <args> <arg>-Xjsr305=strict</arg> </args> <compilerPlugins> <plugin>spring</plugin> </compilerPlugins> </configuration> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
2、RedisTemplate配置,新建RedisContig.kt
package com.example.demo.config import com.fasterxml.jackson.annotation.JsonAutoDetect import com.fasterxml.jackson.annotation.PropertyAccessor import com.fasterxml.jackson.databind.ObjectMapper 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.RedisTemplate import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer import org.springframework.data.redis.serializer.StringRedisSerializer @Configuration class RedisConfig { @Bean fun redisTemplate(factory : RedisConnectionFactory) : RedisTemplate<String, Any> { val om = ObjectMapper() //om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY) om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL) om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY); //om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); val jackson2JsonRedisSerializer = Jackson2JsonRedisSerializer(Any::class.java) jackson2JsonRedisSerializer.setObjectMapper(om) val stringRedisSerializer = StringRedisSerializer() val template = RedisTemplate<String, Any>() template.setConnectionFactory(factory) template.keySerializer = stringRedisSerializer template.hashKeySerializer = stringRedisSerializer template.valueSerializer = jackson2JsonRedisSerializer template.hashValueSerializer = jackson2JsonRedisSerializer template.afterPropertiesSet() return template } }
创建类RedisUtil.kt,作为redis操作类
package com.example.demo.util import org.springframework.data.redis.core.RedisTemplate import org.springframework.stereotype.Component import org.springframework.util.CollectionUtils import java.util.concurrent.TimeUnit import javax.annotation.Resource @Component class RedisUtil { @Resource private lateinit var redisTemplate: RedisTemplate<String, Any> // =============================common============================ /** * 指定缓存失效时间 * @param key 键 * @param time 时间(秒) * @return */ fun expire(key: String, time: Long): Boolean { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS) } return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 根据key 获取过期时间 * @param key 键 不能为null * @return 时间(秒) 返回0代表为永久有效 */ fun getExpire(key: String): Long { return redisTemplate.getExpire(key, TimeUnit.SECONDS) } /** * 判断key是否存在 * @param key 键 * @return true 存在 false不存在 */ fun hasKey(key: String): Boolean { try { return redisTemplate.hasKey(key) } catch (e: Exception) { e.printStackTrace() return false } } /** * 删除缓存 * @param key 可以传一个值 或多个 */ fun del(vararg key: String) { if (key.isNotEmpty()) { if (key.size == 1) { redisTemplate.delete(key[0]) } else { redisTemplate.delete(key.toList()) } } } // ============================String============================= /** * 普通缓存获取 * @param key 键 * @return 值 */ operator fun get(key: String?): Any? { return if (key == null) null else redisTemplate.opsForValue().get(key) } /** * 普通缓存放入 * @param key 键 * @param value 值 * @return true成功 false失败 */ operator fun set(key: String, value: Any): Boolean { try { redisTemplate.opsForValue().set(key, value) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 普通缓存放入并设置时间 * @param key 键 * @param value 值 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ operator fun set(key: String, value: Any, time: Long): Boolean { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS) } else { set(key, value) } return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 递增 * @param key 键 * @param delta 要增加几(大于0) * @return */ fun incr(key: String, delta: Long): Long { if (delta < 0) { throw RuntimeException("递增因子必须大于0") } return redisTemplate.opsForValue().increment(key, delta)!! } /** * 递减 * @param key 键 * @param delta 要减少几(小于0) * @return */ fun decr(key: String, delta: Long): Long { if (delta < 0) { throw RuntimeException("递减因子必须大于0") } return redisTemplate.opsForValue().increment(key, -delta)!! } // ================================Map================================= /** * HashGet * @param key 键 不能为null * @param item 项 不能为null * @return 值 */ fun hget(key: String, item: String): Any? { return redisTemplate.opsForHash<Any, Any>().get(key, item) } /** * 获取hashKey对应的所有键值 * @param key 键 * @return 对应的多个键值 */ fun hmget(key: String): Map<Any, Any> { return redisTemplate.opsForHash<Any, Any>().entries(key) } /** * HashSet * @param key 键 * @param map 对应多个键值 * @return true 成功 false 失败 */ fun hmset(key: String, map: Map<String, Any>): Boolean { try { redisTemplate.opsForHash<Any, Any>().putAll(key, map) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * HashSet 并设置时间 * @param key 键 * @param map 对应多个键值 * @param time 时间(秒) * @return true成功 false失败 */ fun hmset(key: String, map: Map<String, Any>, time: Long): Boolean { try { redisTemplate.opsForHash<Any, Any>().putAll(key, map) if (time > 0) { expire(key, time) } return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 向一张hash表中放入数据,如果不存在将创建 * @param key 键 * @param item 项 * @param value 值 * @return true 成功 false失败 */ fun hset(key: String, item: String, value: Any): Boolean { try { redisTemplate.opsForHash<Any, Any>().put(key, item, value) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 向一张hash表中放入数据,如果不存在将创建 * @param key 键 * @param item 项 * @param value 值 * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 * @return true 成功 false失败 */ fun hset(key: String, item: String, value: Any, time: Long): Boolean { try { redisTemplate.opsForHash<Any, Any>().put(key, item, value) if (time > 0) { expire(key, time) } return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 删除hash表中的值 * @param key 键 不能为null * @param item 项 可以使多个 不能为null */ fun hdel(key: String, vararg item: Any) { redisTemplate.opsForHash<Any, Any>().delete(key, *item) } /** * 判断hash表中是否有该项的值 * @param key 键 不能为null * @param item 项 不能为null * @return true 存在 false不存在 */ fun hHasKey(key: String, item: String): Boolean { return redisTemplate.opsForHash<Any, Any>().hasKey(key, item) } /** * hash递增 如果不存在,就会创建一个 并把新增后的值返回 * @param key 键 * @param item 项 * @param by 要增加几(大于0) * @return */ fun hincr(key: String, item: String, by: Double): Double { return redisTemplate.opsForHash<Any, Any>().increment(key, item, by) } /** * hash递减 * @param key 键 * @param item 项 * @param by 要减少记(小于0) * @return */ fun hdecr(key: String, item: String, by: Double): Double { return redisTemplate.opsForHash<Any, Any>().increment(key, item, -by) } // ============================set============================= /** * 根据key获取Set中的所有值 * @param key 键 * @return */ fun sGet(key: String): Set<Any>? { try { return redisTemplate.opsForSet().members(key) } catch (e: Exception) { e.printStackTrace() return null } } /** * 根据value从一个set中查询,是否存在 * @param key 键 * @param value 值 * @return true 存在 false不存在 */ fun sHasKey(key: String, value: Any): Boolean { try { return redisTemplate.opsForSet().isMember(key, value)!! } catch (e: Exception) { e.printStackTrace() return false } } /** * 将数据放入set缓存 * @param key 键 * @param values 值 可以是多个 * @return 成功个数 */ fun sSet(key: String, vararg values: Any): Long { try { return redisTemplate.opsForSet().add(key, *values)!! } catch (e: Exception) { e.printStackTrace() return 0 } } /** * 将set数据放入缓存 * @param key 键 * @param time 时间(秒) * @param values 值 可以是多个 * @return 成功个数 */ fun sSetAndTime(key: String, time: Long, vararg values: Any): Long { try { val count = redisTemplate.opsForSet().add(key, *values) if (time > 0) expire(key, time) return count!! } catch (e: Exception) { e.printStackTrace() return 0 } } /** * 获取set缓存的长度 * @param key 键 * @return */ fun sGetSetSize(key: String): Long { try { return redisTemplate.opsForSet().size(key)!! } catch (e: Exception) { e.printStackTrace() return 0 } } /** * 移除值为value的 * @param key 键 * @param values 值 可以是多个 * @return 移除的个数 */ fun setRemove(key: String, vararg values: Any): Long { try { val count = redisTemplate.opsForSet().remove(key, *values) return count!! } catch (e: Exception) { e.printStackTrace() return 0 } } // ===============================list================================= /** * 获取list缓存的内容 * @param key 键 * @param start 开始 * @param end 结束 0 到 -1代表所有值 * @return */ fun lGet(key: String, start: Long, end: Long): List<Any>? { try { return redisTemplate.opsForList().range(key, start, end) } catch (e: Exception) { e.printStackTrace() return null } } /** * 获取list缓存的长度 * @param key 键 * @return */ fun lGetListSize(key: String): Long { try { return redisTemplate.opsForList().size(key)!! } catch (e: Exception) { e.printStackTrace() return 0 } } /** * 通过索引 获取list中的值 * @param key 键 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 * @return */ fun lGetIndex(key: String, index: Long): Any? { try { return redisTemplate.opsForList().index(key, index) } catch (e: Exception) { e.printStackTrace() return null } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ fun lSet(key: String, value: Any): Boolean { try { redisTemplate.opsForList().rightPush(key, value) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ fun lSet(key: String, value: Any, time: Long): Boolean { try { redisTemplate.opsForList().rightPush(key, value) if (time > 0) expire(key, time) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ fun lSet(key: String, value: List<Any>): Boolean { try { redisTemplate.opsForList().rightPushAll(key, *value.toTypedArray()) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ fun lSet(key: String, value: List<Any>, time: Long): Boolean { try { redisTemplate.opsForList().rightPushAll(key, *value.toTypedArray()) if (time > 0) expire(key, time) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 根据索引修改list中的某条数据 * @param key 键 * @param index 索引 * @param value 值 * @return */ fun lUpdateIndex(key: String, index: Long, value: Any): Boolean { try { redisTemplate.opsForList().set(key, index, value) return true } catch (e: Exception) { e.printStackTrace() return false } } /** * 移除N个值为value * @param key 键 * @param count 移除多少个 * @param value 值 * @return 移除的个数 */ fun lRemove(key: String, count: Long, value: Any): Long { try { val remove = redisTemplate.opsForList().remove(key, count, value) return remove!! } catch (e: Exception) { e.printStackTrace() return 0 } } }
在application.properties中增加redis配置(实际上默认是这些参数)
#Redis数据库索引(默认为0) spring.redis.database=0 #Redis服务器地址 spring.redis.host=127.0.0.1 #Redis服务器连接端口 spring.redis.port=6379 #Redis服务器连接密码(默认为空) spring.redis.password=
3、单元测试
在src/test/kotlin目录下 com.example.demo包下新建类TestRedisUtil.kt
package com.example.demo import com.example.demo.util.RedisUtil import com.fasterxml.jackson.databind.ObjectMapper import org.junit.Assert import org.junit.FixMethodOrder import org.junit.runners.MethodSorters import org.springframework.boot.test.context.SpringBootTest import javax.annotation.Resource import kotlin.test.Test @SpringBootTest @FixMethodOrder(MethodSorters.NAME_ASCENDING) class TestRedisUtil { @Resource private lateinit var redisUtil: RedisUtil @Test fun test001_javaBean() { val student = Student(0, "Aa") redisUtil.set("student", student) val json = redisUtil.get("student") var result: Student? = null if (json is HashMap<*, *>) { //map 转 bean val mapper = ObjectMapper() //result = mapper.readValue(mapper.writeValueAsString(json), Student::class.java) result = mapper.convertValue(json, Student::class.java) Assert.assertTrue(result == student) } } @Test fun test002_List() { val list = listOf("Aa", "Bb", "Cc") redisUtil.set("listBean", list) val json = redisUtil.get("listBean") if (json != null) { val mapper = ObjectMapper() val type = mapper.typeFactory.constructParametricType(ArrayList::class.java, String::class.java) val result: List<String> = mapper.readValue(mapper.writeValueAsString(json), type) println(result) } } @Test fun test003_stringList() { val list = listOf("Aa", "Bb", "Cc") redisUtil.del("stringList") redisUtil.lSet("stringList", list) val result = redisUtil.lGet("stringList", 0, 10) Assert.assertEquals(list, result) } @Test fun test_studentList() { val list = listOf(Student(1, "Aa"), Student(2, "Bb"), Student(3, "Cc"), null) redisUtil.del("studentList") redisUtil.lSet("studentList", list) val result= redisUtil.lGet("studentList", 0, 10) if (result is List<*> && result.isNotEmpty() && result.get(0) is List<*>) { val resultList = result[0] as List<*> val objectMapper = ObjectMapper() val studentList = resultList.map { item -> objectMapper.convertValue(item, Student::class.java) } Assert.assertEquals(list, studentList) } } @Test fun test_map() { redisUtil.del("map") val map = mutableMapOf<String, Int>() map.put("A", 0) map.put("B", 1) redisUtil.hmset("map", map) val result = redisUtil.hmget("map"); Assert.assertTrue(result == map) } class Student() { var id: Int? = null var name: String? = null constructor(id: Int?, name: String?) : this() { this.id = id this.name = name } override fun hashCode(): Int { var result = id ?: 0 result = 31 * result + (name?.hashCode() ?: 0) return result } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as Student if (id != other.id) return false if (name != other.name) return false return true } override fun toString(): String { return "Student(id=$id, name=$name)" } } }
启动本地redis,即可测试从redis中存取String、list、对象及map等数据。