diff --git a/spring-5-webflux/pom.xml b/spring-5-webflux/pom.xml index d7fb7b7930..3306fd1729 100644 --- a/spring-5-webflux/pom.xml +++ b/spring-5-webflux/pom.xml @@ -1,23 +1,20 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung spring-5-webflux 1.0-SNAPSHOT - spring-5-webflux - http://www.baeldung.com - - UTF-8 - 1.8 - 1.8 - 2.0.2.RELEASE - + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../parent-boot-2 + @@ -58,12 +55,8 @@ - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 + org.springframework.boot + spring-boot-maven-plugin diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java new file mode 100644 index 0000000000..f9de3b4006 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/CustomNettyWebServerFactory.java @@ -0,0 +1,36 @@ +package com.baeldung.spring.serverconfig; + +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.NettyServerCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import reactor.netty.http.server.HttpServer; + +@Configuration +@Profile("skipAutoConfig") +public class CustomNettyWebServerFactory { + + @Bean + public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() { + NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory(); + webServerFactory.addServerCustomizers(new EventLoopNettyCustomizer()); + return webServerFactory; + } + + private static class EventLoopNettyCustomizer implements NettyServerCustomizer { + + @Override + public HttpServer apply(HttpServer httpServer) { + EventLoopGroup parentGroup = new NioEventLoopGroup(); + EventLoopGroup childGroup = new NioEventLoopGroup(); + return httpServer + .tcpConfiguration(tcpServer -> tcpServer.bootstrap( + serverBootstrap -> serverBootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class) + )); + } + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java new file mode 100644 index 0000000000..990ea5cf83 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingController.java @@ -0,0 +1,23 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/greet") +public class GreetingController { + + private final GreetingService greetingService; + + public GreetingController(GreetingService greetingService) { + this.greetingService = greetingService; + } + + @GetMapping("/{name}") + private Mono greet(@PathVariable String name) { + return greetingService.greet(name); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java new file mode 100644 index 0000000000..a6243b2bd0 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/GreetingService.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class GreetingService { + + public Mono greet(String name) { + return Mono.just("Greeting " + name); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java new file mode 100644 index 0000000000..fdde130286 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactoryPortCustomizer.java @@ -0,0 +1,30 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.NettyServerCustomizer; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.stereotype.Component; +import reactor.netty.http.server.HttpServer; + +@Component +public class NettyWebServerFactoryPortCustomizer implements WebServerFactoryCustomizer { + + @Override + public void customize(NettyReactiveWebServerFactory serverFactory) { + serverFactory.addServerCustomizers(new PortCustomizer(8443)); + } + + private static class PortCustomizer implements NettyServerCustomizer { + + private final int port; + + private PortCustomizer(int port) { + this.port = port; + } + + @Override + public HttpServer apply(HttpServer httpServer) { + return httpServer.port(port); + } + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java new file mode 100644 index 0000000000..cf4e5ac8ea --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/NettyWebServerFactorySslCustomizer.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; +import org.springframework.boot.web.embedded.netty.SslServerCustomizer; +import org.springframework.boot.web.server.Http2; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.stereotype.Component; + +@Component +public class NettyWebServerFactorySslCustomizer implements WebServerFactoryCustomizer { + + @Override + public void customize(NettyReactiveWebServerFactory serverFactory) { + Ssl ssl = new Ssl(); + ssl.setEnabled(true); + ssl.setKeyStore("classpath:sample.jks"); + ssl.setKeyAlias("alias"); + ssl.setKeyPassword("password"); + ssl.setKeyStorePassword("secret"); + Http2 http2 = new Http2(); + http2.setEnabled(false); + serverFactory.addServerCustomizers(new SslServerCustomizer(ssl, http2, null)); + serverFactory.setPort(8443); + } +} diff --git a/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java new file mode 100644 index 0000000000..b4f6006be3 --- /dev/null +++ b/spring-5-webflux/src/main/java/com/baeldung/spring/serverconfig/ServerConfigApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ServerConfigApplication { + + public static void main(String[] args) { + SpringApplication.run(ServerConfigApplication.class, args); + } +} diff --git a/spring-5-webflux/src/main/resources/logback.xml b/spring-5-webflux/src/main/resources/logback.xml new file mode 100644 index 0000000000..48b68c6bf1 --- /dev/null +++ b/spring-5-webflux/src/main/resources/logback.xml @@ -0,0 +1,31 @@ + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + netty-access.log + + %msg%n + + + + + + + + + + + + + + + + diff --git a/spring-5-webflux/src/main/resources/sample.jks b/spring-5-webflux/src/main/resources/sample.jks new file mode 100644 index 0000000000..6aa9a28053 Binary files /dev/null and b/spring-5-webflux/src/main/resources/sample.jks differ diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerTests.java b/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java similarity index 97% rename from spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerTests.java rename to spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java index 5112c8ceb2..4c6708e423 100644 --- a/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerTests.java +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/responsestatus/ResponseStatusControllerLiveTest.java @@ -9,7 +9,7 @@ import org.springframework.test.web.reactive.server.WebTestClient; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class ResponseStatusControllerTests { +public class ResponseStatusControllerLiveTest { @Autowired private WebTestClient testClient; diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java new file mode 100644 index 0000000000..ce156beb3f --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingControllerIntegrationTest.java @@ -0,0 +1,41 @@ +package com.baeldung.spring.serverconfig; + +import static org.mockito.Mockito.when; + +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.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import reactor.core.publisher.Mono; + +@RunWith(SpringRunner.class) +@WebFluxTest +public class GreetingControllerIntegrationTest { + + @Autowired + private WebTestClient webClient; + + @MockBean + private GreetingService greetingService; + + private final String name = "Baeldung"; + + @Before + public void setUp() { + when(greetingService.greet(name)).thenReturn(Mono.just("Greeting Baeldung")); + } + + @Test + public void shouldGreet() { + webClient.get().uri("/greet/{name}", name) + .exchange() + .expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Greeting Baeldung"); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java new file mode 100644 index 0000000000..2400272c6e --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingLiveTest.java @@ -0,0 +1,57 @@ +package com.baeldung.spring.serverconfig; + +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import javax.net.ssl.SSLException; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; +import reactor.netty.http.client.HttpClient; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) +@DirtiesContext +public class GreetingLiveTest { + + private static final String BASE_URL = "https://localhost:8443"; + + private WebTestClient webTestClient; + + @Before + public void setup() throws SSLException { + webTestClient = WebTestClient.bindToServer(getConnector()) + .baseUrl(BASE_URL) + .build(); + } + + @Test + public void shouldGreet() { + final String name = "Baeldung"; + + ResponseSpec response = webTestClient.get() + .uri("/greet/{name}", name) + .exchange(); + + response.expectStatus() + .isOk() + .expectBody(String.class) + .isEqualTo("Greeting Baeldung"); + } + + private ReactorClientHttpConnector getConnector() throws SSLException { + SslContext sslContext = SslContextBuilder + .forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE) + .build(); + HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext)); + return new ReactorClientHttpConnector(httpClient); + } +} diff --git a/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java new file mode 100644 index 0000000000..45918dfd70 --- /dev/null +++ b/spring-5-webflux/src/test/java/com/baeldung/spring/serverconfig/GreetingSkipAutoConfigLiveTest.java @@ -0,0 +1,8 @@ +package com.baeldung.spring.serverconfig; + +import org.springframework.test.context.ActiveProfiles; + +@ActiveProfiles("skipAutoConfig") +public class GreetingSkipAutoConfigLiveTest extends GreetingLiveTest { + +} diff --git a/spring-5-webflux/src/test/resources/logback-test.xml b/spring-5-webflux/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..12cedf5952 --- /dev/null +++ b/spring-5-webflux/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + + %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable + + + + + + +