├── 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 | --------------------------------------------------------------------------------