相关链接
1. SpringBoot整合
??Jedis是官方推荐的Java链接开发工具,使用Java操作Redis中间件。
1.1 创建一个SpringBoot项目
??参考 => SpringBoot常用注解、lombok常用注解 中的〇、创建springboot项目;注意额外还要选中NoSQL的Spring Data Redis ??新建的项目检查一下maven位置是否正确
【说明】Jedis -> lettuce
??说明: Spring2.X 之后,原来使用的Jedis被替换成了lettuce ??jedis: 底层采用直连server,多个线程操作是不安全的,如果想要避免不安全的,使用 jedis pool 连接池。就会带来一系列问题(线程过多会导致redis server很大,类似于同步阻塞模式BIO)。 ??lettuce: 采用netty,实例可以在多个线程中共享,不存在线程不安全的情况,可以减少线程数量,性能更好(类似于同步非阻塞式NIO)。
?? lettuce底层使用了netty。
1.2 Redis配置文件
参考源码 RedisProperties,如果是本机,6379端口完全可以不用配置,因为已经有默认值了。 ?Step1. 导包 ??pom.xml:创建springboot项目时,勾选NoSQL->Spring Data Redis自动就导入了。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
?Step2. 配置连接 ??application.properties
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
1.3 测试编码
?Step3. 测试编码,RedisTemplate操作是比较麻烦的,最好再自己封装一个模板来操作。
package com.groupies.springbootredis;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.getConnectionFactory().getConnection().flushDb();
redisTemplate.opsForValue().set("springboot", "redis");
redisTemplate.opsForValue().set("hello", "world");
System.out.println(redisTemplate.opsForValue().get("springboot"));
System.out.println(redisTemplate.opsForValue().get("hello"));
redisTemplate.getConnectionFactory().getConnection().close();
}
}
?redis-cli查看显示是乱码,原因是没有做序列化。
2. Serialize 序列化问题
需要准备一个pojo类User,在SpringbootRedisApplicationTests中测试。
2.1 User未序列化
User
package com.groupies.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User{
private String name;
private Integer age;
}
SpringbootRedisApplicationTests
package com.groupies.springbootredis;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.groupies.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Test
public void test() throws JsonProcessingException {
User user = new User("张三", 3);
String jsonUser = new ObjectMapper().writeValueAsString(user);
redisTemplate.getConnectionFactory().getConnection().flushDb();
redisTemplate.opsForValue().set("user", jsonUser);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.opsForValue().set("user", user);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.getConnectionFactory().getConnection().close();
}
}
2.2 User序列化
User
package com.groupies.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable{
private String name;
private Integer age;
}
SpringbootRedisApplicationTests
package com.groupies.springbootredis;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.groupies.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Test
public void test() throws JsonProcessingException {
User user = new User("张三", 3);
String jsonUser = new ObjectMapper().writeValueAsString(user);
redisTemplate.getConnectionFactory().getConnection().flushDb();
redisTemplate.opsForValue().set("user", jsonUser);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.opsForValue().set("user", user);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.getConnectionFactory().getConnection().close();
}
}
?RedisTemplate中默认序列化jdk序列化,jdk序列化会丢字符串进行转义,这是导致乱码的原因。
3. RedisTemplate自定义模板解决乱码
3.1 自定义模板原理
??通过springboot的autoconfigure找到redis配置文件 RedisAutoConfiguration。
??源码分析: @ConditionalOnMissingBean如果而注册相同类型的bean,就不会成功。以此来保证bean只有一个。当你注册多个相同的bean时,会出现异常。因此可以自定义一个 redisTemplate 来让默认的模板失效。
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = {"redisTemplate"})
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
?【说明】乱码问题:RedisAutoConfiguration使用默认的RedisTemplate,这里是jdk序列化,会产生乱码,所以需要自自定义一个redisTemplate
3.2 模板内容
package com.groupies.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
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
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
3.3 自定义Template测试
User
package com.groupies.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable{
private String name;
private Integer age;
}
SpringbootRedisApplicationTests
package com.groupies.springbootredis;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.groupies.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
@Qualifier("redisTemplate")
RedisTemplate redisTemplate;
@Test
public void test() throws JsonProcessingException {
User user = new User("张三", 3);
String jsonUser = new ObjectMapper().writeValueAsString(user);
redisTemplate.getConnectionFactory().getConnection().flushDb();
redisTemplate.opsForValue().set("user", jsonUser);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.opsForValue().set("user", user);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.getConnectionFactory().getConnection().close();
}
}
仍然是乱码,自定义模板未生效,原因不详
4. StringRedisTemplate解决乱码
??StringRedisTemplate可以解决乱码问题英文乱码问题,但是不支持json格式数据,而且中文仍然显示为乱码。
4.1 测试
User
package com.groupies.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable{
private String name;
private Integer age;
}
SpringbootRedisApplicationTests
package com.groupies.springbootredis;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.groupies.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void test() throws JsonProcessingException {
User user = new User("张三", 3);
String jsonUser = new ObjectMapper().writeValueAsString(user);
redisTemplate.getConnectionFactory().getConnection().flushDb();
redisTemplate.opsForValue().set("user", jsonUser);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.opsForValue().set("user", user);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.getConnectionFactory().getConnection().close();
}
}
5. RedisTemplate解决乱码2
??StringRedisTemplate可以解决乱码问题英文乱码问题,但是不支持json格式数据,而且中文仍然显示为乱码。
5.1 测试
User
package com.groupies.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable{
private String name;
private Integer age;
}
SpringbootRedisApplicationTests
package com.groupies.springbootredis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.groupies.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void redisTemplateSet() throws JsonProcessingException {
redisSerializer(redisTemplate);
User user = new User("张三", 3);
String userStr = new ObjectMapper().writeValueAsString(user);
redisTemplate.getConnectionFactory().getConnection().flushDb();
redisTemplate.opsForValue().set("user", userStr);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.opsForValue().set("userPojo", user);
System.out.println(redisTemplate.opsForValue().get("user"));
redisTemplate.getConnectionFactory().getConnection().close();
}
public static void redisSerializer(RedisTemplate template){
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setKeySerializer(jackson2JsonRedisSerializer);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
}
}
6. RedisUtil
@Component
public final class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
public boolean hasKey(String key) {
try {
redisTemplate.hasKey(key);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 0) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(Arrays.asList(key));
}
}
}
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
redisTemplate.opsForValue().set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
public Object hGet(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
public Map<Object, Object> hMget(String key) {
return redisTemplate.opsForHash().entries(key);
}
public boolean hMset(String key, Map<Object, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean hMset(String key, Map<Object, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean hSet(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean hSet(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public void hDel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
public boolean hHaskey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
public double hIncr(String key, String item, double detal) {
return redisTemplate.opsForHash().increment(key, item, detal);
}
public double hDecr(String key, String item, double detal) {
return redisTemplate.opsForHash().increment(key, item, -detal);
}
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public boolean sHaskey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public long sSet(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public long setRemove(String key, Object... values) {
try {
return redisTemplate.opsForSet().remove(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
22/03/08
M
|