Spring Boot 學習筆記 11 : Redis
在 SpringBoot 開發專案的過程中,使用到了 RedisTemplate 操作 Hash,讀值時遇到關於型別轉換的問題,於是編寫了一個小的測試 demo,現在記錄下來,以後有時間再深入研究。
-
專案結構如下:
進入專案根目錄,使用 tree /f 命令輸出目錄結構如下:
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─example
│ │ │ └─demo
│ │ │ │ SpringBootRedisApplication.java
│ │ │ │
│ │ │ ├─config
│ │ │ │ RedisConfiguration.java
│ │ │ │
│ │ │ ├─domain
│ │ │ │ Permission.java
│ │ │ │ Role.java
│ │ │ │ User.java
│ │ │ │
│ │ │ └─service
│ │ │ │ RedisService.java
│ │ │ │ UserService.java
│ │ │ │
│ │ │ └─util
│ │ │ RedisKey.java
│ │ │
│ │ └─resources
│ │ │ application-dev.yml
│ │ │ application-prod.yml
│ │ │ application.yml
│ │ │
│ │ ├─static
│ │ └─templates
│ └─test
│ └─java
│ └─com
│ └─example
│ └─demo
│ │ SpringBootRedisApplicationTests.java
│ │
│ └─service
│ RedisServiceTest.java -
pom 檔案如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId
-
RedisConfiguration 配置類如下:
package com.example.demo.config; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author smileorsilence */ @Configuration @EnableConfigurationProperties(RedisProperties.class) public class RedisConfiguration { @Autowired private RedisProperties redisProperties; @Bean public JedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); redisConnectionFactory.setHostName(redisProperties.getHost()); redisConnectionFactory.setPort(redisProperties.getPort()); redisConnectionFactory.setDatabase(redisProperties.getDatabase()); if (this.redisProperties.getPassword() != null) redisConnectionFactory.setPassword(redisProperties.getPassword()); if (this.redisProperties.getTimeout() > 0) redisConnectionFactory.setTimeout(redisProperties.getTimeout()); return redisConnectionFactory; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JsonRedisSerializer()); //for hash redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new JsonRedisSerializer()); return redisTemplate; } public static class JsonRedisSerializer implements RedisSerializer<Object> { private ObjectMapper objectMapper = new ObjectMapper(); public JsonRedisSerializer() { } @Override public byte[] serialize(Object o) throws SerializationException { if (o == null) { return new byte[0]; } else { try { return this.objectMapper.writeValueAsBytes(o); } catch (Exception e) { throw new SerializationException("Could not write JSON: " + e.getMessage()); } } } @Override public Object deserialize(byte[] bytes) throws SerializationException { if (bytes == null) { return null; } else { try { return this.objectMapper.readValue(bytes, Object.class); } catch (Exception e) { throw new SerializationException("Could not read JSON: " + e.getMessage()); } } } } }
-
RedisService 工具類如下:
package com.example.demo.service; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; /** * @author smileorsilence */ @Slf4j @Service public class RedisService { /***** ***** ***** ***** ***** ***** Operation for Key ***** ***** ***** ***** ***** *****/ @Autowired private RedisTemplate<String, Object> redisTemplate; public boolean hasKey(String key) { return redisTemplate.hasKey(key); } public void deleteKey(String key) { log.debug("Delete key in redis, key:{}", key); redisTemplate.delete(key); } public void expireKey(String key, Long times, TimeUnit unit) { log.debug("Expire key in redis, key:{}", key); redisTemplate.expire(key, times, unit); } /***** ***** ***** ***** ***** ***** Operation for Value ***** ***** ***** ***** ***** *****/ public void saveValue(String key, String value) { log.debug("Save string into redis, key:{}, value:{}", key, value); redisTemplate.opsForValue().set(key, value); } public void saveObject(String key, Object object) { log.debug("Save object into redis, key:{}, value:{}", key, object); redisTemplate.opsForValue().set(key, object); } public Object readObject(String key) { log.debug("Read object from redis, key:{}", key); return redisTemplate.opsForValue().get(key); } /***** ***** ***** ***** ***** ***** Operation for List ***** ***** ***** ***** ***** *****/ public void saveList(String key, List<?> list) { log.debug("Save a list into redis, key:{}", key); redisTemplate.delete(key); for (Object l : list) { redisTemplate.opsForList().rightPush(key, l); } } public List<?> readList(String key) { log.debug("Read a list from redis, key:{}", key); return redisTemplate.opsForList().range(key, 0, -1); } /** * 放入佇列的最後一個位置 */ public void pushEnd(String key, Object value) { redisTemplate.opsForList().rightPush(key, value); } /** * 取佇列的最後一個元素 */ public Object popEnd(String key) { return redisTemplate.opsForList().rightPop(key); } /** * 放入佇列的第一個位置 */ public void pushFirst(String key, Object value) { redisTemplate.opsForList().leftPush(key, value); } /** * 取佇列的第一個元素 */ public Object popFirst(String key) { return redisTemplate.opsForList().leftPop(key); } /***** ***** ***** ***** ***** ***** Operation for Map ***** ***** ***** ***** ***** *****/ public void saveMap(String key, Map<?, ?> map) { log.debug("Save a map into redis, key:{}", key); redisTemplate.delete(key); redisTemplate.opsForHash().putAll(key, map); } public void saveMapValue(String key, String hashKey, Object hashValue) { log.debug("Save map value into redis, key:{}, hashKey:{}", key, hashKey); redisTemplate.opsForHash().put(key, hashKey, hashValue); } public void deleteMapValue(String key, String hashKey) { log.debug("Delete map value from redis, key:{}, hashKey:{}", key, hashKey); redisTemplate.opsForHash().delete(key, hashKey); } public Map<?, ?> readMap(String key) { log.debug("Read a map from redis, key:{}", key); return redisTemplate.opsForHash().entries(key); } public Object readMapValue(String key, String hashKey) { log.debug("Read map value from redis, key:{}, hashKey:{}", key, hashKey); return redisTemplate.opsForHash().get(key, hashKey); } public Set<?> readMapKeys(String key) { log.debug("Read map keys from redis, key:{}", key); return redisTemplate.opsForHash().keys(key); } public List<?> readMapValues(String key) { log.debug("Read map values from redis, key:{}", key); return redisTemplate.opsForHash().values(key); } public boolean hasHashKey(String key, String hashKey) { return redisTemplate.opsForHash().hasKey(key, hashKey); } }
-
POJO 類如下:
package com.example.demo.domain; import lombok.Data; import java.io.Serializable; import java.util.HashSet; import java.util.Set; /** * @author smileorsilence */ @Data public class User implements Serializable { private Long id; private String username; private String password; private Set<Role> roles = new HashSet<>(); }
-
RedisServiceTest 測試類如下:
package com.example.demo.service; import com.example.demo.config.RedisConfiguration; import com.example.demo.domain.User; import com.example.demo.service.util.RedisKey; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author smileorsilence */ @Slf4j @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {RedisConfiguration.class, RedisService.class}) public class RedisServiceTest { @Autowired private RedisService redisService; @Test pu