Spring Boot 2.X 实战教程(16)使用NoSQL 技术

16.使用NoSQL 技术

Spring Data提供了其他项目,可帮助您访问各种NoSQL技术,包括: MongoDB Neo4J Elasticsearch Solr Redis Gemfire Cassandra CouchbaseLDAP

16.1 Redis

Redis是一个缓存,消息代理和功能丰富的键值存储。Spring BootLettuce Jedis客户端库提供了基本的自动配置, 并为Spring Data Redis提供了它们之外的抽象。

有一个spring-boot-starter-data-redis“Starter”用于以方便的方式收集依赖项。默认情况下,它使用 Lettuce。该启动器处理传统和反应应用程序。

 

 

pom.xml中增加依赖包:

<!-- Spring Data Redis -->        

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-data-redis</artifactId>

        </dependency>

16.1.1安装Redis

Window版下载地址:https://github.com/MSOpenTech/redis/releases

 

16.1.2安装Redis客户端

下载地址:https://github.com/caoxinyu/RedisClient

16.1.3连接到Redis

你可以注入自动配置的RedisConnectionFactory。默认情况下,实例尝试连接到Redis服务器localhost:6379。以下清单显示了这样一个bean的示例:

@Componentpublic class MyBean {

 

private StringRedisTemplate template;

 

@Autowired

public MyBean(StringRedisTemplate template) {

this.template = template;

}

 

// ...

 

}

或者使用配置文件形式:

# Redis服务器主机

spring.redis.host=localhost

# Redis服务器的登录密码

spring.redis.password=

# Redis服务器端口

spring.redis.port=6379

# 连接超时时间

spring.redis.timeout=3000

 

# 允许缓存空值

spring.cache.redis.cache-null-values=true

# 键前缀

spring.cache.redis.key-prefix=#

# 条目过期时间。默认情况下,条目永不过期。

spring.cache.redis.time-to-live=10000

# 写入Redis时是否使用密钥前缀

spring.cache.redis.use-key-prefix=true

# 缓存类型。默认情况下,根据环境自动检测。

spring.cache.type=redis

16.1.4 Redis缓存

l 增加服务类,代码如下所示:

package com.example.demo.city;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cache.annotation.Cacheable;

import org.springframework.stereotype.Service;

 

import com.example.demo.DemoApplication;

 

@Service

public class CityService {

 

private static final Logger LOGGER = LoggerFactory.getLogger(DemoApplication.class);

 

@Autowired // 这意味着要得到一个名为Cityrepository的存储库

private CityRepository cityRepository;

 

/**

 * 根据主键查询单个城市

 *

 * @param id

 * @return

 */

@Cacheable(value = "city")

public City findById(Long id) {

LOGGER.debug("从数据库根据主键查询单个城市...");

return cityRepository.findById(id).orElse(new City());

}

 

/**

 * 查询所有城市列表

 *

 * @return

 */

@Cacheable(value = "cities")

public Iterable<City> findAll() {

LOGGER.debug("从数据库查询所有城市列表...");

return cityRepository.findAll();

}

 

}

 

l 修改控制器类,代码如下所示:

package com.example.demo.city;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.DeleteMapping;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.PutMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

 

/**

 * 城市控制器

 *

 * @author 大强

 *

 */

@Controller // 这意味着这个类是一个控制器

@RequestMapping(path = "/city") // 这意味着URL/city开始(在应用程序路径之后)

public class CityController {

 

@Autowired // 这意味着要得到一个名为Cityrepository的存储库

private CityRepository cityRepository;

 

@Autowired

CityService cityService;

 

/**

 * 根据主键查询单个城市

 *

 * @param id

 * @return

 */

@RequestMapping(value = "/{id}", method = RequestMethod.GET)

public @ResponseBody City getCity(@PathVariable Long id) {

return cityService.findById(id);

}

 

/**

 * 查询所有城市列表

 *

 * @return

 */

@GetMapping(path = "/all")

public @ResponseBody Iterable<City> getAllCitys() {

// 这将返回带有citysJSONXML

return cityService.findAll();

}

 

/**

 * 新增城市

 *

 * @param name

 * @param state

 * @return

 */

@PostMapping(path = "/add") // 仅映射Post请求

public @ResponseBody String addCity(@RequestParam String name, @RequestParam String state) {

// @responseBody表示返回的是response,而不是视图名称

// @requestParam表示它是getpost请求的参数

City city = new City();

city.setName(name);

city.setState(state);

cityRepository.save(city);

return "新增城市成功";

}

 

/**

 * 修改城市

 *

 * @param city

 * @return

 */

@PutMapping(path = "/update") // 仅映射Put请求

public @ResponseBody String updateCity(@RequestBody City city) {

// @responseBody表示返回的是response,而不是视图名称

// @requestParam表示它是getpost请求的参数

cityRepository.save(city);

return "修改城市成功";

}

 

/**

 * 删除城市

 *

 * @param id

 * @return

 */

@DeleteMapping(path = "/{id}") // 仅映射Delete请求

public @ResponseBody String deleteCity(@PathVariable Long id) {

// @responseBody表示返回的是response,而不是视图名称

// @requestParam表示它是getpost请求的参数

City city = new City();

city.setId(id);

cityRepository.delete(city);

return "删除城市成功";

}

 

}

l 修改主类,代码如下所示:

package com.example.demo;

 

import org.springframework.beans.factory.annotation.Value;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cache.annotation.EnableCaching;

import org.springframework.web.bind.annotation.*;

 

import com.example.demo.message.Receiver;

 

import java.time.Duration;

import java.util.concurrent.CountDownLatch;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.Bean;

import org.springframework.data.redis.cache.RedisCacheConfiguration;

import org.springframework.data.redis.cache.RedisCacheManager;

import org.springframework.data.redis.cache.RedisCacheWriter;

import org.springframework.data.redis.connection.RedisConnectionFactory;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.data.redis.listener.PatternTopic;

import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

 

/**

 * Demo应用

 *

 * @author 大强

 *

 */

@SpringBootApplication

@RestController

@EnableCaching

public class DemoApplication {

 

private static final Logger LOGGER = LoggerFactory.getLogger(DemoApplication.class);

 

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

}

 

@Value("${name}")

private String name;

 

@RequestMapping("/")

String home() {

return "Hello " + name;

}

 

/**

 * 缓存配置

 *

 * @param connectionFactory

 * @return

 */

@Bean

public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {

RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()

.entryTtl(Duration.ofSeconds(30L)).disableCachingNullValues();

RedisCacheManager cacheManager = RedisCacheManager

.builder(RedisCacheWriter.lockingRedisCacheWriter(connectionFactory)).cacheDefaults(defaultCacheConfig)

.transactionAware().build();

return cacheManager;

}

 

}

 

l 常见问题

错误信息:

"status": 500,

"error": "Internal Server Error",

"message": "com.example.demo.city.City cannot be cast to com.example.demo.city.City",

解决办法:

注释掉pom.xml终端以下代码:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-devtools</artifactId>

<optional>true</optional>

</dependency>

16.1.5 Redis消息

l 增加接收器类,代码如下所示:

package com.example.demo.message;

 

import java.util.concurrent.CountDownLatch;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

 

/**

 * 接收器

 *

 * @author 大强

 *

 */

public class Receiver {

private static final Logger LOGGER = LoggerFactory.getLogger(Receiver.class);

 

private CountDownLatch latch;

 

@Autowired

public Receiver(CountDownLatch latch) {

this.latch = latch;

}

 

public void receiveMessage(String message) {

LOGGER.info("收到消息:(" + message + "");

latch.countDown();

}

}

l 增加消息控制器类,代码如下所示:

package com.example.demo.message;

 

import java.util.concurrent.CountDownLatch;

 

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.stereotype.Controller;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

/**

 * 消息控制器

 *

 * @author 大强

 *

 */

@Controller

@RequestMapping(path = "/message")

public class MessageController {

 

private static final Logger LOGGER = LoggerFactory.getLogger(MessageController.class);

 

@Autowired

StringRedisTemplate stringRedisTemplate;

 

@Autowired

CountDownLatch countDownLatch;

 

/**

 * 发送消息

 *

 * @param message

 */

@RequestMapping(value = "/sending/{message}", method = RequestMethod.GET)

public void sending(@PathVariable String message) {

 

LOGGER.info("发送消息...");

stringRedisTemplate.convertAndSend("chat", message);

 

try {

countDownLatch.await();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

// System.exit(0);

}

 

}

l 修改主类,代码如下所示:

package com.example.demo;

 

import org.springframework.beans.factory.annotation.Value;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cache.annotation.EnableCaching;

import org.springframework.web.bind.annotation.*;

 

import com.example.demo.message.Receiver;

 

import java.time.Duration;

import java.util.concurrent.CountDownLatch;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.Bean;

import org.springframework.data.redis.cache.RedisCacheConfiguration;

import org.springframework.data.redis.cache.RedisCacheManager;

import org.springframework.data.redis.cache.RedisCacheWriter;

import org.springframework.data.redis.connection.RedisConnectionFactory;

import org.springframework.data.redis.core.StringRedisTemplate;

import org.springframework.data.redis.listener.PatternTopic;

import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

 

/**

 * Demo应用

 *

 * @author 大强

 *

 */

@SpringBootApplication

@RestController

@EnableCaching

public class DemoApplication {

 

private static final Logger LOGGER = LoggerFactory.getLogger(DemoApplication.class);

 

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

}

 

// ...

 

/**

 * 消息配置

 *

 * @param connectionFactory

 * @param listenerAdapter

 * @return

 */

@Bean

RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,

MessageListenerAdapter listenerAdapter) {

RedisMessageListenerContainer container = new RedisMessageListenerContainer();

container.setConnectionFactory(connectionFactory);

container.addMessageListener(listenerAdapter, new PatternTopic("chat"));

return container;

}

 

/**

 * 侦听适配器

 *

 * @param receiver

 * @return

 */

@Bean

MessageListenerAdapter listenerAdapter(Receiver receiver) {

return new MessageListenerAdapter(receiver, "receiveMessage");

}

 

/**

 * 接收器

 *

 * @param latch

 * @return

 */

@Bean

Receiver receiver(CountDownLatch latch) {

return new Receiver(latch);

}

 

@Bean

CountDownLatch latch() {

return new CountDownLatch(1);

}

 

/**

 * String Redis 模板

 *

 * @param connectionFactory

 * @return

 */

@Bean

StringRedisTemplate template(RedisConnectionFactory connectionFactory) {

return new StringRedisTemplate(connectionFactory);

}

 

}

 

如有疑问,请观看视频:https://ke.qq.com/course/428845

 

posted @ 2019-07-30 16:35  大强的博客  阅读(219)  评论(0编辑  收藏  举报