在本文中,我们将介绍如何通过Spring Data Redis将Redis与Spring Boot一起使用的基础知识库。
我们将构建一个应用程序,演示如何通过Web界面执行CRUD操作Redis, Github 上提供了该项目的完整源代码。
Redis是 一个开源的内存中键值数据存储 ,用作数据库,缓存和消息代理。在实现方面,Key Value存储代表NoSQL空间中最大和最老的成员之一。Redis支持数据结构,如字符串,散列,列表,集和带范围查询的有序集。
在 春季数据Redis的框架, 可以很容易地编写,通过提供一个抽象的数据存储使用Redis的键值存储的Spring应用程序。
设置Redis服务器
可从 http://redis.io/download 免费获得。
如果您使用的是Mac,可以使用自制软件安装它:
brew install redis
然后启动服务器:
$ redis-server
Maven依赖
让我们在pom.xml中为我们正在构建的示例应用程序声明必要的依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Redis配置
我们需要将我们的应用程序与Redis服务器连接起来。为了建立这种连接,我们使用的是Redis客户端实现 Jedis 。让我们从配置bean定义开始:
@Bean
JedisConnectionFactory jedisConnectionFactory() {
<b>return</b> <b>new</b> JedisConnectionFactory();
}
@Bean
<b>public</b> RedisTemplate<String, Object> redisTemplate() {
<b>final</b> RedisTemplate<String, Object> template = <b>new</b> RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(<b>new</b> GenericToStringSerializer<Object>(Object.<b>class</b>));
<b>return</b> template;
}
JedisConnectionFactory生成Bean,所以我们可以创建一个RedisTemplate查询数据。
消息发布者
遵循 SOLID 的 原则 ,我们创建一个MessagePublisher接口:
<b>public</b> <b>interface</b> MessagePublisher {
<b>void</b> publish(<b>final</b> String message);
}
我们实现MessagePublisher接口以使用高级RedisTemplate来发布消息,因为RedisTemplate允许任意对象作为消息传入:
@Service
<b>public</b> <b>class</b> MessagePublisherImpl implements MessagePublisher {
@Autowired
<b>private</b> RedisTemplate<String, Object> redisTemplate;
@Autowired
<b>private</b> ChannelTopic topic;
<b>public</b> MessagePublisherImpl() {
}
<b>public</b> MessagePublisherImpl(<b>final</b> RedisTemplate<String, Object> redisTemplate, <b>final</b> ChannelTopic topic) {
<b>this</b>.redisTemplate = redisTemplate;
<b>this</b>.topic = topic;
}
<b>public</b> <b>void</b> publish(<b>final</b> String message) {
redisTemplate.convertAndSend(topic.getTopic(), message);
}
}
我们还在RedisConfig中将其定义为bean :
@Bean
MessagePublisher redisPublisher() {
<b>return</b> <b>new</b> MessagePublisherImpl(redisTemplate(), topic());
}
消息监听器
为了订阅消息,我们需要实现MessageListener接口:每次新消息到达时,都会调用回调,并通过名为onMessage的方法执行用户代码。此接口允许访问消息,通过它接收的通道以及订阅用于匹配通道的任何模式。因此,我们创建一个服务类来实现MessageSubscriber:
@Service
<b>public</b> <b>class</b> MessageSubscriber implements MessageListener {
<b>public</b> <b>static</b> List<String> messageList = <b>new</b> ArrayList<String>();
<b>public</b> <b>void</b> onMessage(<b>final</b> Message message, <b>final</b> byte[] pattern) {
messageList.add(message.toString());
System.out.println(<font>"Message received: "</font><font> + <b>new</b> String(message.getBody()));
}
}
</font>
我们向RedisConfig添加一个bean定义:
@Bean
MessageListenerAdapter messageListener() {
<b>return</b> <b>new</b> MessageListenerAdapter(<b>new</b> MessageSubscriber());
}
RedisRepository
现在我们已经将应用程序配置为与Redis服务器交互,我们将准备应用程序以获取示例数据。
对于此示例,我们使用两个字段定义Movie模型:
<b>private</b> String id; <b>private</b> String name; <font><i>//standard getters and setters</i></font><font> </font>
存储库接口:
与其他Spring Data项目不同,Spring Data Redis确实提供了在其他Spring Data接口之上构建的任何功能。对于那些有其他Spring Data项目经验的人来说是多余的。
通常,不需要使用Spring Data项目编写存储库接口的实现。我们只是简单地与界面进行交互。Spring Data JPA提供了许多存储库接口,可以扩展这些接口以获取CRUD操作,派生查询和分页等功能。
所以,遗憾的是,我们需要编写自己的接口,然后定义方法:
<b>public</b> <b>interface</b> RedisRepository {
Map<Object, Object> findAllMovies();
<b>void</b> add(Movie movie);
<b>void</b> delete(String id);
Movie findMovie(String id);
}
我们的实现类使用 redisTemplate 在我们的配置类中定义RedisConfig。
我们使用Spring Data Redis提供的HashOperations模板:
@Repository
<b>public</b> <b>class</b> RedisRepositoryImpl implements RedisRepository {
<b>private</b> <b>static</b> <b>final</b> String KEY = <font>"Movie"</font><font>;
<b>private</b> RedisTemplate<String, Object> redisTemplate;
<b>private</b> HashOperations hashOperations;
@Autowired
<b>public</b> RedisRepositoryImpl(RedisTemplate<String, Object> redisTemplate){
<b>this</b>.redisTemplate = redisTemplate;
}
@PostConstruct
<b>private</b> <b>void</b> init(){
hashOperations = redisTemplate.opsForHash();
}
<b>public</b> <b>void</b> add(<b>final</b> Movie movie) {
hashOperations.put(KEY, movie.getId(), movie.getName());
}
<b>public</b> <b>void</b> delete(<b>final</b> String id) {
hashOperations.delete(KEY, id);
}
<b>public</b> Movie findMovie(<b>final</b> String id){
<b>return</b> (Movie) hashOperations.get(KEY, id);
}
<b>public</b> Map<Object, Object> findAllMovies(){
<b>return</b> hashOperations.entries(KEY);
}
}
</font>
我们来看一下 init() 方法。在此方法中,我们使用名为opsForHash()的函数,该函数 返回对绑定到给定键的哈希值执行的操作。然后,我们使用在init()中定义的 hashOps进行所有CRUD操作。
Web界面
我们将讨论将Redis CRUD操作功能添加到Web界面。在我们的网页中添加电影。Key是Movie ID,Value是实际对象。但是,我们稍后会解决此问题,因此只有电影名称显示为值。
因此,我们将一个表单添加到HTML文档并分配适当的名称和ID:
<form id=<font>"addForm"</font><font>>
<div <b>class</b>=</font><font>"form-group"</font><font>>
<label <b>for</b>=</font><font>"keyInput"</font><font>>Movie ID (key)</label>
<input name=</font><font>"keyInput"</font><font> id=</font><font>"keyInput"</font><font> <b>class</b>=</font><font>"form-control"</font><font>/>
</div>
<div <b>class</b>=</font><font>"form-group"</font><font>>
<label <b>for</b>=</font><font>"valueInput"</font><font>>Movie Name (field of Movie object value)</label>
<input name=</font><font>"valueInput"</font><font> id=</font><font>"valueInput"</font><font> <b>class</b>=</font><font>"form-control"</font><font>/>
</div>
<button <b>class</b>=</font><font>"btn btn-default"</font><font> id=</font><font>"addButton"</font><font>>Add</button>
</form>
</font>
现在我们使用JavaScript来保存表单提交中的值:
$(document).ready(function() {
<b>var</b> keyInput = $('#keyInput'),
valueInput = $('#valueInput');
refreshTable();
$('#addForm').on('submit', function(event) {
<b>var</b> data = {
key: keyInput.val(),
value: valueInput.val()
};
$.post('/add', data, function() {
refreshTable();
keyInput.val('');
valueInput.val('');
keyInput.focus();
});
event.preventDefault();
});
keyInput.focus();
});
我们为POST请求分配@RequestMapping值,请求键和值,创建一个Movie对象,并将其保存到存储库:
@RequestMapping(value = <font>"/add"</font><font>, method = RequestMethod.POST)
<b>public</b> ResponseEntity<String> add(
@RequestParam String key,
@RequestParam String value) {
Movie movie = <b>new</b> Movie(key, value);
redisRepository.add(movie);
<b>return</b> <b>new</b> ResponseEntity<>(HttpStatus.OK);
}
</font>
查看内容:
一旦电影 对象添加,我们刷新表中显示更新的表。在7.1节的JavaScript代码块中,我们调用了一个名为refreshTable()的JavaScript函数 。此函数执行GET请求以检索存储库中的当前数据:
function refreshTable() {
$.get('/values', function(data) {
<b>var</b> attr,
mainTable = $('#mainTable tbody');
mainTable.empty();
<b>for</b> (attr in data) {
<b>if</b> (data.hasOwnProperty(attr)) {
mainTable.append(row(attr, data[attr]));
}
}
});
}
GET请求由名为findAll()的方法处理,该方法检索存储在存储库中的所有Movie对象,然后将数据类型从Map <Object,Object>转换为Map <String,String>:
@RequestMapping(<font>"/values"</font><font>)
<b>public</b> @ResponseBody Map<String, String> findAll() {
Map<Object, Object> aa = redisRepository.findAllMovies();
Map<String, String> map = <b>new</b> HashMap<String, String>();
<b>for</b>(Map.Entry<Object, Object> entry : aa.entrySet()){
String key = (String) entry.getKey();
map.put(key, aa.get(key).toString());
}
<b>return</b> map;
}
</font>
删除:
我们编写Javascript来执行POST请求/删除,刷新表,并将键盘焦点设置为键输入:
function deleteKey(key) {
$.post('/delete', {key: key}, function() {
refreshTable();
$('#keyInput').focus();
});
}
我们请求Key并根据此Key删除redisRepository中 的对象:
@RequestMapping(value = <font>"/delete"</font><font>, method = RequestMethod.POST)
<b>public</b> ResponseEntity<String> delete(@RequestParam String key) {
redisRepository.delete(key);
<b>return</b> <b>new</b> ResponseEntity<>(HttpStatus.OK);
}
</font>
结论
在本教程中,我们介绍了Spring Data Redis以及将其连接到Web应用程序以执行CRUD操作的一种方法。
示例应用程序的源代码在 Github上 。