Home | 简体中文 | 繁体中文 | 杂文 | 打赏(Donations) | 云栖社区 | OSChina 博客 | Facebook | Linkedin | 知乎专栏 | Github | Search | About

第 8 章 Spring Data

目录

8.1. Spring Data Redis
8.1.1. 集成 Redis
8.1.1.1. pom.xml
8.1.1.2. springframework-servlet.xml
8.1.1.3. Controller
8.1.1.4. index.jsp
8.1.1.5. 测试
8.1.2. RedisTemplate
8.1.2.1. stringRedisTemplate
8.1.2.2. 删除 key
8.1.2.3. ZSET 数据类型
8.1.2.4. Hash
8.1.2.5. List
8.1.2.6. 过期时间未执行
8.1.2.7. 存储 Json 对象
8.1.2.7.1. 集成 RedisTemplate 定义新类 JsonRedisTemplate
8.1.2.7.2. 配置 Redis
8.1.2.7.3. 测试
8.1.3. Spring Data Redis - Repository Examples
8.1.3.1. @EnableRedisRepositories 启动 Redis 仓库
8.1.3.2. 定义 Domain 类
8.1.3.3. Repository 接口
8.1.3.4. 测试代码
8.2. Spring Data MongoDB
8.2.1. Example Spring Data MongoDB
8.2.1.1. pom.xml
8.2.1.2. springframework-servlet.xml
8.2.1.3. POJO
8.2.1.4. Controller
8.2.1.5. 查看测试结果
8.2.1.6. 条件查询
8.2.2. @Document
8.2.2.1. 指定表名
8.2.2.2. @Id
8.2.2.3. @Version
8.2.2.4. @Field 定义字段名
8.2.2.5. @Indexed
8.2.2.5.1. 普通索引
8.2.2.5.2. 唯一索引
8.2.2.5.3. 索引排序方式
8.2.2.5.4. 稀疏索引
8.2.2.5.5. 索引过期时间设置
8.2.2.6. @CompoundIndex 复合索引
8.2.2.6.1. 普通复合索引
8.2.2.6.2. 唯一复合索引
8.2.2.7. @TextIndexed
8.2.2.8. @GeoSpatialIndex 地理位置索引
8.2.2.9. @Transient 丢弃数据,不存到 mongodb
8.2.2.10. @DBRef 做外外键引用
8.2.2.10.1. Article 类
8.2.2.10.2. Hypermedia 类
8.2.2.10.3. MongoRepository
8.2.2.10.4. RestController
8.2.2.10.5. 运行结果
8.2.2.11. @DateTimeFormat
8.2.2.12. @JsonFormat 格式化 json 时间格式
8.2.2.13. @NumberFormat
8.2.2.14. 在 @Document 中使用 Enum 类型
8.2.2.15. 在 @Document 中定义数据结构 List/Map
8.2.2.16. GeoJson 数据类型
8.2.3. MongoRepository
8.2.3.1. 扫描仓库接口
8.2.3.2. findAll()
8.2.3.3. deleteAll()
8.2.3.4. save()
8.2.3.5. count()
8.2.3.6. exists() 判断是否存在
8.2.3.7. existsById()
8.2.3.8. findByXXXX
8.2.3.9. findAll with OrderBy
8.2.3.9.1. order by boolean 布尔型数据排序
8.2.3.10. findAll with Sort
8.2.3.11. FindAll with Pageable
8.2.3.11.1. PageRequest - springboot 1.x 旧版本
8.2.3.12. StartingWith 和 EndingWith
8.2.3.13. Between
8.2.3.14. Before / After
8.2.3.15. @Query
8.2.4. mongoTemplate
8.2.4.1. Save 保存
8.2.4.2. Insert
8.2.4.3. updateFirst 修改符合条件第一条记录
8.2.4.4. updateMulti 修改符合条件的所有
8.2.4.5. 查找并保存
8.2.4.6. upsert - 修改符合条件时如果不存在则添加
8.2.4.7. 删除
8.2.4.8. 查找一条数据
8.2.4.9. 查找所有数据
8.2.4.10. Query
8.2.4.10.1. 翻页
8.2.4.10.2. between
8.2.4.11. Criteria
8.2.4.11.1. is
8.2.4.11.2. Regex 正则表达式搜索
8.2.4.11.3. lt 和 gt
8.2.4.11.4. exists()
8.2.4.11.5. 包含
8.2.4.12. Update
8.2.4.12.1. set
8.2.4.12.2. 追加数据
8.2.4.12.3. 更新数据
8.2.4.12.4. 删除数据
8.2.4.12.5. inc
8.2.4.12.6. update.addToSet
8.2.4.13. BasicUpdate
8.2.4.14. Sort
8.2.4.15. Query + PageRequest
8.2.4.16. newAggregation
8.2.4.17. 创建索引
8.2.4.18. 子对象操作
8.2.4.18.1. List 类型
8.2.5. GeoJson 反序列化
8.2.6. FAQ
8.2.6.1. location object expected, location array not in correct format; nested exception is com.mongodb.MongoWriteException: location object expected, location array not in correct format
8.3. Spring Data MySQL
8.3.1. 选择数据库表引擎
8.3.2. @Entity
8.3.2.1. @Table
8.3.2.1.1. catalog
8.3.2.1.2. schema
8.3.2.1.3. uniqueConstraints
8.3.2.2. @Id
8.3.2.3. @Column
8.3.2.3.1. 字段长度
8.3.2.3.2. 浮点型
8.3.2.3.3. 创建于更新控制
8.3.2.3.4. TEXT 类型
8.3.2.4. @Lob 注解属性将被持久化为 Blog 或 Clob 类型
8.3.2.5. @NotNull 不能为空声明
8.3.2.6. @JsonIgnore 返回json是不含有该字段
8.3.2.7. @Temporal 日期定义
8.3.2.8. @DateTimeFormat 处理日期时间格式
8.3.2.9. 默认时间规则
8.3.2.9.1. CreatedDate
8.3.2.9.2. 与时间日期有关的 hibernate 注解
8.3.2.9.2.1. 设置默认时间
8.3.2.9.2.2. 创建时间
8.3.2.9.2.3. 更新时间
8.3.2.9.3. 数据库级别的默认创建日期时间定义
8.3.2.9.4. 数据库级别的默认创建日期与更新时间定义
8.3.2.9.5. 最后修改时间
8.3.2.10. 索引
8.3.2.10.1. 普通索引
8.3.2.10.2. 唯一索引
8.3.2.10.3. 复合索引
8.3.2.11. Enum 枚举数据类型
8.3.2.11.1. 实体中处理 enum 类型
8.3.2.11.2. 数据库枚举类型
8.3.2.12. SET 数据结构
8.3.2.13. 整形数据类型
8.3.2.14. JSON 数据类型
8.3.2.15. @JoinColumn
8.3.2.16. @OneToOne
8.3.2.17. OneToMany 一对多
8.3.2.18. ManyToMany 多对多
8.3.2.19. 外键级联删除
8.3.2.20. 其他
8.3.2.20.1. Cascade
8.3.2.20.2. @JsonIgnore
8.3.3. 创建复合主键
8.3.4. @EnableJpaAuditing 开启 JPA 审计功能
8.3.5. 实体集成
8.3.6. Repository
8.3.6.1. CrudRepository
8.3.6.2. JpaRepository
8.3.6.3. findByXXX
8.3.6.3.1. 传 Boolean 参数
8.3.6.3.2. Eunm 传递枚举参数
8.3.6.4. count 操作
8.3.6.5. OrderBy
8.3.6.6. GreaterThan
8.3.6.7. PageRequest 翻页操作
8.3.6.7.1. PageRequest.of
8.3.6.7.2. Pageable
8.3.6.8. Sort 排序操作操作
8.3.6.9. Query
8.3.6.9.1. 参数传递
8.3.6.9.2. 原生 SQL
8.3.6.9.3. @Query 与 Pageagble
8.3.6.9.4. 返回指定字段
8.3.6.9.5. 返回指定的模型
8.3.6.10. @Transactional
8.3.6.10.1. 删除更新需要 @Transactional 注解
8.3.6.10.2. 回滚操作
8.3.6.11. 锁 @Lock
8.4. EntityManager
8.5. JdbcTemplate
8.5.1. execute
8.5.2. queryForInt
8.5.3. queryForInt
8.5.4. queryForObject
8.5.4.1. 返回整形与字符型
8.5.4.2. 查询 Double 类型数据库
8.5.4.3. 返回日期
8.5.4.4. 返回结果集
8.5.4.5. 通过 "?" 向SQL传递参数
8.5.4.6. RowMapper 记录映射
8.5.5. queryForList
8.5.6. queryForMap
8.5.7. query
8.5.7.1. ResultSet
8.5.7.2. ResultSetExtractor
8.5.7.3. RowMapper
8.5.8. queryForRowSet
8.5.9. update
8.5.10.
8.5.11. 实例参考
8.5.11.1. 参数传递技巧
8.6. Elasticsearch
8.6.1. 内嵌 Elasticsearch
8.6.1.1. Maven
8.6.1.2. src/main/resources/application.properties
8.6.1.3. Domain Class
8.6.1.4. ElasticsearchRepository
8.6.1.5. SearchRestController
8.6.1.6. 测试
8.6.2. 集群模式
8.6.3. Document
8.6.4. Elasticsearch 删除操作
8.6.5. FAQ
8.6.5.1. java.lang.IllegalStateException: Received message from unsupported version: [2.0.0] minimal compatible version is: [5.0.0]
8.7. Spring Data FAQ
8.7.1. No identifier specified for entity
8.7.2. Oracle Date 类型显示日期和时间
8.7.3. java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer
8.7.4. Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

8.1. Spring Data Redis

8.1.1. 集成 Redis

8.1.1.1. pom.xml

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

8.1.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 template 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 template definition -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jedisConnFactory" />
</beans>				
			
				

8.1.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 template
	@Autowired
	private RedisTemplate<String, String> template;

	// inject the template 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);

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

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

8.1.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.1.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操作,所以我们会设置使用字符串,通过 template.setKeySerializer(new StringRedisSerializer()); 实现

8.1.2. RedisTemplate

8.1.2.1. stringRedisTemplate

		
stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);	//向redis里存入数据和设置缓存时间
stringRedisTemplate.boundValueOps("test").increment(-1);						//val做-1操作
stringRedisTemplate.opsForValue().get("test")									//根据key获取缓存中的val
stringRedisTemplate.boundValueOps("test").increment(1);							//val +1
stringRedisTemplate.getExpire("test")											//根据key获取过期时间
stringRedisTemplate.getExpire("test",TimeUnit.SECONDS)							//根据key获取过期时间并换算成指定单位
stringRedisTemplate.delete("test");												//根据key删除缓存
stringRedisTemplate.hasKey("546545");											//检查key是否存在,返回boolean值
stringRedisTemplate.opsForSet().add("test", "1","2","3");						//向指定key中存放set集合
stringRedisTemplate.expire("test",1000 , TimeUnit.MILLISECONDS);				//设置过期时间
stringRedisTemplate.opsForSet().isMember("test", "1")							//根据key查看集合中是否存在指定数据
stringRedisTemplate.opsForSet().members("test");								//根据key获取set集合		
		
			

8.1.2.2. 删除 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.1.2.3. ZSET 数据类型

		
//添加 一个 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"));

//添加有序的 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));		
		
			
		
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.1.2.4. Hash

		
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.1.2.5. List

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

8.1.2.6. 过期时间未执行

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.1.2.7. 存储 Json 对象

8.1.2.7.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.1.2.7.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.1.2.7.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.1.3. Spring Data Redis - Repository Examples

8.1.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.1.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.1.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.1.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;
	}

}