IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Boot Java Discussion :

Tutoriel sur le développement full stack d'une application Web avec Angular 7 et Spring Boot 2


Sujet :

Spring Boot Java

  1. #1
    Membre chevronné

    Homme Profil pro
    Ingénieur R&D en informatique
    Inscrit en
    Août 2011
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur R&D en informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 313
    Points : 1 855
    Points
    1 855
    Par défaut Tutoriel sur le développement full stack d'une application Web avec Angular 7 et Spring Boot 2
    Bonjour,

    L'article a pour but de présenter la conception, l'architecture et le développement full stack d'une application web en s'appuyant sur les technologies Java, Spring Boot et Angular. Plusieurs concepts sont abordés et expliqués dans l'article par la mise en oeuvre d'un exemple concret d'une application.

    https://gkemayo.developpez.com/tutor...spring-boot-2/

    Qu'en pensez-vous ?

    Retrouvez les meilleurs cours et tutoriels pour apprendre le développement Web avec Spring Boot

  2. #2
    Membre émérite
    Homme Profil pro
    Ingénieur en génie logiciel
    Inscrit en
    Juin 2012
    Messages
    856
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur en génie logiciel
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2012
    Messages : 856
    Points : 2 442
    Points
    2 442
    Par défaut
    bravo pour le tutoriel

    en couplant tes entités, tu brises un peu le concept de package by feature architecture
    il aurait été possible de passer par des id, sinon de copier les données et de passer par un événèment pour les mettres à jour, suppression...

  3. #3
    Membre actif
    Inscrit en
    Juin 2005
    Messages
    578
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 578
    Points : 240
    Points
    240
    Par défaut
    Bonjour

    Très bon tutoriel, cependant je rencontre quelques problèmes lors de l'exécution du code source téléchargeable à la fin de l'article.

    Après avoir installé les dépendances avec npm install, j'exécute ng serve --open. Et là je reçois le message d'erreur suivant:

    Proxy config file D:\workspace-spring_tool_suite\library-ui-master\src\proxy.conf.json does not exist.
    Error: Proxy config file D:\workspace-spring_tool_suite\library-ui-master\src\proxy.conf.json does not exist.
    Je ne sais pas si c'est une erreur de votre part, mais il a fallu que je change le chemin menant vers proxy.conf.json dans le fichier angular.json pour régler le problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "proxyConfig": "proxy.conf.json"
    au lieu de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "proxyConfig": "src/proxy.conf.json"
    Ensuite lorsque j'accède à la page book-page, je reçois le message d'erreur suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    An error occurs when retreiving categories data
    Ci-dessous une capture d'écran:

    Nom : error.PNG
Affichages : 13334
Taille : 50,3 Ko

    Voici l'erreur au niveau du log:

    Error occurred while trying to proxy request /library/rest/category/api/allCategories from localhost:4200 to http://localhost:8082 (ECONNREFUSED) (https
    ://nodejs.org/api/errors.html#errors_common_system_errors)
    Merci

  4. #4
    Membre actif
    Inscrit en
    Juin 2005
    Messages
    578
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 578
    Points : 240
    Points
    240
    Par défaut
    finalement ça marche.

    Je lançais le projet via l'option Spring Boot App, mais j'ai par la suite opté de le lancer via le server tomcat installé, tout en changer le port 8080 en 8082, et ça a marché.

  5. #5
    Candidat au Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2016
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2016
    Messages : 7
    Points : 4
    Points
    4
    Par défaut create-drop inefficace
    Bonjour,

    Le tuto est vraiment bien fait.

    J'ai juste un petit soucis avec la base de données H2. J'ai fait toute la partie back et j'ai voulu tester.
    Au premier démarrage de tomcat, pas de soucis.
    J'ai fais des modifications et depuis impossible de relancer l'application :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Violation d'index unique ou clé primaire: "PUBLIC.PRIMARY_KEY_3 ON PUBLIC.CATEGORY(CODE) VALUES 1"
    Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_3 ON PUBLIC.CATEGORY(CODE) VALUES 1"; SQL statement:
    insert into category values ('INF', 'Informatique') [23505-200]
    Je n'arrive pas à drop les données de la table category :/ j'ai essayé d'ajouté la commande
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    truncate table category;
    dans le fichier sql chargé au début mais cela me retourne une exception ..

    Edit : j'ai augmenté le cache de la log et je vois qu'en fait le soucis provient d'un drop qui ne se fait pas sur mes tables à cause de FK qui ne sont pas supprimées...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Impossible de supprimer "BOOK" car "FK88C0YDLO57PCGP137TNTRGQX1" dépend de lui
    Cannot drop "BOOK" because "FK88C0YDLO57PCGP137TNTRGQX1" depends on it; SQL statement: drop table book if exists [90107-200]

  6. #6
    Membre chevronné

    Homme Profil pro
    Ingénieur R&D en informatique
    Inscrit en
    Août 2011
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur R&D en informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 313
    Points : 1 855
    Points
    1 855
    Par défaut
    Citation Envoyé par marc.collin Voir le message
    bravo pour le tutoriel

    en couplant tes entités, tu brises un peu le concept de package by feature architecture
    il aurait été possible de passer par des id, sinon de copier les données et de passer par un événement pour les mettres à jour, suppression...
    Bonjour Marc.collin,

    Tu as parfaitement raison, la contrainte du package by feature vient vraiment des "ressources" qui sont partagées entre domaines. J'étais bien conscient que je n'ai pas fait un aboutissement de cette architecture dans l'article. Le but est dans un premier temps de sensibiliser le lecteur sur cette architecture qui apporte son lot de concepts, d'avantages et d'inconvénients. Si le lecteur s'y intéresse, il ira chercher plus d'infos.

    Les solutions que l'on peut proposer pour adresser ce problème sont multiples, chacune possédant ces avantages et inconvénients. Pour la solution que tu proposes de copier les données et de d'utiliser l'event sourcing pour les mettre à jour, c'est bien, mais ça passe par une duplication de données et la mise en place de l'event sourcing pour mettre à jour chaque domaine. C'est complexe et impossible d'expliquer tout cela dans un seul et même article .

    Je peux même aller plus loin en disant que l'on peut même mettre en place le pattern Capture Data Change couplé à Kafka qui se chargera de mettre à jour la/les tables de chaque domaine. Là encore c'est très complexe et trop de travail rien que pour respecter le principe du package by feature.

    Il vaut mieux s'y investir sur tout ce que nous venons de citer lorsqu'on est vraiment en contexte Microservice ou une vraie architecture domaine driven.

    D'autres son de cloche, disent de sortir exceptionnellement les "ressources" partagées (en veillant à ce que cela ne devienne pas un fourre tout) dans un package "common" afin que les différents domaines se les partagent. Ce n'est pas moins intelligible, après tout c'est une organisation dans un seul et unique projet.

    Cordialement,
    Georges

  7. #7
    Membre chevronné

    Homme Profil pro
    Ingénieur R&D en informatique
    Inscrit en
    Août 2011
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur R&D en informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 313
    Points : 1 855
    Points
    1 855
    Par défaut
    Citation Envoyé par momjunior Voir le message
    finalement ça marche.

    Je lançais le projet via l'option Spring Boot App, mais j'ai par la suite opté de le lancer via le server tomcat installé, tout en changer le port 8080 en 8082, et ça a marché.

  8. #8
    Membre chevronné

    Homme Profil pro
    Ingénieur R&D en informatique
    Inscrit en
    Août 2011
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur R&D en informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 313
    Points : 1 855
    Points
    1 855
    Par défaut
    Citation Envoyé par DarkChyper Voir le message
    Bonjour,

    Le tuto est vraiment bien fait.

    J'ai juste un petit soucis avec la base de données H2. J'ai fait toute la partie back et j'ai voulu tester.
    Au premier démarrage de tomcat, pas de soucis.
    J'ai fais des modifications et depuis impossible de relancer l'application :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Violation d'index unique ou clé primaire: "PUBLIC.PRIMARY_KEY_3 ON PUBLIC.CATEGORY(CODE) VALUES 1"
    Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_3 ON PUBLIC.CATEGORY(CODE) VALUES 1"; SQL statement:
    insert into category values ('INF', 'Informatique') [23505-200]
    Je n'arrive pas à drop les données de la table category :/ j'ai essayé d'ajouté la commande
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    truncate table category;
    dans le fichier sql chargé au début mais cela me retourne une exception ..

    Edit : j'ai augmenté le cache de la log et je vois qu'en fait le soucis provient d'un drop qui ne se fait pas sur mes tables à cause de FK qui ne sont pas supprimées...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Impossible de supprimer "BOOK" car "FK88C0YDLO57PCGP137TNTRGQX1" dépend de lui
    Cannot drop "BOOK" because "FK88C0YDLO57PCGP137TNTRGQX1" depends on it; SQL statement: drop table book if exists [90107-200]

    Salut DarkChyper,

    Normalement cela ne devrait pas poser de problème si tu arrêtais toute l'application via ton Tomcat en faisant un shutdown en invite de commande dans le dossier bin.
    Puis en redémarrant avec start. Puisque l'appli utilise une base embarquée, tout devrait se réinitialiser au redemarrage.

    Assures toi juste qu'aucun processus lié ne tourne au préalable sur ta machine.

    Cordialement,
    Georges

  9. #9
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Points : 12 815
    Points
    12 815
    Par défaut
    Bravo et merci pour cet excellent article
    Thierry Leriche-Dessirier
    Consultant Java JEE Web Agile freelance
    Rédacteur pour Developpez
    Professeur de Génie Logiciel à l'ESIEA

    Site : http://www.icauda.com / Linked'in : http://www.linkedin.com/in/thierryler / Twitter : @ThierryLeriche

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 43
    Points : 44
    Points
    44
    Par défaut
    Bonjour,
    Toujours admiratif du temps passé à écrire ce type de tutoriel surtout quand la qualité est au rendez vous.
    Merci pour le partage.

  11. #11
    Futur Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2020
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2020
    Messages : 4
    Points : 5
    Points
    5
    Par défaut Prob Tuto
    Salut,
    j'ai bien suivi toutes les étapes de ce tuto,mais j'ai des problèmes à la phase de déploie de déploiment !!

    les erreurs sont indiquées aux pièces jointes.

    Merci de me proposer une solution!
    Images attachées Images attachées  

  12. #12
    Membre chevronné Avatar de jeffray03
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2008
    Messages
    1 501
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 501
    Points : 2 120
    Points
    2 120
    Par défaut
    Salut,
    tu effectues sans doute une Insertion avec la meme clé primaire dans la table Categorie. As tu declaré cette clé Auto_increment ?

    Eric

  13. #13
    Futur Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2020
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2020
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par jeffray03 Voir le message
    Salut,
    tu effectues sans doute une Insertion avec la meme clé primaire dans la table Categorie. As tu declaré cette clé Auto_increment ?

    Eric
    J'ai suivi exactement le tuto: les données de la table Categorie sont nomrmalement insérés une seule fois grace à la fichier "categories.sql" (
    insert into category values ('INF', 'Informatique');
    insert into category values ('MAT', 'Mathématiques, Physiques et Chimie');
    ..)

    l'utilisateur n'as pas besoin de changer les données!

    (clé primaire n'est pas Auto_increment)
    Images attachées Images attachées   

  14. #14
    Membre chevronné Avatar de jeffray03
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2008
    Messages
    1 501
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 501
    Points : 2 120
    Points
    2 120
    Par défaut
    salut,
    cela peut etre due, du fait qu´a chaque demarrage, tu fais un insertion dans la base de données sans l´avoir d´abord supprimmer et recréer.
    montres nous le fichier de configuration.
    Eric

  15. #15
    Futur Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2020
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2020
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    Je suis en train de trouver une autre solution :
    1)j'ai lancé le "Back-end" avec l'option Spring Boot App (port : 8082)

    2)j'ai lancé le "Front-end" avec l'option npm start (port : 4200)

    dans le navigateur je peux voir les 2 projets mais le problème est la connexion entres eux ! car j'ai obtenu cette erreur :
    [HPM] Error occurred while trying to proxy request /library/rest/category/api/allCategories from localhost:4200 to http://localhost:8082 (ECONNREFUSED) (https://nodejs.org/api/errors.html#e..._system_errors)
    Images attachées Images attachées    

  16. #16
    Membre chevronné

    Homme Profil pro
    Ingénieur R&D en informatique
    Inscrit en
    Août 2011
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur R&D en informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 313
    Points : 1 855
    Points
    1 855
    Par défaut
    Citation Envoyé par selmen95 Voir le message
    J'ai suivi exactement le tuto: les données de la table Categorie sont nomrmalement insérés une seule fois grace à la fichier "categories.sql" (
    insert into category values ('INF', 'Informatique');
    insert into category values ('MAT', 'Mathématiques, Physiques et Chimie');
    ..)

    l'utilisateur n'as pas besoin de changer les données!

    (clé primaire n'est pas Auto_increment)

    Bonjour Selmen95,

    Attention !!! Le problème peut provenir du fait que tu essais de lancer plusieurs instances du Back-End. Dans ce cas, tu rencontreras forcément une violation de clef primaire. Car les scripts SQL d'insertion au démarrage de l'application ne sont pas protégés. Peux-tu essayer de stopper toutes les instances de ton serveur Tomcat (commande shutdown) et même aller jusqu'à vérifier dans ton Gestionnaire de tâches que tu n'en a pas un rebelle qui continue de tourner en backoffice ? Tu peux aussi essayer la commande ps pour lister les processus en cours sur ta machine... Je te rappelle enfin que si tu as lancé aussi des traitements sur la Back-end/Front-end dans ton terminal Eclipse, cela peut être source de conflit également lorsque tu essais de les lancer via Tomcat.
    Après avoir vérifié et fermé tous les processus liés, démarre une nouvelle instance de Tomcat et fais moi un retour.

    Merci,
    Georges

  17. #17
    Futur Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2020
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2020
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par misterKool Voir le message
    Bonjour Selmen95,

    Attention !!! Le problème peut provenir du fait que tu essais de lancer plusieurs instances du Back-End. Dans ce cas, tu rencontreras forcément une violation de clef primaire. Car les scripts SQL d'insertion au démarrage de l'application ne sont pas protégés. Peux-tu essayer de stopper toutes les instances de ton serveur Tomcat (commande shutdown) et même aller jusqu'à vérifier dans ton Gestionnaire de tâches que tu n'en a pas un rebelle qui continue de tourner en backoffice ? Tu peux aussi essayer la commande ps pour lister les processus en cours sur ta machine... Je te rappelle enfin que si tu as lancé aussi des traitements sur la Back-end/Front-end dans ton terminal Eclipse, cela peut être source de conflit également lorsque tu essais de les lancer via Tomcat.
    Après avoir vérifié et fermé tous les processus liés, démarre une nouvelle instance de Tomcat et fais moi un retour.

    Merci,
    Georges
    Merci, mais j'ai rencontré le même problème !

  18. #18
    Membre averti
    Avatar de parchemal
    Homme Profil pro
    Ingénieur Développeur Java
    Inscrit en
    Août 2009
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2009
    Messages : 144
    Points : 320
    Points
    320
    Par défaut
    Bonjour et Bravo pour ce tutoriel,

    Voici quelques remarques:
    • L'architecture que vous présentez me semble bonne, mais adaptée pour des applications ayant très peu de classes ou de fonctionnalités , qu'en dites-vous ?
    • Par contre faites attention à vos contrôleurs. Car il y a du code métier dans vos contrôleurs puisque vous n'exploitez pas bien les réponses HttpStatus et ResponseEntity


    Voici un exemple de votre contrôleur avec du traitement métier


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
        @PostMapping("/addCustomer")
        public ResponseEntity<CustomerDTO> createNewCustomer(@RequestBody CustomerDTO customerDTORequest) {
            //, UriComponentsBuilder uriComponentBuilder
            Customer existingCustomer = customerService.findCustomerByEmail(customerDTORequest.getEmail());//pas besoin
            if (existingCustomer != null) { //pas besoin
                return new ResponseEntity<CustomerDTO>(HttpStatus.CONFLICT); // pas besoin, ce traitement doit être fait par le service qui gère la sauvegarde, il faut renvoyer directement l'exception depuis le service
            }
            Customer customerRequest = mapCustomerDTOToCustomer(customerDTORequest);
            customerRequest.setCreationDate(LocalDate.now());
            Customer customerResponse = customerService.saveCustomer(customerRequest);
            if (customerResponse != null) {//idem, pas besoin
                CustomerDTO customerDTO = mapCustomerToCustomerDTO(customerResponse);
                return new ResponseEntity<CustomerDTO>(customerDTO, HttpStatus.CREATED);
            }
            return new ResponseEntity<CustomerDTO>(HttpStatus.NOT_MODIFIED);
        }
    Voici un exemple de solution pour le service que je propose (Classe de gestion des exceptions à créer CustomerResourceException):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    public Customer saveOrUpdateCustomer(Customer customer) throws CustomerResourceException{
    	try{
    		return customerRepository.save(customer);
    	} catch(DataIntegrityViolationException ex){
    		logger.error("customer non existant", ex);
    		throw new CustomerResourceException("DuplicateValueError", "Un customer existe déjà avec le compte : "+customer.getLogin(), HttpStatus.CONFLICT);
    	} catch (CustomerResourceException e) {
    		logger.error("Utilisateur non existant", e);
    		throw new CustomerResourceException("CustomerNotFound", "Aucun utilisateur avec l'identifiant: "+customer.getId(), HttpStatus.NOT_FOUND);
    	} catch(Exception ex){
    		logger.error("Erreur technique de création ou de mise à jour de l'utilisateur", ex);
    		throw new CustomerResourceException("SaveOrUpdateUserError", "Erreur technique de création ou de mise à jour du customer: "+customer.getLogin(), HttpStatus.INTERNAL_SERVER_ERROR);
    	}
    }
    Et voici ce que devient le contrôleur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
        @PostMapping("/addCustomer")
        public ResponseEntity<CustomerDTO> createNewCustomer(@RequestBody CustomerDTO customerDTORequest) {
            //, UriComponentsBuilder uriComponentBuilder
           try{
                Customer customerRequest = mapCustomerDTOToCustomer(customerDTORequest);
                customerRequest.setCreationDate(LocalDate.now());
                Customer customerResponse = customerService.saveCustomer(customerRequest);
                CustomerDTO customerDTO = mapCustomerToCustomerDTO(customerResponse);
                return new ResponseEntity<CustomerDTO>(customerDTO, HttpStatus.CREATED);
           } catch (CustomerResourceException ex) {
             //Traitez vos erreurs ici par un log si nécessaire
            return new ResponseEntity<CustomerDTO>(ex.getHttpStatus()); //Ici tu gères à la fois plusieurs types d'erreurs comme HttpStatus.NOT_MODIFIED, HttpStatus.CONFLICT etc , au lieu de forcer la réponse à HttpStatus.NOT_MODIFIED uniquement
           }  catch (Exception  ex) {
             //Traiter les erreurs techniques ici par un log
           return new ResponseEntity<CustomerDTO>(HttpStatus.INTERNAL_SERVER_ERROR); // un cas typique d'erreur ici serait une erreur liée au mapping, ou autres erreurs non gérées par le service
           }
     
        }
    Voici un exemple du constructeur de ton Exception

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        public CustomerResourceException(String errorCode, String message, HttpStatus httpStatus) {
            super(message);
            this.errorCode = errorCode;
            this.httpStatus = httpStatus;
        }
    Note: Penser aux getter/setter dans l'exception

    Au final, pas besoin d'une requête supplémentaire customerService.findCustomerByEmail(xxx) dans le createNewCustomer car, en cas conflit, le service sait le code d'erreur à retourner

    Bon courage !!!!
    Nguimgo Bertrand
    Ingénieur Etudes et Développement JAVA/JEE

    - Guide d'implémentation des services REST avec Spring Boot et Spring RestTemplate
    - Je vous propose de lire le guide d'implémentation du design pattern MVP-GWT
    - N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  19. #19
    Membre chevronné

    Homme Profil pro
    Ingénieur R&D en informatique
    Inscrit en
    Août 2011
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur R&D en informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2011
    Messages : 313
    Points : 1 855
    Points
    1 855
    Par défaut
    Bonjour parchemal,

    Je te remercie pour tes remarques.

    Citation Envoyé par parchemal Voir le message
    L'architecture que vous présentez me semble bonne, mais adaptée pour des applications ayant très peu de classes ou de fonctionnalités , qu'en dites-vous ?
    Le package by feature est une architecture contraignante qui a ses avantages et ses inconvénients comme j'ai tenté d'en citer quelques uns dans l'article. Je ne peux pas trancher ta question, car elle est philosophique à mon sens. D'aucuns n'y verront aucun souci à tes réserves, d'autres diront autant mieux aller vers les microservices en cas d'un grand nombre de fonctionnalités.

    Citation Envoyé par parchemal Voir le message

    Par contre faites attention à vos contrôleurs. Car il y a du code métier dans vos contrôleurs puisque vous n'exploitez pas bien les réponses HttpStatus et ResponseEntity

    Voici un exemple de votre contrôleur avec du traitement métier


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
        @PostMapping("/addCustomer")
        public ResponseEntity<CustomerDTO> createNewCustomer(@RequestBody CustomerDTO customerDTORequest) {
            //, UriComponentsBuilder uriComponentBuilder
            Customer existingCustomer = customerService.findCustomerByEmail(customerDTORequest.getEmail());//pas besoin
            if (existingCustomer != null) { //pas besoin
                return new ResponseEntity<CustomerDTO>(HttpStatus.CONFLICT); // pas besoin, ce traitement doit être fait par le service qui gère la sauvegarde, il faut renvoyer directement l'exception depuis le service
            }
            Customer customerRequest = mapCustomerDTOToCustomer(customerDTORequest);
            customerRequest.setCreationDate(LocalDate.now());
            Customer customerResponse = customerService.saveCustomer(customerRequest);
            if (customerResponse != null) {//idem, pas besoin
                CustomerDTO customerDTO = mapCustomerToCustomerDTO(customerResponse);
                return new ResponseEntity<CustomerDTO>(customerDTO, HttpStatus.CREATED);
            }
            return new ResponseEntity<CustomerDTO>(HttpStatus.NOT_MODIFIED);
        }
    Voici un exemple de solution pour le service que je propose (Classe de gestion des exceptions à créer CustomerResourceException):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    public Customer saveOrUpdateCustomer(Customer customer) throws CustomerResourceException{
    	try{
    		return customerRepository.save(customer);
    	} catch(DataIntegrityViolationException ex){
    		logger.error("customer non existant", ex);
    		throw new CustomerResourceException("DuplicateValueError", "Un customer existe déjà avec le compte : "+customer.getLogin(), HttpStatus.CONFLICT);
    	} catch (CustomerResourceException e) {
    		logger.error("Utilisateur non existant", e);
    		throw new CustomerResourceException("CustomerNotFound", "Aucun utilisateur avec l'identifiant: "+customer.getId(), HttpStatus.NOT_FOUND);
    	} catch(Exception ex){
    		logger.error("Erreur technique de création ou de mise à jour de l'utilisateur", ex);
    		throw new CustomerResourceException("SaveOrUpdateUserError", "Erreur technique de création ou de mise à jour du customer: "+customer.getLogin(), HttpStatus.INTERNAL_SERVER_ERROR);
    	}
    }
    Et voici ce que devient le contrôleur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
        @PostMapping("/addCustomer")
        public ResponseEntity<CustomerDTO> createNewCustomer(@RequestBody CustomerDTO customerDTORequest) {
            //, UriComponentsBuilder uriComponentBuilder
           try{
                Customer customerRequest = mapCustomerDTOToCustomer(customerDTORequest);
                customerRequest.setCreationDate(LocalDate.now());
                Customer customerResponse = customerService.saveCustomer(customerRequest);
                CustomerDTO customerDTO = mapCustomerToCustomerDTO(customerResponse);
                return new ResponseEntity<CustomerDTO>(customerDTO, HttpStatus.CREATED);
           } catch (CustomerResourceException ex) {
             //Traitez vos erreurs ici par un log si nécessaire
            return new ResponseEntity<CustomerDTO>(ex.getHttpStatus()); //Ici tu gères à la fois plusieurs types d'erreurs comme HttpStatus.NOT_MODIFIED, HttpStatus.CONFLICT etc , au lieu de forcer la réponse à HttpStatus.NOT_MODIFIED uniquement
           }  catch (Exception  ex) {
             //Traiter les erreurs techniques ici par un log
           return new ResponseEntity<CustomerDTO>(HttpStatus.INTERNAL_SERVER_ERROR); // un cas typique d'erreur ici serait une erreur liée au mapping, ou autres erreurs non gérées par le service
           }
     
        }
    Voici un exemple du constructeur de ton Exception

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        public CustomerResourceException(String errorCode, String message, HttpStatus httpStatus) {
            super(message);
            this.errorCode = errorCode;
            this.httpStatus = httpStatus;
        }
    Note: Penser aux getter/setter dans l'exception

    Au final, pas besoin d'une requête supplémentaire customerService.findCustomerByEmail(xxx) dans le createNewCustomer car, en cas conflit, le service sait le code d'erreur à retourner

    Bon courage !!!!
    Pour ton deuxième point, tu as tout à fait raison, mais je dirai tout d'abord que tout code est perfectible. On pourrait même convoquer d'autres notions de clean code pour améliorer d'avantage. Cela dit, cet article ne porte pas sur le clean code ni sur la gestion optimale des exceptions. L'article se focalise sur l'initiation du lecteur à diverses notions et leurs mises en œuvre et non sur une démonstration du code parfait . La revue de code et son optimisation est très important dans un projet professionnel, mais pas dans un cours à mon avis, sauf si cela fait partir des objectifs explicite du cours.

    Qu'à cela ne tienne, je te remercie encore une fois pour tes remarques pertinentes. Ceux qui réussiront à mettre en place les notions distillées dans mon article et qui veulent aller plus loin doivent s'inspirer de tes remarques.

    Georges

  20. #20
    Membre averti
    Homme Profil pro
    Reconversion
    Inscrit en
    Novembre 2018
    Messages
    502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Reconversion
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2018
    Messages : 502
    Points : 300
    Points
    300
    Par défaut Impossible de démarrer le back end avec Tomcat
    Bonjour, et tout d'abord merci beaucoup pour ce tutoriel très bien réalisé au cours duquel j'apprends beaucoup.

    Ayant un profil débutant junior en java/angular, je me suis attelé à ce tutoriel il y a quelques jours. Je rencontre un petit problème que je vais essayer de décrire au mieux :
    En effet, arrivé à la finalisation du back end et au test des web services de l'API Rest, je n'arrive pas à lancer le serveur Tomcat (j'utilise la v.9), j'ai configuré le port en 8082.

    Le problème vient (je suppose) du fait que je n'arrive pas à établir la connexion avec la BDD car je relève un message d'erreur qui jette une DbException avec la mention :
    "Erreur du fichier journal C:/Windows/System32/src/main/resources/database/library-db.trace.db Erreur lors de la création du fichier ""C:/Windows/System32/src""

    D'autre part j'ai une autre exception qui découle de la première du type :
    "org.h2.jdbc.JdbcSQLNonTransientException: Erreur du fichier journal: "C:/Windows/System32/src/main/resources/database/library-db.trace.db"

    Je suppose que j'ai un soucis au niveau de la gestion des ressources de la Database :
    J'ai téléchargé le fichier "library-db.mv.db" dans le dossier database comme indiqué dans l'arborescence du projet, en revanche je n'utilise pas le fichier library-trace.trace.db.
    Je ne sais pas comment me vérifier. Au départ, j'avais tapé tout le code moi-même, et j'ai créé un second projet où j'ai copié-collé les sources sur github et le résultat et le même.

    Vous remerciant

Discussions similaires

  1. Réponses: 22
    Dernier message: 20/08/2023, 14h41
  2. Réponses: 2
    Dernier message: 05/07/2019, 11h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo