SpringBoot integrates Redis, basic use


Hi I'm Shendi


SpringBoot integrates Redis, basic use


Redis basics

After learning Redis before, you can use SpringBoot to integrate Redis, which is very simple to use


Introduction

Jedis used to operate Redis with Java before, in SpringBoot, after version 2.x, it was replaced with Lettuce

Jedis is not thread-safe, if you want to be safe, you need to use jedis pool connection pool, like BIO

Lettuce is implemented based on Netty and is thread-safe, more like NIO


Spring Data

It is a module of data operation in Spring, including the integration of various databases

insert image description here


For Redis, use Spring Data Redis, which provides RedisTemplateto operate Redis

In addition to general commands, the corresponding functions of Redis types are as follows

function describe
opsForValue Operate the String type
opsForHash Operation Hash type
opsForList Operate the List type
opsForSet Operation Set type
opsForZSet Operation ZSet type


Introduce dependencies

Using Spring Data Redis

Maven

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

It should be noted that SpringBoot version 2.5 or below also needs to introduce a connection pool

It is measured that the 2.5.1 version will report an error without introducing the following dependencies, and the 2.6.1 version is no problem

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

configuration

It should be noted that the lettuce used by spring data redis after version 2.x used jedis before, so use it after configuring connection pool 2.xspring.redis.lettuce

application.properties

# 服务器地址
spring.redis.host=localhost
# 端口
spring.redis.port=6379
# 使用哪个数据库,默认有16个数据库,从0开始,0-15
spring.redis.database=0
# 密码
spring.redis.password="admin"

# 连接池配置部分
# 最大连接数,负数代表没有限制
spring.redis.jedis.pool.max-active=30
# 最大阻塞时间,负数代表没有限制,单位毫秒,加上ms更加明确
spring.redis.jedis.pool.max-wait=3000ms
# 最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 最小空闲连接
spring.redis.jedis.pool.min-idle=1
# 连接超时时间,单位毫秒
spring.redis.timeout=6000


use

First you need to get RedisTemplatethe object, you can directly use @Autowirtedthe injection

For example simply set a value, use Junit test

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
public class TestRedis {
    
    

	@Autowired RedisTemplate<String, String> rt;
	
	@Test
	public void test() {
    
    
		rt.opsForValue().set("name", "Shendi");
	}
	
}

Enter redis-cli to see if there is a name value

insert image description here


The method of use is similar to the previous jedis , but there will be problems when setting Chinese in this way, for example

rt.opsForValue().set("name2", "砷碲");

insert image description here


Using redis-cli, the solution is to set the command line encoding to UTF-8, and bring the --raw parameter when starting

# 设置utf-8编码
chcp 65001
redis-cli -p 6379 --raw

insert image description here




custom serialization method

For special requirements, such as directly storing an object (Bean) in Redis, you need to customize the serialization method.


JSON serialization

write a configuration class

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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class RedisConfig {
    
    
	
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory rcf) {
    
    
        RedisTemplate<String, Object> rt = new RedisTemplate<>();
        rt.setConnectionFactory(rcf);
        
        Jackson2JsonRedisSerializer<Object> jsonrs = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jsonrs.setObjectMapper(om);
        
        // 键 key,hashKey 用String序列化
        rt.setKeySerializer(RedisSerializer.string());
        rt.setHashKeySerializer(RedisSerializer.string());
        
        // 值 value,hashValue 用JSON序列化
        rt.setValueSerializer(jsonrs);
        rt.setHashValueSerializer(jsonrs);
        
        return rt;
    }
    
}

Here I stepped on a pit, the new test project did not introduce web dependencies, so an error was reported when the test case was started

Error creating bean with name ‘redisTemplate’ defined in class path

...wasting a lot of time, searching Baidu to add some common, jedis dependencies... Finally, I added the web dependencies by mistake and I was able to run

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


The test code is as follows. It should be noted that the bean must implement the Serializable interface, and the inner class needs to be statically or practically constructed without parameters to create objects

import java.io.Serializable;

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
public class TestRedis {
    
    

	@Autowired RedisTemplate<String, Object> rt;
	
	static class Info implements Serializable {
    
    
		String name;
		String name2;
		String web;
		
		public Info() {
    
    }
		
		public Info(String name, String name2, String web) {
    
    
			this.name = name;
			this.name2 = name2;
			this.web = web;
		}
		
	}
	
	@Test
	public void test() {
    
    
		rt.opsForValue().set("name2", "砷碲");
		rt.opsForValue().set("info", new Info("Shendi", "砷碲", "sdpro.top"));
		
		Object name2 = rt.opsForValue().get("name2");
		Info info = (Info) rt.opsForValue().get("info");
		
		System.out.println(name2);
		System.out.println(info);
	}
	
}

The code execution output is as follows

insert image description here
insert image description here



simple example

The following shows an example of SpringBoot+Redis user login, to deepen the impression, for reference only

The page will not be done, just make the interface and highlight the use of Redis


Redis is a key-value database. Generally, the prefix + content is used as the key, and a class can be used to save and manage all the keys.

Application

@SpringBootApplication
public class Application {
    
    
	
	/** SpringBoot环境 */
	private static ConfigurableApplicationContext context;
	
	public static void main(String[] args) {
    
    
		context = SpringApplication.run(Application.class, args);
	}

	/** @return SpringBoot运行环境 */
	public static ConfigurableApplicationContext getContext() {
    
     return context; }
	
}

The context is provided here for getBean. It should be noted that the context cannot be obtained by using Junit



Because the content is distinguished by the key prefix, the operation of Redis can be encapsulated, such as the temporary information stored by the user login

/**
 * 关于Redis登录信息的操作.<br>
 * <br>
 * @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
 */
@Component
public class RedisLogin {
    
    

	/** key 前缀 */
	public static final String PREFIX = "login:";
	
	public void set(String key, String value) {
    
    
		// 存入的数据一小时后过期
		RedisUtil.RT.opsForValue().set(PREFIX + key, value, 1, TimeUnit.HOURS);
	}
	
	public String get(String key) {
    
    
		return RedisUtil.RT.opsForValue().get(PREFIX + key);
	}
	
}

Marked @Component, you can use it on other classes @Autowiredto get

The RedisUtil.RT above is that I used RedisTemplate as a static object. Of course, I can also define the object directly in the class and then inject it


RedisUtil

public class RedisUtil {
    
    

	/** Redis */
	public static final StringRedisTemplate RT;
	
	public static final RedisLogin LOGIN;
	
	static {
    
    
		RT = Application.getContext().getBean(StringRedisTemplate.class);
		
		LOGIN = Application.getContext().getBean(RedisLogin.class);
	}
	
}


UserControl

@RestController
public class UserControl {
    
    

	private String account = "admin";
	private String pwd = "admin";
	
	@GetMapping("/login")
	public String login(String account, String pwd) {
    
    
		if (this.account.equals(account) && this.pwd.equals(pwd)) {
    
    
			String token = String.valueOf(System.currentTimeMillis());
			
			// 存入Redis
			RedisUtil.LOGIN.set(account, token);
			
			return "登陆成功, token=" + token;
		}
	
		return "登陆失败";
	}
	
	@GetMapping("/info")
	public String info(String account, String token) {
    
    
		// 有效登录则获取信息
		String t = RedisUtil.LOGIN.get(account);
		if (t == null || !t.equals(token)) {
    
    
			return "未登录或登陆失效";
		}
		
		return "信息为xxx";
	}
	
}

There are two interfaces, one login and one info

login obtains token information through account password, and info obtains user information through account number and token

insert image description here

After successful login, you can see the data in redis

insert image description here

insert image description here

Using the wrong information will also fail to obtain

insert image description here


The data is stored on Redis, so that even if SpringBoot restarts, the login information will not be lost

Because the expiration time is set, use the ttl command to view the remaining time of the key (seconds)




END

Guess you like

Origin blog.csdn.net/qq_41806966/article/details/129534560