Cloud computing

Introduction

Architecture de Spring Cloud

Eureka Config Serve Zuul Consul Hystrix Resilience4J

Spring Boot (BackEnd) TPs

Creation,Dépendance,Configuration Exemple Video RestController

Produit Rest API

Entity et repository Ajouter Afficher Liste Produit Détails,Supprimer,Vider Modifier

Angular (FrontEnd)

Angular Rappel CLient CRUD

Spring Security

User Auth

CRUD

Vente CRUD

To be Continued...

Middlewares Orientés Messages

Communication Synchrone vs. Asynchrone API JMS : Java Message Service JMS avec ActiveMQ et HornetQ KAFKA

Spring Batch

Spring Batch

Stream Processing

Kafka Streams

Architectures Serverless

Architectures Serverless Résumé



Spring Boot +Angular+Consul Gateway

Backend (Spring Boot)

Client Entity


package com.emsi.models;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Column;
import jakarta.persistence.Table;

@Entity
@Table(name = "clients")  // Specify the table name
public class Client {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")  // Optional, but can be useful for clarity or customization
    private Long id;

    @Column(name = "nom", nullable = false, length = 100)  // Specifies non-null and a maximum length of 100 characters
    private String nom;

    @Column(name = "prenom", nullable = false, length = 100)
    private String prenom;

    @Column(name = "tel", length = 15)  // Limits the phone number length to 15 characters
    private String tel;

    @Column(name = "email", nullable = false, unique = true)  // Ensures email is unique and non-null
    private String email;

    @Column(name = "password", nullable = false)
    private String password;

    // Constructor
    public Client() {
    }

    // Getters and Setters

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }

    public String getPrenom() {
        return prenom;
    }

    public void setPrenom(String prenom) {
        this.prenom = prenom;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}


Client Repository

package com.emsi.repositories;

import org.springframework.data.jpa.repository.JpaRepository;

import com.emsi.models.Client;

public interface ClientRepository extends JpaRepository {
}

Service Layer

package com.emsi.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.emsi.models.Client;
import com.emsi.repositories.ClientRepository;

import java.util.List;

@Service
public class ClientService {

    @Autowired
    private ClientRepository clientRepository;

    public List getAllClients() {
        return clientRepository.findAll();
    }

    public Client getClientById(Long id) {
        return clientRepository.findById(id).orElse(null);
    }

    public Client saveClient(Client client) {
        return clientRepository.save(client);
    }

    public void deleteClient(Long id) {
        clientRepository.deleteById(id);
    }
}

REST Controller

package com.emsi.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import com.emsi.models.Client;
import com.emsi.services.ClientService;

import java.util.List;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api/clients")
public class ClientController {

    @Autowired
    private ClientService clientService;

    @GetMapping
    public List getAllClients() {
        return clientService.getAllClients();
    }

    @GetMapping("/{id}")
    public Client getClientById(@PathVariable Long id) {
        return clientService.getClientById(id);
    }

    @PostMapping
    public Client saveClient(@RequestBody Client client) {
        return clientService.saveClient(client);
    }

    @PutMapping("/{id}")
    public Client updateClient(@PathVariable Long id, @RequestBody Client client) {
        client.setId(id);
        return clientService.saveClient(client);
    }

    @DeleteMapping("/{id}")
    public void deleteClient(@PathVariable Long id) {
        clientService.deleteClient(id);
    }
}

Consul Gateway

Create a Spring Boot project named api-gateway.

pom.xml



<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
Configure application.yml for the gateway:

spring:
  application:
    name: api-gateway
  cloud:
    consul:
      discovery:
        enabled: true
        register: true
  profiles:
    active: consul
server:
  port: 8080

cloud:
  gateway:
    routes:
      - id: product-service
        uri: lb://product-service
        predicates:
          - Path=/products/**
      - id: client-service
        uri: lb://client-service
        predicates:
          - Path=/clients/**
lb://product-service and lb://order-service use Consul to resolve the actual service locations.

main application class.xml


@SpringBootApplication
public class ApiGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}
In Consul's UI (typically at http://localhost:8500), you should see product-service, order-service, and api-gateway registered.
Access the endpoints via the gateway:
http://localhost:8080/products → routes to product-service
http://localhost:8080/clients → routes to clients-service

Frontend (Angular)

Introduction

Angular est une plateforme et un framework de développement pour construire des applications web en utilisant TypeScript. Ce tutoriel vous guidera à travers les étapes nécessaires pour installer et configurer Angular sur votre machine.

Étapes à suivre

1.Installer Node.js :

Angular nécessite Node.js pour fonctionner. Téléchargez et installez la dernière version de Node.js à partir du site officiel :

Télécharger Node.js

Vérifiez que Node.js est bien installé en exécutant la commande suivante dans un terminal :

node -v

2.Installer Angular CLI :

Angular CLI est l'outil officiel pour créer et gérer des projets Angular. Pour l'installer, exécutez la commande suivante :

npm install -g @angular/cli

Vérifiez que l'installation est correcte :

ng version

3.Créer un nouveau projet Angular :

Une fois Angular CLI installé, vous pouvez créer un nouveau projet avec la commande :

ng new angularprojectOne --no-standalone --routing --ssr=false

Suivez les instructions affichées pour configurer votre projet.

4.Exécuter le projet Angular :

Après avoir créé votre projet, entrez dans le dossier du projet :

cd angularprojectOne

Puis exécutez l'application avec la commande suivante :

ng serve

Ouvrez votre navigateur et accédez à http://localhost:4200 pour voir votre application en action.

6.Structure d'un projet Angular :

Angular utilise une architecture modulaire. Voici une brève description des répertoires principaux :

  • src/ : Contient tout le code source de votre application.
  • app/ : Contient les composants et les services de votre application.
  • assets/ : Contient les fichiers statiques comme les images.

7.Déployer l'application :

Pour générer une version de production de votre application Angular, exécutez :

ng build --prod

Les fichiers de votre application prête à être déployée se trouvent dans le répertoire dist/.

Services


ng generate service services/client

ClientService

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

import { Client } from '../models/Client';
@Injectable({
  providedIn: 'root'
})
export class ClientService {

  private baseUrl = 'http://localhost:8097/api/clients'; // Your Spring Boot API base URL

  constructor(private http: HttpClient) { }

  // Fetch all clients
  getClients(): Observable {
    return this.http.get(this.baseUrl);
  }

  // Fetch a single client by ID
  getClient(id: number): Observable {
    return this.http.get(`${this.baseUrl}/${id}`);
  }

  // Create a new client
  createClient(client: Client): Observable {
    return this.http.post(this.baseUrl, client);
  }

  // Update a client
  updateClient(id: number, client: Client): Observable {
    return this.http.put(`${this.baseUrl}/${id}`, client);
  }

  // Delete a client
  deleteClient(id: number): Observable {
    return this.http.delete(`${this.baseUrl}/${id}`);
  }
}


Client Model :models/Clients


export class Client {
  id!: number;
  nom!: string;
  prenom!: string;
  tel!: string;
  email!: string;
  password!: string;
}

client-list.component.html


ng generate component components/client-list
<div class="client-list-card">
    <h2>Client List</h2>
    <a routerLink="/add-client">Add Client</a>
    
    <table class="client-table">
      <thead>
        <tr>
          <th>Nom</th>
          <th>Prénom</th>
          <th>Téléphone</th>
          <th>Email</th>
          <th>Password</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let client of clients">
          <td>{{ client.nom }}</td>
          <td>{{ client.prenom }}</td>
          <td>{{ client.tel }}</td>
          <td>{{ client.email }}</td>
          <td>{{ client.password }}</td>
          <td>
            <a [routerLink]="['/edit-client', client.id]">Edit</a>
            <button (click)="deleteClient(client.id)">Delete</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>



client-list.component.css

.client-list-card {
    max-width: 800px;
    margin: 20px auto;
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    background-color: #fff;
  }
  
  /* Heading */
  .client-list-card h2 {
    font-size: 24px;
    margin-bottom: 20px;
  }
  
  /* Button styling */
  .add-client-btn {
    padding: 10px 20px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
  }
  
  .add-client-btn:hover {
    background-color: #0056b3;
  }
  
  /* Table styling */
  .client-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 20px;
  }
  
  .client-table th, .client-table td {
    padding: 12px 15px;
    border: 1px solid #ddd;
    text-align: left;
  }
  
  .client-table th {
    background-color: #f2f2f2;
    font-weight: bold;
  }
  
  .client-table tr:nth-child(even) {
    background-color: #f9f9f9;
  }
  
  .client-table tr:hover {
    background-color: #f1f1f1;
  }

CRUD Operations in client/list.component.ts

import { Component, OnInit } from '@angular/core';

import { Client } from '../../../models/Client';
import { ClientService } from '../../../services/client.service';
@Component({
  selector: 'app-client-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ClientListComponent implements OnInit {
  clients: Client[] = [];

  constructor(private clientService: ClientService) {}

  ngOnInit(): void {
    this.clientService.getClients().subscribe(data => {
      this.clients = data;
    });
  }

  deleteClient(id: number): void {
    this.clientService.deleteClient(id).subscribe(() => {
      this.clients = this.clients.filter(client => client.id !== id);
    });
  }
}


ng generate component components/client-add

client-add.component.html


<div>
    <form (ngSubmit)="addClient()">
     <div>
       <label for="nom">Nom:</label>
       <input type="text" id="nom" [(ngModel)]="client.nom" name="nom" required />
     </div>
     <div>
       <label for="prenom">Prénom:</label>
       <input type="text" id="prenom" [(ngModel)]="client.prenom" name="prenom" required />
     </div>
     <div>
       <label for="tel">Téléphone:</label>
       <input type="text" id="tel" [(ngModel)]="client.tel" name="tel" required />
     </div>
     <div>
       <label for="email">Email:</label>
       <input type="email" id="email" [(ngModel)]="client.email" name="email" required />
     </div>
     <div>
       <label for="password">Password:</label>
       <input type="password" id="password" [(ngModel)]="client.password" name="password" required />
     </div>
     <button type="submit">{{ client.id ? 'Update' : 'Add' }}</button>
   </form>
 </div>
 

client-add.component.ts


import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { Client } from '../../models/Client';
import { ClientService } from '../../services/client.service';
@Component({
  selector: 'app-client-add',
  templateUrl: './client-add.component.html',
  styleUrls: ['./client-add.component.css']
})
export class ClientAddComponent {
  client: Client = new Client();

  constructor(private clientService: ClientService, private router: Router) {}

  addClient(): void {
    this.clientService.createClient(this.client).subscribe(() => {
      this.router.navigate(['/clients']);
    });
  }
}

ng generate component components/client-edit

client-edit.component.html


<div>
     <form (ngSubmit)=" updateClient()">
      <div>
        <label for="nom">Nom:</label>
        <input type="text" id="nom" [(ngModel)]="client.nom" name="nom" required />
      </div>
      <div>
        <label for="prenom">Prénom:</label>
        <input type="text" id="prenom" [(ngModel)]="client.prenom" name="prenom" required />
      </div>
      <div>
        <label for="tel">Téléphone:</label>
        <input type="text" id="tel" [(ngModel)]="client.tel" name="tel" required />
      </div>
      <div>
        <label for="email">Email:</label>
        <input type="email" id="email" [(ngModel)]="client.email" name="email" required />
      </div>
      <div>
        <label for="password">Password:</label>
        <input type="password" id="password" [(ngModel)]="client.password" name="password" required />
      </div>
      <button type="submit">{{ client.id ? 'Update' : 'Add' }}</button>
    </form>
  </div>
  

client-edit.component.ts


import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ClientService } from '../../services/client.service';
import { Client } from '../../models/Client';

@Component({
  selector: 'app-client-edit',
  templateUrl: './client-edit.component.html',
  styleUrls: ['./client-edit.component.css']
})
export class ClientEditComponent implements OnInit {
  client: Client = new Client();

  constructor(
    private clientService: ClientService,
    private route: ActivatedRoute,
    private router: Router
  ) {}

  ngOnInit(): void {
    const id = this.route.snapshot.params['id'];
    this.clientService.getClient(id).subscribe(data => {
      this.client = data;
    });
  }

  updateClient(): void {
    const id = this.route.snapshot.params['id'];
    this.clientService.updateClient(id, this.client).subscribe(() => {
      this.router.navigate(['/clients']);
    });
  }
}

app-routing.module.ts


import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ClientListComponent } from './components/clients/list/list.component';
import { ClientAddComponent } from './components/client-add/client-add.component';
import { ClientEditComponent } from './components/client-edit/client-edit.component';

const routes: Routes = [
  { path: '', redirectTo: '/clients', pathMatch: 'full' },
  { path: 'clients', component: ClientListComponent },
  { path: 'add-client', component: ClientAddComponent },
  { path: 'edit-client/:id', component: ClientEditComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

app.module.ts


import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http'; // Import the HttpClientModule

import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms'; 

import { AppComponent } from './app.component';
import { ClientListComponent } from './components/clients/list/list.component';
import { ClientAddComponent } from './components/client-add/client-add.component';
import { ClientEditComponent } from './components/client-edit/client-edit.component';

@NgModule({
  declarations: [
    AppComponent,
    ClientListComponent,
    ClientAddComponent,
    ClientEditComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})

export class AppModule { }

Running the Application

Start the Spring Boot backend:

mvn spring-boot:run
Start the Angular frontend:

ng serve
http://localhost:4200