Prerequisites
Before we start, ensure you have the following:
- Java Development Kit (JDK) installed
- Apache Maven installed
- Node.js and npm installed
- Angular CLI installed (
npm install -g @angular/cli
) - An IDE (such as IntelliJ IDEA, Eclipse, or VS Code) installed
Overview of the Architecture
- Service Registry: Manages service discovery.
- API Gateway: Routes client requests to appropriate microservices.
- Employee Service: Manages employee data.
- Department Service: Manages department data.
- Angular Client: Provides a user interface to interact with the services via the API Gateway.
Step 1: Create the Service Registry
1.1 Create a Spring Boot Project
-
Open Spring Initializr:
- Go to Spring Initializr in your web browser.
-
Configure Project Metadata:
- Project: Maven Project
- Language: Java
- Spring Boot: Select the latest version of Spring Boot 3.2
- Group: com.example
- Artifact: service-registry
- Name: service-registry
- Package Name: com.example.serviceregistry
- Packaging: Jar
- Java Version: 17 (or your preferred version)
- Click
Next
.
-
Select Dependencies:
- On the
Dependencies
screen, select:- Spring Cloud Discovery
- Click
Next
.
- On the
-
Generate the Project:
- Click
Generate
to download the project zip file. - Extract the zip file to your desired location.
- Click
-
Open the Project in Your IDE:
- Open your IDE and import the project as a Maven project.
1.2 Update application.yml
Create an application.yml
file in the src/main/resources
directory and add the following configuration:
server:
port: 8761
spring:
application:
name: service-registry
eureka:
client:
register-with-eureka: false
fetch-registry: false
instance:
hostname: localhost
server:
enable-self-preservation: false
1.3 Enable Eureka Server
Create a class ServiceRegistryApplication
and annotate it with @EnableEurekaServer
:
package com.example.serviceregistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistryApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRegistryApplication.class, args);
}
}
1.4 Run the Service Registry
Run the application by executing the ServiceRegistryApplication
class. The Eureka Dashboard should be accessible at http://localhost:8761
.
Step 2: Create the Employee Service
2.1 Create a Spring Boot Project
-
Open Spring Initializr and configure a new project with the following metadata:
- Group: com.example
- Artifact: employee-service
- Name: employee-service
- Package Name: com.example.employeeservice
- Dependencies: Spring Web, Spring Data JPA, H2 Database, Spring Cloud Discovery, Spring Boot DevTools
-
Generate the Project and open it in your IDE.
2.2 Update application.yml
Create an application.yml
file in the src/main/resources
directory:
server:
port: 8081
spring:
application:
name: employee-service
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password: password
jpa:
hibernate:
ddl-auto: update
database-platform: org.hibernate.dialect.H2Dialect
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
2.3 Create Employee Entity
Create an Employee
entity class in the com.example.employeeservice.model
package:
package com.example.employeeservice.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String department;
// Getters and Setters
}
2.4 Create Employee Repository
Create an EmployeeRepository
interface in the com.example.employeeservice.repository
package:
package com.example.employeeservice.repository;
import com.example.employeeservice.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
2.5 Create Employee Controller
Create an EmployeeController
class in the com.example.employeeservice.controller
package:
package com.example.employeeservice.controller;
import com.example.employeeservice.model.Employee;
import com.example.employeeservice.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private final EmployeeRepository employeeRepository;
@Autowired
public EmployeeController(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@GetMapping
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@PostMapping
public Employee createEmployee(@RequestBody Employee employee) {
return employeeRepository.save(employee);
}
}
2.6 Enable Discovery Client
Annotate the main application class with @EnableDiscoveryClient
:
package com.example.employeeservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class EmployeeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeServiceApplication.class, args);
}
}
2.7 Run the Employee Service
Run the application by executing the EmployeeServiceApplication
class. The service should register itself with the Eureka server.
Step 3: Create the Department Service
Repeat the same steps as for the Employee Service, but with the following changes:
3.1 Create a Spring Boot Project
-
Open Spring Initializr and configure a new project with the following metadata:
- Group: com.example
- Artifact: department-service
- Name: department-service
- Package Name: com.example.departmentservice
- Dependencies: Spring Web, Spring Data JPA, H2 Database, Spring Cloud Discovery, Spring Boot DevTools
-
Generate the Project and open it in your IDE.
3.2 Update application.yml
Create an application.yml
file in the src/main/resources
directory:
server:
port: 8082
spring:
application:
name: department-service
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password: password
jpa:
hibernate:
ddl-auto: update
database-platform: org.hibernate.dialect.H2Dialect
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
3.3 Create Department Entity
Create a Department
entity class in the com.example.departmentservice.model
package:
package com.example.departmentservice.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
}
3.4 Create Department Repository
Create a DepartmentRepository
interface in the com.example.departmentservice.repository
package:
package com.example.departmentservice.repository;
import com.example.departmentservice.model.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DepartmentRepository extends JpaRepository<Department, Long> {
}
3.5 Create Department Controller
Create a DepartmentController
class in the com.example.departmentservice.controller
package:
package com.example.departmentservice.controller;
import com.example.departmentservice.model.Department;
import com.example.departmentservice.repository.DepartmentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/departments")
public class DepartmentController {
private final DepartmentRepository departmentRepository;
@Autowired
public DepartmentController(DepartmentRepository departmentRepository) {
this.departmentRepository = departmentRepository;
}
@GetMapping
public List<Department> getAllDepartments() {
return departmentRepository.findAll();
}
@PostMapping
public Department createDepartment(@RequestBody Department department) {
return departmentRepository.save(department);
}
}
3.6 Enable Discovery Client
Annotate the main application class with @EnableDiscoveryClient
:
package com.example.departmentservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class DepartmentServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DepartmentServiceApplication.class, args);
}
}
3.7 Run the Department Service
Run the application by executing the DepartmentServiceApplication
class. The service should register itself with the Eureka server.
Step 4: Create the API Gateway
4.1 Create a Spring Boot Project
-
Open Spring Initializr and configure a new project with the following metadata:
- Group: com.example
- Artifact: api-gateway
- Name: api-gateway
- Package Name: com.example.apigateway
- Dependencies: Spring Cloud Gateway, Spring Cloud Discovery
-
Generate the Project and open it in your IDE.
4.2 Update application.yml
Create an application.yml
file in the src/main/resources
directory:
server:
port: 8080
spring:
application:
name: api-gateway
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
cloud:
gateway:
routes:
- id: employee_service
uri: lb://employee-service
predicates:
- Path=/employees/**
- id: department_service
uri: lb://department-service
predicates:
- Path=/departments/**
4.3 Enable Discovery Client
Annotate the main application class with @EnableDiscoveryClient
:
package com.example.apigateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
4.4 Run the API Gateway
Run the application by executing the ApiGatewayApplication
class. The API Gateway should register itself with the Eureka server.
Step 5: Create the Angular Client
5.1 Create an Angular Project
- Open a terminal and run the following command to create a new Angular project:
ng new client-app
- Navigate to the project directory:
cd client-app
5.2 Install Dependencies
Install Bootstrap for styling:
npm install bootstrap
Add Bootstrap to angular.json
:
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
5.3 Create Angular Services and Components
5.3.1 Create API Service
Generate the ApiService:
ng generate service services/api
Edit api.service.ts
:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ApiService {
private baseUrl = 'http://localhost:8080';
constructor(private http: HttpClient) { }
getEmployees(): Observable<any> {
return this.http.get(`${this.baseUrl}/employees`);
}
getDepartments(): Observable<any> {
return this.http.get(`${this.baseUrl}/departments`);
}
}
Explanation:
@Injectable({ providedIn: 'root' })
: Marks the service as injectable and available throughout the app.HttpClient
: Service for making HTTP requests.getEmployees()
: Sends a GET request to the employee service via the API Gateway.getDepartments()
: Sends a GET request to the department service via the API Gateway.
5.3.2 Create Components
Generate the components for displaying employees and departments:
ng generate component components/employees
ng generate component components/departments
Edit employees.component.ts
:
import { Component, OnInit } from '@angular/core';
import { ApiService } from '../../services/api.service';
@Component({
selector: 'app-employees',
templateUrl: './employees.component.html',
styleUrls: ['./employees.component.css']
})
export class EmployeesComponent implements OnInit {
employees: any[] = [];
constructor(private apiService: ApiService) { }
ngOnInit(): void {
this.apiService.getEmployees().subscribe(data => {
this.employees = data;
});
}
}
Edit employees.component.html
:
<div class="container mt-5">
<div class="row">
<div class="col-md-12">
<h2>Employees</h2>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Department</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employee of employees">
<td>{{ employee.id }}</td>
<td>{{ employee.name }}</td>
<td>{{ employee.department }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
Edit departments.component.ts
:
import { Component, OnInit } from '@angular/core';
import { ApiService } from '../../services/api.service';
@Component({
selector: 'app-departments',
templateUrl: './departments.component.html',
styleUrls: ['./departments.component.css']
})
export class DepartmentsComponent implements OnInit {
departments: any[] = [];
constructor(private apiService: ApiService) { }
ngOnInit(): void {
this.apiService.getDepartments().subscribe(data => {
this.departments = data;
});
}
}
Edit departments.component.html
:
<div class="container mt-5">
<div class="row">
<div class="col-md-12">
<h2>Departments</h2>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let department of departments">
<td>{{ department.id }}</td>
<td>{{ department.name }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
5.4 Update Angular Routing
Edit app-routing.module.ts
:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EmployeesComponent } from './components/employees/employees.component';
import { DepartmentsComponent } from './components/departments/departments.component';
const routes: Routes = [
{ path: 'employees', component: EmployeesComponent },
{ path: 'departments', component: DepartmentsComponent },
{ path: '', redirectTo: '/employees', pathMatch: 'full' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Explanation:
- Defines routes for the employees and departments components.
- Redirects the root path to the employees component.
5.5 Update Angular App Module
Edit app.module.ts
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EmployeesComponent } from './components/employees/employees.component';
import { DepartmentsComponent } from './components/departments/departments.component';
@NgModule({
declarations: [
AppComponent,
EmployeesComponent,
DepartmentsComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Explanation:
- Imports necessary modules for the Angular app.
- Declares the components used in the app.
- Sets up the app's root module.
5.6 Run the Angular Application
Open a terminal in the Angular project directory and run the application:
ng serve
Visit http://localhost:4200
in your web browser to see the application.
Handling CORS Issue
To handle CORS (Cross-Origin Resource Sharing) issues in the API Gateway, you need to configure CORS settings in the application.yml
file and create a CORS configuration class in the API Gateway project. Here's how you can do it:
Update application.yml
to Include CORS Configuration
Add the CORS configuration under spring.cloud.gateway
in the application.yml
file:
server:
port: 8080
spring:
application:
name: api-gateway
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
cloud:
gateway:
routes:
- id: employee_service
uri: lb://employee-service
predicates:
- Path=/employees/**
- id: department_service
uri: lb://department-service
predicates:
- Path=/departments/**
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
allowedHeaders:
- "*"
Create a CORS Configuration Class
Create a class CorsConfiguration
in the com.example.apigateway.config
package:
package com.example.apigateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.addAllowedOrigin("*");
corsConfig.addAllowedMethod("*");
corsConfig.addAllowedHeader("*");
corsConfig.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfig);
return new CorsWebFilter(source);
}
}
Explanation:
CorsConfiguration
class defines the CORS configuration.CorsWebFilter
bean applies the CORS configuration to all routes.UrlBasedCorsConfigurationSource
is used to map the CORS configuration to the URL patterns.
With this configuration, CORS is globally enabled for all routes handled by the API Gateway, allowing requests from any origin with any HTTP method and headers. This should resolve any CORS issues when your Angular client makes requests to the API Gateway.
Now, your API Gateway will properly handle CORS issues.
Conclusion
In this tutorial, we created a microservices architecture using Spring Boot and Angular. We built two microservices (Employee Service and Department Service), an API Gateway, a Service Registry, and an Angular client that interacts with the microservices through the API Gateway. This setup provides a scalable and maintainable architecture for building enterprise-level applications.
Comments
Post a Comment
Leave Comment