{{announcement.body}}
{{announcement.title}}

DDD and Spring Boot Multi-Module Maven Project

DZone 's Guide to

DDD and Spring Boot Multi-Module Maven Project

In this post we will go through how to create Multi-Module Maven Project with Spring Boot following Domain-Driven Methodology.

· Java Zone ·
Free Resource

In this post we will go through how to create a Multi-Module Maven Project with Spring Boot following Domain-Driven Methodology.

Here I must confess that I am not being a total DDD purist here adhering to all the concepts but instead just covering the first mile. With this in your arsenal you should be in a position to extend this as per your project needs.

A multi-module project is built from a parent pom that manages a group of sub-modules. The parent pom is located in the project’s root directory and must have the packaging of type pom.

The sub-modules are regular maven projects that have packaging type different from pom, such as jar, war, ear. We have the option of running Maven build on separate module’s pom file or the parent’s pom file. By running the maven build on parent’s pom file all sub-modules will be built.

So, without further ado, let's get going.

Create a Parent Module

Open Eclipse, go to File --> New --> Other --> Maven --> Maven Project and click on Next.

select a wizard

Select "Create a simple project (skip archetype selection)" and click on Next.

new maven project

Input "com.purnima.jain" or something similar to Group Id.

Input "spring-boot-multi-module" or something similar to Artifact Id.

Change the packaging to pom. As this is the parent module, its packaging has to be pom.

Feel free to enter the Name and Description of your artifact.

Since it is a Spring Boot application that we are creating, we will include the following as Parent Project:

  • Group Id: org.springframework.boot
  • Artifact Id: spring-boot-starter-parent
  • Version: 2.2.6.RELEASE

And click on Finish.

new maven project

Create Child Modules

Next, we are going to create 5 sub-modules namely application, controller, domain, service, repository.

  • Child Module application is where your @SpringBootApplication, the Main class, will reside.
  • The controller houses the controller classes that provide REST end-points or similar stuff. This is also the module that houses all the DTOs that will be exposed to the outside world as JSON output from the REST end-points.
  • The domain is where your aggregate, entities, value-objects live along with Service and Repository Interfaces.
  • Service is where your Service implementations live.
  • The repository is where your Repository implementations live.

Let's start with creating the sub-module "application".

Right-click the parent project created above, "spring-boot-multi-module", New --> Other --> Maven Module and click on Next.

maven module

Select "Create a simple project (skip archetype selection)", input the Module name as "application", ensure that the selected "Parent Project" is the one created above and click on Finish.

name module

At this point, go to Windows in the top Toolbar in Eclipse and go to Show View --> Project Explorer. This view is better when working with multi-module projects.

Similarly, create other sub-modules like controller, domain, service, repository.

At this point, your Project Explorer view would look like this:

package explorer

Editing Pom.xml(s)

Edit your parent pom, spring-boot-multi-module/pom.xml, to look like below.

Add the properties section to set the Java version as 11. Properties are inherited from parent to child, so we need not mention Java version in any of our child poms.

Add the dependency spring-boot-starter-web in the dependencies section.

XML
 




x
37


1
<project xmlns="http://maven.apache.org/POM/4.0.0"
2
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
    <modelVersion>4.0.0</modelVersion>
5
 
          
6
    <parent>
7
        <groupId>org.springframework.boot</groupId>
8
        <artifactId>spring-boot-starter-parent</artifactId>
9
        <version>2.2.6.RELEASE</version>
10
    </parent>
11
 
          
12
    <groupId>com.purnima.jain</groupId>
13
    <artifactId>spring-boot-multi-module</artifactId>
14
    <version>0.0.1-SNAPSHOT</version>
15
 
          
16
    <packaging>pom</packaging>
17
 
          
18
    <properties>
19
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20
        <java.version>11</java.version>
21
    </properties>
22
 
          
23
    <dependencies>
24
        <dependency>
25
            <groupId>org.springframework.boot</groupId>
26
            <artifactId>spring-boot-starter-web</artifactId>
27
        </dependency>
28
    </dependencies>
29
 
          
30
    <modules>
31
        <module>application</module>
32
        <module>controller</module>
33
        <module>domain</module>
34
        <module>service</module>
35
        <module>repository</module>
36
    </modules>
37
</project>



Edit your child pom, application/pom.xml, to look like below.

In the dependencies section, add the dependency to controller, service, and repository modules. This is needed for auto-wiring and dependency injection.

XML
 




xxxxxxxxxx
1
31


 
1
<project xmlns="http://maven.apache.org/POM/4.0.0"
2
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
    <modelVersion>4.0.0</modelVersion>
5
 
          
6
    <parent>
7
        <groupId>com.purnima.jain</groupId>
8
        <artifactId>spring-boot-multi-module</artifactId>
9
        <version>0.0.1-SNAPSHOT</version>
10
    </parent>
11
 
          
12
    <artifactId>application</artifactId>
13
 
          
14
    <dependencies>
15
        <dependency>
16
            <groupId>com.purnima.jain</groupId>
17
            <artifactId>controller</artifactId>
18
            <version>${project.version}</version>
19
        </dependency>
20
        <dependency>
21
            <groupId>com.purnima.jain</groupId>
22
            <artifactId>service</artifactId>
23
            <version>${project.version}</version>
24
        </dependency>
25
        <dependency>
26
            <groupId>com.purnima.jain</groupId>
27
            <artifactId>repository</artifactId>
28
            <version>${project.version}</version>
29
        </dependency>
30
    </dependencies>
31
</project>



Edit your child pom controller/pom.xml to look like below.

In the dependencies section, add the dependency to the domain because the domain is where your Service Interfaces would reside which Controller will have to call.

XML
 




xxxxxxxxxx
1
21


1
<project xmlns="http://maven.apache.org/POM/4.0.0"
2
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
    <modelVersion>4.0.0</modelVersion>
5
 
          
6
    <parent>
7
        <groupId>com.purnima.jain</groupId>
8
        <artifactId>spring-boot-multi-module</artifactId>
9
        <version>0.0.1-SNAPSHOT</version>
10
    </parent>
11
 
          
12
    <artifactId>controller</artifactId>
13
 
          
14
    <dependencies>
15
        <dependency>
16
            <groupId>com.purnima.jain</groupId>
17
            <artifactId>domain</artifactId>
18
            <version>${project.version}</version>
19
        </dependency>
20
    </dependencies>
21
</project>



Leave your child pom domain/pom.xml as-it-is, no changes needed here.

XML
 




xxxxxxxxxx
1
14


 
1
<project xmlns="http://maven.apache.org/POM/4.0.0"
2
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
    <modelVersion>4.0.0</modelVersion>
5
 
          
6
    <parent>
7
        <groupId>com.purnima.jain</groupId>
8
        <artifactId>spring-boot-multi-module</artifactId>
9
        <version>0.0.1-SNAPSHOT</version>
10
    </parent>
11
 
          
12
    <artifactId>domain</artifactId>
13
 
          
14
</project>



Edit your child pom repository/pom.xml to look like below.

In the dependencies section, add the dependency to the domain because the domain is where your Repository Interfaces would reside which Repository implementations will have to implement.

XML
 




xxxxxxxxxx
1
21


1
<project xmlns="http://maven.apache.org/POM/4.0.0"
2
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
    <modelVersion>4.0.0</modelVersion>
5
 
          
6
    <parent>
7
        <groupId>com.purnima.jain</groupId>
8
        <artifactId>spring-boot-multi-module</artifactId>
9
        <version>0.0.1-SNAPSHOT</version>
10
    </parent>
11
 
          
12
    <artifactId>repository</artifactId>
13
 
          
14
    <dependencies>
15
        <dependency>
16
            <groupId>com.purnima.jain</groupId>
17
            <artifactId>domain</artifactId>
18
            <version>${project.version}</version>
19
        </dependency>
20
    </dependencies>
21
</project>



Edit your child pom service/pom.xml to look like below.

In the dependencies section, add the dependency to the domain because the domain is where your Service Interfaces would reside which Service implementations will have to implement.

XML
 




xxxxxxxxxx
1
21


1
<project xmlns="http://maven.apache.org/POM/4.0.0"
2
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
    <modelVersion>4.0.0</modelVersion>
5
 
          
6
    <parent>
7
        <groupId>com.purnima.jain</groupId>
8
        <artifactId>spring-boot-multi-module</artifactId>
9
        <version>0.0.1-SNAPSHOT</version>
10
    </parent>
11
 
          
12
    <artifactId>service</artifactId>
13
 
          
14
    <dependencies>
15
        <dependency>
16
            <groupId>com.purnima.jain</groupId>
17
            <artifactId>domain</artifactId>
18
            <version>${project.version}</version>
19
        </dependency>
20
    </dependencies>
21
</project>



Our multi-module-maven Spring Boot project is created.

Seeing It in Action

To see it in action, we will have to add some classes in the various modules.

Go to the application module and create a package "com.purnima.jain.customer" in src/main/java and create the main @SpringBootApplication class here called CustomerApplication.java.

Java
 




xxxxxxxxxx
1
19


1
package com.purnima.jain.customer;
2
 
          
3
import org.slf4j.Logger;
4
import org.slf4j.LoggerFactory;
5
import org.springframework.boot.SpringApplication;
6
import org.springframework.boot.autoconfigure.SpringBootApplication;
7
 
          
8
@SpringBootApplication
9
public class CustomerApplication {
10
 
          
11
    private static final Logger logger = LoggerFactory.getLogger(CustomerApplication.class);
12
 
          
13
    public static void main(String[] args) {
14
        SpringApplication.run(CustomerApplication.class, args);
15
        logger.info("CustomerApplication Started........");
16
    }
17
 
          
18
}



Go to the controller module and create a package "com.purnima.jain.customer.controller" in src/main/java and create your controller here:

Java
 




xxxxxxxxxx
1
28


 
1
package com.purnima.jain.customer.controller;
2
 
          
3
import org.slf4j.Logger;
4
import org.slf4j.LoggerFactory;
5
import org.springframework.beans.factory.annotation.Autowired;
6
import org.springframework.web.bind.annotation.GetMapping;
7
import org.springframework.web.bind.annotation.PathVariable;
8
import org.springframework.web.bind.annotation.RestController;
9
 
          
10
import com.purnima.jain.customer.domain.aggregate.Customer;
11
import com.purnima.jain.customer.domain.service.CustomerService;
12
 
          
13
@RestController
14
public class CustomerController {
15
 
          
16
    private static final Logger logger = LoggerFactory.getLogger(CustomerController.class);
17
 
          
18
    @Autowired
19
    private CustomerService customerService;
20
 
          
21
    @GetMapping("customer/{customerId}")
22
    public Customer getCustomer(@PathVariable Integer customerId) {
23
        logger.info("Inside CustomerController........");
24
        return customerService.getCustomerById(customerId);
25
    }
26
 
          
27
}



Go to domain module and create a package "com.purnima.jain.customer.domain.aggregate" in src/main/java and create your Aggregate here:

Java
 




xxxxxxxxxx
1
23


 
1
package com.purnima.jain.customer.domain.aggregate;
2
 
          
3
public class Customer {
4
 
          
5
    private Integer customerId;
6
    private String customerName;
7
 
          
8
    public Customer(Integer customerId, String customerName) {
9
        super();
10
        this.customerId = customerId;
11
        this.customerName = customerName;
12
    }
13
 
          
14
    public Integer getCustomerId() {
15
        return customerId;
16
    }
17
 
          
18
    public String getCustomerName() {
19
        return customerName;
20
    }
21
 
          
22
}



In the same domain module, create another package "com.purnima.jain.customer.domain.service" in src/main/java and create your Service interface here:

Java
 




xxxxxxxxxx
1
10
9


 
1
package com.purnima.jain.customer.domain.service;
2
 
          
3
import com.purnima.jain.customer.domain.aggregate.Customer;
4
 
          
5
public interface CustomerService {
6
 
          
7
    public Customer getCustomerById(Integer customerId);
8
 
          
9
}



In the same domain module, create another package "com.purnima.jain.customer.domain.repository" in src/main/java and create your Repository interface here:

Java
 




xxxxxxxxxx
1
10
9


 
1
package com.purnima.jain.customer.domain.repository;
2
 
          
3
import com.purnima.jain.customer.domain.aggregate.Customer;
4
 
          
5
public interface CustomerRepository {
6
 
          
7
    public Customer getCustomerById(Integer customerId);
8
 
          
9
}



Go to the service module and create a package "com.purnima.jain.customer.service.implementation" in src/main/java and create your service implementation here:

Java
 




xxxxxxxxxx
1
28


1
package com.purnima.jain.customer.service.implementation;
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
import com.purnima.jain.customer.domain.aggregate.Customer;
9
import com.purnima.jain.customer.domain.repository.CustomerRepository;
10
import com.purnima.jain.customer.domain.service.CustomerService;
11
 
          
12
@Service
13
public class CustomerServiceImpl implements CustomerService {
14
 
          
15
    private static final Logger logger = LoggerFactory.getLogger(CustomerServiceImpl.class);
16
 
          
17
    @Autowired
18
    private CustomerRepository customerRepository;
19
 
          
20
    @Override
21
    public Customer getCustomerById(Integer customerId) {
22
        logger.info("Inside CustomerServiceImpl........");
23
        Customer customer = customerRepository.getCustomerById(customerId);
24
        return customer;
25
    }
26
 
          
27
}



Go to the repository module and create a package "com.purnima.jain.customer.repository.implementation" in src/main/java and create your repository implementation here:

Java
 




xxxxxxxxxx
1
24


1
package com.purnima.jain.customer.repository.implementation;
2
 
          
3
import org.slf4j.Logger;
4
import org.slf4j.LoggerFactory;
5
import org.springframework.stereotype.Repository;
6
 
          
7
import com.purnima.jain.customer.domain.aggregate.Customer;
8
import com.purnima.jain.customer.domain.repository.CustomerRepository;
9
 
          
10
@Repository
11
public class CustomerRepositoryImpl implements CustomerRepository {
12
    
13
    private static final Logger logger = LoggerFactory.getLogger(CustomerRepositoryImpl.class);
14
 
          
15
    @Override
16
    public Customer getCustomerById(Integer customerId) {
17
        logger.info("Inside CustomerRepositoryImpl........");
18
        // Replace this code to retrieve from database
19
        Customer customer = new Customer(100, "A New Customer");
20
        return customer;
21
    }
22
 
          
23
}



Once all of this is done, run your Main class in the application module, CustomerApplication.java and you should see your code running.

To test it from a browser, go to http://localhost:8080/customer/100

You should see the JSON representation of Customers in the browser.

Source Code

You can download the source-code here.

Topics:
ddd, java, maven project structure, spring boot

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}