Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

8.2. Spring Data with Redis

8.2.1. 整合 Redis XML 方式

8.2.1.1. pom.xml

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

8.2.1.2. springframework-servlet.xml

		
	<!-- Redis Connection Factory -->
	<bean id="jedisConnFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
		p:host-name="192.168.2.1" p:port="6379" p:use-pool="true" />

	<!-- redis redisTemplate definition -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jedisConnFactory" />
		
			

例 8.1. Spring Data Redis Example

			
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

	<mvc:resources location="/images/" mapping="/images/**" />
	<mvc:resources location="/css/" mapping="/css/**" />

	<context:component-scan base-package="cn.netkiller.controller" />

	<mvc:annotation-driven />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView" />
		<property name="prefix" value="/WEB-INF/jsp/" />
		<property name="suffix" value=".jsp" />
		<!-- <property name="viewNames" value="*.jsp" /> -->
	</bean>

	<bean id="configuracion"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:resources/development.properties" />
	</bean>

	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="cn.netkiller.mapper" />
	</bean>

	<bean id="userService" class="cn.netkiller.service.UserService">
	</bean>

	<!-- Redis Connection Factory -->
	<bean id="jedisConnFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
		p:host-name="192.168.2.1" p:port="6379" p:use-pool="true" />

	<!-- redis redisTemplate definition -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jedisConnFactory" />
</beans>				
			
				

8.2.1.3. Controller

		
package cn.netkiller.controller;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import cn.netkiller.model.User;

@Controller
public class CacheController {

	// inject the actual redisTemplate
	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	// inject the redisTemplate as ListOperations
	@Resource(name = "redisTemplate")
	private ListOperations<String, String> listOps;

	@RequestMapping("/cache")
	public ModelAndView cache() {

		String message = "";

		User user = new User();
		user.setId("1");
		user.setName("Neo");
		user.setAge(30);

		String key = "user";
		listOps.leftPush(key, user.toString());
		message = listOps.leftPop(key);

		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(new StringRedisSerializer());
		redisTemplate.opsForValue().set("key", user.toString());

		return new ModelAndView("index/index", "variable", message);
	}
}
		
			

8.2.1.4. index.jsp

		
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<br>
	<div style="text-align:center">
		<h2>
			${variable}
		</h2>
	</div>
</body>
</html>			
		
			

8.2.1.5. 測試

請求URL http://your.domain.com/your.html

		
[root@master ~]# redis-cli 
redis 127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04user"
2) "key"

redis 127.0.0.1:6379> get key
"\xac\xed\x00\x05t\x00\x1dUser [id=1, name=Neo, age=30]"
		
			
[提示]提示

Spring Redis 預設使用 Byte數據類型存儲Key,在redis-cli中會看到 "\xac\xed\x00\x05t\x00\x04" 首碼不方便get操作,所以我們會設置使用字元串,通過 redisTemplate.setKeySerializer(new StringRedisSerializer()); 實現

8.2.2. RedisTemplate

8.2.2.1. stringRedisTemplate 基本用法

			
stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);	//向redis裡存入數據和設置緩存時間
stringRedisTemplate.opsForValue().get("test")									//根據key獲取緩存中的val
stringRedisTemplate.getExpire("test")											//根據key獲取過期時間
stringRedisTemplate.getExpire("test",TimeUnit.SECONDS)							//根據key獲取過期時間並換算成指定單位
stringRedisTemplate.delete("test");												//根據key刪除緩存
stringRedisTemplate.hasKey("546545");											//檢查key是否存在,返回boolean值
stringRedisTemplate.expire("test",1000 , TimeUnit.MILLISECONDS);				//設置過期時間	
			
			

8.2.2.2. 設置緩存時間

			
例子:設置 name 緩存 10 秒

redisTemplate.opsForValue().set("name","neo",10, TimeUnit.SECONDS);
redisTemplate.opsForValue().get("name")

結果:由於設置的是10秒失效,十秒之內查詢有結果,十秒之後返回為null			
			
			

8.2.2.3. 字元串截取

			
設置:redisTemplate.opsForValue().set("hello","Helloworld");
代碼:System.out.println(redisTemplate.opsForValue().get("hello",0,5));
結果:Hellow
代碼:System.out.println(redisTemplate.opsForValue().get("hello",0,-1));
結果:Helloworld
代碼:System.out.println(redisTemplate.opsForValue().get("hello",-3,-1));
結果:rld			
			
			

8.2.2.4. 追加字元串

			
redisTemplate.opsForValue().append("hello","Hello");
System.out.println(redisTemplate.opsForValue().get("hello"));

redisTemplate.opsForValue().append("hello","world");
System.out.println(redisTemplate.opsForValue().get("hello")); // 結果:Helloworld        			
			
			

8.2.2.5. 設置鍵的字元串值並返回其舊值

			
	redisTemplate.opsForValue().set("name","neo");
    System.out.println(redisTemplate.opsForValue().getAndSet("name","Jerry"));
	// 結果 neo			
			
			

8.2.2.6. increment

			
stringRedisTemplate.opsForValue().set("test", "100");							//向redis裡存入數據			
stringRedisTemplate.boundValueOps("test").increment(-50);						//val做-60操作
stringRedisTemplate.boundValueOps("test").increment(100);						//val +100
stringRedisTemplate.opsForValue().get("test")									//根據key獲取緩存中的val		
			
			

8.2.2.7. 刪除 key

		
	private void cleanNewToday() {
		long begin = System.currentTimeMillis();
        
		redisTemplate.delete("news:today");
    
        long end = System.currentTimeMillis();
		logger.info("Schedule clean redis {} 耗時 {} 秒", "cleanNewFlash()", (end-begin) / 1000 );
	}
		
			

8.2.2.8. 返回字元串長度

			
redisTemplate.opsForValue().set("key","hello world");
System.out.println(redisTemplate.opsForValue().size("key"));			
			
			

8.2.2.9. 如果key不存便緩存。

			
System.out.println(redisTemplate.opsForValue().setIfAbsent("name","neo"));	// name 之前已經存在 false
System.out.println(redisTemplate.opsForValue().setIfAbsent("age","11"));		// age 之前不存在	true
			
			

8.2.2.10. 緩存多個值 /獲取多個值 multiSet / multiGet

			
Map<String,String> maps = new HashMap<String, String>();
	maps.put("multi1","multi1");
	maps.put("multi2","multi2");
	maps.put("multi3","multi3");

redisTemplate.opsForValue().multiSet(maps);

List<String> keys = new ArrayList<String>();
	keys.add("multi1");
	keys.add("multi2");
	keys.add("multi3");

System.out.println(redisTemplate.opsForValue().multiGet(keys));			
			
			

輸出結果

			
[multi1, multi2, multi3]			
			
			

為多個鍵分別設置它們的值,如果存在則返回false,不存在返回true

			
Map<String,String> maps = new HashMap<String, String>();
        maps.put("multi11","multi11");
        maps.put("multi22","multi22");
        maps.put("multi33","multi33");
Map<String,String> maps2 = new HashMap<String, String>();
        maps2.put("multi1","multi1");
        maps2.put("multi2","multi2");
        maps2.put("multi3","multi3");

System.out.println(redisTemplate.opsForValue().multiSetIfAbsent(maps)); 	// 返回 true
System.out.println(redisTemplate.opsForValue().multiSetIfAbsent(maps2));	// 返回 false
			
			

8.2.2.11. List

8.2.2.11.1. rightPush
			
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush("books", "Linux");
list.rightPush("books", "Java");
System.out.println(list.range("books", 0, 1));

System.out.println(redisTemplate.opsForList().size("list"));
			
				
8.2.2.11.2. rightPushAll
				
		String[] stringarrays = new String[]{"1","2","3"};
        redisTemplate.opsForList().rightPushAll("listarrayright",stringarrays);
        System.out.println(redisTemplate.opsForList().range("listarrayright",0,-1));				
				
				
				
		List<Object> strings = new ArrayList<Object>();
        strings.add("1");
        strings.add("2");
        strings.add("3");
        redisTemplate.opsForList().rightPushAll("listcollectionright", strings);
        System.out.println(redisTemplate.opsForList().range("listcollectionright",0,-1));				
				
				
8.2.2.11.3. rightPushIfPresent
				
		System.out.println("========== KEY 不存在===========");
		System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","aa"));
        System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","bb"));
        System.out.println("========== KEY 已經存在===========");
        System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","aa"));
        System.out.println(redisTemplate.opsForList().rightPushIfPresent("rightPushIfPresent","bb"));				
				
				
8.2.2.11.4. leftPush
			
redisTemplate.opsForList().leftPush("list","java");
redisTemplate.opsForList().leftPush("list","python");
redisTemplate.opsForList().leftPush("list","c++");			
			
				
8.2.2.11.5. leftPushAll

批量把一個數組插入到列表中

				
	String[] stringarrays = new String[]{"1","2","3"};
    redisTemplate.opsForList().leftPushAll("listarray",stringarrays);	
				
				

批量把一個集合插入到列表中

			
使用:List<Object> strings = new ArrayList<Object>();
        strings.add("1");
        strings.add("2");
        strings.add("3");
        redisTemplate.opsForList().leftPushAll("listcollection", strings);
        System.out.println(redisTemplate.opsForList().range("listcollection",0,-1));
結果:[3, 2, 1]			
			
				
8.2.2.11.6. range
			
    System.out.println(redisTemplate.opsForList().range("listarray",0,-1));
	// 結果:[3, 2, 1]				
			
				

8.2.2.12. SET 數據類型

Redis的Set是無序集合並且集合成員是唯一的,這就意味着集合中不能出現重複的數據。

			
stringRedisTemplate.opsForSet().add("test", "1","2","3");						//向指定key中存放set集合
stringRedisTemplate.opsForSet().isMember("test", "1")							//根據key查看集合中是否存在指定數據
stringRedisTemplate.opsForSet().members("test");								//根據key獲取set集合				
			
			
		
//添加 一個 set 集合
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add("Member", "neo");
set.add("Member", "36");
set.add("Member", "178cm");
//輸出 set 集合
System.out.println(set.members("Member"));	
		
			
		
package cn.netkiller.api.restful;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import common.pojo.ResponseRestful;

@RestController
@RequestMapping("/news")
public class NewsRestController {

	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	@RequestMapping(value = "/flash/{count}")
	public ResponseRestful flash(@PathVariable("count") long count) {
		if(count == 0L) {
			count=10L;
		}
		Set<String> news = this.redisTemplate.opsForZSet().reverseRange("news:flash", 0, count);
		if (news == null) {
			return new ResponseRestful(false, 10, "沒有查詢到結果", news);
		}
		return new ResponseRestful(true, 0, "返回數據: " + news.size() + " 條", news);
	}
	
	public void addRecentUser(long userId, String name) {  
	    String key = RedisKeyGenerator.genRecentBrowsingPositionsKey(String.valueOf(userId));  
	    // 獲取已緩存的最近瀏覽的職位  
	    ZSetOperations<String, String> zSetOperations = redisTempalte.opsForZSet();  
        //zset內部是按分數來排序的,這裡用當前時間做分數  
	    zSetOperations.add(key, name, System.currentTimeMillis());  
	    zSetOperations.removeRange(key, 0, -6);  
	}  
	
}
		
			
8.2.2.12.1. 返回集合中的所有成員
				
System.out.println(redisTemplate.opsForSet().members("setTest"));				
				
				
8.2.2.12.2. 取出一個成員
				
System.out.println(redisTemplate.opsForSet().pop("setTest"));				
				
				
8.2.2.12.3. 隨機獲取無序集合中的一個元素
				
System.out.println("Random member: " + redisTemplate.opsForSet().randomMember("setTest"));				
				
				
8.2.2.12.4. 隨機獲取 n 個成員(存在重複數據)
				
System.out.println("Random member: " + redisTemplate.opsForSet().randomMembers("setTest",5));
// 結果 Random member: [ccc, ddd, ddd, ddd, aaa]				
				
				
8.2.2.12.5. 隨機獲取 n 個不重複成員
				
System.out.println("Random members: " + redisTemplate.opsForSet().distinctRandomMembers("setTest",5));
//結果 Random members: [aaa, bbb, ddd, ccc]				
				
				
8.2.2.12.6. 在兩個 SET 間移動數據
				
	redisTemplate.opsForSet().move("key1","aaa","key2");
	System.out.println(redisTemplate.opsForSet().members("key1"));
    System.out.println(redisTemplate.opsForSet().members("key2"));				
				
				
8.2.2.12.7. 成員刪除
				
String[] arrays = new String[]{"Java","PHP"};
System.out.println(redisTemplate.opsForSet().remove("setTest",arrays));				
				
				
8.2.2.12.8. 返回集合數量
				
System.out.println(redisTemplate.opsForSet().size("setTest"));				
				
				
8.2.2.12.9. 判斷元素是否在集合成員中
				
ystem.out.println(redisTemplate.opsForSet().isMember("setTest","Linux"));				
				
				
8.2.2.12.10. 對比兩個集合求交集
				
	System.out.println(redisTemplate.opsForSet().members("key"));
    System.out.println(redisTemplate.opsForSet().members("otherKey"));
    System.out.println(redisTemplate.opsForSet().intersect("key","otherKey"));				
				
				
				
        List<String> library2 = new ArrayList<String>();
        library2.add("Linux");
        library2.add("FreeBSD");
        System.out.println(redisTemplate.opsForSet().intersect("library1",library2));				
				
				
8.2.2.12.11. 對比兩個集合求交集,然後存儲到新的 key 中
				
System.out.println(redisTemplate.opsForSet().intersectAndStore("key","otherKey","destKey"));				
				
				
				
		List<String> otherKey = new ArrayList<String>();
        otherKey.add("《Netkiller Java 手札》");
        otherKey.add("《Netkiller Spring Cloud 手札》");
        System.out.println(redisTemplate.opsForSet().intersectAndStore("key",otherKey,"destKey"));				
				
				
8.2.2.12.12. 合併兩個集合,並去處重複數據
				
	System.out.println(redisTemplate.opsForSet().union("setTest1","setTest2"));
	
	List<String> otherKey = new ArrayList<String>();
    otherKey.add("《Netkiller Java 手札》");
    otherKey.add("《Netkiller Spring Cloud 手札》");
    System.out.println(redisTemplate.opsForSet().union("setTest",otherKey));		
				
				
8.2.2.12.13. 合併兩個集合去重複後保存到新的 key 中
				
	System.out.println(redisTemplate.opsForSet().unionAndStore("key","otherKey","destKey"));
	System.out.println(redisTemplate.opsForSet().unionAndStore("key",otherKey,"destKey"));					
				
				
8.2.2.12.14. 計算兩個合集的差集
				
	System.out.println(redisTemplate.opsForSet().difference("key","otherKey"));		
	
	List<String> otherKey = new ArrayList<String>();
    otherKey.add("setTest2");
    otherKey.add("setTest3");
    System.out.println(redisTemplate.opsForSet().difference("key",otherKey));		
				
				
8.2.2.12.15. 計算兩個合集的差集,然後保存到新的 key 中
				
	System.out.println(redisTemplate.opsForSet().differenceAndStore("key","otherKey","destKey"));
				
				
8.2.2.12.16. 遍歷 SET 集合
				
	Cursor<Object> curosr = redisTemplate.opsForSet().scan("setTest", ScanOptions.NONE);
    while(curosr.hasNext()){
        System.out.println(curosr.next());
    }				
				
				

8.2.2.13. 有序的 set 集合

			
//添加有序的 set 集合
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add("zMember", "neo", 0);
zset.add("zMember", "36", 1);
zset.add("zMember", "178cm", 2);
//輸出有序 set 集合
System.out.println(zset.rangeByScore("zMember", 0, 2));				
			
			

8.2.2.14. Hash

8.2.2.14.1. put
				
	redisTemplate.opsForHash().put("redisHash","name","neo");
    redisTemplate.opsForHash().put("redisHash","age",30);
    redisTemplate.opsForHash().put("redisHash","nickname","netkiller");				
				
				
8.2.2.14.2. putAll
				
HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();
Map<String,Object> map = new HashMap<String,Object>();
map.put("name", "neo");
map.put("age", "36");
hash.putAll("member", map);

System.out.println(hash.entries("member"));		
				
				
8.2.2.14.3. 從鍵中的哈希獲取給定hashKey的值
				
	System.out.println(redisTemplate.opsForHash().get("redisHash","age"));				
				
				
8.2.2.14.4. delete

刪除指定的哈希 hashKeys

				
	System.out.println(redisTemplate.opsForHash().delete("redisHash","name"));
				
				
8.2.2.14.5. 確定哈希hashKey是否存在

確定哈希hashKey是否存在

				
System.out.println(redisTemplate.opsForHash().hasKey("redisHash","age"));				
				
				
8.2.2.14.6. 從哈希中獲取指定的多個 hashKey 的值
				
	List<Object> keys = new ArrayList<Object>();
    keys.add("name");
    keys.add("age");
    System.out.println(redisTemplate.opsForHash().multiGet("redisHash",keys))				
				
				
8.2.2.14.7. 只有hashKey不存在時才能添加值
				
	System.out.println(redisTemplate.opsForHash().putIfAbsent("redisHash","age",30));				
				
				
8.2.2.14.8. 獲取整個Hash
				
System.out.println(redisTemplate.opsForHash().entries("redisHash"));					
				
				
8.2.2.14.9. 獲取所有key
				

System.out.println(redisTemplate.opsForHash().keys("redisHash1"));				
				
				
8.2.2.14.10. 通過 hashKey 獲取所有值
				
System.out.println(redisTemplate.opsForHash().values("redisHash"));				
				
				
8.2.2.14.11. 值加法操作
				
System.out.println(redisTemplate.opsForHash().increment("redisHash","age",1)				
				
				
8.2.2.14.12. 遍歷 Hash 表
				
	Cursor<Map.Entry<Object, Object>> curosr = redisTemplate.opsForHash().scan("redisHash", ScanOptions.ScanOptions.NONE);
	while(curosr.hasNext()){
	    Map.Entry<Object, Object> entry = curosr.next();
	    System.out.println(entry.getKey()+":"+entry.getValue());
	}				
				
				

8.2.2.15. 過期時間未執行

Spring Redis 中設置過期時間方法如下

		
設置 key
redisTemplate.opsForValue().setIfAbsent("key", "value");
設置過期時間
redisTemplate.expire("key", 30000, TimeUnit.MILLISECONDS);
釋放 key
redisTemplate.delete("key");		
		
			

這樣存在一個問題,當程序運行一半被強行終止,可能導致setIfAbsent運行完成,但是expire未被執行,這樣 key 便永遠不會釋放。解決方案如下,使用RedisCallback執行原生 Redis 命令。

		
String result = redisTemplate.execute(new RedisCallback<String>() {
	@Override
	public String doInRedis(RedisConnection connection) throws DataAccessException {
		JedisCommands commands = (JedisCommands) connection.getNativeConnection();
		return commands.set(key, value, "NX", "PX", expire);
	}
});		
		
			

8.2.2.16. setBit / getBit 二進制位操作

			
setBit Boolean setBit(K key, long offset, boolean value);

offset 二進制位置(從左向右數)
value 位 ture 表示 0,false 表示 1			
			
			
			
    // 'a' 的ASCII碼是 97 轉換為二進制是:01100001
    // 'b' 的ASCII碼是 98 轉換為二進制是:01100010
    // 'c' 的ASCII碼是 99 轉換為二進制是:01100011
    			
	redisTemplate.opsForValue().set("bitTest","a");    
    
    redisTemplate.opsForValue().setBit("bitTest",7, false); 	// 01100011
    redisTemplate.opsForValue().setBit("bitTest",8, true);	// 01100010
    System.out.println(redisTemplate.opsForValue().get("bitTest"));
    redisTemplate.opsForValue().setBit("bitTest",8, false);	// 01100011
    System.out.println(redisTemplate.opsForValue().get("bitTest"));			
			
			

getBit Boolean getBit(K key, long offset); 獲取鍵對應值的ascii碼的在offset處位值

			
System.out.println(redisTemplate.opsForValue().getBit("bitTest",7));			
			
			

8.2.2.17. 存儲 Json 對象

8.2.2.17.1. 整合 RedisTemplate 定義新類 JsonRedisTemplate
			
package cn.netkiller.wallet.redis;

import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonRedisTemplate extends RedisTemplate<String, Object> {

	public JsonRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper, Class<?> valueType) {
		RedisSerializer<String> stringSerializer = new StringRedisSerializer();
		super.setKeySerializer(stringSerializer);
		super.setHashKeySerializer(stringSerializer);
		super.setHashValueSerializer(stringSerializer);
		Jackson2JsonRedisSerializer<?> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(valueType);
		jsonRedisSerializer.setObjectMapper(objectMapper);
		super.setValueSerializer(jsonRedisSerializer);
		super.setConnectionFactory(connectionFactory);
		super.afterPropertiesSet();
	}
}
			
			
				
8.2.2.17.2. 配置 Redis
			
package cn.netkiller.wallet.config;

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.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.netkiller.wallet.redis.JsonRedisTemplate;
import cn.netkiller.wallet.redis.RedisMessageSubscriber;

@Configuration
public class RedisConfig {

	public RedisConfig() {
	}

	@Bean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
		StringRedisTemplate redisTemplate = new StringRedisTemplate();
		redisTemplate.setConnectionFactory(connectionFactory);
		return redisTemplate;
	}

	@Bean
	public MessageListenerAdapter messageListener() {
		return new MessageListenerAdapter(new RedisMessageSubscriber());
	}

	@Bean
	public ChannelTopic topic() {
		return new ChannelTopic("demo");
	}

	@Bean
	public RedisMessageListenerContainer redisContainer(RedisConnectionFactory connectionFactory, MessageListenerAdapter messageListener) {
		RedisMessageListenerContainer container = new RedisMessageListenerContainer();

		container.setConnectionFactory(connectionFactory);
		container.addMessageListener(messageListener(), topic());
		container.addMessageListener(messageListener(), new ChannelTopic("test"));
		return container;
	}

	@Bean
	public ObjectMapper objectMapper() {
		return new ObjectMapper();
	}

	@Bean
	public JsonRedisTemplate jsonRedisTemplate(RedisConnectionFactory connectionFactory, ObjectMapper objectMapper) {
		return new JsonRedisTemplate(connectionFactory, objectMapper, Object.class);
	}

}
			
			
				
8.2.2.17.3. 測試
			
package cn.netkiller.wallet.restful;

import java.io.IOException;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import cn.netkiller.wallet.pojo.RestfulResponse;
import cn.netkiller.wallet.redis.JsonRedisTemplate;
import cn.netkiller.wallet.redis.RedisMessagePublisher;

@RestController
public class TestRestController {
	private static final Logger logger = LoggerFactory.getLogger(TestRestController.class);

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@Autowired
	private JsonRedisTemplate jsonRedisTemplate;

	public TestRestController() {

	}

	@GetMapping("/version")
	public String version() throws IOException {
		Web3ClientVersion web3ClientVersion = web3j.web3ClientVersion().send();
		String clientVersion = web3ClientVersion.getWeb3ClientVersion();
		logger.info(clientVersion);
		return clientVersion;
	}

	@GetMapping("/pub/demo")
	public String pub() {

		RedisMessagePublisher publisher = new RedisMessagePublisher(stringRedisTemplate, new ChannelTopic("demo"));
		String message = "Message " + UUID.randomUUID();
		publisher.publish(message);
		return message;
	}

	@GetMapping("/pub/test")
	public String pub(@RequestParam String message) {

		RedisMessagePublisher publisher = new RedisMessagePublisher(stringRedisTemplate, new ChannelTopic("test"));
		publisher.publish(message);
		return message;
	}

	@GetMapping("/pub/json")
	public RestfulResponse pubJson() {
		RestfulResponse restfulResponse = new RestfulResponse(true, 0, null, null);
		jsonRedisTemplate.opsForValue().set("test", restfulResponse);
		jsonRedisTemplate.convertAndSend("test", restfulResponse);
		return restfulResponse;
	}
}
			
				

8.2.3. Spring Data Redis - Repository Examples

8.2.3.1. @EnableRedisRepositories 啟動 Redis 倉庫

			
package api.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;

@Configuration
@EnableRedisRepositories
public class CachingConfigurer {

}			
			
			

8.2.3.2. 定義 Domain 類

			
package api.domain;

import java.util.List;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Reference;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

@RedisHash("persons")
public class Person {

	public enum Gender {
		FEMALE, MALE
	}

	@Id
	private String id;

	@Indexed
	private String firstname;
	@Indexed
	private String lastname;

	private Gender gender;
	private Address address;

	@Reference
	private List<Person> children;

	public Person() {
		// TODO Auto-generated constructor stub
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getFirstname() {
		return firstname;
	}

	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}

	public String getLastname() {
		return lastname;
	}

	public void setLastname(String lastname) {
		this.lastname = lastname;
	}

	public Gender getGender() {
		return gender;
	}

	public void setGender(Gender gender) {
		this.gender = gender;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	public List<Person> getChildren() {
		return children;
	}

	public void setChildren(List<Person> children) {
		this.children = children;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", firstname=" + firstname + ", lastname=" + lastname + ", gender=" + gender + ", address=" + address + ", children=" + children + "]";
	}

}
			
			
			

			
package api.domain;

import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.index.GeoIndexed;
import org.springframework.data.redis.core.index.Indexed;

public class Address {

	private @Indexed String city;
	private String country;
	private @GeoIndexed Point location;

	public Address(String city, String country, Point location) {
		this.city = city;
		this.country = country;
		this.location = location;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public Point getLocation() {
		return location;
	}

	public void setLocation(Point location) {
		this.location = location;
	}

}			
			
			

8.2.3.3. Repository 介面

			
package api.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.geo.Circle;
import org.springframework.data.repository.CrudRepository;

import api.domain.Person;

public interface PersonRepository extends CrudRepository<Person, String> {
	List<Person> findByLastname(String lastname);

	Page<Person> findPersonByLastname(String lastname, Pageable page);

	List<Person> findByFirstnameAndLastname(String firstname, String lastname);

	List<Person> findByFirstnameOrLastname(String firstname, String lastname);

	List<Person> findByAddress_City(String city);

	List<Person> findByAddress_LocationWithin(Circle circle);
}
			
			
			

8.2.3.4. 測試代碼

			
package api.restful;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import api.domain.Person;
import api.domain.Address;

import api.repository.PersonRepository;

@RestController
@RequestMapping("/test")
public class TestRestController {
	private static final Logger logger = LoggerFactory.getLogger(TestRestController.class);

	@Autowired
	private PersonRepository personRepository;

	public TestRestController() {

	}

	@GetMapping("/redis")
	public Person redis() {

		Person children = new Person();
		children.setFirstname("Lisa");
		children.setLastname("Chen");
		children.setGender(Person.Gender.FEMALE);

		Person person = new Person();
		person.setFirstname("Neo");
		person.setLastname("Chen");
		person.setGender(Person.Gender.MALE);

		// List<Person> childrens = new ArrayList<Person>();

		person.setChildren(Arrays.asList(children));

		Point point = new Point(Double.valueOf("28.352734"), Double.valueOf("32.807382"));
		Address address = new Address("Shenzhen", "China", point);
		person.setAddress(address);
		personRepository.save(person);
		return person;
	}

}