Spring Boot Billing System Architecture design, registration flow code walk-thru practical demo

Spring Boot Billing System Architecture design, registration flow code walk-thru practical demo

Please watch this full video for the Billing System code walk-thru and System design and demo
https://youtu.be/PlGqs9XTSqc

Presentation Layer

The following are part of the Presentation layer component.
com.itgarden.controller and com.itgarden.dto
The Controller package contains only the Controller class where we can implement all Rest end-point
The presentation layer focused only on Client-side logic which related to Presentation Layer. For Example. It handles Request, Response data, and Client Headers, etc.

We have two main Components in Client-side which are RestController class where we implementing the Rest Endpoint and Value object which known as DTO (Data Transfer Object) classes. All DTO classes under in the following Package “com.itgarden.dto

I don’t want to expose the Entity objects in the Presentation Layer. it should available only in Service Layer. The Service class converts Entity objects as DTO class which is visible for Presentation Layer. These DTO classes designed for Client-side response. Spring Boot converts DTO to JSON data and sends it to the client-side as a response. The Entity object has unnecessary values that are not required for the Client-side so, those values are eliminated in DTO classes. This strategy is known as DTO Design Pattern.
Request Handling
The controller receives the request from the client and maps it to DTO Class, i.e. The client data tightly coupled with DTO classes. The client should follow the DTO class attributes as request data for their JSON Request.

User DTO Object' Attributes
private String firstName;
private String middleName;
private String lastName;
private String mobileNo;
JSON Attributes
{
"firstName": "Suresh1",
"middleName":"test",
"lastName": "Stalin",
"mobileNo": "987652553",
"emailId": "suresh@gmail.com"
}

The above example UserDTO object used in the Presentation layer. The same attributes used in Client-side JSON Attributes. This is the Contract between client and server. The client and Server strictly follow this data format for the data exchange. This Concept called as Content Negotiation in the Web Service world

Response Handling
The Controller sends all responses in the form for the following type.

ResponseEntity<ResponseMessage<T>>.
We don’t want to change the response type for each endpoint so, I came up with a Generic Response Type for all the endpoints available in the System. In the future, if you want to develop any Rest Service, This response type is compatible(Accepted).
ResponseMessage class contains the following three attributes and three different static method

@Data
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PUBLIC)
@RequiredArgsConstructor(access = AccessLevel.PUBLIC)
public class ResponseMessage<T> {

@NonNull
private T responseClassType;

private String message;

private String messageType;

public static <T> ResponseMessage<T> withResponseData(T classType, String message,String messageType) {
return new ResponseMessage<T>(classType, message, messageType);
}

public static <T> ResponseMessage<T> withResponseData(T classType) {
return new ResponseMessage<T>(classType);
}

public static ResponseMessage<Void> empty() {
return new ResponseMessage<>();
}
}

@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PUBLIC)
@RequiredArgsConstructor(access = AccessLevel.PUBLIC)
The meaning of the above three annotations is, the Lombok create three different constructors for this class which are….

public ResponseMessage() {

}

public ResponseMessage(T responseClassType) {
this.responseClassType = responseClassType;
}

public ResponseMessage(T responseClassType,String message,String messageType) {
this.responseClassType = responseClassType;
this.message = message;
this.messageType = messageType;
}


I am using the above three constructors in the following method.



public static <T> ResponseMessage<T> withResponseData(T classType, String message,String messageType) {
return new ResponseMessage<T>(classType, message, messageType);
}

public static <T> ResponseMessage<T> withResponseData(T classType) {
return new ResponseMessage<T>(classType);
}

public static ResponseMessage<Void> empty() {
return new ResponseMessage<>();
}

Use of these methods are, Let say I want to send EmployeeDTO as a response in the client-side, in such case I can call this method like below

responseMessage = ResponseMessage.withResponseData(employeeDto);

This will return ResponseMessage with Type of EmploeeDTO. Finally, I can return this ResponseMessage like below to the Client.

return new ResponseEntity<ResponseMessage<EmployeeDto>>(responseMessage, HttpStatus.CREATED);

Please go through my YouTube video for a better understanding and take a look at the code which committed to the following GitHub URL
https://github.com/sureshstalin/billingsystem

This the standard flow I am following in the Presentation Layer. This applies to every flow in the Presentation Layer i.e. if you want to work with any type of entity object, we can follow the same design, Still, I need to add the Generic Exception and validation framework.

Service Layer

There are two types of Service class I have created in the Billing System. One is always talking to DAO (Data Access Object) Layer for CRUD (Create, Read, Update and Delete) operation
Another Service class is implemented for Business logic, after execution of Business logic, will send to the Service class that talks to the DAO Layer for CRUD Operation.

Service Layer for Business Logic

I have implemented a RegistrationService for new User Registration which focuses on Business logic for Three different types of user Creation (Employee, Customer, and Vendor). As I told before the client Request bound with the DTO class i.e. Whatever JSON Request coming from the client-side, those are converted to its respective DTO class. In the Employee Registration scenario, I am sending the following request from the PostMan client for Employee Registration.

{
"firstName": "Suresh1",
"middleName":"test",
"lastName": "Stalin",
"mobileNo": "987652553",
"emailId": "suresh@gmail.com",
"flowType": "employee",
"roles":[
{
"name":"Guru",
"description":"This is Guru Role"
}
],
"addressList": [
{
"address1": "Ram Street",
"address2": "1st Lane",
"city": "Trichy",
"state": "TN",
"country": "India",
"landmark": "far",
"mobile": "343171771"
}
]
}

The above request converted to UserDTO by Spring Boot Jaxson API. The Rest Endpoint accepts this Request as UserDTO in the Request parameter as shown the below.

public ResponseEntity<ResponseMessage<EmployeeDto>> saveUser(@RequestBody UserDto requestBody)

According to the below method implementation, it accepts BaseDto as parameter. The BaseDto is parent class for all DTO methods so we can send any child class reference here. It could be UserDto, EmployeeDto ,CustomerDto or VendorDto et. In our case we are passing UserDto reference to the BaseDTo class.

public ResponseMessage<BaseDto> doRegistration(BaseDto baseDto) {

ResponseMessage<BaseDto> responseMessage = null;
String flowType = baseDto.getFlowType();
if(flowType.equalsIgnoreCase("employee")) {

UserDto userDto = (UserDto)baseDto;
User user = UserMapper.INSTANCE.userDTOtoUser(userDto);
Employee employee = new Employee();
employee.setFullName(new StringBuilder(user.getFirstName()).append(" ").append(user.getLastName()).toString());
employee.setEmployeeCode("EMP001");
employee.setUser(user);
Employee newEmployee = billingBaseService.save(employee);
EmployeeDto employeeDto = EmployeeMapper.INSTANCE.employeeToDTO(newEmployee);
responseMessage = ResponseMessage.withResponseData(employeeDto);
}
return responseMessage;
}

When you go through the above method, it converts UserDTO to User Entity Object. From the User Data, I am creating an Employee Entity object and passing this entity object to another service class called “billingBaseService.save(employee)”, This Service class talks to DB for CRUD operation. After successful saving, the save method returns a new Employee entity object with generated Primary key Id. and Again I am converting the Employee entity object into Employee DTO to client-side as a response. The following line wraps the employee DTO as part of ResponseMessage.
responseMessage =ResponseMessage.withResponseData(employeeDto);
The Controller class returns the ResponseMessage like below.
return new ResponseEntity<ResponseMessage<EmployeeDto>>(responseMessage, HttpStatus.CREATED)
;

In the above method, you can see the following line of code. This is the method convert DTO Object to Entity object and Entity Object to DTO Object. I am not writing any code to convert for Data Transfer.

User user = UserMapper.INSTANCE.userDTOtoUser(userDto);
EmployeeDto employeeDto = EmployeeMapper.INSTANCE.employeeToDTO(newEmployee);

I am Using the Mapper Framework called “mapstruct”. It does the conversion magic for us. It is a very popular framework for converting Objects. The reason it popular for, it will generate the converter code in compilation time itself. We can use that. it is much faster than other mappers Framework. Please read this story for mapstruct configuration.
Mapstruct configuration for billing System

In the “doRegistration” method there is another line of code that talks to DAO class for saving the employee information to Database.

Employee newEmployee = billingBaseService.save(employee);

Code implementation for BillingService

@Component
public class BillingBaseService<T, ID> {

@Autowired
private JpaRepository<T, ID> repository;

public <S extends T> S save(S entity) {
return repository.save(entity);
}

public List<T> findAll() {

return repository.findAll();
}

public Optional<T> findById(ID id) {

return repository.findById(id);
}

public void deleteById(ID id) {

repository.deleteById(id);
}

public void delete(T type) {

repository.delete(type);
}
}

This class is implemented using generics, this class talking to DAO Layer for CRUD operation for all types of entity objects. Look at the all method’s parameter, it accepts ID or type class so, this class works for Basic CRUD operation for all entity objects. you Don’t have to create a separate service class for CRUD operation for each entity object in the Database Table. I have annotated this class with @Component Annotation. Because, this class act as a common class for Manipulating data for the different database table. So, we can call this class as a Component class. There is no difference between @Service and @Component Annotation. Both annotations used to create a Service class. If any service class used in a Particular flow, we can use the @Service. If any Service class used in multiple places for reusing a particular operation, we can use @component Annotation. Technically there is no difference between @Service and @Component

DAO Layer

DAO Layer is where we have all Repository classes in our Project. I have stored all the Repository classes in “com.itgarden.repository”. As of now, I have not created any Repository class instead I am just using JPARepository in BillingBaseService class to perform CRUD Operation for All entity Object. If I need any Specific operation in the DB apart from basic CRUD operation, I will create a Repository interface in the Repository package. As of now, JPA Repository’s method doing all my DB operations through BillingBaseService.

Please watch this full video for the Billing System code walk-thru and System design and demo
https://youtu.be/PlGqs9XTSqc

Download the source code from the following GitHub Repository
https://github.com/sureshstalin/billingsystem

How to setup Lombok in Intellij, Eclipse, and STS?
https://youtu.be/Mp48aUwRf0s
How to setup MapStruct in Spring Boot application while using Lombok Library
https://youtu.be/LnSwxREmzXk
How to create an Entity Relationship Diagram — ER Diagram. Using MySQL Workbench
https://youtu.be/ZR2Q0qVbmLs

 

Close Menu
×
×

Cart