Show List
Spring Boot Rest Web Service Using Embedded Redis Server
Here's an example of a Spring Boot application that uses the embedded Redis DB and provides REST endpoints to save and fetch data
1. Go to Spring initializr website and create a Java Maven Project with Web dependency. Download the project zip and extract to a folder.
2. Import the project into IDE (I am using IntelliJ Idea). Add dependencies as below in the Pom.xml. Here are the notable dependencies used in this project:
- spring-boot-starter-data-redis with version 2.7.2 is used for integrating Redis with Spring Boot.
- spring-boot-starter-test and reactor-test are dependencies for testing.
- embedded-redis with version 0.7.2 is used for embedded Redis instances during testing.
- spring-boot-starter-web is a dependency for building web applications using Spring Boot.
- lombok is an optional dependency for generating boilerplate code.
- springdoc-openapi-ui with version 1.6.4 is a dependency for generating OpenAPI documentation and providing a UI for it.
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.redis</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>it.ozimov</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. Create DataModel class in the com.redis.demo.model package.
- The @Data annotation is from Lombok and automatically generates standard getter and setter methods, equals(), hashCode(), and toString() methods for all non-static fields of the class.
- The @AllArgsConstructor annotation from Lombok generates a constructor with parameters for all fields of the class.
- The @NoArgsConstructor annotation from Lombok generates a default, no-argument constructor for the class.
package com.redis.demo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DataModel {
private String key;
private String value;
}
Add Redis host properties in the application.properties file:
spring.redis.host=localhost
spring.redis.port=6399
3. Create Redis server configuration classes as below:
- The @Configuration annotation indicates that this class provides configuration for the Spring application.
- The class has two private fields: redisPort and redisHost, representing the port and host of the Redis server, respectively.
- The constructor of the RedisProperties class is annotated with @Value annotations. These annotations are used to inject values from external configuration sources, such as properties files or environment variables.
- The @Value("${spring.redis.port}") annotation injects the value of the property spring.redis.port into the redisPort parameter of the constructor.
- Similarly, the @Value("${spring.redis.host}") annotation injects the value of the property spring.redis.host into the redisHost parameter of the constructor.
- By using these @Value annotations, the values of redisPort and redisHost are set based on the corresponding properties defined in the application's configuration.
package com.redis.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedisProperties {
private int redisPort;
private String redisHost;
public RedisProperties(
@Value("${spring.redis.port}") int redisPort,
@Value("${spring.redis.host}") String redisHost) {
this.redisPort = redisPort;
this.redisHost = redisHost;
}
// getters
public int getRedisPort() {
return redisPort;
}
public String getRedisHost() {
return redisHost;
}
}
RedisConfig.java:
- The class has a private field redisPort annotated with @Value("${spring.redis.port}"). This annotation injects the value of the property spring.redis.port into the redisPort field.
- The class also has a private field redisServer of type RedisServer, which represents the embedded Redis server.
- The @PostConstruct annotation is used on the startRedis() method. This annotation indicates that the method should be executed after the bean has been constructed and its dependencies have been injected. In this method, an instance of RedisServer is created using the provided redisPort value and the desired Redis server configuration settings.
- The @PreDestroy annotation is used on the stopRedis() method. This annotation indicates that the method should be executed before the bean is destroyed. In this method, the embedded Redis server is stopped by invoking the stop() method on the redisServer instance.
- The @Bean annotation is used on the redisServer() method. This annotation declares that the method produces a bean of type RedisServer that can be used by other parts of the application.
- The redisServer() method returns the redisServer instance, which allows other components to access and utilize the embedded Redis server.
package com.redis.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.embedded.RedisServer;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
@Configuration
public class RedisConfig {
@Value("${spring.redis.port}")
private int redisPort;
private RedisServer redisServer;
@PostConstruct
public void startRedis() throws IOException {
redisServer = RedisServer.builder().port(redisPort).setting("maxmemory 128M").build();
redisServer.start();
}
@PreDestroy
public void stopRedis() {
redisServer.stop();
}
@Bean
public RedisServer redisServer() {
return redisServer;
}
}
RedisConfiguration.java
The @Configuration annotation indicates that this class provides configuration for the Spring application.
The @EnableRedisRepositories annotation enables Spring Data Redis repositories in the application, allowing easy interaction with Redis data using repository interfaces.
The class has two @Bean methods that define beans for the Redis connection factory and RedisTemplate.
redisConnectionFactory method:
It takes a RedisProperties parameter which is automatically injected into the method.
It creates and configures a LettuceConnectionFactory bean, which represents the connection to the Redis server.
The RedisProperties bean provides the Redis server host and port values needed for establishing the connection.
redisTemplate method:
It takes a LettuceConnectionFactory parameter which is automatically injected into the method.
It creates a RedisTemplate bean, which is a high-level abstraction for interacting with Redis.
The LettuceConnectionFactory is set as the connection factory for the RedisTemplate, establishing the connection to the Redis server.
The RedisTemplate can be used to perform various Redis operations, such as reading, writing, and querying data. By enabling Spring Data Redis repositories (@EnableRedisRepositories), you can also define repository interfaces and utilize the built-in repository features provided by Spring Data Redis.
package com.redis.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
@Configuration
@EnableRedisRepositories
public class RedisConfiguration {
@Bean
public LettuceConnectionFactory redisConnectionFactory(
RedisProperties redisProperties) {
return new LettuceConnectionFactory(
redisProperties.getRedisHost(),
redisProperties.getRedisPort());
}
@Bean
public RedisTemplate<?, ?> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
return template;
}
}
4. Create controller class DataController.
The @RestController annotation indicates that this class is a controller that handles RESTful requests and automatically serializes responses as JSON.
The @RequestMapping("/data") annotation specifies the base URL path for all the request mapping methods in this controller.
redisTemplate field:
It is autowired using the @Autowired annotation, which injects an instance of the RedisTemplate class.
The RedisTemplate is a pre-configured Spring template class that provides high-level Redis operations.
saveData method:
It is mapped to the HTTP POST request with the base URL path ("/data").
The @RequestBody annotation binds the request body to the dataModel parameter, automatically deserializing the JSON data into a DataModel object.
It uses the redisTemplate to save the data by invoking the opsForValue().set() method, which sets the value of a Redis key.
fetchData method:
It is mapped to the HTTP GET request with the URL path "/data/{key}", where {key} is a path variable representing the Redis key to fetch.
The @PathVariable annotation binds the value of the "key" path variable to the key parameter.
It uses the redisTemplate to retrieve the value associated with the given key by invoking the opsForValue().get() method.
If the value is null, it throws a RuntimeException with the message "Key not found".
If the value is present, it creates a new DataModel object, sets the key and value, and returns it as the response.
The RedisTemplate provides convenient methods (opsForValue(), in this case) for performing Redis operations such as setting and getting values associated with keys.
The DataModel class represents the data structure for storing key-value pairs in Redis.
package com.redis.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import com.redis.demo.model.DataModel;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/data")
public class DataController {
@Autowired
RedisTemplate redisTemplate;
@PostMapping
public void saveData(@RequestBody DataModel dataModel) {
redisTemplate.opsForValue().set(dataModel.getKey(), dataModel.getValue());
}
@GetMapping("/{key}")
public DataModel fetchData(@PathVariable String key) {
String value = (String) redisTemplate.opsForValue().get(key);
if (value == null) {
throw new RuntimeException("Key not found");
}
DataModel dataModel = new DataModel();
dataModel.setKey(key);
dataModel.setValue(value);
return dataModel;
}
}
5. Run the Spring Boot application and test using web service client
"C:\Program Files\Java\jdk-11.0.15\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\lib\idea_rt.jar=64325:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\mail2\Downloads\redis-demo\demo\target\classes;D:\.m2\repository\org\springframework\boot\spring-boot-starter-data-redis\2.7.12\spring-boot-starter-data-redis-2.7.12.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter\2.7.12\spring-boot-starter-2.7.12.jar;D:\.m2\repository\org\springframework\boot\spring-boot\2.7.12\spring-boot-2.7.12.jar;D:\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.12\spring-boot-autoconfigure-2.7.12.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.7.12\spring-boot-starter-logging-2.7.12.jar;D:\.m2\repository\ch\qos\logback\logback-classic\1.2.12\logback-classic-1.2.12.jar;D:\.m2\repository\ch\qos\logback\logback-core\1.2.12\logback-core-1.2.12.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\.m2\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\.m2\repository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;D:\.m2\repository\org\springframework\data\spring-data-redis\2.7.12\spring-data-redis-2.7.12.jar;D:\.m2\repository\org\springframework\data\spring-data-keyvalue\2.7.12\spring-data-keyvalue-2.7.12.jar;D:\.m2\repository\org\springframework\data\spring-data-commons\2.7.12\spring-data-commons-2.7.12.jar;D:\.m2\repository\org\springframework\spring-tx\5.3.27\spring-tx-5.3.27.jar;D:\.m2\repository\org\springframework\spring-oxm\5.3.27\spring-oxm-5.3.27.jar;D:\.m2\repository\org\springframework\spring-aop\5.3.27\spring-aop-5.3.27.jar;D:\.m2\repository\org\springframework\spring-context-support\5.3.27\spring-context-support-5.3.27.jar;D:\.m2\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\.m2\repository\io\lettuce\lettuce-core\6.1.10.RELEASE\lettuce-core-6.1.10.RELEASE.jar;D:\.m2\repository\io\netty\netty-common\4.1.92.Final\netty-common-4.1.92.Final.jar;D:\.m2\repository\io\netty\netty-handler\4.1.92.Final\netty-handler-4.1.92.Final.jar;D:\.m2\repository\io\netty\netty-resolver\4.1.92.Final\netty-resolver-4.1.92.Final.jar;D:\.m2\repository\io\netty\netty-buffer\4.1.92.Final\netty-buffer-4.1.92.Final.jar;D:\.m2\repository\io\netty\netty-transport-native-unix-common\4.1.92.Final\netty-transport-native-unix-common-4.1.92.Final.jar;D:\.m2\repository\io\netty\netty-codec\4.1.92.Final\netty-codec-4.1.92.Final.jar;D:\.m2\repository\io\netty\netty-transport\4.1.92.Final\netty-transport-4.1.92.Final.jar;D:\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.3\jakarta.xml.bind-api-2.3.3.jar;D:\.m2\repository\jakarta\activation\jakarta.activation-api\1.2.2\jakarta.activation-api-1.2.2.jar;D:\.m2\repository\org\springframework\spring-core\5.3.27\spring-core-5.3.27.jar;D:\.m2\repository\org\springframework\spring-jcl\5.3.27\spring-jcl-5.3.27.jar;D:\.m2\repository\io\projectreactor\reactor-core\3.4.29\reactor-core-3.4.29.jar;D:\.m2\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;D:\.m2\repository\it\ozimov\embedded-redis\0.7.2\embedded-redis-0.7.2.jar;D:\.m2\repository\com\google\guava\guava\21.0\guava-21.0.jar;D:\.m2\repository\commons-io\commons-io\2.5\commons-io-2.5.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.7.12\spring-boot-starter-web-2.7.12.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.7.12\spring-boot-starter-json-2.7.12.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.13.5\jackson-databind-2.13.5.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.13.5\jackson-annotations-2.13.5.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.5\jackson-datatype-jdk8-2.13.5.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.5\jackson-datatype-jsr310-2.13.5.jar;D:\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.5\jackson-module-parameter-names-2.13.5.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.12\spring-boot-starter-tomcat-2.7.12.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.75\tomcat-embed-core-9.0.75.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.75\tomcat-embed-el-9.0.75.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.75\tomcat-embed-websocket-9.0.75.jar;D:\.m2\repository\org\springframework\spring-web\5.3.27\spring-web-5.3.27.jar;D:\.m2\repository\org\springframework\spring-beans\5.3.27\spring-beans-5.3.27.jar;D:\.m2\repository\org\springframework\spring-webmvc\5.3.27\spring-webmvc-5.3.27.jar;D:\.m2\repository\org\springframework\spring-context\5.3.27\spring-context-5.3.27.jar;D:\.m2\repository\org\springframework\spring-expression\5.3.27\spring-expression-5.3.27.jar;D:\.m2\repository\org\projectlombok\lombok\1.18.26\lombok-1.18.26.jar;D:\.m2\repository\org\springdoc\springdoc-openapi-ui\1.6.4\springdoc-openapi-ui-1.6.4.jar;D:\.m2\repository\org\springdoc\springdoc-openapi-webmvc-core\1.6.4\springdoc-openapi-webmvc-core-1.6.4.jar;D:\.m2\repository\org\springdoc\springdoc-openapi-common\1.6.4\springdoc-openapi-common-1.6.4.jar;D:\.m2\repository\io\swagger\core\v3\swagger-core\2.1.12\swagger-core-2.1.12.jar;D:\.m2\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;D:\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.13.5\jackson-dataformat-yaml-2.13.5.jar;D:\.m2\repository\io\swagger\core\v3\swagger-annotations\2.1.12\swagger-annotations-2.1.12.jar;D:\.m2\repository\io\swagger\core\v3\swagger-models\2.1.12\swagger-models-2.1.12.jar;D:\.m2\repository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\.m2\repository\org\webjars\swagger-ui\4.1.3\swagger-ui-4.1.3.jar;D:\.m2\repository\org\webjars\webjars-locator-core\0.50\webjars-locator-core-0.50.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.13.5\jackson-core-2.13.5.jar;D:\.m2\repository\io\github\classgraph\classgraph\4.8.138\classgraph-4.8.138.jar com.redis.demo.DemoApplication . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.7.12) 2023-05-19 16:40:35.418 INFO 13308 --- [ main] com.redis.demo.DemoApplication : Starting DemoApplication using Java 11.0.15 on sm15 with PID 13308 (C:\Users\mail2\Downloads\redis-demo\demo\target\classes started by mail2 in C:\Users\mail2\Downloads\redis-demo\demo) 2023-05-19 16:40:35.427 INFO 13308 --- [ main] com.redis.demo.DemoApplication : No active profile set, falling back to 1 default profile: "default" 2023-05-19 16:40:36.492 INFO 13308 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode 2023-05-19 16:40:36.493 INFO 13308 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode. 2023-05-19 16:40:36.530 INFO 13308 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 Redis repository interfaces. 2023-05-19 16:40:36.921 INFO 13308 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode 2023-05-19 16:40:36.921 INFO 13308 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode. 2023-05-19 16:40:36.927 INFO 13308 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 5 ms. Found 0 Redis repository interfaces. 2023-05-19 16:40:38.242 INFO 13308 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2023-05-19 16:40:38.260 INFO 13308 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2023-05-19 16:40:38.261 INFO 13308 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.75] 2023-05-19 16:40:38.480 INFO 13308 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2023-05-19 16:40:38.481 INFO 13308 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2920 ms 2023-05-19 16:40:41.244 INFO 13308 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2023-05-19 16:40:41.263 INFO 13308 --- [ main] com.redis.demo.DemoApplication : Started DemoApplication in 6.932 seconds (JVM running for 7.873) 2023-05-19 16:43:26.756 INFO 13308 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2023-05-19 16:43:26.757 INFO 13308 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2023-05-19 16:43:26.758 INFO 13308 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
Swagger UI can be accessed from http://localhost:8080/swagger-ui/index.html. Use post end point to save some data.
To view the data in the Redis Database, we will use Redis Insight. Download it from the official website https://redis.com/redis-enterprise/redis-insight/.
After installation add the Redis database.
Redis Data can be viewed either on the UI display or using the CLI Commands
Source Code:
https://github.com/it-code-lab/redis
Leave a Comment