济宁君天建设公司网站,上海品划网络做网站,亚马逊跨境电商,中华室内设计网怎么样1. 准备工作 环境说明 java 8#xff1b;redis7.2.2#xff0c;redis集成RedisSearch、redisJson 模块#xff1b;spring boot 2.5在执行 redis 命令#xff0c; 或者监控 程序执行的redis 指令时#xff0c;可以采用 redisinsight查看#xff0c;下载地址。 背景说明 需…1. 准备工作 环境说明 java 8redis7.2.2redis集成RedisSearch、redisJson 模块spring boot 2.5在执行 redis 命令 或者监控 程序执行的redis 指令时可以采用 redisinsight查看下载地址。 背景说明 需要对在线的用户进行搜索之前是存储成 string, 每次搜索需要先全部遍历然后加载到内存然后进行筛选。十分消耗性能并且速度极慢。使用 redisJson redisSearch 可以极大的优化查询性能项目后期需要支持全文搜索。 实现思路采用 RedisTemplate 执行 lua 脚本。
2. 实现
2.1 配置
引入依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency配置 redisTermplate, 配置 lua 脚本便于 redisTemplate 执行[^2]
Configuration
EnableCaching
public class RedisConfig extends CachingConfigurerSupport
{BeanSuppressWarnings(value { unchecked, rawtypes })public RedisTemplateString, Object redisTemplate1(RedisConnectionFactory connectionFactory){RedisTemplateString, 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 脚本配置Beanpublic DefaultRedisScriptString jsonSetScript(){DefaultRedisScriptString redisScript new DefaultRedisScript();redisScript.setScriptText(return redis.call(JSON.SET, KEYS[1], $, ARGV[1]););redisScript.setResultType(String.class);return redisScript;}Beanpublic DefaultRedisScriptObject jsonGetScript(){DefaultRedisScriptObject redisScript new DefaultRedisScript();redisScript.setScriptText(return redis.call(JSON.GET, KEYS[1]););redisScript.setResultType(Object.class);return redisScript;}Beanpublic DefaultRedisScriptList jsonSearchScript(){DefaultRedisScriptList 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;}
}RedisSearchSerializer 序列化配置 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 RedisSearchSerializerT implements RedisSerializerT {public static final Charset DEFAULT_CHARSET Charset.forName(UTF-8);private ClassT clazz;public RedisSearchSerializer(ClassT clazz) {super();this.clazz clazz;}Overridepublic 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);}Overridepublic 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的 操作
redisService Service
public class RedisService {Autowiredprivate RedisScriptString jsonSetScript;Autowiredprivate RedisScriptObject jsonGetScript;Autowiredprivate RedisScriptList jsonSearchScript;Autowiredprivate RedisTemplateString, 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 PageString 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);ListString 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 text3. 测试 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 {Autowiredprivate RedisService redisService;Testpublic 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());}Testpublic 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);}Testpublic 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);// 搜索测试PageString 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));}
}