parent
3c71e5e677
commit
c9f2162f98
|
@ -7,17 +7,61 @@
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
<artifactId>parent-boot-2</artifactId>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>parent-spring-5</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<relativePath>../../parent-spring-5</relativePath>
|
<relativePath>../../parent-boot-2</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
|
||||||
<version>${spring-data-redis}</version>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-surefire-provider</artifactId>
|
||||||
|
<version>${junit.platform.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.platform</groupId>
|
||||||
|
<artifactId>junit-platform-runner</artifactId>
|
||||||
|
<version>${junit.platform.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -33,42 +77,12 @@
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-core</artifactId>
|
|
||||||
<version>${spring.version}</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-context</artifactId>
|
|
||||||
<version>${spring.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-test</artifactId>
|
|
||||||
<version>${spring.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lordofthejars</groupId>
|
<groupId>com.lordofthejars</groupId>
|
||||||
<artifactId>nosqlunit-redis</artifactId>
|
<artifactId>nosqlunit-redis</artifactId>
|
||||||
<version>${nosqlunit.version}</version>
|
<version>${nosqlunit.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.data</groupId>
|
|
||||||
<artifactId>spring-data-commons</artifactId>
|
|
||||||
<version>${spring-data-commons.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.kstyrc</groupId>
|
<groupId>com.github.kstyrc</groupId>
|
||||||
<artifactId>embedded-redis</artifactId>
|
<artifactId>embedded-redis</artifactId>
|
||||||
|
@ -77,12 +91,13 @@
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring-data-redis>2.0.3.RELEASE</spring-data-redis>
|
|
||||||
<cglib.version>3.2.4</cglib.version>
|
<cglib.version>3.2.4</cglib.version>
|
||||||
<jedis.version>2.9.0</jedis.version>
|
<jedis.version>2.9.0</jedis.version>
|
||||||
<nosqlunit.version>0.10.0</nosqlunit.version>
|
<nosqlunit.version>0.10.0</nosqlunit.version>
|
||||||
<spring-data-commons.version>2.0.3.RELEASE</spring-data-commons.version>
|
<spring-data-commons.version>2.0.3.RELEASE</spring-data-commons.version>
|
||||||
<embedded-redis.version>0.6</embedded-redis.version>
|
<embedded-redis.version>0.6</embedded-redis.version>
|
||||||
|
<junit.platform.version>1.0.0</junit.platform.version>
|
||||||
|
<junit.jupiter.version>5.0.2</junit.jupiter.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.spring.data.reactive.redis;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringRedisReactiveApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringRedisReactiveApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package com.baeldung.spring.data.reactive.redis.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.reactive.redis.model.Employee;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.ReactiveKeyCommands;
|
||||||
|
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.connection.ReactiveStringCommands;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.ReactiveRedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class RedisConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
RedisConnectionFactory factory;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ReactiveRedisTemplate<String, Employee> reactiveRedisTemplate(ReactiveRedisConnectionFactory factory) {
|
||||||
|
Jackson2JsonRedisSerializer<Employee> serializer = new Jackson2JsonRedisSerializer<>(Employee.class);
|
||||||
|
RedisSerializationContext.RedisSerializationContextBuilder<String, Employee> builder = RedisSerializationContext.newSerializationContext(new StringRedisSerializer());
|
||||||
|
RedisSerializationContext<String, Employee> context = builder.value(serializer)
|
||||||
|
.build();
|
||||||
|
return new ReactiveRedisTemplate<>(factory, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ReactiveRedisTemplate<String, String> reactiveRedisTemplateString(ReactiveRedisConnectionFactory connectionFactory) {
|
||||||
|
return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ReactiveKeyCommands keyCommands(final ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
|
||||||
|
return reactiveRedisConnectionFactory.getReactiveConnection()
|
||||||
|
.keyCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ReactiveStringCommands stringCommands(final ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
|
||||||
|
return reactiveRedisConnectionFactory.getReactiveConnection()
|
||||||
|
.stringCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void cleanRedis() {
|
||||||
|
factory.getConnection()
|
||||||
|
.flushDb();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.baeldung.spring.data.reactive.redis.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class Employee implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1603714798906422731L;
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private String department;
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package com.baeldung.spring.data.redis.config;
|
package com.baeldung.spring.data.redis.config;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import com.baeldung.spring.data.redis.queue.MessagePublisher;
|
||||||
|
import com.baeldung.spring.data.redis.queue.RedisMessagePublisher;
|
||||||
|
import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -13,10 +15,6 @@ import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
||||||
import org.springframework.data.redis.serializer.GenericToStringSerializer;
|
import org.springframework.data.redis.serializer.GenericToStringSerializer;
|
||||||
|
|
||||||
import com.baeldung.spring.data.redis.queue.MessagePublisher;
|
|
||||||
import com.baeldung.spring.data.redis.queue.RedisMessagePublisher;
|
|
||||||
import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan("com.baeldung.spring.data.redis")
|
@ComponentScan("com.baeldung.spring.data.redis")
|
||||||
@EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo")
|
@EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo")
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.baeldung.spring.data.reactive.redis.template;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.reactive.redis.SpringRedisReactiveApplication;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.redis.connection.ReactiveKeyCommands;
|
||||||
|
import org.springframework.data.redis.connection.ReactiveStringCommands;
|
||||||
|
import org.springframework.data.redis.connection.ReactiveStringCommands.SetCommand;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisReactiveApplication.class)
|
||||||
|
public class RedisKeyCommandsIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ReactiveKeyCommands keyCommands;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ReactiveStringCommands stringCommands;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFluxOfKeys_whenPerformOperations_thenPerformOperations() {
|
||||||
|
Flux<String> keys = Flux.just("key1", "key2", "key3", "key4");
|
||||||
|
|
||||||
|
Flux<SetCommand> generator = keys.map(String::getBytes)
|
||||||
|
.map(ByteBuffer::wrap)
|
||||||
|
.map(key -> SetCommand.set(key)
|
||||||
|
.value(key));
|
||||||
|
|
||||||
|
StepVerifier.create(stringCommands.set(generator))
|
||||||
|
.expectNextCount(4L)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
Mono<Long> keyCount = keyCommands.keys(ByteBuffer.wrap("key*".getBytes()))
|
||||||
|
.flatMapMany(Flux::fromIterable)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
StepVerifier.create(keyCount)
|
||||||
|
.expectNext(4L)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.baeldung.spring.data.reactive.redis.template;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.reactive.redis.SpringRedisReactiveApplication;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.redis.core.ReactiveListOperations;
|
||||||
|
import org.springframework.data.redis.core.ReactiveRedisTemplate;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisReactiveApplication.class)
|
||||||
|
public class RedisTemplateListOpsIntegrationTest {
|
||||||
|
|
||||||
|
private static final String LIST_NAME = "demo_list";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ReactiveRedisTemplate<String, String> redisTemplate;
|
||||||
|
|
||||||
|
private ReactiveListOperations<String, String> reactiveListOps;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
reactiveListOps = redisTemplate.opsForList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenListAndValues_whenLeftPushAndLeftPop_thenLeftPushAndLeftPop() {
|
||||||
|
Mono<Long> lPush = reactiveListOps.leftPushAll(LIST_NAME, "first", "second")
|
||||||
|
.log("Pushed");
|
||||||
|
|
||||||
|
StepVerifier.create(lPush)
|
||||||
|
.expectNext(2L)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
Mono<String> lPop = reactiveListOps.leftPop(LIST_NAME)
|
||||||
|
.log("Popped");
|
||||||
|
|
||||||
|
StepVerifier.create(lPop)
|
||||||
|
.expectNext("second")
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.baeldung.spring.data.reactive.redis.template;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baeldung.spring.data.reactive.redis.SpringRedisReactiveApplication;
|
||||||
|
import com.baeldung.spring.data.reactive.redis.model.Employee;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.redis.core.ReactiveRedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.ReactiveValueOperations;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisReactiveApplication.class)
|
||||||
|
public class RedisTemplateValueOpsIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ReactiveRedisTemplate<String, Employee> redisTemplate;
|
||||||
|
|
||||||
|
private ReactiveValueOperations<String, Employee> reactiveValueOps;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
reactiveValueOps = redisTemplate.opsForValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenEmployee_whenSet_thenSet() {
|
||||||
|
|
||||||
|
Mono<Boolean> result = reactiveValueOps.set("123", new Employee("123", "Bill", "Accounts"));
|
||||||
|
|
||||||
|
StepVerifier.create(result)
|
||||||
|
.expectNext(true)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenEmployeeId_whenGet_thenReturnsEmployee() {
|
||||||
|
|
||||||
|
Mono<Employee> fetchedEmployee = reactiveValueOps.get("123");
|
||||||
|
|
||||||
|
StepVerifier.create(fetchedEmployee)
|
||||||
|
.expectNext(new Employee("123", "Bill", "Accounts"))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenEmployee_whenSetWithExpiry_thenSetsWithExpiryTime() throws InterruptedException {
|
||||||
|
|
||||||
|
Mono<Boolean> result = reactiveValueOps.set("129", new Employee("129", "John", "Programming"), Duration.ofSeconds(1));
|
||||||
|
|
||||||
|
Mono<Employee> fetchedEmployee = reactiveValueOps.get("129");
|
||||||
|
|
||||||
|
StepVerifier.create(result)
|
||||||
|
.expectNext(true)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
Thread.sleep(2000L);
|
||||||
|
|
||||||
|
StepVerifier.create(fetchedEmployee)
|
||||||
|
.expectNextCount(0L)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ public class RedisMessageListenerIntegrationTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void startRedisServer() throws IOException {
|
public static void startRedisServer() throws IOException {
|
||||||
redisServer = new redis.embedded.RedisServer(6379);
|
redisServer = new redis.embedded.RedisServer(6380);
|
||||||
redisServer.start();
|
redisServer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class StudentRepositoryIntegrationTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void startRedisServer() throws IOException {
|
public static void startRedisServer() throws IOException {
|
||||||
redisServer = new redis.embedded.RedisServer(6379);
|
redisServer = new redis.embedded.RedisServer(6380);
|
||||||
redisServer.start();
|
redisServer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
pom.xml
1
pom.xml
|
@ -451,6 +451,7 @@
|
||||||
<module>spring-5</module>
|
<module>spring-5</module>
|
||||||
<module>spring-5-data-reactive</module>
|
<module>spring-5-data-reactive</module>
|
||||||
<module>spring-5-reactive</module>
|
<module>spring-5-reactive</module>
|
||||||
|
<module>spring-data-5-reactive/spring-5-data-reactive-redis</module>
|
||||||
<module>spring-5-reactive-security</module>
|
<module>spring-5-reactive-security</module>
|
||||||
<module>spring-5-reactive-client</module>
|
<module>spring-5-reactive-client</module>
|
||||||
<module>spring-5-mvc</module>
|
<module>spring-5-mvc</module>
|
||||||
|
|
Loading…
Reference in New Issue