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

16.使用NoSQL 技术

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

16.1 Redis

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

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



在pom.xml中增加依赖包:

       

        

            org.springframework.boot

            spring-boot-starter-data-redis

        

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缓存

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

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 findAll() {

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

return cityRepository.findAll();

}


}


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

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 getAllCitys() {

// 这将返回带有citys的JSON或XML

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表示它是get或post请求的参数

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表示它是get或post请求的参数

cityRepository.save(city);

return "修改城市成功";

}


/**

 * 删除城市

 *

 * @param id

 * @return

 */

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

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

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

// @requestParam表示它是get或post请求的参数

City city = new City();

city.setId(id);

cityRepository.delete(city);

return "删除城市成功";

}


}

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

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;

}


}


常见问题

错误信息:

"status": 500,

"error": "Internal Server Error",

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

解决办法:

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

org.springframework.boot

spring-boot-devtools

true

16.1.5 Redis消息

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

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();

}

}

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

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);

}


}

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

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

你可能感兴趣的:(Spring Boot 2.X 实战教程(16)使用NoSQL 技术)