Redis——基于Spring的开发示例(连接、序列化、high/low api)

文章目录

在前面的文章中,我们学习了有关 Redis 的几乎所有的重点内容,都属于理论内容,只有要掌握这些底层知识,这样我们才能设计出良好的系统架构;而且当系统出现问题的时候,我们只有熟知了各种场景可能会发生什么问题,这样才能快速的定位、排查以及解决问题

下面我们就来学习一下如何基于 SpringBoot 框架进行简单的 Redis 的 API 进行开发

SpringBoot 集成 Redis 官网教程:

https://docs.spring.io/spring-data/redis/docs/2.3.4.RELEASE/reference/html/#reference

一、基本开发

我们这里就不演示基于 spring mvc 的 web 访问方式,而是基于功能,简单的进行代码开发

1、建立spring boot项目

spring boot 项目中集成 redis

在这里插入图片描述

2、与vm中的redis建立连接

启动redis实例:端口号 8888

//随意创建一个目录
mkdir springboot
//切换到此目录
cd springboot/
//启动一个redis实例,端口号为 8888
redis-server --port 8888

修改远程访问安全策略级别

//连接redis
redis-cli
//临时修改安全策略,默认为 yes,修改为 no
config set 
protected-mode no

查看本机IP地址:192.168.159.111

[root@node01 ~]# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0C:29:F0:66:24  
          inet addr:192.168.159.111  Bcast:192.168.159.255  Mask:255.255.255.0

在 application.properties 配置文件中统一配置连接信息

application.properties

spring.redis.host=192.168.159.111
spring.redis.port=8888

3、测试连接

TestRedis.java

@Component
public class TestRedis {
    @Autowired
    RedisTemplate redisTemplate;//注入 template
    public void testRedis(){
        //设置data
        redisTemplate.opsForValue().set("hello", "china");
        //获取data
        System.out.println(redisTemplate.opsForValue().get("hello"));
    }
}

DemoApplication.java

@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
        //获取 ctx
        ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
        //获取容器中的bean对象
        TestRedis testRedis = ctx.getBean(TestRedis.class);
        testRedis.testRedis();
    }
}

运行结果:能够连接到本地虚拟机的 redis 服务实例,并且能够正常 set 和 get 数据

在这里插入图片描述

二、high/low API及序列化

在 Redis 支持的value类型中,其实可以分为两类,一类就是单值类型,比如 string,还有一类就是复值类型,即hash,对于不同的类型的操作是不一样的

1、high level api

RedisTemplate

在上面测试中,我们已经把数据写入了 Redis 中,所以 Redis 中应该存在数据,在 vm 中通过命令行获取 key,发现出现乱码,说明序列化的时候出现问题

127.0.0.1:8888> keys *
1) "\xac\xed\x00\x05t\x00\x05hello"

为什么会出现乱码?我们知道 Redis 是针对很多语言提供服务的,所以它是二进制安全的,只存储字节数组,任何一个客户端都应该注意:我的数据是怎么变成的字节数组?是怎么进行的序列化?

上面使用的高阶的 RedisTemplate 是面向基本的 JAVA 序列化方式,JAVA 序列化方式是要加一些东西,而不是字面意义上的编码,所以在 key 前面多出了一些乱码。

StringRedisTemplate

而我们在使用 Redis 的时候,更多的场景是基于 String 这种方式的,此时除了通用的 RedisTemplate,其实还有面向 String 的 StringRedisTemplate

TestRedis.java(使用StringRedisTemplate)

@Component
public class TestRedis {
    @Autowired
    RedisTemplate redisTemplate;//注入通用的 RedisTemplate
    @Autowired
    StringRedisTemplate stringRedisTemplate;//注入操作String的StringRedisTemplate
    public void testRedis(){
        //设置data
        stringRedisTemplate.opsForValue().set("hello01", "china");
        //获取data
        System.out.println(stringRedisTemplate.opsForValue().get("hello"));
    }
}

此时在vm中通过命令行获取所有key,可以发现 hello01 没有出现乱码

127.0.0.1:8888> keys *
1) "\xac\xed\x00\x05t\x00\x05hello"
2) "hello01"

2、low level api

上面的 RedisTemplate 和 StringRedisTemplate 都是封装好的 Template,可以直接拿来用,属于 high level api,其实我们还可以使用低阶API

@Component
public class TestRedis {
    @Autowired
    RedisTemplate redisTemplate;//注入通用的 RedisTemplate
    @Autowired
    StringRedisTemplate stringRedisTemplate;//注入操作String的StringRedisTemplate
    public void testRedis(){
        /*//设置data
        stringRedisTemplate.opsForValue().set("hello01", "china");
        //获取data
        System.out.println(stringRedisTemplate.opsForValue().get("hello01"));*/
        //使用低阶API,相当于能够以命令行的方式操作 Redis
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        //开发人员手动进行字节数组转换,比较累
        connection.set("hello02".getBytes(),"china".getBytes());
        System.out.println(new String(connection.get("hello02".getBytes())));
    }
}

运行结果:正常设置data

在这里插入图片描述

此时在vm中通过命令行获取所有key,可以发现 hello02 也没有出现乱码情况

127.0.0.1:8888> keys *
1) "hello02"
2) "\xac\xed\x00\x05t\x00\x05hello"
3) "hello01"

使用低阶的 API,我们可以相当于以命令行的方式操作 Redis,可以进行更细粒度的灵活控制,就是操作有点繁琐,不如高阶 API 用着舒服

3、操作复值——hash

前面我们操作的是 String,在 Redis 中还支持 key-calue 类型的复值,那么对于 hash 这样的复值应该怎样操作呢?

1、原始方式存取
@Component
public class TestRedis {
    @Autowired
    RedisTemplate redisTemplate;//注入通用的 RedisTemplate
    @Autowired
    StringRedisTemplate stringRedisTemplate;//注入操作String的StringRedisTemplate
    public void testRedis(){
        //操作复值 hash
        HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
        hash.put("john", "name", "weijiangming");
        hash.put("john","age", "20");
        System.out.println(hash.entries("john"));
    }
}

运行结果:能够正常设置和获取data

在这里插入图片描述

此时在vm中通过命令行查看 john 信息,也能正常获取和操作

127.0.0.1:8888> hgetall john
1) "name"
2) "weijiangming"
3) "age"
4) "20"
127.0.0.1:8888> hincrby john age 2
(integer) 22
2、封装成JSON对象存取(Jackson2HashMapper)

原始方式操作对象很麻烦,需要一个属性一个属性的往里放,我们更倾向于从外界获取封装好的对象,可以直接把对象传入和取出

1、创建实体对象

Person.class

public class Person {
    private String name;
    private Integer age;
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}

既然有这样的对象,怎样才能正确的放入 Redis?别人怎样才能正确的取出来?

官方提供说明:

https://docs.spring.io/spring-data/redis/docs/2.3.4.RELEASE/reference/html/#redis.hashmappers.root

下面我们就以Jackson2HashMapper来演示如何将对象进行映射存储

首先Jackson2HashMapper需要导入 pom 支持

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
</dependency>

然后使用Jackson2HashMapper进行对象的存取

@Component
public class TestRedis {
    @Autowired
    RedisTemplate redisTemplate;//注入通用的 RedisTemplate
    @Autowired
    StringRedisTemplate stringRedisTemplate;//注入操作String的StringRedisTemplate
    @Autowired
    ObjectMapper objectMapper;
    public void testRedis(){
        //对象有了,怎么放入 Redis?
        Person p = new Person();
        p.setName("mjt");
        p.setAge(22);
        //创建Jackson2HashMapper对象 jm
        Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper,false);
        //通过 jm,可以完成对象到 hash 的映射
        redisTemplate.opsForHash().putAll("mjt01", jm.toHash(p));
        //取出对象并转换成map
        Map map = redisTemplate.opsForHash().entries("mjt01");
        Person per = objectMapper.convertValue(map, Person.class);
        System.out.println(per);
    }
}

运行结果:发现能够以对象地方式正常地存取数据

在这里插入图片描述

此时在vm中通过命令行查看 mjt01 信息:发现 mjt 出现乱码

127.0.0.1:8888> keys *
1) "\xac\xed\x00\x05t\x00\x05mjt01"

既然使用高阶 API 中的 RedisTemplate 会出现乱码,那我们换一个高阶 API StringRedisTemplate

运行结果:出现类型不匹配问题

在这里插入图片描述

此时我们发现使用高阶 API,要么 JAVA 序列化把 String 破环了,出现乱码;要么出现类型差异不匹配,序列化会有差异

3、设置序列化器

要解决这个问题,我们条件反射的就会想到设置合适的序列化器就可以了,StringRedisTemplate提供了多种序列化方式,它很灵活

在这里插入图片描述

所以在下面的代码中,我们只比以前多加了一行代码,其余为改动,就能够完成 Integer 类型的数据序列化

@Component
public class TestRedis {
    @Autowired
    RedisTemplate redisTemplate;//注入通用的 RedisTemplate
    @Autowired
    StringRedisTemplate stringRedisTemplate;//注入操作String的StringRedisTemplate
    @Autowired
    ObjectMapper objectMapper;
    public void testRedis(){
        //对象有了,怎么放入 Redis?
        Person p = new Person();
        p.setName("mjt02");
        p.setAge(88);
        //未来使用stringRedisTemplate高阶api的时候,凡是对hash类型,value都会直接写成 json 这种格式来完成序列化
        stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        //创建Jackson2HashMapper对象 jm
        Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper,false);
        //通过 jm,可以完成对象到 hash 的映射
        stringRedisTemplate.opsForHash().putAll("mjt02", jm.toHash(p));
        //取出对象并转换成map
        Map map = stringRedisTemplate.opsForHash().entries("mjt02");
        Person per = objectMapper.convertValue(map, Person.class);
        System.out.println(per);
    }
}

运行结果:正常进行存取,序列化成功

在这里插入图片描述

此时在vm中通过命令行查看 mjt02 信息:能够正常获取和操作

127.0.0.1:8888> keys *
1) "mjt02"
127.0.0.1:8888> hgetall mjt02
1) "name"
2) "\"mjt02\""
3) "age"
4) "88"
127.0.0.1:8888> hincrby mjt02 age 2
(integer) 90
4、自定义 Template

上面演示的只是一个方法,里面需要做一堆事情,还需要设置序列化器,如果每一个方法都这样做是不是有点累?有点扯?如果我们开始的时候,能够直接拿到一个配置好序列化器的 Template 是不是就很方便?

我们可以自定义一个 Template,创建之初就已经包含了序列化器 Jackson2HashMapper,注入Spring容器之中,拿来即用就行

通过工厂 RedisConnectionFactory 获得 template,并设置序列化器
MyTemplate.class

@Configuration
public class MyTemplate {
    //把每个方法都需要设置序列化器的步骤抽离出来
    //封装好,能够拿来即用
    @Bean
    public StringRedisTemplate ooxx(RedisConnectionFactory fc){
        StringRedisTemplate tp = new StringRedisTemplate(fc);
        //设置序列化器
        tp.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        return tp;
    }
}

此时在原来的代码中就不必再设置序列化器了

@Component
public class TestRedis {
    @Autowired
    @Qualifier("ooxx")
    StringRedisTemplate stringRedisTemplate;//注入操作String的StringRedisTemplate
    @Autowired
    ObjectMapper objectMapper;
    public void testRedis(){
        //对象有了,怎么放入 Redis?
        Person p = new Person();
        p.setName("mjt02");
        p.setAge(88);
        //不必再手动指定序列化器
        //stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        //创建Jackson2HashMapper对象 jm
        Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper,false);
        //通过 jm,可以完成对象到 hash 的映射
        stringRedisTemplate.opsForHash().putAll("mjt02", jm.toHash(p));
        //取出对象并转换成map
        Map map = stringRedisTemplate.opsForHash().entries("mjt02");
        Person per = objectMapper.convertValue(map, Person.class);
        System.out.println(per);
    }
}

虽然看起来只是简单的消除了一行代码,但是再整个项目组中都使用自定义的 Template,我们可以针对不同情况自定义很多个 Template,这样能够很大的简化开发,减少出现问题的概率,代码更加灵活,更加优雅

三、开发流程总结

使用 Redis 开发流程如下

  1. 怎么建立连接
  2. 怎么去用:high/low level api,高阶/低阶 API
  3. 数据怎么正确存取:序列化

关联文章:

Redis入门–万字长文详解epoll

Redis——详解五种数据结构

Redis——Redis的进阶使用(管道/发布订阅/事务/布隆过滤器)

Redis——Redis用作缓存(内存回收/穿透/击穿/雪崩)

Redis——Redis用作数据库(持久化/RDB/AOF)

Redis——Redis集群理论

Redis——集群高可用(脑裂/主从复值/哨兵Sentinel)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以使用`spring.session.servlet.filter-dispatcher-types`属性来排除以`/api/`开头的请求。具体来说,您可以配置该属性,使其不拦截`/api/**`路径下的请求。 例如,以下配置将排除以`/api/`开头的请求: ``` spring.session.servlet.filter-dispatcher-types=REQUEST,ASYNC spring.session.servlet.filter.enabled=false spring.session.store-type=redis spring.session.redis.flush-mode=on_save spring.session.redis.namespace=spring:session spring.session.redis.cleanup-cron=0 * * * * * spring.session.redis.save-mode=on_set_attribute spring.session.redis.redis-url=redis://localhost:6379 spring.session.redis.redis-password=password spring.session.redis.redis-sentinel-master-id=mymaster spring.session.redis.redis-sentinel-nodes=sentinel://localhost:26379,sentinel://localhost:26380,sentinel://localhost:26381 spring.session.redis.redis-sentinel-password=password spring.session.redis.redis-cluster-nodes=localhost:6379,localhost:6380,localhost:6381 spring.session.redis.redis-cluster-max-redirects=3 spring.session.redis.redis-properties.ssl=true spring.session.redis.redis-properties.ssl-truststore=classpath:redis.truststore spring.session.redis.redis-properties.ssl-truststore-password=redispassword spring.session.redis.redis-properties.ssl-keystore=classpath:redis.keystore spring.session.redis.redis-properties.ssl-keystore-password=redispassword spring.session.redis.redis-properties.useSsl=true spring.session.redis.redis-properties.sslProtocols=TLSv1.2,TLSv1.3 spring.session.redis.redis-properties.sslCipherSuites=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 spring.session.redis.redis-properties.sslProvider=JDK spring.session.redis.redis-properties.sslEnableEndpointIdentification=true spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.session.SessionAutoConfiguration ``` 在以上配置中,我们使用了`spring.session.servlet.filter-dispatcher-types`属性配置,使其不拦截`/api/**`路径下的请求。注意,我们也排除了Spring Boot自动配置的会话管理,因为我们已经使用了Spring Session Redis进行会话管理。 请注意,这只是一个示例配置,您需要根据您的具体需求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值