Redis通用模块

由于 Redis 在很多模块中都可能会用到,因此需要将其抽取出来单独的作为一个模块 ruoyi-common-redis, 别的模块想使用 Redis,只需要引入自定义的 ruoyi-common-redis 模块即可。

创建通用模块的父模块

通用的模块可能不止 一个,因此需要创建 通用模块的父工程 ruoyi-common,其余通用模块继承它就可以。
新建模块 ruoyi-common ,其 pom.xml 内容为:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>ruoyi</artifactId>
  7. <groupId>com.ruoyi</groupId>
  8. <version>1.0.0</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <packaging>pom</packaging>
  12. <modules>
  13. <module>ruoyi-common-redis</module>
  14. </modules>
  15. <artifactId>ruoyi-common</artifactId>
  16. </project>

创建Redis通用模块

创建 ruoyi-common-redis 模块,其父模块为 ruoyi-common。其 pom.xml 文件内容:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>ruoyi-common</artifactId>
  7. <groupId>com.ruoyi</groupId>
  8. <version>1.0.0</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>ruoyi-common-redis</artifactId>
  12. <dependencies>
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-data-redis</artifactId>
  16. </dependency>
  17. </dependencies>
  18. </project>

版本号声明

在 父工程 ruoyi 中定义 ruoyi-common-redis 模块的版本号。

  1. <properties>
  2. <ruoyi.version>1.0.0</ruoyi.version>
  3. </properties>
  4. <dependency>
  5. <groupId>com.ruoyi</groupId>
  6. <artifactId>ruoyi-common-redis</artifactId>
  7. <version>${ruoyi.version}</version>
  8. </dependency>

Redis使用

在 ruoyi-system 模块中使用 Redis

引入依赖

  1. <dependency>
  2. <groupId>com.ruoyi</groupId>
  3. <artifactId>ruoyi-common-redis</artifactId>
  4. </dependency>

编写测试代码

  1. package com.ruoyi.system.controller;
  2. import com.ruoyi.system.api.domain.SysUser;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.data.redis.core.RedisTemplate;
  5. import org.springframework.data.redis.core.StringRedisTemplate;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. @RestController
  9. public class TestRedisController {
  10. @Autowired
  11. private RedisTemplate redisTemplate;
  12. @Autowired
  13. private StringRedisTemplate stringRedisTemplate;
  14. @GetMapping("/testStringRedisTemplate")
  15. public void testStringRedisTemplate() {
  16. stringRedisTemplate.opsForValue().set("name","马小六");
  17. }
  18. @GetMapping("/testRedisTemplate")
  19. public void testRedisTemplate() {
  20. SysUser user = new SysUser();
  21. user.setUserId(1L);
  22. user.setNickName("张无忌");
  23. user.setUserName("zwj");
  24. user.setEmail("23@qq.com");
  25. redisTemplate.opsForValue().set("user",user);
  26. }
  27. }

测试结果

请求:http://localhost:9201/testRedisTemplate
image.png

优化改进

从上图中的测试结果,我们可以看出当我们把一个 Object对象存放到 Redis 中是,它的 Key 和 value 都是这种十六进制的。我们希望 key 是字符串, value 是 JSON 格式的对象

Redis 配置

引入依赖

在 ruoyi-common-redis 模块中引入依赖

  1. <!-- Jackson -->
  2. <dependency>
  3. <groupId>com.fasterxml.jackson.core</groupId>
  4. <artifactId>jackson-databind</artifactId>
  5. </dependency>
  6. <!-- Alibaba Fastjson -->
  7. <dependency>
  8. <groupId>com.alibaba</groupId>
  9. <artifactId>fastjson</artifactId>
  10. </dependency>

版本号声明

  1. <properties>
  2. <fastjson.version>1.2.75</fastjson.version>
  3. </properties>
  4. <!-- JSON 解析器和生成器 -->
  5. <dependency>
  6. <groupId>com.alibaba</groupId>
  7. <artifactId>fastjson</artifactId>
  8. <version>${fastjson.version}</version>
  9. </dependency>

Redis值的序列号

  1. package com.ruoyi.common.redis.configure;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.parser.ParserConfig;
  4. import com.alibaba.fastjson.serializer.SerializerFeature;
  5. import com.fasterxml.jackson.databind.JavaType;
  6. import com.fasterxml.jackson.databind.ObjectMapper;
  7. import com.fasterxml.jackson.databind.type.TypeFactory;
  8. import org.springframework.data.redis.serializer.RedisSerializer;
  9. import org.springframework.data.redis.serializer.SerializationException;
  10. import org.springframework.util.Assert;
  11. import java.nio.charset.Charset;
  12. public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
  13. @SuppressWarnings("unused")
  14. private ObjectMapper objectMapper = new ObjectMapper();
  15. public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
  16. private Class<T> clazz;
  17. static {
  18. ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
  19. }
  20. public FastJson2JsonRedisSerializer(Class<T> clazz) {
  21. super();
  22. this.clazz = clazz;
  23. }
  24. @Override
  25. public byte[] serialize(T t) throws SerializationException {
  26. if (t == null) {
  27. return new byte[0];
  28. }
  29. return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
  30. }
  31. @Override
  32. public T deserialize(byte[] bytes) throws SerializationException {
  33. if (bytes == null || bytes.length <= 0) {
  34. return null;
  35. }
  36. String str = new String(bytes, DEFAULT_CHARSET);
  37. return JSON.parseObject(str, clazz);
  38. }
  39. public void setObjectMapper(ObjectMapper objectMapper) {
  40. Assert.notNull(objectMapper, "'objectMapper' must not be null");
  41. this.objectMapper = objectMapper;
  42. }
  43. protected JavaType getJavaType(Class<?> clazz) {
  44. return TypeFactory.defaultInstance().constructType(clazz);
  45. }
  46. }

Redis配置类

key使用 StringRedisSerializer 序列号, value 使用 FastJson2JsonRedisSerializer 序列号

  1. package com.ruoyi.common.redis.config;
  2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  3. import com.fasterxml.jackson.annotation.PropertyAccessor;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import com.ruoyi.common.redis.configure.FastJson2JsonRedisSerializer;
  6. import org.springframework.cache.annotation.CachingConfigurerSupport;
  7. import org.springframework.cache.annotation.EnableCaching;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10. import org.springframework.data.redis.connection.RedisConnectionFactory;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.data.redis.serializer.StringRedisSerializer;
  13. @Configuration
  14. @EnableCaching
  15. public class RedisConfig extends CachingConfigurerSupport {
  16. @Bean
  17. @SuppressWarnings(value = {"unchecked", "rawtypes", "deprecation"})
  18. public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
  19. RedisTemplate<Object, Object> template = new RedisTemplate<>();
  20. template.setConnectionFactory(connectionFactory);
  21. FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
  22. ObjectMapper mapper = new ObjectMapper();
  23. mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  24. mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  25. serializer.setObjectMapper(mapper);
  26. template.setValueSerializer(serializer);
  27. // 使用StringRedisSerializer来序列化和反序列化redis的key值
  28. template.setKeySerializer(new StringRedisSerializer());
  29. template.afterPropertiesSet();
  30. return template;
  31. }
  32. }

redisTemplate 二次封装

  1. package com.ruoyi.common.redis.service;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.data.redis.core.BoundSetOperations;
  4. import org.springframework.data.redis.core.HashOperations;
  5. import org.springframework.data.redis.core.RedisTemplate;
  6. import org.springframework.data.redis.core.ValueOperations;
  7. import org.springframework.stereotype.Component;
  8. import java.util.*;
  9. import java.util.concurrent.TimeUnit;
  10. @Component
  11. public class RedisService {
  12. @Autowired
  13. public RedisTemplate redisTemplate;
  14. /**
  15. * 缓存基本的对象,Integer、String、实体类等
  16. *
  17. * @param key 缓存的键值
  18. * @param value 缓存的值
  19. */
  20. public <T> void setCacheObject(final String key, final T value) {
  21. redisTemplate.opsForValue().set(key, value);
  22. }
  23. /**
  24. * 缓存基本的对象,Integer、String、实体类等
  25. *
  26. * @param key 缓存的键值
  27. * @param value 缓存的值
  28. * @param timeout 时间
  29. * @param timeUnit 时间颗粒度
  30. */
  31. public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) {
  32. redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
  33. }
  34. /**
  35. * 设置有效时间
  36. *
  37. * @param key Redis键
  38. * @param timeout 超时时间
  39. * @return true=设置成功;false=设置失败
  40. */
  41. public boolean expire(final String key, final long timeout) {
  42. return expire(key, timeout, TimeUnit.SECONDS);
  43. }
  44. /**
  45. * 设置有效时间
  46. *
  47. * @param key Redis键
  48. * @param timeout 超时时间
  49. * @param unit 时间单位
  50. * @return true=设置成功;false=设置失败
  51. */
  52. public boolean expire(final String key, final long timeout, final TimeUnit unit) {
  53. return redisTemplate.expire(key, timeout, unit);
  54. }
  55. /**
  56. * 获得缓存的基本对象。
  57. *
  58. * @param key 缓存键值
  59. * @return 缓存键值对应的数据
  60. */
  61. public <T> T getCacheObject(final String key) {
  62. ValueOperations<String, T> operation = redisTemplate.opsForValue();
  63. return operation.get(key);
  64. }
  65. /**
  66. * 删除单个对象
  67. *
  68. * @param key
  69. */
  70. public boolean deleteObject(final String key) {
  71. return redisTemplate.delete(key);
  72. }
  73. /**
  74. * 删除集合对象
  75. *
  76. * @param collection 多个对象
  77. * @return
  78. */
  79. public long deleteObject(final Collection collection) {
  80. return redisTemplate.delete(collection);
  81. }
  82. /**
  83. * 缓存List数据
  84. *
  85. * @param key 缓存的键值
  86. * @param dataList 待缓存的List数据
  87. * @return 缓存的对象
  88. */
  89. public <T> long setCacheList(final String key, final List<T> dataList) {
  90. Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
  91. return count == null ? 0 : count;
  92. }
  93. /**
  94. * 获得缓存的list对象
  95. *
  96. * @param key 缓存的键值
  97. * @return 缓存键值对应的数据
  98. */
  99. public <T> List<T> getCacheList(final String key) {
  100. return redisTemplate.opsForList().range(key, 0, -1);
  101. }
  102. /**
  103. * 缓存Set
  104. *
  105. * @param key 缓存键值
  106. * @param dataSet 缓存的数据
  107. * @return 缓存数据的对象
  108. */
  109. public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
  110. BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
  111. Iterator<T> it = dataSet.iterator();
  112. while (it.hasNext()) {
  113. setOperation.add(it.next());
  114. }
  115. return setOperation;
  116. }
  117. /**
  118. * 获得缓存的set
  119. *
  120. * @param key
  121. * @return
  122. */
  123. public <T> Set<T> getCacheSet(final String key) {
  124. return redisTemplate.opsForSet().members(key);
  125. }
  126. /**
  127. * 缓存Map
  128. *
  129. * @param key
  130. * @param dataMap
  131. */
  132. public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
  133. if (dataMap != null) {
  134. redisTemplate.opsForHash().putAll(key, dataMap);
  135. }
  136. }
  137. /**
  138. * 获得缓存的Map
  139. *
  140. * @param key
  141. * @return
  142. */
  143. public <T> Map<String, T> getCacheMap(final String key) {
  144. return redisTemplate.opsForHash().entries(key);
  145. }
  146. /**
  147. * 往Hash中存入数据
  148. *
  149. * @param key Redis键
  150. * @param hKey Hash键
  151. * @param value 值
  152. */
  153. public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
  154. redisTemplate.opsForHash().put(key, hKey, value);
  155. }
  156. /**
  157. * 获取Hash中的数据
  158. *
  159. * @param key Redis键
  160. * @param hKey Hash键
  161. * @return Hash中的对象
  162. */
  163. public <T> T getCacheMapValue(final String key, final String hKey) {
  164. HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
  165. return opsForHash.get(key, hKey);
  166. }
  167. /**
  168. * 获取多个Hash中的数据
  169. *
  170. * @param key Redis键
  171. * @param hKeys Hash键集合
  172. * @return Hash对象集合
  173. */
  174. public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
  175. return redisTemplate.opsForHash().multiGet(key, hKeys);
  176. }
  177. /**
  178. * 获得缓存的基本对象列表
  179. *
  180. * @param pattern 字符串前缀
  181. * @return 对象列表
  182. */
  183. public Collection<String> keys(final String pattern) {
  184. return redisTemplate.keys(pattern);
  185. }
  186. }

组件扫描

默认情况下,SpringBoot包扫描的路径为 main 方法所在类的包及其子包。在这里也就是扫描 com.ruoyi.system 包及其子包,而我们的 RedisService 组件是在 com.ruoyi.common.redis.service。为了能够扫描到,我们需求修改包扫描路径为:com.ruoyi

  1. @MapperScan("com.ruoyi.system.mapper")
  2. @EnableDiscoveryClient
  3. @SpringBootApplication(scanBasePackages = {"com.ruoyi"})
  4. public class RuoYiSystemApplication {

测试

测试类

  1. @Autowired
  2. private RedisService redisService;
  3. @GetMapping("/testRedisService")
  4. public void testRedisService() {
  5. SysUser user = new SysUser();
  6. user.setUserId(1L);
  7. user.setNickName("张无忌");
  8. user.setUserName("zwj");
  9. user.setEmail("23@qq.com");
  10. redisService.setCacheObject("user",user);
  11. }

测试结果

image.png