From 508a04086767d06b2e6eb32424114c4510569b1f Mon Sep 17 00:00:00 2001 From: Kai Moritz <kai@juplo.de> Date: Fri, 20 Nov 2020 21:40:28 +0100 Subject: [PATCH] Demonstration of multiple dynamically instantiated beans --- pom.xml | 6 +++ .../demos/multiplebeans/HomeController.java | 23 +++++++++ .../MultipleBeansApplication.java | 10 +++- ...pleBeansApplicationContextInitializer.java | 24 +++++++++ ...MultipleBeansEnvironmentPostProcessor.java | 29 +++++++++++ .../demos/multiplebeans/SiteController.java | 26 ++++++++++ src/main/resources/META-INF/spring.factories | 2 + src/main/resources/application.properties | 1 - src/main/resources/application.yml | 2 + src/main/resources/templates/400.html | 15 ++++++ src/main/resources/templates/error.html | 51 +++++++++++++++++++ src/main/resources/templates/home.html | 25 +++++++++ src/main/resources/templates/layout.html | 20 ++++++++ src/main/resources/templates/site.html | 23 +++++++++ 14 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/juplo/demos/multiplebeans/HomeController.java create mode 100644 src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplicationContextInitializer.java create mode 100644 src/main/java/de/juplo/demos/multiplebeans/MultipleBeansEnvironmentPostProcessor.java create mode 100644 src/main/java/de/juplo/demos/multiplebeans/SiteController.java create mode 100644 src/main/resources/META-INF/spring.factories delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/templates/400.html create mode 100644 src/main/resources/templates/error.html create mode 100644 src/main/resources/templates/home.html create mode 100644 src/main/resources/templates/layout.html create mode 100644 src/main/resources/templates/site.html diff --git a/pom.xml b/pom.xml index c5a9621..0c9e4dc 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,12 @@ <artifactId>lombok</artifactId> <optional>true</optional> </dependency> + <dependency> + <groupId>org.webjars</groupId> + <artifactId>bootstrap</artifactId> + <version>4.5.2</version> + <scope>runtime</scope> + </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> diff --git a/src/main/java/de/juplo/demos/multiplebeans/HomeController.java b/src/main/java/de/juplo/demos/multiplebeans/HomeController.java new file mode 100644 index 0000000..5a488cf --- /dev/null +++ b/src/main/java/de/juplo/demos/multiplebeans/HomeController.java @@ -0,0 +1,23 @@ +package de.juplo.demos.multiplebeans; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@RequiredArgsConstructor +public class HomeController implements Controller { + + private final String[] sites; + + + @Override + public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { + + ModelAndView mav = new ModelAndView("home"); + mav.addObject("sites", sites); + return mav; + } +} diff --git a/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplication.java b/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplication.java index 618ba8e..16f82eb 100644 --- a/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplication.java +++ b/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplication.java @@ -1,13 +1,21 @@ package de.juplo.demos.multiplebeans; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class MultipleBeansApplication { + @Bean("/") + public HomeController homeController(@Value("${juplo.sites}")String[] sites) { + + return new HomeController(sites); + } + + public static void main(String[] args) { SpringApplication.run(MultipleBeansApplication.class, args); } - } diff --git a/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplicationContextInitializer.java b/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplicationContextInitializer.java new file mode 100644 index 0000000..28f22df --- /dev/null +++ b/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansApplicationContextInitializer.java @@ -0,0 +1,24 @@ +package de.juplo.demos.multiplebeans; + +import lombok.AllArgsConstructor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; + +@AllArgsConstructor +public class MultipleBeansApplicationContextInitializer + implements + ApplicationContextInitializer<ConfigurableApplicationContext> { + + private final String[] sites; + + + @Override + public void initialize(ConfigurableApplicationContext context) { + ConfigurableListableBeanFactory factory = context.getBeanFactory(); + for (String site : sites) { + SiteController controller = new SiteController(site, "Descrition of site " + site); + factory.registerSingleton("/" + site, controller); + } + } +} diff --git a/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansEnvironmentPostProcessor.java b/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansEnvironmentPostProcessor.java new file mode 100644 index 0000000..0e31555 --- /dev/null +++ b/src/main/java/de/juplo/demos/multiplebeans/MultipleBeansEnvironmentPostProcessor.java @@ -0,0 +1,29 @@ +package de.juplo.demos.multiplebeans; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertySource; + +import java.util.Arrays; + +public class MultipleBeansEnvironmentPostProcessor implements EnvironmentPostProcessor { + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + String sites = null; + for (PropertySource source : environment.getPropertySources()) { + Object found = source.getProperty("juplo.sites"); + if (found != null) + sites = found.toString(); + } + + if (sites == null) + throw new IllegalArgumentException("Parameter juplo.sites is not set!"); + + application.addInitializers(new MultipleBeansApplicationContextInitializer( + Arrays.stream(sites.split(",")) + .map(site -> site.trim()) + .toArray(size -> new String[size]))); + } +} \ No newline at end of file diff --git a/src/main/java/de/juplo/demos/multiplebeans/SiteController.java b/src/main/java/de/juplo/demos/multiplebeans/SiteController.java new file mode 100644 index 0000000..99e1ece --- /dev/null +++ b/src/main/java/de/juplo/demos/multiplebeans/SiteController.java @@ -0,0 +1,26 @@ +package de.juplo.demos.multiplebeans; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.mvc.Controller; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@RequiredArgsConstructor +public class SiteController implements Controller { + + private final String name; + private final String description; + + + public ModelAndView handleRequest( + HttpServletRequest request, + HttpServletResponse response) throws Exception { + + ModelAndView mav = new ModelAndView("site"); + mav.addObject("name", name); + mav.addObject("description", description); + return mav; + } +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..cb8c09a --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + de.juplo.demos.multiplebeans.MultipleBeansEnvironmentPostProcessor diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 8b13789..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..01ec1b0 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,2 @@ +juplo: + sites: peter, ute, franz diff --git a/src/main/resources/templates/400.html b/src/main/resources/templates/400.html new file mode 100644 index 0000000..36ba0c0 --- /dev/null +++ b/src/main/resources/templates/400.html @@ -0,0 +1,15 @@ +<!DOCTYPE HTML> +<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layout :: pagelayout(~{:: title}, ~{:: h1}, ~{:: div.card-text})}"> + <head> + <title th:text="'400: ' + ${exception.getClass().getSimpleName()}">Testing Exception-Handling - Template for 400</title> + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + </head> + <body> + <h1 th:text="'400: ' + ${exception.getClass().getSimpleName()}">Template for 400</h1> + <div class="card-text table"> + <p><strong th:text="'Catched exception: ' + ${exception}">EXCEPTION</strong></p> + <p><a href="#" th:href="@{/}" class="btn btn-primary">Back to HOME</a></p> + </div> + </body> +</html> diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html new file mode 100644 index 0000000..a5e8149 --- /dev/null +++ b/src/main/resources/templates/error.html @@ -0,0 +1,51 @@ +<!doctype html> +<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layout :: pagelayout(~{:: title}, ~{:: h1}, ~{:: table.card-text})}"> + <head> + <title th:text="|${status}: ${error}">XXX: ERROR</title> + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + </head> + <body> + <h1 th:text="|${status}: ${error}">XXX: ERROR</h1> + <table class="card-text table"> + <tbody> + <tr class="border-top-0"> + <th scope="row">Status</th> + <td th:text="${status}">ERROR.STATUS</td> + </tr> + <tr> + <th scope="row">Error</th> + <td th:text="${error}">ERROR.ERROR</td> + </tr> + <tr th:if="!${#strings.isEmpty(message)}"> + <th scope="row">Message</th> + <td th:text="${message}">ERROR.MESSAGE</td> + </tr> + <tr th:if="!${#strings.isEmpty(requestId)}"> + <th class="text-nowrap" scope="row">Request-ID</th> + <td th:text="${requestId}">ERROR.REQUEST_ID</td> + </tr> + <tr> + <th scope="row">Timstamp</th> + <td th:text="${timestamp}">ERROR.TIMESTAMP</td> + </tr> + <tr th:if="!${#strings.isEmpty(path)}"> + <th scope="row">Path</th> + <td th:text="${path}">ERROR.PATH</td> + </tr> + <!--/**--> + <tr th:if="!${#strings.isEmpty(trace)}"> + <th scope="row">Trace</th> + <td> + <div class="overflow-hidden"> + <pre class="overflow-hidden" th:text="${trace}">ERROR.TRACE</pre> + </div> + </td> + </tr> + <!--**/--> + </tbody> + </table> + <p><a href="#" th:href="@{/}" class="btn btn-primary">Back to HOME</a> + </div> + </body> +</html> diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html new file mode 100644 index 0000000..cb75a1d --- /dev/null +++ b/src/main/resources/templates/home.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layout :: pagelayout(~{:: title}, ~{:: h1}, ~{:: div.card-text})}"> + <head> + <title>Home</title> + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + </head> + <body> + <h1>Home</h1> + <div class="card-text"> + <ul> + <li th:each="site : ${sites}"> + <a href="#" th:href="'/' + ${site}" th:text="${site}">SITE</a> + </li> + </ul> + </div> + <div class="card-text"> + <p> + <em> + This page links to the pages, that are served by the dynamically created beans. + </em> + </p> + </div> + </body> +</html> diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html new file mode 100644 index 0000000..3ad68ed --- /dev/null +++ b/src/main/resources/templates/layout.html @@ -0,0 +1,20 @@ +<!doctype html> +<html lang="en" xmlns:th="http://www.thymeleaf.org" th:fragment="pagelayout(title,header,body)"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <title th:replace="${title}">TITLE</title> + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.5.2/css/bootstrap.min.css}"> + </head> + <body> + <nav class="navbar navbar-dark bg-primary navbar-expand navbar-dark flex-column"> + <h2 class="navbar-brand">Demo: Creating Multiple Beans In Spring-Boot Pogrammatically</h2> + </nav> + <main class="container mt-5"> + <div id="content" class="card"> + <div class="card-header"><h1 th:replace="${header}">HEADER</h1></div> + <div class="card-body"><div th:replace="${body}">BODY</div></div> + </div> + </main> + </body> +</html> diff --git a/src/main/resources/templates/site.html b/src/main/resources/templates/site.html new file mode 100644 index 0000000..6ea90f5 --- /dev/null +++ b/src/main/resources/templates/site.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html xmlns:th="http://www.thymeleaf.org" th:replace="~{layout :: pagelayout(~{:: title}, ~{:: h1}, ~{:: div.card-text})}"> + <head> + <title th:text="${name}">SITE-TEMPLATE</title> + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + </head> + <body> + <h1 th:text="${name}">SITE</h1> + <div class="card-text"> + <p th:text="${description}">DESCRIPTION</p> + </div> + <div class="card-text"> + <p> + <em> + Each site is defined in the configuration with name and description inside an array. + This demo shows, how to create multiple beans of the same type based on the configuration. + </em> + </p> + </div> + <div class="card-text">Back <a href="#" th:href="@{/}">Home</a></div> + </body> +</html> -- 2.20.1