lundi 2 décembre 2024

📜 Spring Boot :Clé pour maîtriser les précédences des fichiers de propriétés 🚀

 Dans Spring Boot, la gestion des propriétés est essentielle pour créer des applications flexibles et bien configurées. Voici un résumé clair et élégant des règles de précédence, présenté sous forme de tableau, pour vous aider à mieux comprendre et maîtriser ce processus.


🌟 Les Grandes Précédences (Globales)

🏆 Rang🔍 Source📖 Description
1Propriétés par défaut (SpringApplication.setDefaultProperties)Base de départ définie via le code pour toutes les propriétés.
2Annotations @PropertySource dans vos classes @ConfigurationCharge des propriétés externes mais arrive tard (après logging.*).
3Fichiers de configuration (application.properties ou YAML)Cœur des propriétés : globales et spécifiques aux profils.
4Propriétés aléatoires (random.*)Génération dynamique de UUIDs, nombres aléatoires, etc.
5Variables d’environnementConfiguration pratique via votre OS (export SPRING_DATASOURCE_URL=...).
6Propriétés système Java-JVM SYSTEM Param (System.getProperties())Passées via la ligne de commande Java avec -D.
7JNDI (java:comp/env)Attributs JNDI spécifiques (pour conteneurs supportés comme Tomcat).
8Paramètres init du ServletContextValeurs configurées au niveau du contexte servlet.
9Paramètres init du ServletConfigValeurs spécifiques à un servlet particulier.
10Propriétés JSON intégrées (SPRING_APPLICATION_JSON)Configuration JSON inline pour des cas complexes.
11Arguments de ligne de commandePrioritaires et pratiques pour les environnements dynamiques (--server.port=8081).
12Propriétés des tests (dans @SpringBootTest)Définies spécifiquement pour les scénarios de test.
13Annotations @TestPropertySourceSurcharge de propriétés dans les tests unitaires.
14Paramètres globaux DevToolsDisponible dans $HOME/.config/spring-boot uniquement si DevTools est actif.

🛠️ Précédences dans les Fichiers application.properties

🏆 Rang📁 Type de fichier📖 Description
1Fichiers internes au JAR (application.properties)Contient les configurations par défaut packagées dans votre application.
2Fichiers spécifiques au profil internes au JAR (application-{profile}.properties)Chargés en fonction du profil actif (ex.: dev, prod).
3Fichiers externes au JAR (application.properties)Surchargent les fichiers internes.
4Fichiers spécifiques au profil externes au JAR (application-{profile}.properties)Plus haut niveau : adaptées aux environnements externes (cloud, conteneurs).

💡 Pourquoi c’est important ?

Comprendre cet ordre permet de :

  • Gérer vos configurations efficacement.
  • Définir des priorités entre vos environnements (local, dev, prod).
  • Éviter les conflits de configuration et les surprises en production.

Avec ce tableau en main, vous avez toutes les clés pour devenir un maître de la configuration Spring Boot ! 🎯

dimanche 24 novembre 2024

[VueJS] [Composition API] transmettre et recevoir des données aux composants enfants (enfant <--> parent)

 Avec la Composition API de Vue.js, la gestion des props, des événements et des données suit un modèle différent, plus structuré et modulaire, qui permet de mieux organiser le code dans les composants. Voici les principaux changements pour la gestion des props et des événements avec la Composition API.




1. Gestion des props avec la Composition API

Avec Options API :

Dans l’Options API, les props sont définies dans l'objet props, et on y accède directement via this :

export default { props: { enPromotion: { type: Boolean, required: true } }, template: `<div v-show="enPromotion">🏷️ Produit en promotion !</div>` };

Avec Composition API :

Les props sont passées en tant qu’argument à la fonction setup(), où elles deviennent des objets réactifs (props).

Code équivalent :

<script setup> defineProps({ enPromotion: { type: Boolean, required: true } }); </script> <template> <div v-show="enPromotion">🏷️ Produit en promotion !</div> </template>

2. Transmission de données via props (parent → enfant)

Le fonctionnement est similaire entre Options API et Composition API. Cependant, avec la Composition API :

  • Définir les props est plus explicite grâce à defineProps.
  • Le code devient plus lisible et modulaire, car tout est géré dans setup ou via <script setup>.

Exemple complet (Parent → Enfant) :

Composant parent :

<template> <product-component :enPromotion="true" /> </template>

Composant enfant :

<script setup> defineProps({ enPromotion: Boolean }); </script> <template> <div v-show="enPromotion">🏷️ Produit en promotion !</div> </template>

3. Gestion des événements avec la Composition API

Avec Options API :

Dans l’Options API, on émet un événement avec this.$emit, et le parent écoute cet événement dans le template :

methods: { notifyParent() { this.$emit('add-to-cart', this.productId); } }

Avec Composition API :

Les événements sont émis avec la fonction emit, passée en tant qu'argument dans setup.

Code équivalent :

<script setup> import { defineEmits } from 'vue'; const emit = defineEmits(['add-to-cart']); function notifyParent(productId) { emit('add-to-cart', productId); } </script> <template> <button @click="notifyParent(123)">Ajouter au panier</button> </template>

4. Transmission des données avec des événements (enfant → parent)

Avec la Composition API, l'émission d'un événement reste similaire, mais le système est plus clair grâce à defineEmits. On peut également documenter explicitement les événements émis par le composant.

Exemple complet (Enfant → Parent) :

Composant enfant :

<script setup> defineEmits(['add-to-cart']); function ajouterProduit(productId) { emit('add-to-cart', productId); } </script> <template> <button @click="ajouterProduit(123)">Ajouter au panier</button> </template>

Composant parent :

<template> <product-component @add-to-cart="mettreDansPanier" /> </template> <script setup> function mettreDansPanier(productId) { console.log('Produit ajouté au panier :', productId); } </script>

5. Avantages de la Composition API

  • Meilleure organisation du code : Toutes les fonctionnalités liées à une fonctionnalité (props, événements, données) sont regroupées dans setup, ce qui simplifie les composants complexes.

  • Réutilisabilité accrue : Le code peut facilement être déplacé dans des composables (fonctions réutilisables), ce qui améliore la modularité.

  • Clarté explicite : Les fonctions comme defineProps et defineEmits documentent directement le contrat entre un composant et ses parents/enfants.


En résumé :

Avec la Composition API :

  • Les props sont définies avec defineProps et utilisées directement dans le template sans avoir besoin de this.
  • Les événements sont gérés avec defineEmits, ce qui rend leur usage plus explicite et documenté.
  • Le code est plus structuré et réutilisable, particulièrement utile pour les projets complexes. https://fr.vuejs.org/api/sfc-script-setup#defineprops-defineemits 

[VueJs] Transmettre des données aux composants enfants avec les props

Comment un composant parent peut transmettre des données à un composant enfant grâce aux props, en utilisant une propriété indiquant si un produit est en promotion.






1. Problème initial :

  • L'application est composée de deux composants principaux :
    • Composant Parent : Gère l'ensemble de la page et contient des données globales comme celles liées au panier.
    • Composant Enfant : Affiche les détails du produit, comme sa description ou des badges spécifiques.
  • Le composant enfant ne peut pas accéder directement aux données du parent.

2. Solution : Utiliser des props :

  • Les props permettent au composant parent de transmettre des données spécifiques à son enfant.

3. Étapes pour utiliser les props :

a) Déclarer une donnée dans le parent :

  • Dans le composant parent, on crée une donnée enPromotionProduct qui indique si le produit est en promotion.
data() { return { enPromotionProduct: true // Par défaut, le produit est en promotion }; }

b) Passer cette donnée au composant enfant :

  • Dans le template du parent, on transmet la donnée via un attribut personnalisé :
  • <product-component :enPromotion="enPromotionProduct"></product-component>

c) Déclarer et utiliser la prop dans l'enfant :

  1. Déclarer la prop dans le composant enfant pour qu'il puisse recevoir et utiliser cette donnée :
    props: { enPromotion: { type: Boolean, // La prop doit être de type booléen required: true // Cette prop est obligatoire } }
  2. Utiliser la prop dans le template du composant enfant. Par exemple, afficher un badge "Promotion" si la prop est vraie :
    <div v-show="enPromotion" class="promotion-badge"> 🏷️ Produit en promotion ! </div>

4. Résultat final :

  • Lorsque la donnée enPromotionProduct dans le parent est true, un badge "🏷️ Produit en promotion !" s'affiche dans le composant enfant.
  • Si cette donnée est modifiée dans le parent (par exemple, false), le composant enfant met automatiquement à jour son rendu, et le badge disparaît.

Points importants :

  1. Unidirectionnalité : Les props permettent un flux de données clair du parent → enfant.
  2. Validation des props : On peut préciser le type, rendre la prop obligatoire, ou même définir des valeurs par défaut.
  3. Dynamisme : Toute modification de la donnée dans le parent se répercute automatiquement sur l’enfant.

Avantages de l'exemple enPromotion :

Cet exemple montre clairement comment un composant parent peut contrôler le rendu du composant enfant de manière conditionnelle. Cela illustre aussi un cas d'usage réaliste pour des sites e-commerce, où des informations comme l'état de promotion d'un produit sont essentielles.

[VueJs] Émettre des événements depuis un composant enfant

 Comment émettre des événements personnalisés depuis un composant enfant pour communiquer avec un composant parent.



Voici les étapes clés :

  1. Problème initial :

    • L'application est structurée en deux composants :
      • Parent : Contient la page globale et le panier.
      • Enfant : Contient la description du produit.
    • En déplaçant le bouton "Ajouter" dans le composant enfant, le panier ne fonctionne plus, car il dépend d'une action dans le parent.
  2. Émission d’un événement :

    • Dans le composant enfant :
      • On utilise this.$emit('nom-de-l-evenement') pour informer le parent qu’une action s’est produite.
      • Exemple : Lorsqu'un utilisateur clique sur "Ajouter", l'événement personnalisé add-product est émis.
  3. Écoute par le parent :

    • Dans le composant parent :
      • On ajoute un écouteur d’événement avec @add-product="methodeParent".
      • Cette méthode implémente la logique, comme mettre à jour le panier.
  4. Transmission de données :

    • L'événement peut transporter des données via un second argument
    • Exemple :
      • this.$emit('add-product', price) dans l'enfant.
    • Dans le parent, la méthode liée peut récupérer ces données via $event.
      Exemple : addCard(price) { this.totalPrice += price; }
  5. Résultat final :

    • En cliquant sur "Ajouter", le composant enfant émet un événement avec le prix du produit.
    • Le parent écoute cet événement, récupère les données et met à jour le panier (quantité et total des prix).

Points importants :

  • Événements personnalisés sont une solution efficace pour la communication enfant → parent.
  • Transport de données : Les événements peuvent inclure des arguments pour transmettre des informations au parent.
  • Flexibilité : Ce mécanisme permet de maintenir une architecture de composants propre et modulaire.

vendredi 25 octobre 2024

[Spring boot] Problème rencontré avec `ddl-auto` par défaut dans les tests Hibernate

Lorsque nous exécutons nos tests Spring, nous avons remarqué qu’Hibernate **supprime** (drop) et **recrée** les tables à chaque exécution. Ce comportement entraîne la perte de données après chaque test.


Cela est dû à la configuration par défaut de Spring Boot : si une **base de données embarquée** (comme H2) est détectée et qu’aucun outil de gestion de schéma (par exemple Flyway ou Liquibase) n'est utilisé, alors `spring.jpa.hibernate.ddl-auto` passe automatiquement à `create-drop`. Ce mode initialise le schéma à chaque exécution, ce qui peut ne pas être souhaité en test ou en production.


**Documentation de référence :**

[Spring Boot Data Initialization](https://docs.spring.io/spring-boot/how-to/data-initialization.html)


---


### Solution : Configuration pour éviter la suppression du schéma dans les tests et en production

Ou bien utiliser CommandLineRunner pour peupler la BDD avant que spring ne soit prêt à recevoir des requêtes

1. **Configurer pour les tests** :

   Si vous souhaitez garder une base de données H2 pour les tests sans que les données soient perdues à chaque exécution, configurez `ddl-auto` comme suit :


   ```yaml

   spring:

     jpa:

       hibernate:

         ddl-auto: update  # Ne supprime rien, mais adapte la structure au besoin

     datasource:

       platform: h2

       url: jdbc:h2:./test-h2/test-db;DB_CLOSE_DELAY=-1;MODE=Oracle;TRACE_LEVEL_FILE=4;AUTO_SERVER=TRUE

       driver-class-name: org.h2.Driver

       username: sa

       password:

     h2:

       console:

         path: /manage/h2/console

         enabled: true

     jpa:

       properties:

         hibernate:

           dialect: org.hibernate.dialect.H2Dialect

   ```


   Cette configuration empêche Hibernate de supprimer les tables, mais permet toujours de mettre à jour leur structure si des changements sont détectés.


2. **Configurer pour la production** :

   En production, il est recommandé de **désactiver** `ddl-auto` ou de le configurer en mode `validate` pour empêcher Hibernate de modifier le schéma automatiquement. Utilisez des outils de migration de schéma comme **Flyway** ou **Liquibase** pour gérer les modifications.


   ```yaml

   spring:

     jpa:

       hibernate:

         ddl-auto: none

   ```


   Cette configuration garantit que Hibernate n’effectue aucune modification sur les tables SQL en production, laissant le contrôle du schéma aux outils de migration.


---


### Notes importantes


- Par défaut, si la propriété `spring.jpa.hibernate.ddl-auto` n’est pas explicitement définie, Spring Boot utilise `create-drop` pour les bases de données embarquées (comme H2).

- En production, il est **fortement recommandé** de définir `ddl-auto` sur `none` ou `validate` pour éviter les manipulations non intentionnelles du schéma.


En résumé, adaptez `ddl-auto` à l’environnement : utilisez `update` pour les tests si vous souhaitez conserver les données, et `none` ou `validate` en production pour un schéma sous contrôle.

jeudi 3 octobre 2024

[Spring] Le bean singleton dans Spring est-il thread-safe ?

 La réponse est non, il n'est pas thread-safe, et c'est pourquoi beaucoup de développeurs préfèrent utiliser l'injection par le constructeur plutôt que par le champ. De cette manière, ils peuvent définir leurs objets singleton comme immuables. Cela commence par rendre les attributs final.



La raison pour laquelle je veux que mes attributs soient immuables est de m'assurer que personne ne les modifie, car un singleton n'est pas synchronisé par Spring de quelque manière que ce soit. Il n'est même pas recommandé de le faire, ne changez jamais les attributs d'un objet singleton. Théoriquement, c'est possible, si pour une raison quelconque vous choisissez de le faire, assurez-vous de gérer la synchronisation vous-même. Vous pouvez utiliser le mot-clé synchronized en Java, vous pouvez utiliser des outils comme les sémaphores, ReadWriteLock, des barrières cycliques, etc.

Autre raccourcis avec Lombok :

@RestController

@RequiredArgsConstructor

public class DemoController {

    private final DemoService demoService;


    @GetMapping("/demo")

    public String getDemo() {

        return demoService.getDemoMessage();

    }

}


dimanche 8 septembre 2024

[Thread] Why was the stop() method on thread deprecated?

Thread. stop is being deprecated because it is inherently unsafe.

https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html#:~:text=Because%20it%20is%20inherently%20unsafe,exception%20propagates%20up%20the%20stack.)

https://docs.oracle.com/cd/E19455-01/806-3461/6jck06gr5/index.html#:~:text=of%20JDK%201.1.-,Thread.,because%20it%20is%20inherently%20unsafe.