Saturday, May 7, 2022

Microservices Using Spring Boot With Http Communication

What are Microservices? 

Microservices are an architectural and organizational approach to software development where software is composed of small independent services that communicate over well-defined APIs 


Project Design



Full Project on github can be found under the following link.

What you will need?

  •  Java 1.8 or later
  •  Maven
  •  Intellij IDE 
  •  Any Type of SQL DB 

Project Setup 

1) Creating the project
  • Install Maven Plugin using the following link 

To make sure the apache maven is installed correctly using the following command to confirm 
mvn --version 

  • Navigate to your directory that you need where the project is created and run the below command
mvn archetype:generate -DgroupId=com.microservices.toutrial -DartifactId=microservices.toutrial -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false 
 
Specify your groupId and artifactId

After the project finishes building, you will receive the below message


  • Open the created project in IntelliJ IDE.

Open the main pom.xml file and add the following configuration
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.microservices.toutrial</groupId>
  <artifactId>microservices.toutrial</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>

  <name>microservices.toutrial</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <spring.boot.maven.plugin.version>2.5.7</spring.boot.maven.plugin.version>
    <spring-boot-dependencies.version>2.5.7</spring-boot-dependencies.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot-dependencies.version}</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.20</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>

  <build>
  <pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring.boot.maven.plugin.version}</version>
      </plugin>
    </plugins>
  </pluginManagement>
</build>
</project>

  • Add a new module to the project 


  • Select the module type as maven.

  • Click next and specify the name and the parent module.


  • Click finish you should find the project structure below.

  • Open the customer pom file, and notice the parent reference.

  • Now notice the parent pom file having the created module referenced.



  • Creating the Customer Microservice


Add the following dependancies to the customer pom file.

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>

Now for this project i will be orginizing my code as follows


1) Create the CustomerApplication class under the main package com.microservices.customer .

@SpringBootApplication annotation is used to mark a configuration class that declares one or more @Bean methods and also triggers auto-configuration and component scanning.


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CustomerApplication {
public static void main(String[] args){
SpringApplication.run(CustomerApplication.class,args);
}

}
2) Create the Entity Class
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="customer")
public class CustomerEntity {

@javax.persistence.Id
@Column(name = "Id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;

@Column(name = "firstName")
private String firstName;

@Column(name = "lastName")
private String lastName;

@Column(name = "email")
private String email;
}
3) Create the Repository Interface
import com.microservices.customer.core.entities.CustomerEntity;
import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<CustomerEntity,Long> {
}

4) Create the Customer Service Class.

@Service annotates classes at the service layer.

@Service
@AllArgsConstructor
public class CustomerService {

@Autowired
private CustomerRepository customerRepository;

public CustomerEntity registerCustomer(CustomerEntity customerEntity){
return customerRepository.save(customerEntity);
}
}
5) Create the datasource class

HikariDataSource

Hikari is the default DataSource implementation with Spring Boot 2

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CustomerDS {

@Bean
@ConfigurationProperties("app.datasource")
public HikariDataSource hikariDataSource(){
return DataSourceBuilder
.create()
.type(HikariDataSource.class)
.build();
}
}

Add this confiugration to the application.properties file under resources (if it is not created then create a text file and name it application.properties)

app.datasource.jdbc-url=jdbc:mysql://IP:Port/microservices_customer?serverTimezone=UTC&useUnicode=yes&characterEncoding=UTF-8
app.datasource.username=
app.datasource.password=
app.datasource.pool-size=30
# Hibernate
spring.datasource.initialize=true
#spring.datasource.platform=oracle
#update-validate-create-
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

spring.jpa.properties.hibernate.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.
PhysicalNamingStrategyStandardImpl


6) Moving on to the Rest Service , you will need to create a model and a controller
  • Model Class
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CustomerModel {

private long id;
private String firstName;
private String lastName;
private String email;
}
  • Controller Class
import com.microservices.customer.core.entities.CustomerEntity;
import com.microservices.customer.core.services.CustomerService;
import com.microservices.customer.web.models.CustomerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api/v1/customer")
public class CustomerController {

@Autowired
CustomerService customerService;

@PostMapping(path = "/registerCustomer")
public CustomerModel registerCustomer(@RequestBody CustomerModel customerModel) {
CustomerEntity customerEntity =
customerService.registerCustomer(new CustomerEntity(null,
customerModel.getFirstName(),
customerModel.getLastName(),
customerModel.getEmail()));
return new CustomerModel(customerEntity.getId(),
customerEntity.getFirstName(),
customerEntity.getLastName(),
customerEntity.getEmail());
}
}

Now let's test what we have build , run the customer application class and use postman or any 
other client to test the microservice.




Record was created succefully in the database.

  • Creating the Email Notification Microservice.

Create a new module based on maven and name it util , this will hold all our utility microservices.



Notice that the util module is refrenced in the main pom.xml


I will be using the following strucutre to organize my code

1) Add the following dependancies in the util pom.xml file.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2) Create the util application class under the main package "com.microservices.util".
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UtilApplication {

public static void main(String[] args){
SpringApplication.run(UtilApplication.class,args);
}
}
3) Create the Email Sender Intrerface to allow future dependancy Injection.
public interface EmailSender {
boolean sendEmail(String to,String subject,String email);
}
4) Create the Email Util Implementation Class.
@Service
@AllArgsConstructor
public class EmailUtil implements EmailSender {

@Autowired
private final JavaMailSender mailSender;

@Override
@Async
public boolean sendEmail(String to,String subject,String email) {
try {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,"utf-8");
helper.setTo(to);
helper.setText(email);
helper.setSubject(subject);
helper.setFrom("Hello@microservices.com");
mailSender.send(mimeMessage);

}catch (Exception ex){
ex.printStackTrace();
return false;
}
return true;
}
}

5) Now lets create the controller and model
  • Model Class
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmailModel {
private String to;
private String subject;
private String text;
}
  • Controller Class
@RestController
@RequestMapping(path = "api/v1/email")
public class EmailController {

@Autowired
private EmailUtil emailUtil;

@PostMapping(path = "/send")
public boolean sendEmail(@RequestBody EmailModel emailModel){
        return emailUtil.sendEmail(emailModel.getTo(), emailModel.getSubject(),
    emailModel.getText());
}
}

6) Finally add the configuration needed to send email in the application.properties file
i will be using gmail.
spring.application.name=Util
server.port=8083

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=
spring.mail.password=

# Other properties
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000

# TLS , port 587
spring.mail.properties.mail.smtp.starttls.enable=true
For the sake of testing you will need to enable less secure apps on gmail.


Now Lets run the Util Application Class and test the microservice using a client.

And the recieved email


Acheving Http Communication between Microservices.

  • Open the customer module and add the following referance to the email microservice to the application.properties file.
notification.service.url=http://IP:Port/api/v1/email/send
  • Create the Configuration class Customer Config
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class CustomerConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}

  • Create the Outbound Reqeust Model Bean
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@AllArgsConstructor
@Data
@Builder
public class NotificationServiceRequest {
private String to;
private String subject;
private String text;
} 
  • Modify the Customer Service Class to the following 
@Service
@AllArgsConstructor
public class CustomerService {

@Autowired
private CustomerRepository customerRepository;
@Autowired
Environment environment;

@Autowired
RestTemplate restTemplate;

public CustomerEntity registerCustomer(CustomerEntity customerEntity){
    customerEntity = customerRepository.save(customerEntity);
String emailBody = "New customer was registred with the user " +
customerEntity.getFirstName() + " " +customerEntity.getLastName();
NotificationServiceRequest notificationServiceRequest = new NotificationServiceRequest(
customerEntity.getEmail(),
"Registration Confirmation",
emailBody
);

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<NotificationServiceRequest> httpEntity =
new HttpEntity<>(notificationServiceRequest, headers);
restTemplate.postForObject(
environment.getProperty("notification.service.url"),
httpEntity,
String.class
);

return customerEntity;
}
}
Now lets test the changes




And the recived email upon registration.



Thats it , to be hounest this is the bare minimum , you can achieve so much more with the microservices architectural pattern.






No comments:

Post a Comment

Microservices Communication Enhancement Using Service Discovery

What is Service Discovery? Sevice Discovery is the process of automatically detecting devices and services on a network, we will be using Eu...