在本文中,我们将介绍如何通过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() { return new JedisConnectionFactory(); } @Bean public RedisTemplate<String, Object> redisTemplate() { final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(jedisConnectionFactory()); template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class)); return template; }
|
JedisConnectionFactory生成Bean,所以我们可以创建一个RedisTemplate查询数据。
消息发布者
遵循SOLID的原则,我们创建一个MessagePublisher接口:
public interface MessagePublisher { void publish(final String message); }
|
我们实现MessagePublisher接口以使用高级RedisTemplate来发布消息,因为RedisTemplate允许任意对象作为消息传入:
@Service public class MessagePublisherImpl implements MessagePublisher { @Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private ChannelTopic topic; public MessagePublisherImpl() { } public MessagePublisherImpl(final RedisTemplate<String, Object> redisTemplate, final ChannelTopic topic) { this.redisTemplate = redisTemplate; this.topic = topic; } public void publish(final String message) { redisTemplate.convertAndSend(topic.getTopic(), message); } }
|
我们还在RedisConfig中将其定义为bean :
@Bean MessagePublisher redisPublisher() { return new MessagePublisherImpl(redisTemplate(), topic()); }
|
消息监听器
为了订阅消息,我们需要实现MessageListener接口:每次新消息到达时,都会调用回调,并通过名为onMessage的方法执行用户代码。此接口允许访问消息,通过它接收的通道以及订阅用于匹配通道的任何模式。因此,我们创建一个服务类来实现MessageSubscriber:
@Service public class MessageSubscriber implements MessageListener { public static List<String> messageList = new ArrayList<String>(); public void onMessage(final Message message, final byte[] pattern) { messageList.add(message.toString()); System.out.println("Message received: " + new String(message.getBody())); } }
|
我们向RedisConfig添加一个bean定义:
@Bean MessageListenerAdapter messageListener() { return new MessageListenerAdapter(new MessageSubscriber()); }
|
RedisRepository
现在我们已经将应用程序配置为与Redis服务器交互,我们将准备应用程序以获取示例数据。
对于此示例,我们使用两个字段定义Movie模型:
private String id; private String name; //standard getters and setters
|
存储库接口:
与其他Spring Data项目不同,Spring Data Redis确实提供了在其他Spring Data接口之上构建的任何功能。对于那些有其他Spring Data项目经验的人来说是多余的。
通常,不需要使用Spring Data项目编写存储库接口的实现。我们只是简单地与界面进行交互。Spring Data JPA提供了许多存储库接口,可以扩展这些接口以获取CRUD操作,派生查询和分页等功能。
所以,遗憾的是,我们需要编写自己的接口,然后定义方法:
public interface RedisRepository { Map<Object, Object> findAllMovies(); void add(Movie movie); void delete(String id); Movie findMovie(String id); }
|
我们的实现类使用 redisTemplate 在我们的配置类中定义RedisConfig。
我们使用Spring Data Redis提供的HashOperations模板:
@Repository public class RedisRepositoryImpl implements RedisRepository { private static final String KEY = "Movie"; private RedisTemplate<String, Object> redisTemplate; private HashOperations hashOperations; @Autowired public RedisRepositoryImpl(RedisTemplate<String, Object> redisTemplate){ this.redisTemplate = redisTemplate; } @PostConstruct private void init(){ hashOperations = redisTemplate.opsForHash(); } public void add(final Movie movie) { hashOperations.put(KEY, movie.getId(), movie.getName()); } public void delete(final String id) { hashOperations.delete(KEY, id); } public Movie findMovie(final String id){ return (Movie) hashOperations.get(KEY, id); } public Map<Object, Object> findAllMovies(){ return hashOperations.entries(KEY); } }
|
我们来看一下 init() 方法。在此方法中,我们使用名为opsForHash()的函数,该函数 返回对绑定到给定键的哈希值执行的操作。然后,我们使用在init()中定义的 hashOps进行所有CRUD操作。
Web界面
我们将讨论将Redis CRUD操作功能添加到Web界面。在我们的网页中添加电影。Key是Movie ID,Value是实际对象。但是,我们稍后会解决此问题,因此只有电影名称显示为值。
因此,我们将一个表单添加到HTML文档并分配适当的名称和ID:
<form id="addForm"> <div class="form-group"> <label for="keyInput">Movie ID (key)</label> <input name="keyInput" id="keyInput" class="form-control"/> </div> <div class="form-group"> <label for="valueInput">Movie Name (field of Movie object value)</label> <input name="valueInput" id="valueInput" class="form-control"/> </div> <button class="btn btn-default" id="addButton">Add</button> </form>
|
现在我们使用JavaScript来保存表单提交中的值:
$(document).ready(function() { var keyInput = $('#keyInput'), valueInput = $('#valueInput'); refreshTable(); $('#addForm').on('submit', function(event) { var 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 = "/add", method = RequestMethod.POST) public ResponseEntity<String> add( @RequestParam String key, @RequestParam String value) { Movie movie = new Movie(key, value); redisRepository.add(movie); return new ResponseEntity<>(HttpStatus.OK); }
|
查看内容:
一旦电影 对象添加,我们刷新表中显示更新的表。在7.1节的JavaScript代码块中,我们调用了一个名为refreshTable()的JavaScript函数 。此函数执行GET请求以检索存储库中的当前数据:
function refreshTable() { $.get('/values', function(data) { var attr, mainTable = $('#mainTable tbody'); mainTable.empty(); for (attr in data) { if (data.hasOwnProperty(attr)) { mainTable.append(row(attr, data[attr])); } } }); }
|
GET请求由名为findAll()的方法处理,该方法检索存储在存储库中的所有Movie对象,然后将数据类型从Map