kotlin + springboot 整合redis,Redis工具类编写及单元测试
参考自: 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等数据。
kotlin + springboot 整合redis,Redis工具类编写及单元测试的更多相关文章
- springboot整合mybatis,redis,代码(二)
一 说明: springboot整合mybatis,redis,代码(一) 这个开发代码的复制粘贴,可以让一些初学者直接拿过去使用,且没有什么bug 二 对上篇的说明 可以查看上图中文件: 整个工程包 ...
- springboot整合mybatis,redis,代码(一)
一 搭建项目,代码工程结构 使用idea或者sts构建springboot项目 二 数据库sql语句 SQLyog Ultimate v12.08 (64 bit) MySQL - 5.7.14-l ...
- SpringBoot整合集成redis
Redis安装:https://www.cnblogs.com/zwcry/p/9505949.html 1.pom.xml <project xmlns="http://maven. ...
- kotlin + springboot整合mybatis操作mysql数据库及单元测试
项目mybatis操作数据库参考: http://how2j.cn/k/springboot/springboot-mybatis/1649.html?p=78908 junit对controller ...
- springboot整合mybatis,redis,代码(四)
一 说明 这是spring整合redis注解开发的系类: 二 正文 在注解开发时候,会有这几个注解需要注意: 具体含义: 1.@Cacheable 可以标记在方法上,也可以标记在类上.当标记在方法上时 ...
- springboot整合mybatis,redis,代码(五)
redis注解开发过程中包含许多注解 1.@Cacheable 可以标记在方法上,也可以标记在类上.当标记在方法上时表示该方法是支持缓存的,当标记在类上时则表示该类所有的方法都是支持缓存的.应用到读取 ...
- springboot整合mybatis,redis,代码(三)
一 说明 接着上篇讲述redis缓存配置的用法: 二 正文 首先要使用缓存就必须要开开启缓存,第二步是需要开redis-server 下载redis包之后,点击图中两个都可以开启redis 怎么看是否 ...
- 09-java学习-数组-冒泡排序-选择排序-数组工具类编写-查找-扩容
数组的排序算法 查找算法 数组协助类Arrays的学习和使用 数组的扩容
- SpringBoot整合Redis及Redis工具类撰写
SpringBoot整合Redis的博客很多,但是很多都不是我想要的结果.因为我只需要整合完成后,可以操作Redis就可以了,并不需要配合缓存相关的注解使用(如@Cacheable). ...
随机推荐
- MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数
MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数 计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数,这里主要分享的是通过MySql内置的函数 TimeStampDiff() ...
- SharpDX初学者教程第1部分:在Visual Studio 2013中设置SharpDX项目
原文 http://www.johanfalk.eu/blog/sharpdx-tutorial-part-1-setting-up-a-sharpdx-project-in-visual-studi ...
- 2019-10-23-WPF-使用-SharpDx-渲染博客导航
title author date CreateTime categories WPF 使用 SharpDx 渲染博客导航 lindexi 2019-10-23 21:10:13 +0800 2019 ...
- Spring AOP 的实现 原理
反射实现 AOP 动态代理模式实例说明(Spring AOP 的实现 原理) 比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们 ...
- Libev源码分析06:异步信号同步化--sigwait、sigwaitinfo、sigtimedwait和signalfd
一:信号简述 信号是典型的异步事件.内核在某个信号出现时有三种处理方式: a:忽略信号,除了SIGKILL和SIGSTOP信号不能忽略外,其他大部分信号都可以被忽略: b:捕捉信号,也就是在信号发生时 ...
- angularjs 自定义指令弹窗
(function() { 'use strict'; angular.module('frontierApp') .directive('confirmPopup', ['$timeout', Co ...
- Python3:ImportError: No module named 'compiler.ast'
from compiler.ast import flatten 上面这条语句好像在python3 以后就废除了,如果使用的话就会报错.Traceback (most recent call last ...
- Python--day69--ORM聚合查询和分组查询
聚合查询和分组查询 聚合 aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典. 键的名称是聚合值的标识符,值是计算出来的聚合值.键的名称是按照字段和聚合 ...
- 基于 Laravel-Admin 在十分钟内搭建起功能齐全的后台模板
http://laravelacademy.org/post/6468.html 1.简介 为 Laravel 提供后台模板的项目越来越多,学院君已陆续为大家介绍过Laravel Angular Ad ...
- InetlliJ IDEA的快捷键及各种配置
在IDEA中新建Maven工程,之后再新建一个Maven模块,此时在模块中的src/main/java中右键新建Java文件时,发现只能新建普通文件,不能新建Java类了,怎么回事,和eclipse的 ...