一)背景
redis在springboot2.x中语法有一些变化,所以该章编写的时间花费的久一点,以此来记录。
二)在pom.xml文件中引入redis需要的jar
<?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>
<groupId>com.oysept.springboot</groupId>
<artifactId>oysept-springboot-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>oysept-springboot-redis</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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>
<!-- springboot redis缓存支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 分布式场景redis共享session -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!-- 添加json处理jar -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
三)在application.properties中添加redis配置
server.port=8080
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.timeout=60000
四)添加一个redis配置工具类
package com.oysept.springboot.conf;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
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;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* redis配置类
* @author ouyangjun
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 自定义redis key生成规则
* 使用时,需要指定keyGenerator
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder builder = new StringBuilder();
builder.append(target.getClass().getName());
builder.append(method.getName());
for (Object obj : params) {
// 由于参数可能不同, hashCode肯定不一样
builder.append(JSON.toJSONString(obj).hashCode());
}
return builder.toString();
}
};
}
/**
* redis全局缓存配置
* 备注: 2.X的版本相对于1.X的版本有变化,在初始化RedisCacheManager不一样
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
//默认配置
/*
RedisCacheManager redisCacheManager = RedisCacheManager.create(factory);
return redisCacheManager;
*/
// 自定义配置
/*
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 设置过期时间,并不缓存空值,分钟
config = config.entryTtl(Duration.ofMinutes(10)).disableCachingNullValues();
// 设置一个初始化的缓存空间set集合
Set<String> cacheNames = new HashSet<>();
cacheNames.add("redis-cache1");
cacheNames.add("redis-cache2");
// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("redis-cache1", config);
configMap.put("redis-cache2",config.entryTtl(Duration.ofMinutes(60)).disableCachingNullValues());
RedisCacheManager redisCacheManager = RedisCacheManager.builder(factory).initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap).build();
return redisCacheManager;
*/
// 自定义配置
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(factory);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 需要重新赋值,否则无效果
// 设置过期时间,并不缓存空值,分钟。如果系统访问量非常大,建议单独做时间有效期控制,放置redis缓存雪崩
config = config.entryTtl(Duration.ofMinutes(10)).disableCachingNullValues();
RedisCacheManager redisCacheManager = new RedisCacheManager(redisCacheWriter, config);
return redisCacheManager;
}
/**
* 自定义序列化方式
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 值采用json序列化
redisTemplate.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值, 默认方式容易出现乱码
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jacksonSeial);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
五)编写一个Controller测试类,方便通过浏览器和测试工具来测试
package com.oysept.springboot.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON;
/**
* redis web访问接口类
* @author ouyangjun
*/
@RestController
@RequestMapping(value="/redis")
public class RedisController {
// 自动redis缓存-----------------------------------------------------------------------------
/**
* @Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。
* value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。
* key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。
* 请求地址: http://localhost:8080/redis/hello
* @return
*/
@RequestMapping(value="/hello")
@Cacheable(value="hello-world", keyGenerator="keyGenerator")
public @ResponseBody String helloWorld() {
System.out.println("-------------------aaaa--------------------");
return "Hello oysept springboot redis!";
}
/**
* @CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。
* value表示清除操作是发生在哪些Cache上的(对应Cache的名称)
* key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key
* allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。
* 请求地址: http://localhost:8080/redis/hello/clean
* @return
*/
@RequestMapping(value="/hello/clean")
@CacheEvict(value = "hello-world", allEntries = true)
public String cleanCache() {
return "success";
}
// 手动redis缓存-----------------------------------------------------------------------------
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 缓存字符串
* 请求地址: http://localhost:8080/redis/hm/string
* @return
*/
@RequestMapping(value="hm/string")
public @ResponseBody String hmString() {
// key
String key = "redisString";
// String缓存
stringRedisTemplate.opsForValue().set(key, "wwwwwwww");
// 生效时间,3分钟
stringRedisTemplate.expire(key, 3, TimeUnit.MINUTES);
// 返回
return stringRedisTemplate.opsForValue().get(key);
}
/**
* 缓存List
* 请求地址: http://localhost:8080/redis/hm/list
* @return
*/
@RequestMapping(value="hm/list")
public @ResponseBody String hmList() {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("A", "1111");
map1.put("B", "2222");
map1.put("C", "3333");
list.add(map1);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("A", "444");
map2.put("B", "555");
map2.put("C", "666");
list.add(map2);
Map<String, Object> map3 = new HashMap<String, Object>();
map3.put("A", "777");
map3.put("B", "888");
map3.put("C", "999");
list.add(map3);
// key
String key = "redisList";
// List缓存
boolean bool = redisTemplate.hasKey(key);
if (!bool) {
redisTemplate.opsForList().leftPush(key, list);
} else {
// 如果key不存在,直接set会报错
redisTemplate.opsForList().set(key, 0, list);
}
// 生效时间,3分钟
stringRedisTemplate.expire(key, 3, TimeUnit.MINUTES);
// 返回缓存的内容
return JSON.toJSONString(redisTemplate.opsForList().range(key, 0, -1));
}
/**
* 缓存Hash
* 请求地址: http://localhost:8080/redis/hm/hash
* @return
*/
@RequestMapping(value="hm/hash")
public @ResponseBody String hmHash() {
// key
String key = "redisHash";
// Hash缓存
redisTemplate.opsForHash().put(key, "name", "ouyangjun");
redisTemplate.opsForHash().put(key, "age", 27);
redisTemplate.opsForHash().put(key, "phone", "13600425791");
// 生效时间,3分钟
stringRedisTemplate.expire(key, 3, TimeUnit.MINUTES);
// 打印
Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
for (Object keyStr : map.keySet()) {
System.out.println("key: " + keyStr + ", value: " + map.get(keyStr));
}
// 返回缓存的内容
return JSON.toJSONString(map);
}
}
六)编写一个main方法测试类
package com.oysept.springboot.test;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.oysept.springboot.controller.RedisController;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
private MockMvc mvc;
@Before
public void setHelloWord() {
mvc = MockMvcBuilders.standaloneSetup(new RedisController()).build();
}
@Test
public void getHelloWord() {
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/redis/hello").accept(MediaType.APPLICATION_JSON);
try {
MvcResult result = mvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
System.out.println("返回值: "+response.getContentAsString());
} catch (Exception e){
System.out.println(e.fillInStackTrace());
}
}
}
七)添加springboot启动类,并展示项目结构图
package com.oysept.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* springboot启动类
* @author ouyangjun
*/
@SpringBootApplication
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}
项目结构图:
最后启动RedisApplication类,可用main方法测试类测试,也可以用浏览器和测试工具测试。
识别二维码关注个人微信公众号
本章完结,待续,欢迎转载!
本文说明:该文章属于原创,如需转载,请标明文章转载来源!