Spring – Project Modules
Last Updated :
09 Jan, 2023
Every Spring Boot project has several modules and each module match some application layer (service layer, repository layer, web layer, model, etc..). In this article, let us see a maven-driven project as an example for showing Project Modules.
Example
pom.xml (overall project level)
XML
<? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
< modelVersion >4.0.0</ modelVersion >
< parent >
< groupId >io.spring.platform</ groupId >
< artifactId >platform-bom</ artifactId >
< version >2.0.1.RELEASE</ version >
</ parent >
< groupId >gfg.multimodule</ groupId >
< artifactId >gfg.multimodule</ artifactId >
< version >0.0.1-SNAPSHOT</ version >
< packaging >pom</ packaging >
< name >Parent - Pom Aggregator</ name >
< description >This pom is a maven aggregator that contains all application modules. Also, include all
common dependencies needed by more than one module. Dependencies are defined without version because
this project has defined Spring IO Platform as parent.</ description >
< properties >
< java.version >1.6</ java.version >
</ properties >
< modules >
< module >model</ module >
< module >repository</ module >
< module >service-api</ module >
< module >service-impl</ module >
< module >application</ module >
</ modules >
< dependencies >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter</ artifactId >
</ dependency >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-data-jpa</ artifactId >
</ dependency >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-test</ artifactId >
< scope >test</ scope >
</ dependency >
</ dependencies >
</ project >
|
This sample project is containing the below modules
application (Here the starting point of the spring boot application is kept and it will also contain rendering pages)
Let us see the key important files
GfgWebJspApplication.java
Java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GfgWebJspApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(GfgWebJspApplication. class , args);
}
}
|
WelcomeController.java
Java
import gfg.multimodule.domain.entity.SalaryAccount;
import gfg.multimodule.service.api.EmployeeAccountService;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class WelcomeController {
@Value ( "${application.message:Hello World}" )
private String message = "Hello World" ;
@Autowired
protected EmployeeAccountService accountService;
@RequestMapping ( "/" )
public String welcome(Map<String, Object> model)
{
SalaryAccount account
= accountService.findOne( "100" );
if (account == null ) {
model.put( "message" , "Error getting account!" );
model.put( "account" , "" );
return "welcome/show" ;
}
String accountInfo
= "Your account number is " .concat(
account.getEmployeeAccountNumber());
model.put( "message" , this .message);
model.put( "account" , accountInfo);
return "welcome/show" ;
}
@RequestMapping ( "foo" )
public String foo(Map<String, Object> model)
{
throw new RuntimeException( "Foo" );
}
}
|
show.html (Once the account is available, we can see the output from show.html)
HTML
<!DOCTYPE HTML>
< head >
< title >Spring Boot Multimodule</ title >
< meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" />
< style >
#orangerow
{
background:orange;
font:17 px "Times New Roman", serif;
color:#000000;
}
#yellowrow
{
background:yellow;
font:17 px "Times New Roman", serif;
color:#000000;
}
</ style >
</ head >
< body >
< table border = "1" >
< tr id = "yellowrow" >
< td >
Welcome Message
</ td >
< td >
Account Details
</ td >
</ tr >
< tr id = "orangerow" >
< td >
< span th:text = "${message}" />
</ td >
< td >
< span th:text = "${account}" />
</ td >
</ tr >
</ table >
</ body >
</ html >
|
For this application folder, we need to have a specific pom.xml that will show the dependencies for this module
application -> pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
< modelVersion >4.0.0</ modelVersion >
< parent >
< groupId >gfg.multimodule</ groupId >
< artifactId >gfg.multimodule</ artifactId >
< version >0.0.1-SNAPSHOT</ version >
</ parent >
< artifactId >gfg.multimodule.application</ artifactId >
< packaging >jar</ packaging >
< name >Project Module - Application</ name >
< description >This is the main module of the project. It contains Application.java class, that contains main method,
necessary to run Spring Boot applications. It contains all necessary application configuration properties.
It contains all web controllers, views and web resources. It include Service Implementation module
as dependency that contains Model Module, Repository Module and Service Api Module. </ description >
< dependencies >
< dependency >
< groupId >gfg.multimodule</ groupId >
< artifactId >gfg.multimodule.service.impl</ artifactId >
< version >${project.version}</ version >
</ dependency >
< dependency >
< groupId >org.apache.tomcat.embed</ groupId >
< artifactId >tomcat-embed-jasper</ artifactId >
< scope >provided</ scope >
</ dependency >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-web</ artifactId >
</ dependency >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-thymeleaf</ artifactId >
</ dependency >
</ dependencies >
< build >
< plugins >
< plugin >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-maven-plugin</ artifactId >
</ plugin >
</ plugins >
</ build >
</ project >
|
Next module that we are going to see as a model (Here we will be having our POJO/entity classes and their related details).
SalaryAccount.java
Java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class SalaryAccount {
@Id
@GeneratedValue (strategy = GenerationType.AUTO)
private Long employeeAccountId;
private String employeeAccountNumber;
private String type;
private String creditCardNumber;
public SalaryAccount() {}
public SalaryAccount(Long employeeAccountId,
String employeeAccountNumber)
{
this .employeeAccountNumber = employeeAccountNumber;
this .employeeAccountId = employeeAccountId;
}
public Long getEmployeeAccountId()
{
return employeeAccountId;
}
public void setEmployeeAccountId(Long employeeAccountId)
{
this .employeeAccountId = employeeAccountId;
}
public String getEmployeeAccountNumber()
{
return employeeAccountNumber;
}
public void
setEmployeeAccountNumber(String employeeAccountNumber)
{
this .employeeAccountNumber = employeeAccountNumber;
}
public String getType() { return type; }
public void setType(String type) { this .type = type; }
public String getCreditCardNumber()
{
return creditCardNumber;
}
public void setCreditCardNumber(String creditCardNumber)
{
this .creditCardNumber = creditCardNumber;
}
}
|
model -> pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
< modelVersion >4.0.0</ modelVersion >
< parent >
< groupId >gfg.multimodule</ groupId >
< artifactId >gfg.multimodule</ artifactId >
< version >0.0.1-SNAPSHOT</ version >
</ parent >
< artifactId >gfg.multimodule.model</ artifactId >
< packaging >jar</ packaging >
< name >Project Module - Model</ name >
< description >Module that contains all Entities and Visual Objects
to be used in the project. It doesn't have any dependencies.</ description >
</ project >
|
Next, let us see the repository module. This is the module where we can have our CRUD-related operations interface can be written. Usually, it will have searching/inserting/updating/deleting
SalaryAccountRepository.java
Java
import gfg.multimodule.domain.entity.SalaryAccount;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SalaryAccountRepository
extends CrudRepository<SalaryAccount, Long> {
SalaryAccount findByEmployeeAccountNumber(
String employeeAccountNumber);
}
|
pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
< modelVersion >4.0.0</ modelVersion >
< parent >
< groupId >gfg.multimodule</ groupId >
< artifactId >gfg.multimodule</ artifactId >
< version >0.0.1-SNAPSHOT</ version >
</ parent >
< artifactId >gfg.multimodule.repository</ artifactId >
< packaging >jar</ packaging >
< name >Project Module - Repository</ name >
< description >Module that contains all repositories to be used in the project.
Depends of Model Module.</ description >
< dependencies >
< dependency >
< groupId >gfg.multimodule</ groupId >
< artifactId >gfg.multimodule.model</ artifactId >
< version >${project.version}</ version >
</ dependency >
< dependency >
< groupId >org.hsqldb</ groupId >
< artifactId >hsqldb</ artifactId >
< scope >runtime</ scope >
</ dependency >
</ dependencies >
</ project >
|
The next one is service-api. Business logic-related methods are introduced here
Important key files
EmployeeAccountService.java
Java
package gfg.multimodule.service.api;
import gfg.multimodule.domain.entity.SalaryAccount;
import java.util.List;
public interface EmployeeAccountService {
SalaryAccount findOne(String number)
throws EmployeeAccountNotFoundException;
SalaryAccount
createAccountByEmployeeAccountNumber(String number);
}
|
EmployeeAccountNotFoundException.java
Java
public class EmployeeAccountNotFoundException
extends RuntimeException {
private static final long serialVersionUID
= -3891534644498421234L;
public EmployeeAccountNotFoundException(
String accountId)
{
super ( "No such account with id: " + accountId);
}
}
|
The final one is the implementation one. The service-impl This will implement the service methods (business logic requirements) and real implementation is getting done here
EmployeeAccountServiceImpl.java
Java
import gfg.multimodule.domain.entity.SalaryAccount;
import gfg.multimodule.repository.SalaryAccountRepository;
import gfg.multimodule.service.api.EmployeeAccountService;
import gfg.multimodule.service.api.EmployeeAccountNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class EmployeeAccountServiceImpl
implements EmployeeAccountService {
@Value ( "${dummy.type}" ) private String dummyType;
@Autowired
private SalaryAccountRepository accountRepository;
@Override
public SalaryAccount
findOne(String employeeAccountNumber)
throws EmployeeAccountNotFoundException
{
if (employeeAccountNumber.equals( "0000" )) {
throw new EmployeeAccountNotFoundException(
"0000" );
}
SalaryAccount salaryAccount
= accountRepository.findByEmployeeAccountNumber(
employeeAccountNumber);
if (salaryAccount == null ) {
salaryAccount
= createAccountByEmployeeAccountNumber(
employeeAccountNumber);
}
return salaryAccount;
}
@Override
public SalaryAccount
createAccountByEmployeeAccountNumber(
String employeeAccountNumber)
{
SalaryAccount account = new SalaryAccount();
account.setEmployeeAccountNumber(
employeeAccountNumber);
return accountRepository.save(account);
}
public String getDummyType() { return dummyType; }
public void setDummyType(String dummyType)
{
this .dummyType = dummyType;
}
}
|
Now let us see how to run the whole project. “mvn clean install” has to be given where the project got hosted (parent folder where pom,xml) present
Now we need to step ahead to the application folder and execute it as mvn spring-boot:run
On successful startup (Tomcat dependency is given and it is running on port 8080)
http://localhost:8080/
We can able to see as
By combining different project modules, as a maven project, we need to include all the modules and all the required dependencies need to be given, then the whole project is run successfully and we will get the output as above.
Share your thoughts in the comments
Please Login to comment...