Migrate WebFlux sample to Boot
Closes gh-923
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
<suppressions>
|
||||
<suppress files=".+Application\.java" checks="HideUtilityClassConstructor"/>
|
||||
<suppress files=".+Configuration\.java" checks="HideUtilityClassConstructor"/>
|
||||
<suppress files=".+SSEFluxWebConfig\.java" checks="RegexpHeader"/>
|
||||
|
||||
<suppress files="[\\/]src[\\/]test[\\/]java[\\/]" checks="Javadoc"/>
|
||||
<suppress files="[\\/]src[\\/]integration-test[\\/]java[\\/]" checks="Javadoc"/>
|
||||
|
||||
@@ -20,36 +20,18 @@ dependencyManagement {
|
||||
entry 'testcontainers'
|
||||
}
|
||||
|
||||
dependency 'ch.qos.logback:logback-classic:1.2.3'
|
||||
dependency 'com.h2database:h2:1.4.196'
|
||||
dependency 'com.maxmind.geoip2:geoip2:2.3.1'
|
||||
dependency 'commons-codec:commons-codec:1.11'
|
||||
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
|
||||
dependency 'io.lettuce:lettuce-core:5.0.0.RELEASE'
|
||||
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1'
|
||||
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02'
|
||||
dependency 'javax.servlet:javax.servlet-api:3.1.0'
|
||||
dependency 'junit:junit:4.12'
|
||||
dependency 'mysql:mysql-connector-java:5.1.44'
|
||||
dependency 'org.apache.derby:derby:10.14.1.0'
|
||||
dependency 'org.apache.httpcomponents:httpclient:4.5.3'
|
||||
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
|
||||
dependency 'org.assertj:assertj-core:3.8.0'
|
||||
dependency 'org.hsqldb:hsqldb:2.4.0'
|
||||
dependency 'org.mariadb.jdbc:mariadb-java-client:2.1.2'
|
||||
dependency 'org.mockito:mockito-core:2.11.0'
|
||||
dependency 'org.postgresql:postgresql:42.1.4'
|
||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.27'
|
||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.25'
|
||||
dependency 'org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.1.RELEASE'
|
||||
dependency 'org.thymeleaf:thymeleaf-spring5:3.0.8.RELEASE'
|
||||
dependency 'org.webjars:bootstrap:2.3.2'
|
||||
dependency 'org.webjars:html5shiv:3.7.3'
|
||||
dependency 'org.webjars:jquery:1.12.4'
|
||||
dependency 'org.webjars:knockout:2.3.0'
|
||||
dependency 'org.webjars:sockjs-client:0.3.4'
|
||||
dependency 'org.webjars:stomp-websocket:2.3.0'
|
||||
dependency 'org.webjars:webjars-taglib:0.3'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample-boot'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-redis')
|
||||
compile "org.springframework.boot:spring-boot-starter-webflux"
|
||||
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
|
||||
compile "org.springframework.boot:spring-boot-starter-data-redis"
|
||||
compile "org.springframework.boot:spring-boot-devtools"
|
||||
compile 'org.webjars:bootstrap'
|
||||
|
||||
testCompile "org.springframework.boot:spring-boot-starter-test"
|
||||
|
||||
integrationTestCompile seleniumDependencies
|
||||
integrationTestCompile "org.testcontainers:testcontainers"
|
||||
}
|
||||
@@ -16,21 +16,26 @@
|
||||
|
||||
package sample;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import sample.pages.HomePage;
|
||||
import sample.pages.HomePage.Attribute;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -40,11 +45,18 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = HelloWebfluxApplication.class)
|
||||
@TestPropertySource(properties = { "spring.profiles.active=embedded-redis", "server.port=0" })
|
||||
@SpringBootTest(classes = HelloWebFluxApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@ContextConfiguration(initializers = AttributeTests.Initializer.class)
|
||||
public class AttributeTests {
|
||||
@Value("#{@nettyContext.address().getPort()}")
|
||||
int port;
|
||||
|
||||
private static final String DOCKER_IMAGE = "redis:4.0.2";
|
||||
|
||||
@ClassRule
|
||||
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
|
||||
.withExposedPorts(6379);
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
@@ -87,4 +99,18 @@ public class AttributeTests {
|
||||
assertThat(row.getAttributeValue()).isEqualTo("b");
|
||||
}
|
||||
|
||||
static class Initializer
|
||||
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
@Override
|
||||
public void initialize(
|
||||
ConfigurableApplicationContext configurableApplicationContext) {
|
||||
TestPropertyValues
|
||||
.of("spring.redis.host=" + redisContainer.getContainerIpAddress(),
|
||||
"spring.redis.port=" + redisContainer.getFirstMappedPort())
|
||||
.applyTo(configurableApplicationContext.getEnvironment());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,19 +16,17 @@
|
||||
|
||||
package sample;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.session.data.redis.config.annotation.web.server.EnableRedisWebSession;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@Import(EmbeddedRedisConfig.class)
|
||||
// tag::class[]
|
||||
@EnableRedisWebSession
|
||||
public class HelloWebfluxSessionConfig {
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class HelloWebFluxApplication {
|
||||
|
||||
@Bean
|
||||
public LettuceConnectionFactory lettuceConnectionFactory() {
|
||||
return new LettuceConnectionFactory();
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HelloWebFluxApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
// end::class[]
|
||||
BIN
samples/boot/webflux/src/main/resources/static/favicon.ico
Normal file
BIN
samples/boot/webflux/src/main/resources/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
18
samples/gradle/dependency-management.gradle
Normal file
18
samples/gradle/dependency-management.gradle
Normal file
@@ -0,0 +1,18 @@
|
||||
dependencyManagement {
|
||||
dependencies {
|
||||
dependency 'ch.qos.logback:logback-classic:1.2.3'
|
||||
dependency 'com.maxmind.geoip2:geoip2:2.3.1'
|
||||
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1'
|
||||
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02'
|
||||
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
|
||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.25'
|
||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.25'
|
||||
dependency 'org.webjars:bootstrap:2.3.2'
|
||||
dependency 'org.webjars:html5shiv:3.7.3'
|
||||
dependency 'org.webjars:jquery:1.12.4'
|
||||
dependency 'org.webjars:knockout:2.3.0'
|
||||
dependency 'org.webjars:sockjs-client:0.3.4'
|
||||
dependency 'org.webjars:stomp-websocket:2.3.0'
|
||||
dependency 'org.webjars:webjars-taglib:0.3'
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
apply plugin: 'io.spring.convention.spring-sample'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-session-data-redis')
|
||||
compile 'io.lettuce:lettuce-core'
|
||||
compile 'io.netty:netty-buffer'
|
||||
compile 'io.projectreactor.ipc:reactor-netty'
|
||||
compile 'org.springframework:spring-context'
|
||||
compile 'org.springframework:spring-web'
|
||||
compile 'org.springframework:spring-webflux'
|
||||
compile 'org.thymeleaf.extras:thymeleaf-extras-java8time'
|
||||
compile 'org.thymeleaf:thymeleaf-spring5'
|
||||
compile 'org.webjars:bootstrap'
|
||||
compile 'org.webjars:webjars-taglib'
|
||||
compile jstlDependencies
|
||||
compile slf4jDependencies
|
||||
compile 'org.testcontainers:testcontainers'
|
||||
|
||||
testCompile 'junit:junit'
|
||||
testCompile 'org.assertj:assertj-core'
|
||||
|
||||
integrationTestCompile seleniumDependencies
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
|
||||
@Configuration
|
||||
@Profile("embedded-redis")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.2";
|
||||
|
||||
@Bean(initMethod = "start")
|
||||
public GenericContainer redisContainer() {
|
||||
return new GenericContainer(REDIS_DOCKER_IMAGE) {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
try {
|
||||
this.dockerClient.close();
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}.withExposedPorts(6379);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public LettuceConnectionFactory redisConnectionFactory() {
|
||||
return new LettuceConnectionFactory(redisContainer().getContainerIpAddress(),
|
||||
redisContainer().getFirstMappedPort());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import reactor.ipc.netty.NettyContext;
|
||||
import reactor.ipc.netty.http.server.HttpServer;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.server.reactive.HttpHandler;
|
||||
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebFlux
|
||||
@ComponentScan
|
||||
public class HelloWebfluxApplication {
|
||||
@Value("${server.port:8080}")
|
||||
private int port = 8080;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
HelloWebfluxApplication.class)) {
|
||||
context.getBean(NettyContext.class).onClose().block();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NettyContext nettyContext(ApplicationContext context) {
|
||||
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context).build();
|
||||
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
|
||||
HttpServer httpServer = HttpServer.create("localhost", this.port);
|
||||
return httpServer.newHandler(adapter).block();
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* =============================================================================
|
||||
*
|
||||
* Copyright (c) 2011-2014, The THYMELEAF team (http://www.thymeleaf.org)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* =============================================================================
|
||||
*/
|
||||
package sample;
|
||||
|
||||
import org.thymeleaf.spring5.ISpringWebFluxTemplateEngine;
|
||||
import org.thymeleaf.spring5.SpringWebFluxTemplateEngine;
|
||||
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
|
||||
import org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver;
|
||||
import org.thymeleaf.templatemode.TemplateMode;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SSEFluxWebConfig {
|
||||
|
||||
// TODO * Once there is a Spring Boot starter for thymeleaf-spring5, there would be no
|
||||
// need to have
|
||||
// TODO that @EnableConfigurationProperties annotation or use it for declaring the
|
||||
// beans down in the
|
||||
// TODO "thymeleaf" section below.
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public SSEFluxWebConfig(final ApplicationContext applicationContext) {
|
||||
super();
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* -------------------------------------- THYMELEAF CONFIGURATION
|
||||
* --------------------------------------
|
||||
*/
|
||||
|
||||
// TODO * If there was a Spring Boot starter for thymeleaf-spring5 most probably some
|
||||
// or all of these
|
||||
// TODO resolver and engine beans would not need to be specifically declared here.
|
||||
|
||||
@Bean
|
||||
public SpringResourceTemplateResolver thymeleafTemplateResolver() {
|
||||
|
||||
final SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setApplicationContext(this.applicationContext);
|
||||
resolver.setPrefix("classpath:/templates/");
|
||||
resolver.setSuffix(".html");
|
||||
resolver.setTemplateMode(TemplateMode.HTML);
|
||||
resolver.setCacheable(false);
|
||||
resolver.setCheckExistence(true);
|
||||
return resolver;
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ISpringWebFluxTemplateEngine thymeleafTemplateEngine() {
|
||||
// We override here the SpringTemplateEngine instance that would otherwise be
|
||||
// instantiated by
|
||||
// Spring Boot because we want to apply the SpringWebFlux-specific context
|
||||
// factory, link builder...
|
||||
final SpringWebFluxTemplateEngine templateEngine = new SpringWebFluxTemplateEngine();
|
||||
templateEngine.setTemplateResolver(thymeleafTemplateResolver());
|
||||
return templateEngine;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ThymeleafReactiveViewResolver thymeleafChunkedAndDataDrivenViewResolver() {
|
||||
final ThymeleafReactiveViewResolver viewResolver = new ThymeleafReactiveViewResolver();
|
||||
viewResolver.setTemplateEngine(thymeleafTemplateEngine());
|
||||
viewResolver.setOrder(1);
|
||||
viewResolver.setResponseMaxChunkSizeBytes(8192); // OUTPUT BUFFER size limit
|
||||
return viewResolver;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package sample;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.config.ViewResolverRegistry;
|
||||
import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@Configuration
|
||||
public class ThymeleafWebfluxConfig implements WebFluxConfigurer {
|
||||
|
||||
@Autowired(required = false)
|
||||
List<ViewResolver> views = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void configureViewResolvers(ViewResolverRegistry registry) {
|
||||
for (ViewResolver view : this.views) {
|
||||
registry.viewResolver(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- <logger name="org.springframework.security" level="DEBUG"/> -->
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user