本文介绍: 主要介绍了如何在 Spring Boot 中使用 RedisTemplate 对 Redis 的 JSON 类型进行单个查询、模糊搜索、设置等操作。作者通过实例代码和详细解释,让读者深入了解了 Redis 的基本操作和使用技巧,并提供了一些解决 Redis 遇到的常见问题的方法和建议。
1. 准备工作
2. 实现
2.1 配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置 redisTermplate, 配置 lua 脚本,便于 redisTemplate 执行[^2]
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport
{
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public RedisTemplate<String, Object> redisTemplate1(RedisConnectionFactory connectionFactory)
{
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
RedisSearchSerializer serializer = new RedisSearchSerializer(Object.class);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
// lua 脚本配置
@Bean
public DefaultRedisScript<String> jsonSetScript()
{
DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText("return redis.call('JSON.SET', KEYS[1], '$', ARGV[1]);");
redisScript.setResultType(String.class);
return redisScript;
}
@Bean
public DefaultRedisScript<Object> jsonGetScript()
{
DefaultRedisScript<Object> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText("return redis.call('JSON.GET', KEYS[1]);");
redisScript.setResultType(Object.class);
return redisScript;
}
@Bean
public DefaultRedisScript<List> jsonSearchScript()
{
DefaultRedisScript<List> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(
"local offset = tonumber(ARGV[2])n" +
"local count = tonumber(ARGV[3])n" +
"return redis.call('FT.SEARCH', KEYS[1], ARGV[1], 'return', 0, 'limit', offset, count);");
redisScript.setResultType(List.class);
return redisScript;
}
}
import com.alibaba.fastjson2.JSON;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
/**
* Redis使用FastJson序列化
*
* @author ruoyi
*/
public class RedisSearchSerializer<T> implements RedisSerializer<T> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public RedisSearchSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
if (t instanceof String) {
return ((String)t).getBytes(DEFAULT_CHARSET);
}
return JSON.toJSONString(t).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
// 不是 json 也不是 序列化的字符串,那就只能是数字,如果不是数字直接返回
if (!str.startsWith("{") && !str.startsWith("[") && !str.startsWith(""") && !str.matches("^\d*$")) {
return clazz.cast(str);
}
return JSON.parseObject(str, clazz);
}
}
@Data
public class LoginUser {
private String ipaddr;
private String username;
public LoginUser(String ipaddr, String username) {
this.ipaddr = ipaddr;
this.username = username;
}
}
2.2 封装 对 json的 操作
@Service
public class RedisService {
@Autowired
private RedisScript<String> jsonSetScript;
@Autowired
private RedisScript<Object> jsonGetScript;
@Autowired
private RedisScript<List> jsonSearchScript;
@Autowired
private RedisTemplate<String, Object> redisTemplate1;
public LoginUser getLoginUser(String uuid) {
String key = RedisKeys.LOGIN_TOKEN_KEY + uuid;
JSONObject obj = (JSONObject) redisTemplate1.execute(this.jsonGetScript, Collections.singletonList(key));
if (obj == null) {
return null;
}
return obj.toJavaObject(LoginUser.class);
}
public void setLoginUser(String uuid, LoginUser loginUser, int expireTime, TimeUnit unit) {
String key = RedisKeys.LOGIN_TOKEN_KEY + uuid;
redisTemplate1.execute(this.jsonSetScript, Collections.singletonList(key), loginUser);
redisCache.expire(key, expireTime, unit);
}
public Page<String> searchLoginUser(String query, Pageable page) {
List list = redisTemplate1.execute(
this.jsonSearchScript,
Collections.singletonList("login_tokens_idx"),
query, page.getOffset(), page.getPageSize());
Long total = (Long) list.get(0);
List<String> ids = new ArrayList<>();
for (int i = 1; i < list.size(); i++) {
ids.add(((String) list.get(i)).replaceAll(RedisKeys.LOGIN_TOKEN_KEY, ""));
}
return new PageImpl<>(ids, page, total);
}
public interface RedisKeys {
String LOGIN_TOKEN_KEY = "login_tokens1:";
}
}
2.3 在 redis 中创建索引
redis 创建索引[^1], 其中 ipaddr 是 IP 字段,包含 “.” 等特殊字符,所以需要将 索引中的 ipaddr 设置成 tag 类型,才能搜索到[^3]
# 连接redis, 如果使用 redisinsight 则不需要这步
redis-cli -a "password"
# 创建索引
FT.CREATE login_tokens_idx
on JSON prefix 1 "login_tokens1:"
SCHEMA $.ipaddr tag $.username text
3. 测试
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = YourApplication.class)
@ActiveProfiles("prod-local")
public class RedisServiceTest {
@Autowired
private RedisService redisService;
@Test
public void testSetAndGetLoginUser() {
LoginUser user = new LoginUser("192.168.1.1", "testUser");
redisService.setLoginUser("123456", user, 60, TimeUnit.SECONDS);
LoginUser getUser = redisService.getLoginUser("123456");
Assert.assertEquals(user.getIpaddr(), getUser.getIpaddr());
Assert.assertEquals(user.getUsername(), getUser.getUsername());
}
@Test
public void testDeleteLoginUser() {
LoginUser user = new LoginUser("192.168.1.1", "testUser");
redisService.setLoginUser("123456", user, 60, TimeUnit.SECONDS);
redisService.deleteLoginUser("123456");
LoginUser getUser = redisService.getLoginUser("123456");
Assert.assertNull(getUser);
}
@Test
public void testSearchLoginUser() {
// 添加测试数据
LoginUser user1 = new LoginUser("192.168.1.1", "user1");
LoginUser user2 = new LoginUser("192.168.1.2", "user2");
redisService.setLoginUser("123456", user1, 60, TimeUnit.SECONDS);
redisService.setLoginUser("789012", user2, 60, TimeUnit.SECONDS);
// 搜索测试
Page<String> page = redisService.searchLoginUser("user*", PageRequest.of(0, 10));
Assert.assertEquals(page.getTotalElements(), 2);
Assert.assertEquals(page.getContent().size(), 2);
Assert.assertTrue(page.getContent().contains("123456"));
Assert.assertTrue(page.getContent().contains("789012"));
}
}
原文地址:https://blog.csdn.net/qq_22783587/article/details/134446850
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_33278.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。