<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>
--- /dev/null
+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;
+ }
+}
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);
}
-
}
--- /dev/null
+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);
+ }
+ }
+}
--- /dev/null
+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
--- /dev/null
+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;
+ }
+}
--- /dev/null
+org.springframework.boot.env.EnvironmentPostProcessor=\
+ de.juplo.demos.multiplebeans.MultipleBeansEnvironmentPostProcessor
--- /dev/null
+juplo:
+ sites: peter, ute, franz
--- /dev/null
+<!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>
--- /dev/null
+<!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>
--- /dev/null
+<!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>
--- /dev/null
+<!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>
--- /dev/null
+<!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>