Spring Boot Redis Cache

By Arvind Rai, August 11, 2018
This page will walk through Spring Boot Redis cache example. RedisCacheManager is the CacheManager backed by Redis. If Redis is available and configured in our Spring Boot application, RedisCacheManager will be auto-configured. Redis connections are obtained from Lettuce or Jedis Java Redis clients. Redis dependencies are resolved by spring-boot-starter-data-redis starter. In Spring Boot 2.0 Lettuce are resolved by default instead of Jedis. To work with Jedis, we need to include jedis dependency in our build file.
Spring @EnableCaching enables Spring cache management capability in our application. It is annotated with @SpringBootApplication annotation. @Cacheable indicates that the result of invoking method can be cached and once result is cached, next call to method execution is skipped and only cached result is served. @CachePut adds or updates cache but does not skip method execution. @CacheEvict evicts cache but does not skip method execution. @Caching is used to group multiple cache annotations.

Technologies Used

Find the technologies being used in our example.
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 File

Spring provides spring-boot-starter-data-redis to resolve Redis dependencies. It provides basic auto configurations for Lettuce and Jedis client libraries. By default Spring Boot 2.0 uses Lettuce. To get pooled connection factory we need to provide commons-pool2 dependency. Find the Maven file.
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

Find the application property file used in our demo application.
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 

Using Lettuce Configurations

Spring Boot 2.0 starter spring-boot-starter-data-redis resolves Lettuce by default. Spring provides LettuceConnectionFactory to get connections. To get pooled connection factory we need to provide commons-pool2 on the classpath. To work with Lettuce we need following Maven dependencies.
<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> 
To configure Lettuce pool we need to use spring.redis.* prefix with Lettuce pool connection properties. Find the Lettuce pool sample configurations.
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 
We can override default Redis host, port and password configurations. Use max-wait a negative value if we want to block indefinitely.

Using Jedis Configurations

By default Spring Boot 2.0 starter spring-boot-starter-data-redis uses Lettuce. To use Jedis we need to exclude Lettuce dependency and include Jedis. Find the Maven dependencies to use Jedis.
<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 dependency will automatically resolve commons-pool2 on the classpath.
To configure Jedis pool we need to use spring.redis.* prefix with Jedis pool connection properties. Find the Jedis pool sample configurations.
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

In Spring Boot, RedisCacheManager is auto-configured. Here we will discuss how to configure Spring Boot Redis cache properties to change its default value for auto-configured RedisCacheManager and then we will create a sample own RedisCacheManager to get full control on configurations.

1. Auto-configured RedisCacheManager
If Redis is available and configured in our Spring Boot application, RedisCacheManager will be auto-configured. We can control Spring cache configurations using spring.cache.* property.
spring.cache.type: Defines cache type. If we do not configure this property, It will be auto-detected to the environment. For Redis cache its value is redis .
spring.cache.cache-names: Creates additional caches on startup.

Redis cache defaults can be configured by spring.cache.redis.* .
spring.cache.redis.cache-null-values: It accepts Boolean value. When the value is true, it will allow caching null values otherwise not.
spring.cache.redis.time-to-live: Cache expiration time.
spring.cache.redis.use-key-prefix: It accepts Boolean value. If true then key prefix will be used while writing to Redis. Default value is true
spring.cache.redis.key-prefix: Defines key prefix. By default a key prefix is added to avoid overlapping keys when two separate caches uses same key.

Find the sample Redis cache configurations.
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 
The caches articleCache and allArticlesCache will be alive for 10 minutes.

2. Create own RedisCacheManager
We can create our own RedisCacheManager to get the full control of the Redis configurations. We need to create LettuceConnectionFactory bean, RedisCacheConfiguration bean and RedisCacheManager as following.
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 is immutable class that helps customizing Redis cache behavior such as cache expiry time, disable caching null values etc. It is also helpful in customizing serialization strategy.

Enable Caching using @EnableCaching

To enable cache abstraction in our application, Spring provides @EnableCaching annotation. @EnableCaching enables annotation-driven cache management capability. It is responsible to register required Spring components to enable annotation-driven cache management. @EnableCaching is annotated with @Configuration or @SpringBootApplication annotations.
SpringBootAppStarter.java
@SpringBootApplication
@EnableCaching
public class SpringBootAppStarter {  
    public static void main(String[] args) {
	SpringApplication.run(SpringBootAppStarter.class, args);
    }       
} 


Using @Cacheable

@Cacheable indicates that the result of invoking method can be cached and once result is cached, next call to method execution is skipped and only cached result is served. Find some of its elements.
cacheNames: Name of the caches in which method result are stored.
value: Alias for cacheNames.
condition: Spring SpEL expression to make conditional caching.
key: SpEL to compute key dynamically.
keyGenerator: Bean name for custom KeyGenerator.
unless: SpEL to veto method caching.
sync: It is uses to synchronize method invocation when several threads are attempting to load a value for same key.

To compute key, condition or unless, we can use following meta-data in SpEL.
#result: Reference to the result of method.
#root.method: Reference to the method.
#root.target: Reference to the target object.
#root.caches: Reference to the affected caches.
#root.methodName: Shortcut to the method name.
#root.targetClass: Shortcut to target class.
#root.args[1], #p1 or #a1: They give second argument of method. Changing numerical value, we can get other arguments. We can also access arguments by their name.

Now find the sample code snippet to use @Cacheable annotation.
@Cacheable(value= "articleCache", key= "#articleId")		
public Article getArticleById(long articleId) {
  ------
} 
In the above code, method result will be cached with articleCache cache name using key as passed article id. It means for different article id, result will be cached with different key but with same cache name. Once the method result is cached for a key, then for the same key, method will not execute and the cached result will be served.
Find one more example.
@Cacheable(value= "allArticlesCache", unless= "#result.size() == 0")	
public List<Article> getAllArticles(){
  ------
} 
In the above code, method result will not be cached if size of the result will be 0. If we do not provide key, by default it will be ("") or method parameters are used to compute the key if available.

Using @CachePut

@CachePut triggers a cache put operation. It does not skip method execution and result is cached in associated cache for every execution. @CachePut has elements same like @Cacheable such as cacheNames, value, condition, key, unless, keyGenerator etc. Find the sample code snippet to use @CachePut.
@CachePut(value= "articleCache", key= "#article.articleId")
public Article addArticle(Article article){
   ------
} 
The above method will execute for every call and method result will be added or updated in cache corresponding to key for given cache name.

Using @CacheEvict

@CacheEvict triggers a cache evict operation. It does not skip method execution and evicts cache for every execution. It has elements such as cacheNames, value, condition, key, keyGenerator, allEntries etc. If allEntries= true, all entries inside the caches are removed. Find the code snippet to use @CacheEvict.
@CacheEvict(value= "allArticlesCache", allEntries= true)	
public void deleteArticle(long articleId) {
  ------
} 
The above method will execute every call and all the entries of caches will be removed.

Using @Caching

@Caching is the group annotation for multiple cache annotations. It has cacheable, put and evict elements.
Find the code snippet to use @CachePut and @CacheEvict in group using @Caching.
@Caching(
   put= { @CachePut(value= "articleCache", key= "#article.articleId") },
   evict= { @CacheEvict(value= "allArticlesCache", allEntries= true) }
)
public Article updateArticle(Article article) {
   ------
} 
Find the code snippet to use multiple @CacheEvict in group using @Caching.
	
@Caching(
   evict= { 
	@CacheEvict(value= "articleCache", key= "#articleId"),
	@CacheEvict(value= "allArticlesCache", allEntries= true)
   }
)
public void deleteArticle(long articleId) {
   ------
} 

Spring Boot Cache + Redis + MySQL CRUD Example

Here we will provide a complete example for Spring Boot Cache + Redis + MySQL CRUD operation. Find the project structure in Eclipse.
Spring Boot Redis Cache
Now find the complete code.
Table: 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();    	
    }    
} 

Test Application

To test our demo application, find the steps.
1. Install and start Redis using the link.
2. If you are using Windows OS, you can install Cygwin first and then install Redis in it.
3. Redis will start on localhost at port 6379.
4. Import table in MySQL database given above in the article.

5. We can run our Spring Boot application in following ways.
a. Using Maven Command: Download the project source code. Go to the root folder of the project using command prompt and run the command.
mvn spring-boot:run 
Tomcat server will be started.

b. Using Eclipse: Download the project source code using the download link given at the end of article. Import the project into eclipse. Using command prompt, go to the root folder of the project and run.
mvn clean eclipse:eclipse 
and then refresh the project in eclipse. Run Main class SpringBootAppStarter by clicking Run as -> Java Application. Tomcat server will be started.

c. Using Executable JAR: Using command prompt, go to the root folder of the project and run the command.
mvn clean package 
We will get executable JAR spring-boot-app-0.0.1-SNAPSHOT.jar in target folder. Run this JAR as
java -jar target/spring-boot-app-0.0.1-SNAPSHOT.jar 
Tomcat server will be started.

6. Now we are ready to test the application. Run RestClientUtil.java as Java Application.

References

Spring Boot Reference Guide
Spring Data Redis
Spring Boot Redis
Spring Data Redis Cache

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI









©2023 concretepage.com | Privacy Policy | Contact Us