【Spring Boot】Spring Boot Redis 缓存示例 | 自动缓存查询结果减少数据库交互

本页将介绍Spring Boot Redis缓存实例。RedisCacheManager是由Redis支持的CacheManager。如果Redis在我们的Spring Boot应用程序中可用并已配置,RedisCacheManager将被自动配置。Redis连接从LettuceJedis Java Redis客户端获得。Redis的依赖性由spring-boot-starter-data-redis 启动器解决。在Spring Boot 2.0中,Lettuce被默认解决,而不是Jedis。要使用Jedis,我们需要在构建文件中包含jedis依赖。

Spring @EnableCaching在我们的应用程序中启用Spring缓存管理能力。它被@SpringBootApplication注解所注解。@Cacheable表示调用方法的结果可以被缓存,一旦结果被缓存,下一次调用方法的执行将被跳过,只有缓存的结果被提供。@CachePut 添加或更新缓存,但不跳过方法的执行。@CacheEvict 清空缓存但不跳过方法的执行。@Caching被用来分组多个缓存注释。

演示工具版本

  1. Java 9
  2. Spring 5.0.8.RELEASE
  3. Spring Data 2.0.9.RELEASE
  4. Spring Boot 2.0.4.RELEASE
  5. Maven 3.5.2
  6. MySQL 5.5
  7. Eclipse Oxygen

Maven 依赖

Spring提供了spring-boot-starter-data-redis来解决Redis的依赖关系。

它为LettuceJedis客户端库提供基本的自动配置。

默认情况下,Spring Boot 2.0使用Lettuce。为了获得池化连接工厂,我们需要提供commons-pool2依赖。

找到Maven文件。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-boot-app</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-boot-app</name>
	<description>Spring Boot Application</description>
	<parent>
	    <groupId>org.springframework.boot</groupId>
  	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>2.0.4.RELEASE</version>
 	    <relativePath/>
	</parent>
	<properties>
	    <java.version>9</java.version>
	</properties>
	<dependencies>
          <dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-web</artifactId>
          </dependency>
          <dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-data-jpa</artifactId>
          </dependency>
          <dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>	  
          <dependency>
	    <groupId>org.apache.commons</groupId>
	    <artifactId>commons-pool2</artifactId>
          </dependency> 	  
          <dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	    <version>6.0.5</version>
          </dependency>	  	  	  
          <dependency>
	    <groupId>javax.xml.bind</groupId>
	    <artifactId>jaxb-api</artifactId>
	    <version>2.3.0</version>
          </dependency>  	      	  	  	  
	  <dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-devtools</artifactId>
	    <optional>true</optional>
	  </dependency> 
	</dependencies>
	<build>
	  <plugins>
	     <plugin>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-maven-plugin</artifactId>
	     </plugin>
	  </plugins>
	</build>
</project> 

application.properties

找到我们的演示程序中使用的应用程序属性文件。

application.properties

#Redis specific configurations

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password= 

spring.redis.lettuce.pool.max-active=7 
spring.redis.lettuce.pool.max-idle=7
spring.redis.lettuce.pool.min-idle=2
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.shutdown-timeout=200ms

spring.cache.redis.cache-null-values=false
spring.cache.redis.time-to-live=600000
spring.cache.redis.use-key-prefix=true

spring.cache.type=redis
#spring.cache.cache-names=articleCache,allArticlesCache

#Database specific configurations 

spring.datasource.url=jdbc:mysql://localhost:3306/concretepage
spring.datasource.username=root
spring.datasource.password=cp

spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=12
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1200000

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.id.new_generator_mappings=false
spring.jpa.properties.hibernate.format_sql=true 

使用 Lettuce 配置

Spring Boot 2.0启动器spring-boot-starter-data-redis默认解决了LettuceSpring提供LettuceConnectionFactory来获取连接。要获得池化连接工厂,我们需要在类路径上提供commons-pool2。要使用Lettuce,我们需要以下Maven依赖项。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>		
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency> 

为了配置Lettuce池,我们需要使用spring.redis.*前缀与Lettuce池连接属性。找到Lettuce池的样本配置。

application.properties

spring.redis.host=localhost 
spring.redis.port=6379
spring.redis.password= 

spring.redis.lettuce.pool.max-active=7 
spring.redis.lettuce.pool.max-idle=7
spring.redis.lettuce.pool.min-idle=2
spring.redis.lettuce.pool.max-wait=-1ms  
spring.redis.lettuce.shutdown-timeout=200ms 

我们可以覆盖默认的Redis主机、端口和密码配置。如果我们想无限期地阻塞,请使用max-wait这个负值。

使用 Jedis 配置

默认情况下,Spring Boot 2.0启动器spring-boot-starter-data-redis使用Lettuce。要使用Jedis,我们需要排除Lettuce的依赖,并包含Jedis。找到使用JedisMaven依赖项。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
  <exclusions>
    <exclusion>
	 <groupId>io.lettuce</groupId>
	 <artifactId>lettuce-core</artifactId>
    </exclusion>
  </exclusions>		    
</dependency>		
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency> 

jedis的依赖将自动解决类路径上的commons-pool2

为了配置Jedis池,我们需要使用spring.redis.*前缀与Jedis池连接属性。找到Jedis池的样本配置。

application.properties

spring.redis.host=localhost 
spring.redis.port=6379
spring.redis.password= 

spring.redis.jedis.pool.max-active=7 
spring.redis.jedis.pool.max-idle=7
spring.redis.jedis.pool.min-idle=2
spring.redis.jedis.pool.max-wait=-1ms 

RedisCacheManager

Spring Boot中,RedisCacheManager是自动配置的。这里我们将讨论如何配置Spring Boot Redis缓存属性以改变自动配置的RedisCacheManager的默认值,然后我们将创建一个自己的RedisCacheManager示例,以获得对配置的完全控制。

1. 自动配置的 RedisCacheManager

如果Redis在我们的Spring Boot应用程序中可用并已配置,RedisCacheManager将被自动配置。我们可以使用spring.cache.*属性来控制Spring缓存的配置。

spring.cache.type: 定义了缓存类型。如果我们不配置这个属性,它将被自动检测到环境。对于Redis缓存,其值为redis

spring.cache.cache-names: 在启动时创建额外的缓冲区。

Redis缓存的默认值可以通过spring.cache.redis.*进行配置。

spring.cache.redis.cache-null-values: 它接受布尔值。当该值为true时,它将允许缓存空值,否则不允许。

spring.cache.redis.time-to-live: 缓存过期时间。

spring.cache.redis.use-key-prefix: 它接受布尔值。如果是true,那么在写到Redis时将会使用键的前缀。默认值是true

spring.cache.redis.key-prefix: 定义键前缀。默认情况下,当两个独立的缓存使用同一个键时,会添加一个键前缀以避免键重叠。

找到Redis缓存配置的示例。

application.properties

spring.cache.redis.cache-null-values=false
spring.cache.redis.time-to-live=600000
spring.cache.redis.use-key-prefix=true

spring.cache.type=redis
spring.cache.cache-names=articleCache,allArticlesCache 

缓存articleCacheallArticleCache将存活10分钟。

2. 自定义的 RedisCacheManager

我们可以创建自己的RedisCacheManager来获得对Redis配置的完全控制。我们需要创建LettuceConnectionFactory BeanRedisCacheConfiguration BeanRedisCacheManager,如下所示。

RedisConfig.java

package com.concretepage;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

@Configuration
@EnableCaching
@PropertySource("classpath:application.properties")
public class RedisConfig {
   @Autowired
   private Environment env;	
	
   @Bean
   public LettuceConnectionFactory redisConnectionFactory() {
	RedisStandaloneConfiguration redisConf = new RedisStandaloneConfiguration();
	redisConf.setHostName(env.getProperty("spring.redis.host"));
	redisConf.setPort(Integer.parseInt(env.getProperty("spring.redis.port")));
	redisConf.setPassword(RedisPassword.of(env.getProperty("spring.redis.password")));	    
        return new LettuceConnectionFactory(redisConf);
   }
   @Bean
   public RedisCacheConfiguration cacheConfiguration() {
	RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
	  .entryTtl(Duration.ofSeconds(600))
	  .disableCachingNullValues();	
	return cacheConfig;
   }
   @Bean
   public RedisCacheManager cacheManager() {
	RedisCacheManager rcm = RedisCacheManager.builder(redisConnectionFactory())
	  .cacheDefaults(cacheConfiguration())
	  .transactionAware()
	  .build();
	return rcm;
   }  
} 

RedisCacheConfiguration是一个不可变的类,它有助于自定义Redis的缓存行为,如缓存过期时间,禁止缓存空值等。它也有助于自定义序列化策略。

使用 @EnableCaching 启用缓存

为了在我们的应用程序中启用缓存,Spring提供了@EnableCaching注解。@EnableCaching启用注释驱动的缓存管理能力。

它负责注册所需的Spring组件以启用注释驱动的缓存管理。@EnableCaching是用@Configuration@SpringBootApplication注解来注释的。

SpringBootAppStarter.java

@SpringBootApplication
@EnableCaching
public class SpringBootAppStarter {  
    public static void main(String[] args) {
	SpringApplication.run(SpringBootAppStarter.class, args);
    }       
} 

使用 @Cacheable

@Cacheable表示调用方法的结果可以被缓存,一旦结果被缓存,下一次调用方法的执行将被跳过,并且只提供缓存的结果。找出其中的一些元素。

cacheNames: 储存方法结果的缓存名称。

value: cacheNames的别名。

condition: Spring SpEL表达式可以进行有条件缓存。

key: SpEL动态地计算key

keyGenerator: 自定义KeyGeneratorBean名称。

unless: SpEL来否决方法缓存。

sync: 当多个线程试图为同一个key加载一个值时,它被用来同步方法的调用。

为了计算key, conditionunless,我们可以在SpEL中使用以下元数据。

#result: 引用方法的结果。

#root.method: 引用方法。

#root.target: 对目标对象的引用。

#root.caches: 引用受影响的缓存。

#root.methodName:方法名称的快捷方式。

#root.targetClass:目标类的快捷方式。

#root.args[1], #p1 or #a1: 它们给出了方法的第二个参数。改变数值,我们可以得到其他参数。我们也可以通过他们的名字来访问参数。

现在找到使用@Cacheable注解的示例代码片段。

@Cacheable(value= "articleCache", key= "#articleId")		
public Article getArticleById(long articleId) {
  ------
} 

在上面的代码中,方法的结果将用articleCache的缓存名称来缓存,使用的键是传递的文章ID。这意味着对于不同的文章ID,结果将以不同的键被缓存,但有相同的缓存名称。一旦方法的结果被缓存为一个键,那么对于相同的键,方法将不会执行,缓存的结果将被提供。

@Cacheable(value= "allArticlesCache", unless= "#result.size() == 0")	
public List<Article> getAllArticles(){
  ------
} 

在上面的代码中,如果结果的大小为0,方法的结果将不会被缓存。 如果我们不提供键,默认情况下,它将是("")或方法参数被用来计算键(如果有的话)。

使用 @CachePut

@CachePut 触发了一个缓存投放操作。它不会跳过方法的执行,每次执行的结果都会缓存在相关的缓存中。@CachePut拥有与@Cacheable相同的元素,如cacheNames, value, condition, key, unless, keyGenerator等。找到使用@CachePut的示例代码片段。

@CachePut(value= "articleCache", key= "#article.articleId")
public Article addArticle(Article article){
   ------
} 

上述方法将在每次调用时执行,方法结果将被添加或更新到与给定的缓存名称的键相对应的缓存中。

使用 @CacheEvict

@CacheEvict 触发了一个缓存清空操作。它不会跳过方法的执行,并且每次执行都会清空缓存。它的元素包括cacheNames, value, condition, key, keyGenerator, allEntries等。如果allEntries= true,缓存中的所有条目都被移除。找到使用@CacheEvict的代码片段。

@CacheEvict(value= "allArticlesCache", allEntries= true)	
public void deleteArticle(long articleId) {
  ------
} 

上述方法将执行每一次调用,所有缓存的条目将被删除。

使用 @Caching

@Caching是多个缓存注解的组注解。它有cacheableputevict元素。

找到使用@CachePut@CacheEvict的代码片段,在组中使用@Caching

@Caching(
   put= { @CachePut(value= "articleCache", key= "#article.articleId") },
   evict= { @CacheEvict(value= "allArticlesCache", allEntries= true) }
)
public Article updateArticle(Article article) {
   ------
} 

@Caching组中使用多个@CacheEvict的代码段。

@Caching(
   evict= { 
	@CacheEvict(value= "articleCache", key= "#articleId"),
	@CacheEvict(value= "allArticlesCache", allEntries= true)
   }
)
public void deleteArticle(long articleId) {
   ------
} 

Spring Boot Cache + Redis + MySQL CRUD 完整示例

这里我们将提供一个Spring Boot Cache + Redis + MySQL CRUD操作的完整例子。在Eclipse中查找项目结构。

在这里插入图片描述
现在找到完整的代码。

articles

CREATE TABLE IF NOT EXISTS `articles` (
  `article_id` int(5) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL,
  `category` varchar(100) NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

INSERT INTO `articles` (`article_id`, `title`, `category`) VALUES
	(1, 'Spring REST Security', 'Spring'),
	(2, 'Java Concurrency', 'Java'); 

ArticleService.java

package com.concretepage.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import com.concretepage.entity.Article;
import com.concretepage.repository.ArticleRepository;

@Service
public class ArticleService implements IArticleService {
	@Autowired
	private ArticleRepository articleRepository;
	
	@Override	
	@Cacheable(value= "articleCache", key= "#articleId")		
	public Article getArticleById(long articleId) {
		System.out.println("--- Inside getArticleById() ---");		
		return  articleRepository.findById(articleId).get();
	}
	@Override	
	@Cacheable(value= "allArticlesCache", unless= "#result.size() == 0")	
	public List<Article> getAllArticles(){
		System.out.println("--- Inside getAllArticles() ---");
		List<Article> list = new ArrayList<>();
		articleRepository.findAll().forEach(e -> list.add(e));
		return list;
	}
	@Override	
	@Caching(
		put= { @CachePut(value= "articleCache", key= "#article.articleId") },
		evict= { @CacheEvict(value= "allArticlesCache", allEntries= true) }
	)
	public Article addArticle(Article article){
		System.out.println("--- Inside addArticle() ---");		
		return articleRepository.save(article);
	}
	@Override	
	@Caching(
		put= { @CachePut(value= "articleCache", key= "#article.articleId") },
		evict= { @CacheEvict(value= "allArticlesCache", allEntries= true) }
	)
	public Article updateArticle(Article article) {
		System.out.println("--- Inside updateArticle() ---");		
		return articleRepository.save(article);
	}
	@Override	
	@Caching(
		evict= { 
			@CacheEvict(value= "articleCache", key= "#articleId"),
			@CacheEvict(value= "allArticlesCache", allEntries= true)
		}
	)
	public void deleteArticle(long articleId) {
		System.out.println("--- Inside deleteArticle() ---");		
		articleRepository.delete(articleRepository.findById(articleId).get());
	}
} 

IArticleService.java

package com.concretepage.service;
import java.util.List;
import com.concretepage.entity.Article;

public interface IArticleService {
     List<Article> getAllArticles();
     Article getArticleById(long articleId);
     Article addArticle(Article article);
     Article updateArticle(Article article);
     void deleteArticle(long articleId);
} 

Article.java

package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="articles")
public class Article implements Serializable { 
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="article_id")
        private long articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public long getArticleId() {
		return articleId;
	}
	public void setArticleId(long articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
} 

ArticleRepository.java

package com.concretepage.repository;
import org.springframework.data.repository.CrudRepository;
import com.concretepage.entity.Article;

public interface ArticleRepository extends CrudRepository<Article, Long>  {
} 

ArticleController.java

package com.concretepage.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.util.UriComponentsBuilder;
import com.concretepage.entity.Article;
import com.concretepage.service.IArticleService;

@Controller
@RequestMapping("user")
public class ArticleController {
	@Autowired
	private IArticleService articleService;
	
	@GetMapping("article/{id}")
	public ResponseEntity<Article> getArticleById(@PathVariable("id") Long id) {
		Article article = articleService.getArticleById(id);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@GetMapping("articles")
	public ResponseEntity<List<Article>> getAllArticles() {
		List<Article> list = articleService.getAllArticles();
		return new ResponseEntity<List<Article>>(list, HttpStatus.OK);
	}
	@PostMapping("article")
	public ResponseEntity<Void> addArticle(@RequestBody Article article, UriComponentsBuilder builder) {
		Article savedArticle = articleService.addArticle(article);  
                HttpHeaders headers = new HttpHeaders();
                headers.setLocation(builder.path("/article/{id}").buildAndExpand(savedArticle.getArticleId()).toUri());
                return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
	}
	@PutMapping("article")
	public ResponseEntity<Article> updateArticle(@RequestBody Article article) {
		articleService.updateArticle(article);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@DeleteMapping("article/{id}")
	public ResponseEntity<Void> deleteArticle(@PathVariable("id") Long id) {
		articleService.deleteArticle(id);
		return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
	}	
} 

SpringBootAppStarter.java

package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class SpringBootAppStarter {  
    public static void main(String[] args) {
	SpringApplication.run(SpringBootAppStarter.class, args);
    }       
} 

RestClientUtil.java

package com.concretepage;
import java.net.URI;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.concretepage.entity.Article;

public class RestClientUtil {
    public void getArticleByIdDemo(long id) {
    	HttpHeaders headers = new HttpHeaders();
    	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/article/{id}";
        HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article.class, id);
        Article article = responseEntity.getBody();
        System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
                 +", Category:"+article.getCategory());      
    }
    public void getAllArticlesDemo() {
	HttpHeaders headers = new HttpHeaders();
	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/articles";
        HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article[].class);
        Article[] articles = responseEntity.getBody();
        for(Article article : articles) {
              System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
                      +", Category: "+article.getCategory());
        }
    }
    public void addArticleDemo(Article objArticle) {
    	HttpHeaders headers = new HttpHeaders();
    	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/article";
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(objArticle, headers);
        URI uri = restTemplate.postForLocation(url, requestEntity);
        System.out.println(uri.getPath());    	
    }
    public void updateArticleDemo(Article objArticle) {
    	HttpHeaders headers = new HttpHeaders();
    	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/article";
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(objArticle, headers);
        restTemplate.put(url, requestEntity);
    }
    public void deleteArticleDemo(long id) {
    	HttpHeaders headers = new HttpHeaders();
    	headers.setContentType(MediaType.APPLICATION_JSON);
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/article/{id}";
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(headers);
        restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Void.class, id);        
    }
    public static void main(String args[]) {
    	RestClientUtil util = new RestClientUtil();
    	//Add article
	Article objArticle = new Article();
	objArticle.setTitle("Spring REST Security");
	objArticle.setCategory("Spring");
     	//util.addArticleDemo(objArticle);
        
    	//Update article
	objArticle.setArticleId(1);
	objArticle.setTitle("Java Concurrency");
	objArticle.setCategory("Java");	    
    	//util.updateArticleDemo(objArticle);
	    
    	//util.deleteArticleDemo(2);
        util.getArticleByIdDemo(1);	    
        System.out.println("---- All articles ----");
    	util.getAllArticlesDemo();    	
    }    
} 

测试应用程序

要测试我们的演示应用程序,请找到下面的步骤。

1. 使用链接安装并启动Redis

2. 如果你使用的是Windows操作系统,你可以先安装Cygwin,然后在其中安装Redis

3. Redis将在6379端口的localhost上启动。

4. 在上面的文章中给出的表导入MySQL数据库中。

5. 我们可以通过以下方式运行我们的Spring Boot应用程序。

a. 使用Eclipse

使用页面末尾的下载链接下载项目的源代码。

将该项目导入eclipse

使用命令提示符,进入项目的根文件夹并运行。

mvn clean eclipse:eclipse 

然后在eclipse中刷新该项目。点击Run as -> Java Application来运行主类MyApplication

Tomcat服务器将被启动。

b. 使用Maven命令

下载项目的源代码。使用命令提示符进入项目的根文件夹并运行命令。

mvn spring-boot:run 

Tomcat服务器将被启动。

c. 使用可执行的JAR

使用命令提示符,转到项目的根文件夹并运行该命令。

mvn clean package 

我们将在目标文件夹中得到可执行的spring-boot-app-0.0.1-SNAPSHOT.jar。以下列方式运行这个JAR

java -jar target/spring-boot-app-0.0.1-SNAPSHOT.jar 

Tomcat服务器将被启动。

6. 现在我们已经准备好测试这个应用程序了。要运行客户端,在eclipse中进入RestClientUtil类,点击Run as -> Java Application

参考文献

【1】Spring Boot Reference Guide
【2】Spring Data Redis
【3】Spring Boot Redis
【4】Spring Data Redis Cache
【5】Spring Boot Redis Cache

源码下载

提取码:mao4

spring-boot-redis-cache.zip

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫巳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值