├── web
├── src
│ ├── test
│ │ ├── resources
│ │ │ └── application-test.yml
│ │ └── java
│ │ │ └── example
│ │ │ └── api
│ │ │ └── WebApplicationTests.java
│ └── main
│ │ ├── java
│ │ └── example
│ │ │ └── api
│ │ │ ├── config
│ │ │ ├── AppConfiguration.java
│ │ │ ├── LoggerConfiguration.java
│ │ │ └── SwaggerConfiguration.java
│ │ │ ├── WebApplication.java
│ │ │ └── controller
│ │ │ └── v1
│ │ │ └── CustomerController.java
│ │ └── resources
│ │ ├── application-local.yml
│ │ └── application.yml
└── pom.xml
├── core
├── src
│ └── main
│ │ └── java
│ │ └── example
│ │ └── api
│ │ └── core
│ │ ├── entity
│ │ └── package-info.java
│ │ ├── mapper
│ │ └── package-info.java
│ │ ├── repository
│ │ └── package-info.java
│ │ └── service
│ │ └── package-info.java
└── pom.xml
├── common
├── src
│ └── main
│ │ └── java
│ │ └── example
│ │ └── api
│ │ └── common
│ │ ├── util
│ │ └── package-info.java
│ │ ├── exception
│ │ └── package-info.java
│ │ ├── service
│ │ └── package-info.java
│ │ └── dto
│ │ └── package-info.java
└── pom.xml
├── security-lib
├── src
│ └── main
│ │ ├── resources
│ │ └── META-INF
│ │ │ └── spring.factories
│ │ └── java
│ │ └── example
│ │ └── security
│ │ └── SecurityConfiguration.java
└── pom.xml
├── run-docker.sh
├── mail-lib
├── src
│ └── main
│ │ └── java
│ │ └── example
│ │ └── mail
│ │ ├── MailService.java
│ │ ├── EnableMail.java
│ │ ├── MailServiceImpl.java
│ │ ├── MailProperties.java
│ │ └── MailConfiguration.java
└── pom.xml
├── .gitignore
├── Dockerfile
├── pom.xml
└── README.md
/web/src/test/resources/application-test.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/src/main/java/example/api/core/entity/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for the entities.
3 | */
4 | package example.api.entity;
--------------------------------------------------------------------------------
/core/src/main/java/example/api/core/mapper/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for the mappers.
3 | */
4 | package example.api.mapper;
--------------------------------------------------------------------------------
/common/src/main/java/example/api/common/util/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for common utils.
3 | */
4 | package example.api.common.util;
--------------------------------------------------------------------------------
/core/src/main/java/example/api/core/repository/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for the repositories.
3 | */
4 | package example.api.repository;
--------------------------------------------------------------------------------
/core/src/main/java/example/api/core/service/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for the service implementations.
3 | */
4 | package example.api.service;
--------------------------------------------------------------------------------
/common/src/main/java/example/api/common/exception/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for the exceptions.
3 | */
4 | package example.api.common.exception;
--------------------------------------------------------------------------------
/common/src/main/java/example/api/common/service/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for service interfaces.
3 | */
4 | package example.api.common.service;
--------------------------------------------------------------------------------
/common/src/main/java/example/api/common/dto/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Package for the data transfer objects (dto).
3 | */
4 | package example.api.common.dto;
--------------------------------------------------------------------------------
/security-lib/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | example.security.SecurityConfiguration
--------------------------------------------------------------------------------
/web/src/main/java/example/api/config/AppConfiguration.java:
--------------------------------------------------------------------------------
1 | package example.api.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 |
5 | @Configuration
6 | public class AppConfiguration {
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/main/resources/application-local.yml:
--------------------------------------------------------------------------------
1 | logging:
2 | level:
3 | example.api: DEBUG
4 |
5 | # Mail settings
6 | mail:
7 | default-subject: Test subject
8 |
9 | # Swagger settings
10 | swagger:
11 | enabled: true
12 |
13 | # Security settings
14 | security:
15 | enabled: true
--------------------------------------------------------------------------------
/web/src/test/java/example/api/WebApplicationTests.java:
--------------------------------------------------------------------------------
1 | package example.api;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class WebApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/run-docker.sh:
--------------------------------------------------------------------------------
1 | echo " *** Build && Run Docker Image for the application *** "
2 | docker build -t app-image . && docker run --name app-container -p 8080:8080 app-image
3 | # if you want to hardcode the build artifact location with the build command, run:
4 | # docker build --build-arg JAR_FILE=web/target/*.jar -t app-image .
--------------------------------------------------------------------------------
/web/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | servlet:
3 | context-path: /api
4 |
5 | spring:
6 | profiles:
7 | active: local
8 |
9 | logging:
10 | level:
11 | root: INFO
12 |
13 | # Swagger settings
14 | swagger:
15 | enabled: false
16 |
17 | # Security settings
18 | security:
19 | enabled: true
--------------------------------------------------------------------------------
/mail-lib/src/main/java/example/mail/MailService.java:
--------------------------------------------------------------------------------
1 | package example.mail;
2 |
3 | /**
4 | * The interface Mail service.
5 | */
6 | public interface MailService {
7 |
8 | /**
9 | * Send email.
10 | *
11 | * @param subject the subject
12 | * @param text the text
13 | */
14 | void sendEmail(String subject, String text);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/mail-lib/src/main/java/example/mail/EnableMail.java:
--------------------------------------------------------------------------------
1 | package example.mail;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.context.annotation.Import;
5 |
6 | import java.lang.annotation.*;
7 |
8 | /**
9 | * The annotation Enable mail.
10 | */
11 | @Retention(RetentionPolicy.RUNTIME)
12 | @Target({ElementType.TYPE})
13 | @Documented
14 | @Import(MailConfiguration.class)
15 | @Configuration
16 | public @interface EnableMail {
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### MAC ###
8 | .DS_Store
9 |
10 | ### STS ###
11 | .apt_generated
12 | .classpath
13 | .factorypath
14 | .project
15 | .settings
16 | .springBeans
17 | .sts4-cache
18 |
19 | ### IntelliJ IDEA ###
20 | .idea
21 | *.iws
22 | *.iml
23 | *.ipr
24 |
25 | ### NetBeans ###
26 | /nbproject/private/
27 | /nbbuild/
28 | /dist/
29 | /nbdist/
30 | /.nb-gradle/
31 | build/
32 |
33 | ### VS Code ###
34 | .vscode/
35 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM adoptopenjdk/openjdk11:alpine-jre
2 | ARG JAR_FILE=web/target/web-1.0-SNAPSHOT.jar
3 | WORKDIR /opt/app
4 | COPY ${JAR_FILE} app.jar
5 | ENTRYPOINT ["java","-jar","app.jar"]
6 |
7 | #multi stage option
8 | #FROM adoptopenjdk/openjdk11:alpine as mvn-builder
9 | #WORKDIR /workspace/app
10 | #COPY mvnw .
11 | #COPY .mvn .mvn
12 | #COPY pom.xml .
13 | #COPY common common
14 | #COPY core core
15 | #COPY mail-lib mail-lib
16 | #COPY security-lib security-lib
17 | #COPY web web
18 | #RUN ./mvnw package -DskipTests
19 | #
20 | #FROM adoptopenjdk/openjdk11:alpine-jre
21 | #WORKDIR /opt/app
22 | #COPY --from=mvn-builder /workspace/app/web/target/web-1.0-SNAPSHOT.jar /opt/app
23 | #ENTRYPOINT ["java","-jar","web-1.0-SNAPSHOT.jar"]
24 |
--------------------------------------------------------------------------------
/common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | example.api
7 | app
8 | 1.0-SNAPSHOT
9 |
10 | common
11 | 1.0-SNAPSHOT
12 | ${project.groupId}:${project.artifactId}
13 | It's the common application module
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/web/src/main/java/example/api/WebApplication.java:
--------------------------------------------------------------------------------
1 | package example.api;
2 |
3 | import example.mail.EnableMail;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 |
8 | /**
9 | * The Web application boot.
10 | *
11 | * Notes:
12 | * - The security module is automatically imported by the auto configuration if the property security.enabled = true;
13 | * - The mail module is imported using the annotation @EnableMail. However, it can also be imported directly via @Import(MailConfiguration.class);
14 | */
15 | @SpringBootApplication
16 | @EnableMail
17 | public class WebApplication {
18 |
19 | public static void main(String[] args) {
20 | SpringApplication.run(WebApplication.class, args);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | example.api
7 | app
8 | 1.0-SNAPSHOT
9 |
10 | core
11 | 1.0-SNAPSHOT
12 | ${project.groupId}:${project.artifactId}
13 | It's the core application module
14 |
15 |
16 |
17 | example.api
18 | common
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/mail-lib/src/main/java/example/mail/MailServiceImpl.java:
--------------------------------------------------------------------------------
1 | package example.mail;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Service;
7 |
8 | /**
9 | * The type Mail service.
10 | */
11 | @Service
12 | public class MailServiceImpl implements MailService {
13 |
14 | /**
15 | * The constant logger.
16 | */
17 | private static final Logger logger = LoggerFactory.getLogger(MailServiceImpl.class);
18 |
19 | /**
20 | * The Mail properties.
21 | */
22 | @Autowired
23 | private MailProperties mailProperties;
24 |
25 | @Override
26 | public void sendEmail(String subject, String text) {
27 | logger.info("Start sending the email with subject {} and text {}",
28 | subject == null ? mailProperties.getDefaultSubject() : subject, text);
29 | // business logic here
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/web/src/main/java/example/api/config/LoggerConfiguration.java:
--------------------------------------------------------------------------------
1 | package example.api.config;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.beans.factory.InjectionPoint;
6 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.context.annotation.Scope;
10 |
11 | /**
12 | * The type Logger configuration.
13 | */
14 | @Configuration
15 | public class LoggerConfiguration {
16 |
17 | /**
18 | * Logger logger.
19 | *
20 | * @param injectionPoint the injection point
21 | * @return the logger
22 | */
23 | @Bean
24 | @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
25 | public Logger logger(InjectionPoint injectionPoint){
26 | return LoggerFactory.getLogger(injectionPoint.getField().getDeclaringClass());
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/mail-lib/src/main/java/example/mail/MailProperties.java:
--------------------------------------------------------------------------------
1 | package example.mail;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 | import lombok.ToString;
6 | import org.springframework.boot.context.properties.ConfigurationProperties;
7 | import org.springframework.stereotype.Component;
8 | import org.springframework.validation.annotation.Validated;
9 |
10 | import javax.validation.constraints.NotEmpty;
11 |
12 | /**
13 | * The type Mail properties.
14 | *
15 | * Alternatives to register this class as bean in the spring app context:
16 | * a) create a MailConfiguration and use @Bean;
17 | * b) create a MailConfiguration and use @EnableConfigurationProperties(MailProperties.class);
18 | */
19 | @Component
20 | @ConfigurationProperties(prefix = "mail")
21 | @Getter
22 | @Setter
23 | @ToString
24 | @Validated
25 | public class MailProperties {
26 |
27 | /**
28 | * The Default subject.
29 | */
30 | @NotEmpty
31 | private String defaultSubject;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/security-lib/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | example.api
7 | app
8 | 1.0-SNAPSHOT
9 |
10 | example.security
11 | security-lib
12 | 1.0-SNAPSHOT
13 | ${project.groupId}:${project.artifactId}
14 | It's the security lib module
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter-security
20 |
21 |
22 | org.springframework.boot
23 | spring-boot-starter-web
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/mail-lib/src/main/java/example/mail/MailConfiguration.java:
--------------------------------------------------------------------------------
1 | package example.mail;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.context.annotation.ComponentScan;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | import javax.annotation.PostConstruct;
9 |
10 | /**
11 | * The type Mail configuration.
12 | */
13 | @Configuration
14 | @ComponentScan("example.mail")
15 | //@EnableConfigurationProperties(MailModuleProperties.class) -> alternative b)
16 | public class MailConfiguration {
17 |
18 | /**
19 | * The constant logger.
20 | */
21 | private static final Logger logger = LoggerFactory.getLogger(MailConfiguration.class);
22 |
23 | /*@Bean -> to use instead of @ComponentScan
24 | public MailService mailService(){
25 | return new MailServiceImpl();
26 | }*/
27 |
28 | /*@Bean -> alternative a)
29 | @Validated
30 | @ConfigurationProperties(prefix = "mail")
31 | public MailProperties mailProperties(){
32 | return new MailProperties();
33 | }*/
34 |
35 | /**
36 | * Post construct.
37 | */
38 | @PostConstruct
39 | public void postConstruct() {
40 | logger.info("Mail module loaded!");
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/mail-lib/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | example.api
7 | app
8 | 1.0-SNAPSHOT
9 |
10 | example.mail
11 | mail-lib
12 | 1.0-SNAPSHOT
13 | ${project.groupId}:${project.artifactId}
14 | It's the mail lib module
15 |
16 |
17 |
18 | org.springframework.boot
19 | spring-boot-starter
20 |
21 |
22 |
23 | org.projectlombok
24 | lombok
25 | true
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-configuration-processor
30 | true
31 |
32 |
33 |
34 | jakarta.validation
35 | jakarta.validation-api
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/web/src/main/java/example/api/controller/v1/CustomerController.java:
--------------------------------------------------------------------------------
1 | package example.api.controller.v1;
2 |
3 | import example.mail.MailService;
4 | import io.swagger.annotations.Api;
5 | import io.swagger.annotations.ApiOperation;
6 | import org.slf4j.Logger;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.http.ResponseEntity;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RestController;
12 |
13 | /**
14 | * The type Customer controller.
15 | */
16 | @RestController
17 | @RequestMapping("/v1/customer")
18 | @Api(value = "Customer API")
19 | public class CustomerController {
20 |
21 | /**
22 | * The Logger.
23 | */
24 | @Autowired
25 | private Logger logger;
26 |
27 | /**
28 | * The Mail service.
29 | */
30 | @Autowired
31 | private MailService mailService;
32 |
33 | /**
34 | * Guest endpoint response entity.
35 | *
36 | * @return the response entity
37 | */
38 | @ApiOperation(value = "Test endpoint for guest", response = String.class)
39 | @GetMapping("/guest")
40 | public ResponseEntity guestEndpoint() {
41 | logger.info("Entering in guest endpoint");
42 |
43 | // test mail library
44 | mailService.sendEmail(null, "content here");
45 |
46 | return ResponseEntity.ok("Hello from customer api - GUEST");
47 | }
48 |
49 | /**
50 | * Admin endpoint response entity.
51 | *
52 | * @return the response entity
53 | */
54 | @ApiOperation(value = "Test endpoint for admin", response = String.class)
55 | @GetMapping("/admin")
56 | public ResponseEntity adminEndpoint() {
57 | logger.info("Entering in admin endpoint");
58 | return ResponseEntity.ok("Hello from customer api - ADMIN");
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/security-lib/src/main/java/example/security/SecurityConfiguration.java:
--------------------------------------------------------------------------------
1 | package example.security;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9 | import org.springframework.security.config.annotation.web.builders.WebSecurity;
10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
11 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
12 |
13 | import javax.annotation.PostConstruct;
14 |
15 | /**
16 | * The type Security configuration.
17 | */
18 | @Configuration
19 | @ConditionalOnProperty(name = "security.enabled", havingValue = "true")
20 | @EnableWebSecurity
21 | public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
22 |
23 | /**
24 | * The constant logger.
25 | */
26 | private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);
27 |
28 | @Override
29 | protected void configure(HttpSecurity http) throws Exception {
30 | http.httpBasic().and().authorizeRequests()
31 | .antMatchers("/v1/customer/guest/**").hasRole("GUEST")
32 | .antMatchers("/v1/customer/admin/**").hasRole("ADMIN")
33 | .and().csrf().disable();
34 | }
35 |
36 | @Override
37 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
38 | auth.inMemoryAuthentication().withUser("user").password("{noop}password").roles("GUEST");
39 | auth.inMemoryAuthentication().withUser("admin").password("{noop}password").roles("ADMIN");
40 | }
41 |
42 | @Override
43 | public void configure(WebSecurity web) {
44 | web.ignoring().antMatchers("/resources/**");
45 | }
46 |
47 | /**
48 | * Post constructor.
49 | */
50 | @PostConstruct
51 | public void postConstructor() {
52 | logger.info("Security module loaded!");
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/web/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | example.api
7 | app
8 | 1.0-SNAPSHOT
9 |
10 | web
11 | 1.0-SNAPSHOT
12 | ${project.groupId}:${project.artifactId}
13 | It's the web application module
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-starter-web
19 |
20 |
21 |
22 | example.api
23 | core
24 |
25 |
26 |
27 | example.mail
28 | mail-lib
29 |
30 |
31 |
32 | example.security
33 | security-lib
34 |
35 |
36 |
37 | io.springfox
38 | springfox-swagger2
39 |
40 |
41 |
42 | io.springfox
43 | springfox-swagger-ui
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-test
49 | test
50 |
51 |
52 | org.junit.vintage
53 | junit-vintage-engine
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.springframework.boot
63 | spring-boot-maven-plugin
64 |
65 |
66 | false
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/web/src/main/java/example/api/config/SwaggerConfiguration.java:
--------------------------------------------------------------------------------
1 | package example.api.config;
2 |
3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import springfox.documentation.builders.ApiInfoBuilder;
7 | import springfox.documentation.builders.PathSelectors;
8 | import springfox.documentation.builders.RequestHandlerSelectors;
9 | import springfox.documentation.service.*;
10 | import springfox.documentation.spi.DocumentationType;
11 | import springfox.documentation.spi.service.contexts.SecurityContext;
12 | import springfox.documentation.spring.web.plugins.Docket;
13 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
14 |
15 | import java.util.Arrays;
16 |
17 | /**
18 | * The type Swagger configuration.
19 | */
20 | @Configuration
21 | @ConditionalOnProperty(name = "swagger.enabled", havingValue = "true", matchIfMissing = true)
22 | @EnableSwagger2
23 | public class SwaggerConfiguration {
24 |
25 | /**
26 | * Api docket.
27 | *
28 | * @return the docket
29 | */
30 | @Bean
31 | public Docket api() {
32 | return new Docket(DocumentationType.SWAGGER_2)
33 | .select()
34 | .apis(RequestHandlerSelectors.basePackage("example.api.web.controller"))
35 | .paths(PathSelectors.any())
36 | .build()
37 | .useDefaultResponseMessages(false)
38 | .securitySchemes(Arrays.asList(basicAuthScheme()))
39 | .securityContexts(Arrays.asList(securityContext()))
40 | .apiInfo(infoApi());
41 | }
42 |
43 | /**
44 | * Security context security context.
45 | *
46 | * @return the security context
47 | */
48 | private SecurityContext securityContext() {
49 | return SecurityContext.builder()
50 | .securityReferences(Arrays.asList(basicAuthReference()))
51 | .forPaths(PathSelectors.ant("/v1/customer/**"))
52 | .build();
53 | }
54 |
55 | /**
56 | * Basic auth scheme security scheme.
57 | *
58 | * @return the security scheme
59 | */
60 | private SecurityScheme basicAuthScheme() {
61 | return new BasicAuth("basicAuth");
62 | }
63 |
64 | /**
65 | * Basic auth reference security reference.
66 | *
67 | * @return the security reference
68 | */
69 | private SecurityReference basicAuthReference() {
70 | return new SecurityReference("basicAuth", new AuthorizationScope[0]);
71 | }
72 |
73 | /**
74 | * Info api.
75 | *
76 | * @return the api info
77 | */
78 | private ApiInfo infoApi() {
79 | return new ApiInfoBuilder()
80 | .title("Spring Boot Multi Module REST API")
81 | .description("Example API")
82 | .version("1.0.0")
83 | .build();
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.2.4.RELEASE
9 |
10 |
11 |
12 | example.api
13 | app
14 | pom
15 | 1.0-SNAPSHOT
16 | ${project.groupId}:${project.artifactId}
17 | It's a simple example of a multi module project
18 |
19 |
20 |
21 | 1.8
22 | 2.9.2
23 | 1.0-SNAPSHOT
24 | 1.0-SNAPSHOT
25 |
26 |
27 |
28 |
29 |
30 |
31 | ${project.groupId}
32 | common
33 | ${project.version}
34 |
35 |
36 | ${project.groupId}
37 | core
38 | ${project.version}
39 |
40 |
41 | ${project.groupId}
42 | web
43 | ${project.version}
44 |
45 |
46 | example.mail
47 | mail-lib
48 | ${mail.version}
49 |
50 |
51 | example.security
52 | security-lib
53 | ${security.version}
54 |
55 |
56 | io.springfox
57 | springfox-swagger2
58 | ${swagger.version}
59 |
60 |
61 | io.springfox
62 | springfox-swagger-ui
63 | ${swagger.version}
64 |
65 |
66 |
67 |
68 |
69 | mail-lib
70 | security-lib
71 | common
72 | core
73 | web
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring Boot multi-module application example
2 | This project shows you how can you modularize a Spring Boot application with Maven and how can you use some of the modules as libraries in other Spring Boot applications. Note that the project structure of this example is intended to be used to learn and play with these concepts. When you are building a real application you should think what makes sense for your project. For small projects, do not forget the KISS principle. For complex projects, a well-organized application is a must. In any approach, you need to always take into consideration the maintainability of your project.
3 |
4 | **Overview about Spring Boot application context:**
5 |
6 | As you should know the Spring application context contains all the beans that makes up the application (e.g. controllers, services, repositories, etc). You can register beans to your Spring Boot application context using the annotation `@Configuration` in any class in order to act as a beans factory. The annotated classes can contain factory methods annotated with `@Bean` whose return objects are automatically added to the application context by Spring. Another way to register beans is using the annotation `@ComponentScan(basePackages="base.package.to.search")` along with `@Configuration` to specify the packages that you want to be scanned. It will look through all classes in the specified base package (if nothing is specified it will search the current package and all its sub packages) and load an instance of each class that is annotated with one of Spring’s stereotype annotations (e.g. `@Component`, `@Service`, etc) into the application context.
7 |
8 | The `@SpringBootApplication` annotation used in the entry point Spring Boot application class is equivalent to using `@Configuration`, `@EnableAutoConfiguration` and `@ComponentScan`. The auto-configuration feature allows a `@Configuration` class to be automatically discovered by Spring. Additional `@Conditional` annotations can be used to constrain when the auto-configuration should apply.
9 |
10 | **Multi-module project structure:**
11 |
12 | Taking the above overview into account, let's look and take some conclusions about this project structure! As you can see in the code, the Spring Boot entry point application class ([WebApplication.java](/web/src/main/java/example/api/WebApplication.java)) is defined in the *web module* (responsible for the application boot) and it is under the package `example.api`. Therefore, all the Spring configurations and beans/components defined in that package (and in its sub-packages) will be detected and taken into account for the application context. The *core module* and the *common module* are examples of this. On the other hand, the *mail-lib module* and the *security-lib module* are in different packages (`example.mail` /` example.security`) and for that reason we need to have other strategies for importing the Spring configurations and components into the correct application context. These modules can be easily adapted for use in other applications (e.g. imagine that you need to have some libraries shared across multiple applications in your organization/company). Options for importing the modules:
13 |
14 | a) Using `@Import` annotation
15 | - This annotation is used to import specific configuration classes and will import all beans that come with them (declared by `@ComponentScan` or `@Bean` annotations). In the *mail-lib module* a custom annotation `@EnableMail` is being used as a wrapper to add the `@Import(MailConfiguration.class)` annotation that imports our configuration class. This strategy is mainly used for modules that contain business logic.
16 |
17 | b) Using Auto-Configuration
18 | - If you want to load a module automatically instead of hard-coding the import, you can use the Spring Boot’s auto-configuration feature. To make the configuration an auto-configuration, you must list it in the file `META-INF/spring.factories` (check the [spring.factories](/security-lib/src/main/resources/META-INF/spring.factories) file in the *security-lib module*). Spring Boot searches through all `spring.factories` files it finds on the classpath and loads the configurations declared within. This strategy is mainly used for importing technical modules (like security or logging/monitoring features).
19 |
20 | **System requirements**
21 | - JDK 11
22 | - Maven
23 | - Docker
24 |
25 | ## How to build and run
26 | *With docker*:
27 |
28 | Execute the provided script [run-docker.sh](run-docker.sh) or run directly the following commands to build and run the docker image: `docker build -t app-example-image . && docker run --name app-example-container -p 8080:8080 app-example-image`
29 |
30 | *Without docker*:
31 |
32 | Build and generate the artifact file with the maven command `mvn clean package` and then run the maven spring boot plugin
33 | `mvn spring-boot:run` (or the java command `java -jar `).
34 |
35 | The application will be accessible at [http:localhost:8080](http:localhost:8080) (note that the configured application context path is /api).
36 |
37 |
38 | ## References
39 |
40 | [https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/using-boot-using-springbootapplication-annotation.html](https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/using-boot-using-springbootapplication-annotation.html)
41 |
42 | [https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/using-boot-auto-configuration.html](https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/using-boot-auto-configuration.html)
43 |
44 | [https://docs.spring.io/spring-boot/docs/2.1.12.RELEASE/reference/html/boot-features-developing-auto-configuration.html](https://docs.spring.io/spring-boot/docs/2.1.12.RELEASE/reference/html/boot-features-developing-auto-configuration.html)
45 |
46 | [https://reflectoring.io/spring-boot-starter/](https://reflectoring.io/spring-boot-starter/)
47 |
48 | [https://reflectoring.io/spring-boot-modules/](https://reflectoring.io/spring-boot-modules/)
49 |
50 | [https://www.baeldung.com/spring-boot-configuration-metadata](https://www.baeldung.com/spring-boot-configuration-metadata)
51 |
52 | [https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-configuration-metadata.html#configuration-metadata-annotation-processor](https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-configuration-metadata.html#configuration-metadata-annotation-processor)
53 |
54 | [https://plugins.jetbrains.com/plugin/10229-spring-assistant](https://plugins.jetbrains.com/plugin/10229-spring-assistant)
55 |
--------------------------------------------------------------------------------