Open In App

Java Spring Boot Microservices Sample Project

Improve
Improve
Like Article
Like
Save
Share
Report

Microservices are more popular nowadays. They can be written in any language. In this article, let us see Spring Boot Microservices. in this article let us see a base project “currency-exchange-sample-service” which has a business logic and which can be invoked in another project “currency-conversion-sample-service“. Both are Maven projects and let us see them one by one

Microservice 1: currency-exchange-sample-service

Project Structure

Project structure

 

pom.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg.microservices</groupId>
    <artifactId>currency-exchange-sample-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>currency-exchange-sample-service</name>
    <description>Demo project for Spring Boot</description>
 
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.RC2</spring-cloud.version>
    </properties>
 
    <dependencies>
       
        <!-- Starter for building web, including RESTful,
             applications using Spring MVC. -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!-- The spring-boot-devtools module can be included in any
             project to provide additional development-time features -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!-- H2 is an open-source lightweight Java database -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>             
            <scope>runtime</scope
        </dependency
        <!--  starter for using Spring Data JPA with Hibernate. -->
        <dependency
          <groupId>org.springframework.boot</groupId
          <artifactId>spring-boot-starter-data-jpa</artifactId
          <version>2.1.3.RELEASE</version
        </dependency>
        <!-- provides secured endpoints for monitoring
             and managing your Spring Boot application -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
 
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
 
</project>


Let us see the important files 

CurrencyExchangeServiceSampleApplication.java

Java




import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
// It is equivalent to using @Configuration,
// @EnableAutoConfiguration and @ComponentScan with their
// default attributes:
public class CurrencyExchangeServiceSampleApplication {
 
    public static void main(String[] args)
    {
        SpringApplication.run(
            CurrencyExchangeServiceSampleApplication.class,
            args);
    }
}


CurrencyExchangeSampleController.java

@GetMapping("/currency-exchange-sample/fromCurrency/{fromCurrency}/toCurrency/{toCurrency}") 
// where {fromCurrency} and {toCurrency} are path variable
// fromCurrency can be USD,EUR,AUD,INR and toCurrency can be the opposite of any fromCurrency

Java




import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
 
@SpringBootApplication
@RestController
// The @RestController annotation in Spring is essentially
// just a combination of
// @Controller and @ResponseBody. This annotation was added
// during Spring 4.0 to remove the redundancy of declaring
// the @ResponseBody annotation in your controller
public class CurrencyExchangeSampleController {
    @Autowired private Environment environment;
 
    @GetMapping(
        "/currency-exchange-sample/fromCurrency/{fromCurrency}/toCurrency/{toCurrency}")
    // where {fromCurrency} and {toCurrency} are path
    // variable
    // fromCurrency can be USD,EUR,AUD,INR and toCurrency
    // can be the opposite of any fromCurrency
    public ExchangeValue
    retrieveExchangeValue(@PathVariable String fromCurrency,
                          @PathVariable String toCurrency)
    {
        // Here we need to write all of our business logic
        BigDecimal conversionMultiple = null;
        ExchangeValue exchangeValue = new ExchangeValue();
        if (fromCurrency != null && toCurrency != null) {
            if (fromCurrency.equalsIgnoreCase("USD")
                && toCurrency.equalsIgnoreCase("INR")) {
                conversionMultiple = BigDecimal.valueOf(78);
            }
            if (fromCurrency.equalsIgnoreCase("INR")
                && toCurrency.equalsIgnoreCase("USD")) {
                conversionMultiple
                    = BigDecimal.valueOf(0.013);
            }
            if (fromCurrency.equalsIgnoreCase("EUR")
                && toCurrency.equalsIgnoreCase("INR")) {
                conversionMultiple = BigDecimal.valueOf(82);
            }
            if (fromCurrency.equalsIgnoreCase("AUD")
                && toCurrency.equalsIgnoreCase("INR")) {
                conversionMultiple = BigDecimal.valueOf(54);
            }
        }
        // setting the port
        exchangeValue = new ExchangeValue(
            1000L, fromCurrency, toCurrency,
            conversionMultiple);
        exchangeValue.setPort(Integer.parseInt(
            environment.getProperty("local.server.port")));
        return exchangeValue;
    }
}


ExchangeValue.java

Java




import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
 
// @Entity annotation defines that a class can be mapped to
// a table
@Entity
 
// Representation of the table name
@Table(name = "Exchange_Value")
public class ExchangeValue {
    // The @Id annotation is inherited from
    // javax.persistence.Id, indicating the member field
    // below is the primary key of the current entity
    @Id @Column(name = "id") private Long id;
    @Column(name = "currency_from")
    private String fromCurrency;
    @Column(name = "currency_to") private String toCurrency;
    @Column(name = "conversion_multiple")
    private BigDecimal conversionMultiple;
    @Column(name = "port") private int port;
 
    public ExchangeValue() {}
 
    // generating constructor using fields
    public ExchangeValue(Long id, String fromCurrency,
                         String toCurrency,
                         BigDecimal conversionMultiple)
    {
        super();
        this.id = id;
        this.fromCurrency = fromCurrency;
        this.toCurrency = toCurrency;
        this.conversionMultiple = conversionMultiple;
    }
 
    // generating getters
    public int getPort() { return port; }
 
    public void setPort(int port) { this.port = port; }
 
    public Long getId() { return id; }
 
    public String getFrom() { return fromCurrency; }
 
    public String getTo() { return toCurrency; }
 
    public BigDecimal getConversionMultiple()
    {
        return conversionMultiple;
    }
}


application.properties

spring.application.name=currency-exchange-sample-service
server.port=8000 #Representation of the port number . We can set different port number in run configuration also
spring.jpa.show-sql=true  #To display the SQL
spring.h2.console.enabled=true  
spring.datasource.platform=h2  #As we are using h2 datasource 
spring.datasource.url=jdbc:h2:mem:gfg 

data.sql

insert into exchange_value(id,currency_from,currency_to,conversion_multiple,port)  
values(10001,'USD', 'INR' ,65,0);  
insert into exchange_value(id,currency_from,currency_to,conversion_multiple,port)  
values(10002,'EUR', 'INR' ,82,0);  
insert into exchange_value(id,currency_from,currency_to,conversion_multiple,port)  
values(10003,'AUD', 'INR' ,53,0);

By default, it has been set to run on port 8000. We can create another instance and can make the project run on port 8001 in the below ways

 

As this is the spring boot application, it can be normally run as Java application

 

If we set to run the application on two different ports, we will get the below options

 

Let us select the first one. On running the application, in the console, we see as

 

From the console, we can see that it used default Tomcat and the project is running on port 8080. As we have used 3 insert scripts, automatically table is created and the data is inserted. We can able to do the following 

http://localhost:8000/currency-exchange-sample/fromCurrency/USD/toCurrency/INR

 

When this URL is hit, it will be redirected to the controller, and fromCurrency is taken as “USD” and toCurrency is taken as “INR”

Because of this,

// Below set of code is executed and hence we are seeing the result like above
if (fromCurrency != null && toCurrency != null) {
            if (fromCurrency.equalsIgnoreCase("USD") && toCurrency.equalsIgnoreCase("INR")) {
                conversionMultiple = BigDecimal.valueOf(78);
            }

Similarly, we can able to execute the below following URLs

http://localhost:8000/currency-exchange-sample/fromCurrency/EUR/toCurrency/INR

 

http://localhost:8000/currency-exchange-sample/fromCurrency/AUD/toCurrency/INR

 

Hence according to our business needs, we can add business logic to the controller file. Let us see how the above service is getting called in the currency-conversion project

Microservice 2:currency-conversion-sample-service

 

This is also a maven project

pom.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.gfg.microservices</groupId>
    <artifactId>currency-conversion-sample-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>currency-conversion-servicce</name>
    <description>Demo project for Spring Boot</description>
 
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.RC2</spring-cloud.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
 
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
 
</project>


Main important java files

CurrencyConversionSampleServiceApplication.java

Java




import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class CurrencyConversionSampleServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(CurrencyConversionSampleServiceApplication.class, args);
    }
}


CurrencyConversionSampleBean.java

Java




import java.math.BigDecimal;
 
public class CurrencyConversionSampleBean {
    // We need to set all the fields that is going to
    // received in response
    private Long id;
    private String from;
    private String to;
    private BigDecimal ConversionMultiple;
    private BigDecimal quantity;
    private BigDecimal totalCalculatedAmount;
    private int port;
 
    // default constructor
    public CurrencyConversionSampleBean() {}
 
    // creating constructor
    public CurrencyConversionSampleBean(
        Long id, String from, String to,
        BigDecimal conversionMultiple, BigDecimal quantity,
        BigDecimal totalCalculatedAmount, int port)
    {
        super();
        this.id = id;
        this.from = from;
        this.to = to;
        ConversionMultiple = conversionMultiple;
        this.quantity = quantity;
        this.totalCalculatedAmount = totalCalculatedAmount;
        this.port = port;
    }
 
    // creating setters and getters
    public Long getId() { return id; }
 
    public void setId(Long id) { this.id = id; }
 
    public String getFrom() { return from; }
 
    public void setFrom(String from) { this.from = from; }
 
    public String getTo() { return to; }
 
    public void setTo(String to) { this.to = to; }
 
    public BigDecimal getConversionMultiple()
    {
        return ConversionMultiple;
    }
 
    public void
    setConversionMultiple(BigDecimal conversionMultiple)
    {
        ConversionMultiple = conversionMultiple;
    }
 
    public BigDecimal getQuantity() { return quantity; }
 
    public void setQuantity(BigDecimal quantity)
    {
        this.quantity = quantity;
    }
 
    public BigDecimal getTotalCalculatedAmount()
    {
        return totalCalculatedAmount;
    }
 
    public void setTotalCalculatedAmount(
        BigDecimal totalCalculatedAmount)
    {
        this.totalCalculatedAmount = totalCalculatedAmount;
    }
 
    public int getPort() { return port; }
 
    public void setPort(int port) { this.port = port; }
}


CurrencyConversionSampleController.java

@GetMapping("/currency-converter-sample/fromCurrency/{fromCurrency}/toCurrency/{toCurrency}/quantity/{quantity}")

Java




package com.gfg.microservices.currencyconversionservice;
 
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
 
// To invoke an external service, RestTemplate() constructor
// is used
@RestController
public class CurrencyConversionSampleController {
    @GetMapping(
        "/currency-converter-sample/fromCurrency/{fromCurrency}/toCurrency/{toCurrency}/quantity/{quantity}")
    // where {from} and {to} represents the
    // column
    // returns a bean back
    public CurrencyConversionSampleBean
    convertCurrency(@PathVariable String fromCurrency,
                    @PathVariable String toCurrency,
                    @PathVariable BigDecimal quantity)
    {
 
        // setting variables to currency exchange service
        Map<String, String> uriVariables = new HashMap<>();
        // urlParams should match properly
        uriVariables.put("fromCurrency", fromCurrency);
        uriVariables.put("toCurrency", toCurrency);
        // calling the currency-exchange-sample-service
        // http://localhost:8000/currency-exchange-sample/fromCurrency/{fromCurrency}/toCurrency/{toCurrency}
        // is the service that got called from part 1. Its
        // response is received and via
        // CurrencyConversionSampleBean we are getting the
        // results back
        ResponseEntity<CurrencyConversionSampleBean>
            responseEntity
            = new RestTemplate().getForEntity(
                "http://localhost:8000/currency-exchange-sample/fromCurrency/{fromCurrency}/toCurrency/{toCurrency}",
                CurrencyConversionSampleBean.class,
                uriVariables);
        CurrencyConversionSampleBean response
            = responseEntity.getBody();
        // creating a new response bean and getting the
        // response back and taking it into Bean Hence the
        // output bean should have all the fields that is
        // received from the response
        return new CurrencyConversionSampleBean(
            response.getId(), fromCurrency, toCurrency,
            response.getConversionMultiple(), quantity,
            quantity.multiply(
                response.getConversionMultiple()),
            response.getPort());
    }
}


That is this project is started on port 8100. Now we can able to execute the following URLS

http://localhost:8100/currency-converter-sample/fromCurrency/USD/toCurrency/INR/quantity/1000

 

When this service is called, it will in turn invoke.

Assumption: currency-exchange-sample is running in port 8000 and it produces the required response

http://localhost:8000/currency-exchange-sample/fromCurrency/USD/toCurrency/INR

And then as the logic is written as

ResponseEntity<CurrencyConversionSampleBean>responseEntity=new RestTemplate().getForEntity("http://localhost:8000/currency-exchange-sample/fromCurrency/{fromCurrency}/toCurrency/{toCurrency}",CurrencyConversionSampleBean.class, uriVariables);
        CurrencyConversionSampleBean response=responseEntity.getBody();  
        // creating a new response bean and getting the response back and taking it into Bean
        // Hence the output bean should have all the fields that is received from the response
        return new CurrencyConversionSampleBean(response.getId(), fromCurrency,toCurrency,response.getConversionMultiple(), quantity,quantity.multiply(response.getConversionMultiple()),response.getPort());  

We are seeing the totalCalculatedAmount as 78 * 1000  i.e. 78000. We are getting “conversionMultiple” from the first URL and it is multiplied with the quantity value here. It is very ideal that, we no need to carry exchange service logic into this application i.e. part 1 project can be separate and part 2 project can invoke part 1 URLs here. So microservices can run separately and other services can use them. Rest of the URLs that can be checked

Example

http://localhost:8100/currency-converter-sample/fromCurrency/EUR/toCurrency/INR/quantity/5000

This will call in turn

http://localhost:8000/currency-exchange-sample/fromCurrency/EUR/toCurrency/INR

And the output will be 

 

Example

http://localhost:8100/currency-converter-sample/fromCurrency/AUD/toCurrency/INR/quantity/2000

This will call in turn

http://localhost:8000/currency-exchange-sample/fromCurrency/AUD/toCurrency/INR

And the output will be

 



Last Updated : 06 Jan, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads