WordPress et CMS 2/4

Installation de WordPress

Après tous ces réglages et tests qui permettent de comprendre le fonctionnement assez général d’un serveur Web Apache (les autres marques de serveurs Web fonctionnent de manière similaire: Nginx, Microsoft IIS, NodeJs, Django, Tomcat, etc.).

Télécharger le fichier WordPress soit:

Commencer par dézipper le fichier WordPress-5.5.1-fr_FR.zip ( version Français de France oui il y a un WordPress fr_CA pour le Français du Canada) avec l’outil classique que vous utiliser dans un dossier et indiquer ce dossier à filezilla pour assurer le transfert.

NOTA: Les numéro de versions (par exemple 5.4.1) de WordPress sont à comprendre dans ce sens:

  • Le premier chiffre 5 est le plus important, nous avons WordPress en version 5 sortie le 12 décembre 2018
  • Le second chiffre 4 est le numéro de version secondaire qui indique des évolutions surtout dans la correction de bug dans cette version de WordPress
  • Le troisième chiffre 1 est le numéro de version sur les mises à jours de sécurités

Il faut installer la version la plus récente et réaliser rapidement la mise à jours de cette version pour obtenir la dernière version la plus débuggée et la plus sécurisée. Pour les mises à jours (upgrade) il faut garder à l’esprit que la mise à jours de sécurités ne doit pas avoir beaucoup d’impact sur votre site web par contre le changement de version important entraine des modifications importantes de votre WordPress.

 

Maintenant avec Filezilla, on va transférer tous les fichiers et les dossiers du WordPress vers le dossier www du serveur www.master-ctn.mines-ales.fr .

Indiquer bien le dossier où se trouve WordPress sur votre PC (en partie gauche), indiquez bien (ou cliquer sur le bon dossier à droite) le bon dossier www sur le serveur (en partie droite), sélectionner tous les fichiers/dossiers à gauche et faire glisser l’ensemble dans la zone fichier à droite (ou faite un clic droit > Envoyer):

Dans la « zone trasnfert de fichier » en bas vous devriez voir le transfert de fichier vers le serveur. Historiquement, le TP était en présentiel donc le transfert était assez rapide entre la salle de classe et la salle des serveurs dans le même bâtiment M. Maintenant, en fonction de votre hébergeur (de son coût aussi), de votre type de connexion, etc. le transfert peut prendre du temps. Regardez bien dans l’onglet « Transferts échoués » et s’il y a des messages d’erreur en rouge dans la « ZONE TECHNIQUE DE FILEZILLA ».

IMPORTANT: il faut que tous les fichiers et dossiers soient correctement transférer avant de démarrer l’installation. Ne commencer pas l’étape suivante tant que tous les fichiers et dossiers sont bien sur le serveur et non pas rejetés.

Une fois l’opération de transfert réalisée, on peut retourner sur le site web à l’adresse: http://www.master-ctn.mines-ales.fr/ctn20_jean/:

Appuyez sur « C’est parti! » et dans la nouvelle page, il faut indiquer les informations techniques récupérées à la page précédente:

  • nom de la base de données: ctn20_jean
  • identifiant de l’utilisateur de la base de données: ctn20_jean
  • mot de passe de l’utilisateur de la base de données
  • adresse du serveur de la base de données: localhost (essayez en cas de problème 127.0.0.1 ou le nom du serveur complet www.master-ctn.mines-ales.fr)
  • Préfixe de tables: laisser tel quel et voir la note technique plus bas

 

NOTE TECHNIQUE: le préfixe des tables de la base de données de Mysql est une technique qui permet dans une seule et unique base de données de mettre 2 wordpress qui font avoir un préfixe de table différent. Comme les hébergeurs facturent chaque base de données, les concepteurs de WordPress ont pensé que l’on puisse mettre plusieurs WordPress chez un hébergeur qui ne propose qu’une seule base de données. Chaque WordPress serait dans un sous-dossier dans www par exemple www/wordpress1/ et www/ mais tout deux seraient dans la même base de données en étant différencier par un prefix différent de nom de tables de base de données.

NOTE TECHNIQUE 2: Pour information l’Adresse IP (IP=Internet Procol) 127.0.0.1 est particulière. Chaque ordinateur a une adresse IP unique qui permet d’identifier les 2 ordinateurs qui communiquent en échangeant des informations. Votre ordinateur a une adresse IP, le serveur www.master-ctn.mines-ales.fr a une adresse IP (159.31.200.5). Parfois on doit indiquer à un ordinateur qu’il doit se consulter lui-même donc il y a une adresse spéciale 127.0.0.1 (appelé aussi localhost) qui indique que l’ordinateur doit communiquer avec lui-même. Une fois l’installation du serveur apache en local sur l’oridnateur via Mamp/Wamp, notre navigateur devra consulter ce serveur apache en local via l’adresse 127.0.0.1 qui a comme alias localhost.

 

Appuyez sur « Envoyer »

Cette page indique que l’installateur de WordPress a bien réussit à communiquer avec le logiciel de base de données Mysql et qu’il a constaté que l’installation peut se faire par rapport à ce logiciel.

NOTA: en cas d’erreur, il faut bien vérifier tous les réglages pour voir si les informations pour l’accès à la base de données sont correctes

 

La dernière étape permet d’indiquer des informations liés à l’installation du WordPress. La plus part des informations peuvent être modifiées par la suite mais ce sont des informations importantes:

  • Titre du site: Une information qui apparait ensuite dans le bandeau du site WordPress et qui apparait dans l’onglet du navigateur
  • Identifiant: l’identifiant de l’administrateur du site WordPress, habituellement on indique admin mais je recommande de mettre une autre information car ce nom d’utilisateur est l’identifiant qui permet de se connecter au site WordPress pour accéder à son backoffice
  • Le mot de passe: cette information est générée par WordPress comme mot de passe et modifiable. Il est critique de disposer d’un bon mot de passe pour votre identifiant sur le site WordPress
  • Adresse de messagerie: un email pour la récupération des informations de connexion en cas de perte du mot de passe
  • Visibilité par les moteurs de recherche: peu de moteur de recherche le prennent en compte, inutile tant que la réglementation n’obligera pas à prendre en compte cette information

NOTE TECHNIQUE: actuellement, beaucoup de site WordPress se font piratés car:

  • il est rentable d’attaquer des sites WordPress car le nombre de site cible est important par rapport aux autres CMS, WordPress serait utilisé dans 38% des sites dans le monde (https://fr.wikipedia.org/wiki/WordPress)
  • le nom de l’administrateur du WordPress est le nom du site web, nom du site www.truc.fr , nom de l’utilisateur truc.
  • les mots de passes sont trop simples à trouver (mot de passe déjà vu: wordpress , ou le nom du site , admin, 123456, etc.) et surtout ne sont jamais changés pendant des années.
  • le site est délaissé sans recevoir les mises à jours, le principe: »ça fonctionne, on n’y touche pas » entraine des failles de sécurités publiées par WordPress qui donne la méthode pour attaquer le site
  • des plugins/extensions/themes exotiques et/ou délaissés installés en nombre augmentant la surface d’attaque en proposant plus de failles potentielle
  • le mot de passe est utilisé sur un autre site dont l’attaquant a réussit à obtenir par une méthode ou une autre. Certains sites distribuant des contenus pirates demandent de créer un compte pour obtenir un couple identifiant/mot de passe qu’ils essayent sur différents sites en « espérant » qu’ils peuvent réutiliser.

Pour votre mot de passe, je ne peux que vous recommander de fabriquer une phrase dont certains mots sont remplacés par des symboles. Pour avoir des idées de robutesse: https://fr.wikipedia.org/wiki/Mot_de_passe#Crit%C3%A8res_de_robustesse

En cas de perte du mot de passe du site WordPress, nous verrons une méthode exploitant l’accès à la base de données directe pour refabriquer un mot de passe valide et de retrouver le nom de l’utilisateur si aussi il est oublié.

 

Appuyez sur « Installer WordPress » pour passer à la dernière étape:

Appuyez sur « Se connecter » pour avoir la page du backoffice:

La page pour accéder au  backoffice a un alias très utilisé http://www.master-ctn.mines-ales.fr/ctn20_jean/wp-admin/ qui est un accès similaire.

Notre site WordPress est opérationnel et en ligne.

Nous pouvons donc utiliser l’identifiant et le mot de passe de l’administrateur du site WordPress  pour accéder au backoffice, où nous constatons qu’il n’est pas à jours:

Donc il faut mettre à jours immédiatement notre WordPress, sauf que…

Le serveur www.master-ctn.mines-ales.fr utilise le protocole sftp pour la sécurité des connexions et malheureusement WordPress n’utilise pas ce protocole par défaut. Donc nous devons installer un plugin pour gérer l’installation via sftp, sauf que nous ne pouvons pas utiliser WordPress pour installer cet outil pour installer.

Donc nous devons installer cette extension/plugin à la main sans utiliser WordPress. Ce type d’installation arrive parfois sur certaines extensions/plugin donc ce mode de fonctionnement est utilisé de temps en temps et pour comprendre ce qu’il se passe sous le capot de Wordpess, je trouve cela très utile de l’avoir vu dans la formation.

En premier lieu, nous avons besoin de l’extension/plugin (https://fr.wordpress.org/plugins/ssh-sftp-updater-support/) ou via le serveur du Master CTN ( http://www.master-ctn.mines-ales.fr/install/ ). Téléchargez et dézippez ce fichier pour trouver le plugin dans filezilla pour le transférer:

  • En partie droite, trouver le dossier wp-content/plugins/ , on peut voir qu’il y a un plugin par défaut akismet que l’on retira plus tard.
  • Envoyer le dossier ssh-sftp-update-support sur le serveur via clic droit « Envoyer » ou en faisant glisser le dossier vers la droite
  • ATTENTION: une erreur classique est que l’outil qui fait le dezippage a pour le fichier ssh-sftp-updater-support.0.8.2.zip fabriquer un dossier parent ssh-sftp-updater-support.0.8.2/ contenant ssh-sftp-update-support/ et nous souhaitons envoyer ssh-sftp-update-support/ et non pas sftp-updater-support.0.8.2/ssh-sftp-update-support/

Une fois le transfert réalisé on doit disposer de cette structure sur le serveur avec le contenu du plugin/extension dans le dossier wp-content/plugins/, chaque extension devra être dans un sous-dossier de wp-content/plugins/.

Le transfert du dossier n’est pas suffisant, il faut aussi activer l’extension/plugin dans le backoffice. Cette double étape permet de conserver des plugins/extensions sur le site sans qu’ils ne soient actifs par exemple le temps de faire des tests.

Dans le backoffice, il faut aller dans « Extensions » et « Activer » le plugin « SSH SFTP Updater Support ».

On peut effacer maintenant les 2 plugins de démonstrations « Akismet Anti-Spam » et « Hello Dolly », cette opération déclenchera l’appel au plugin d’installation que nous venons d’installer, sauf que le nom du sFTP est mal nomé en SSH2:

  • Nom de l’hôte (localhost en fait): 127.0.0.1 (en cas de problème essayez www.master-ctn.mines-ales.fr)
  • Identifiant du sFTP: ctn20_jean
  • mot de passe: ce mot de passe est associé à l’utilisateur de filezilla
  • Type de connexion : SSH2 , attention l’écran change après avoir coché SSH2

La nouvelle fenêtre qui propose d’utiliser un système de clef public/clef privé que nous n’utiliserons pas:

Appuyez sur « Continuer » et normalement ce processus devrait désinstaller le plugin sélectionné.

L’étape critique suivante est de mettre à jours le WordPress grâce à ce nouveau plugin via le lien en haut (ou le menu « Mises à jours » à gauche): 

Le processus est similaire que pour retirer un plugin mais cette fois nous mettons à jours WordPress, la maintenance à jours des sites WordPress est une opération à faire de manière très régulière surtout si vous entendez des informations sur des périodes d’attaques de sites WordPress dans le monde:

Attention, comme indiqué par WordPress, la sauvegarde de votre site doit être fait avant les mises à jours pour pouvoir revenir en arrière. Nous n’avions pas beaucoup réalisé d’opérations pour devoir faire cette sauvegarde mais le premier plugin que nous allons installer gère la sauvegarde et la restauration de notre WordPress.

Pour ajouter une extensions faire « Extensions » puis « Ajouter » et chercher « Duplicator » qui doit sortir en premier le plugin « Duplicator » à installer et à activer de manière similaire à ce que l’on a vu précédemment:

Allez ensuite dans le menu « Duplicator » qui vient d’apparaitre, nous proposant de « Créer un paquet », chaque paquet sera une sauvegarde de notre site:

L’écran suivant inclus les informations critiques suivantes:

  • Le nom du paquet qui permet de le retrouver ensuite, la bonne pratique est de mettre la date pour le retrouver dans le liste
  • Le dossier sur le serveur qui contiendra le paquet de sauvegarde duplicator pour par exemple récupérer ces fichiers pour transférer le WordPress sur votre PC

Il est à noter que parfois votre WordPress est devenu trop gros pour être sauvegarder d’un seul coup par Duplicator. La solution est souvent de demander à Duplicator d’exclure le dossier wp-content/uploads/ qui contient toutes les ressources multimédia de la Médiathèque, à notre charge de réaliser la sauvegarde via Filezilla de ce dossier spécifique:

  • Activer les filtres de fichiers
  • Dossiers: le nom du dossier que l’on trouve via filezilla sur le serveur

NOTA: pour recréer ensuite le site web complet, on copiera ce dossier wp-content/uploads/ qui a été exclus dans le package Duplicator.

Nous pouvons constater que tous les informations techniques sont disponibles pour réaliser l’opération finale de création du « Paquet Duplicator ». Il peut y avoir par exemple des problèmes de fichiers trop importants ou de nom de fichier problématique (souvent avec accents):

 

La dernière étape permet de vérifier que la création du « Paquet Duplicator » et propose de télécharger les 2 fichiers soit le fichier d’installeur et le fichier zip d’archive. Ce dernier fichier est le plus critique car le fichier d’installation peut être retrouver dans le plugin Duplicator:

Le principe est donc de conserver l’archive et son installeur dans un lieu sécurisé pour pouvoir repartir sur cette version en cas de problème. Duplicator permet aussi de dupliquer le WordPress en local sur votre ordinateur pour disposer d’une version de test ou de pré-production sur un ordinateur avant chaque mise à jours ou ajout de contenu critique sur la version en ligne.

Télécharger le « Paquet Duplicator » et de l’installeur sur votre ordinateur dans un dossier sur votre PC en local pour préparer l’installation prochaine avec Wamp/Mamp.

En revenant sur la listes des « Paquets Duplicator », nous retrouverons la liste des sauvegardes disponibles pour WordPress. Attention à l’espace de stockage sur un serveur d’hébergement qui limiterait le stockage, heureusement le serveur www.master-ctn.mines-ales.fr dispose de suffisamment d’espace donc  multiplier les sauvegarde et les manipulations sur le serveur.

 

 

NOTA: via filezilla vous pouvez consulter le dossier wp-content/backups-dup-lite/ qui contient les fichiers du « Paquet Duplicator » et de l’installeur. on trouvera aussi des fichiers techniques (log, scan, config et log) pour gérer les problèmes techniques de Duplicator:

Nous verrons ensuite la restauration de ce « Paquet Duplicator » sur un PC pour réaliser une opération de duplication donc de sauvegarde.

NOTA: Il est critique de vérifier que le « Paquet Duplicator » est bien fonctionnel en réalisation une opération de restauration en local. En effet tout le processus peut sembler fonctionner et surtout la restauration peut avoir lieu dans un contexte de stress important.

Dernier point, utilisez votre WordPress, entrainez-vous à installer/réinstaller/utiliser/casser votre WordPress car c’est un bon moyen pour acquérir des connaissances sur son fonctionnement.

Il est par exemple important de comprendre la différence entre une page et un article. Historiquement, WordPress est un outil de blog donc les articles étaient la forme classique de présentation d’informations par catégorie mais l’ajout des pages de contenu statique permet de montrer un contenu unique qui n’est pas de type regroupement par rubrique de contenu. Comme exemple, sur ce site les articles de la catégorie « CTN » sont appelé par le menu « CTN » en haut alors que la page « Pierre JEAN ? » est un contenu unique accessible aussi par le menu.

 

 

 

 

Publié dans CTN | Laisser un commentaire

WordPress et CMS 1/4

Notes de cours et rappel de procédures

Préambule

L’objectif de ce cours est de travailler sur un CMS de référence WordPress. Bien sur, tout ce qui est décris ici peut s’appliquer de manière similaire (au moins la partie installation) sur les autres CMS tel que Drupal, Joomla mais aussi des outils comme Prestashop et SugarCRM dans la partie installation sur un serveur distant.

Je vais prendre comme base l’installation de WordPress sur un serveur dédié que nous avons spécialement pour le master CTN (www.master-ctn.mines-ales.fr). Cette installation est similaire à une installation sur un serveur d’un hébergeur tel qu’OVH dont je montrerai sa console de gestion pour retrouver les réglages.

Je ne peux accepter la diffusion et la duplication de ce contenu sans l’aval de ma direction. Je vous prie de maintenir ces contenus à un usage interne pour le Master CTN. 

 

Prérequis:

Les seuls prérequis nécessaires pour ce cours et les TPs qui suivent sont de savoir manipuler les fichiers/dossiers de son ordinateurs, de télécharger, dézipper, installer des logiciels (filezilla, wamp/mamp), utiliser un navigateur pour consulter une URL, éditer des fichiers PHP, Html, Css selon des instructions données.

Installation des logiciels gratuits et/ou opensource si vous n’avez pas un portable de l’IMT Mines Alès:

Note aux utilisateurs de Wamp sur Microsoft: il  faut disposer de ce logiciel fourni par Microsoft en français ( http://www.microsoft.com/en-us/download/details.aspx?id=30679 ) et je conseille de faire un dossier C:\Developpement\ dans lequel on installe Wamp et les autres outils de développement.

 

 

Récupération des informations pour l’installation de wordpress

Pour réaliser l’installation sur le serveur du Master CTN ou pour le faire sur un serveur d’un hébergeur, il faut un certain nombre d’information techniques. Je prends comme base pour l’installation sur le serveur du Master CTN avec mes réglages à mon nom (ctn20_jean); à vous d’adapter bien sur avec vos identifiants. Les mots de passe ne sont pas indiquées mais c’est toujours le même dans tous les cas.

  • adresse du serveur: www.master-ctn.mines-ales.fr
  • nom d’utilisateur/login/uid/identifiant: ctn20_jean
  • mot de passe de cet utilisateur
  • adresse du serveur sftp: www.master-ctn.mines-ales.fr
  • identifiant du serveur sftp: ctn20_jean
  • mot de passe de cet utilisateur:
  • adresse pour worpdress du serveur de la base de données mysql: 127.0.0.1
  • adresse pour phpmyadmin du serveur de la base de données mysql: http://www.master-ctn.mines-ales.fr/phpmyadmin/
  • utilisateur de la base de données mysql: ctn20_jean
  • mot de passe de l’utilisateur de la base de donnée
  • nom de la base de données mysql: ctn20_jean

 

Note pour OVH (et autres hébergeurs) vous pouvez avoir des informations différentes sur l’identifiant du serveur ftp/sftp, le mot de passe de cet utilisateur, une adresse différente pour l’adresse du serveur de base de données, un utilisateur de base de données avec son mot de passe différent des autres utilisateur. Pour plus de simplicité, j’ai groupé autant que ce peut les nom et les mots de passes mais il y a des cas où chaque utilisateur/mot de passe est différent. Exemple OVH avec euromov.eu:

  • adresse du serveur: euromov.eu
  • nom de l’utilisateur/identifiant: pj12345-ovh
  • mot de passe de cet utilisateur
  • adresse du serveur ftp: ftp.xxx.hosting.ovh.net
  • identifiant du serveur ftp: euromov-mamas
  • mot de passe du serveur ftp
  • adresse pour wordpress du serveur de la base de données mysql: euromovXXX.mysqldb
  • utilisateur de la base de donnée mysql: euromovXXX
  • mot de passe de l’utilisateur de la base de donnée
  • nom de la base de données mysql: euromovXXX

Voici un exemple pour récupérer des informations sur le site console d’administration d’OVH, les informations critiques ont été floutées.

 

Console d'administration d'euromov.eu avec informations sur les réglages du serveur FTP

Console d’administration d’euromov.eu avec informations sur les réglages du serveur FTP

Console d'administration d'OVH avec les informations sur le base de données Mysql

Console d’administration d’OVH avec les informations sur le base de données Mysql

Console OVH lien pour accéder à l'outil phpMyAdmin

Console OVH lien pour accéder à l’outil phpMyAdmin

 

L’accès à ces informations est nécessaires pour l’installation sur un serveur que cela soit celui du Master CTN ou chez un hébergeur de site. Cet opération nous permet de constater que nous allons utiliser différents logiciels qui ont chacun leur utilité:

  • WordPress le Content Management System
  • Un serveur FTP (ou sftp, s=secure) avec adresse, utilisateur et mot de passe
  • Un client FTP, filezilla pour se connecter au serveur ftp/sftp que l’on peut installer depuis ces adresses: (Windows : https://filezilla-project.org/download.php?platform=win64 ou MacOS: https://filezilla-project.org/download.php?platform=osx )
  • Un serveur de base de données Mysql, avec adresse, utilisateur , mot de passe et un nom de base de données
  • Un outil en ligne phpMyAdmin pour manipuler la base de Mysql au besoin avec une adresse. L’utilisateur et le mot de passe sont ceux de la base de données

Il vaut mieux comprendre quel est l’utilité de chaque logiciel car ils peuvent être remplacer par un concurrent dans votre future structure. Comme exemple:  MariaDB ou Postgresql sont des alternatives à Mysql, phpMyAdmin peut être remplacé par Mysql Workbench ou Adminer, Filezilla par l’explorateur Windows ou le Finder Mac ou un outil en ligne de l’hébergeur.

 

Testons les informations pour l’installation de WordPress

Accès au site web comme internaute

En premier lieu, nous allons accéder au serveur du master CTN comme un utilisateur normal: http://www.master-ctn.mines-ales.fr/ctn20_jean/

Bien sur chacun d’entre vous a un site indépendant donc merci de corriger avec votre identifiant ctn20_jean pour moi, et vous avez cette fenêtre d’authentification qui apparait:

Cette fenêtre s’appelle une fenêtre d’authentification htaccess (ou htpasswd du nom d’un des outil). Elle permet de demande un nom d’utilisateur et un mot de passe sur une URL du site web géré par Apache Web Server.

Pourquoi j’ai installé cette fonction ? Je ne pense pas souhaitable que les élèves « regardent » le travail des autres sans leur accord en devinant le nom d’utilisateur dans l’URL ( ctn20_jean pour moi, vous le voyez souvent) et surtout, une année un site d’un élève était mieux référencé que celui de son commanditaire… Avec cette fenêtre pas d’accès sur votre site.

 

En cas d’échec de l’authentification vous vous retrouvez avec le message suivant:

Unauthorized

This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.
Apache/2.4.29 (Ubuntu) Server at www.master-ctn.mines-ales.fr Port 80

Autre élément, l’accès à l’URL d’administration des wordpress que j’installe (par exemple http://euromov.eu/wp-admin/) est aussi contrôlé par ce type de protection car j’ai plein de gens qui tente de deviner les mots de passes sur les serveurs wordpress que je gère.

Donc authentifions-nous sur notre site web http://www.master-ctn.mines-ales.fr/ctn20_jean/ avec notre identifiant qui marche pour tout. Votre navigateur va retenir ce mot de passe pour toute la période où il n’est pas fermé, bien sûr vous pouvez le lui faire retenir pour éviter cette étape, par contre si vous transmettez l’URL de votre site à une autre personne (par exemple à titre d’exemple pour chercher un stage), vous devez lui indiquer le nom d’utilisateur et le mot de passe pour y accéder.

Truc & astuce:

L’ajout du nom d’utilisateur et du mot de passe sous cette forme existe et fonctionne avec la plus par des navigateurs:

http://ctn20_jean:mot_de_passe@www.master-ctn.mines-ales.fr/ctn20_jean/

Donc nous avons maintenant l’accès à ce site web qui est fonctionnel mais vide (notez la réponse du logiciel serveur Web : Apache/2.4.29 Ubuntu Server …)

Maintenant nous pouvons rajouter du contenu sur ce serveur Web.

NOTA: je vous rappelle que vous avez signé une charte d’utilisation des moyens informatiques de l’IMT Mines Alès, merci de ne pas utiliser ce service pour échanger des ressources qui ne seraient pas en accord avec cette charte.

 

Accès en Ftp/sftp pour l’échange de fichier

Maintenant que nous avons un serveur opérationnel, nous pouvons y ajouter des fichiers et créer des dossiers. Le serveur se trouve physiquement dans la salle serveur du LGI2P au bâtiment M mais nous aurions du mal à aller avec une clef USB faire les modifications sur le disque du de ce serveur.

Nous allons utiliser le logiciel Filezilla (client) pour accéder au dossier que chacun d’entre nous a sur ce serveur et qui est utilisé par le site web apache pour afficher du contenu sur le Web.

A la première connexion, vous allez avoir une fenêtre indiquant que « La clef du système hôte n’est pas connue » (le message peut différer selon les versions ). Vous pouvez accepter les empruntes sans problème et faire retenir cette opération.

 

Entrez les informations suivantes dans Filezilla:

  • Hote: sftp://www.master-ctn.mines-ales.fr/
  • Identifiant: ctn20_jean
  • Mot de passe
  • Appuyez sur le bouton « connexion rapide »

 

Détaillons les différentes zones du logiciel:

  • La zone de « Message technique de Filezilla » sert à afficher des messages techniques de la discussion entre Filezilla et le serveur FTP/sftp. Je l’utilise que quand il y a des erreurs indiquées en rouge. Ce n’est pas la zone la plus utilisée, vous pouvez réduire sa taille au besoin
  • La zone à gauche DOSSIERS DU PC et FICHIERS DU PC sont les moyens pour trouver sur votre ordinateur (PC=Personal Computer) un ou des fichiers
  • La zone à droite DOSSIERS DU SERVEUR et FICHIERS DU SERVEUR sont les moyens pour trouver les dossiers et les fichiers sur le serveur www.master-ctn.mines-ales.fr
  • La zone en bas « ZONE TRANSFERT DE FICHIER » indique comment le transfert de fichiers et de dossier se passe. Vous pouvez voir les 3 onglets en bas qui gère les situations selon le fonctionnement de ce transfert

Il y a de nombreuses fonctionnalités à Filezilla mais nous allons nous concentrer sur le l’échange des fichiers entre votre ordinateur et le serveur. Habituellement le transfert se fait dans le sens du PC vers le serveur mais parfois nous devons récupérer des sauvegardes ou des fichiers depuis le serveur vers le PC.

Attention à ne pas détruire sur le serveur une ressource utile au site web et attention de ne pas récupérer depuis le serveur une ressource qui va remplacer sur votre PC une ressource plus récente. C’est à vous de gérer les échanges. Faites des sauvegardes avant toutes manipulations complexes et travailler de manière à pouvoir toujours revenir en arrière en conservant une ressource dans une zone sécurisée pour le cas où un problème technique apparait

On voit qu’il existe 2 dossiers par défaut sur le serveur. Le dossier .gnupg est un dossier qui est normalement caché (il commence par .) mais il ne faut pas y toucher ni le manipuler. Le second dossier est très important, c’est le dossier www qui va contenir le contenu sur le serveur en ligne.

 

NOTA: Pourquoi on met les fichiers dans le sous dossier www/ et pas directement dans le dossier ouvert par défaut par Filezilla. En fait, il y a une raison technique précise (pour ceux passionnés: https://www.tecmint.com/restrict-ssh-user-to-directory-using-chrooted-jail/) mais au final OVH et les autres hébergeurs ont le même fonctionnement. Ce que l’on peut faire c’est d’exploiter pour créer un dossier BACKUP/ qui contiendra des sauvegardes qui ne seront pas accessible par le serveur web mais qui seront sur le serveur.

Créons un dossier BACKUP dans le dossier de base /home/ctn20/ctn20_jean/ et créons un dossier logos dans le dossier /home/ctn20/ctn20_jean/www/logos.

La création de dossier se fait sur le serveur dans la zone droite avec clic droit et « Créer un dossier »:

Retourner sur votre navigateur sur l’adresse du site web http://www.master-ctn.mines-ales.fr/ctn20_jean/ pour constater que l’on voit bien le dossier logos mais pas le dossier BACKUP

Bien sur vous pouvez accéder au dossier logos ce qui changeras votre URL en http://www.master-ctn.mines-ales.fr/ctn20_jean/logos/

Nous pouvons donc comprendre que l’architecture d’un site web avec ces dossiers dans l’URL correspondent à des dossiers sur le disque dur (habituellement mais il peut y avoir des exceptions que l’on verra plus tard).

Essayez de mettre sur le serveur différentes ressources: fichiers PDF, images, petits fichiers vidéo dans différents dossiers pour consulter ces différentes ressources via votre navigateurs.

Il faut bien comprendre la relation entre les dossiers et fichiers sur le serveur et les URLs correspondantes.

Modification de droits sur le serveur

Une opération exceptionnelle qui doit être la modification des droits sur les fichiers et les dossiers du serveur.

Ce qu’il faut comprendre c’est que l’utilisateur qui exécute le serveur apache2 s’appelle www-data hors cet utilisateur (non-humain) n’a pas les mêmes droits que votre utilisateur humain (par exemple pour moi ctn20_jean). Donc il faut parfois modifier les droits sur les dossiers et les fichiers pour le dossier www (et ses sous-dossiers).

Sur le dossier www, faire clic droit « droits d’accès au fichier » et les permissions de groupes doivent être toutes cochées (et la valeur numérique à 775 en fait)

Comme cela, le serveur apache (qui fera un exécutera le logiciel WordPress) aura le droit de créer des fichiers sur le serveur dans votre dossier pour finaliser l’installation. Par exemple à l’installation, le fichier wp-config.php sera construit automatiquement par l’installateur de WordPress et contiendra les informations techniques de votre WordPress.

NOTE TECHNIQUE: en fait l’utilisateur ctn20_jean appartient au même groupe que l’utilisateur www-data, du coup le droit « Écriture » par le groupe permet à l’utilisateur www-data de créer des fichiers sur le serveur de la même façon que l’utilisateur ctn20_jean.

 

 

Publié dans CTN | Laisser un commentaire

Angular2 & Spring boot en mode RESTful 2020

Version 2020, le but de ce TP est de refaire le projet Todo Tomcat/Servlet/JSP en s’appuyant sur des technologies très modernes du développement web avancé (Spring/Restful/Hibernate/Json/Angular2).

Prérequis logiciels à installer :

 

NOTE: Installation de Spring Tool Suite

Pour installer plus simplement l’outil Spring Tool Suite™ , téléchargez le et lancer son installation soit en associant les fichiers .java au programme de Java soit via une ligne de commande:

java -jar c:\DEV\spring-tool-suite-4-4.8.1.RELEASE-e4.17.0-win32.win32.x86_64.self-extracting.jar

 

NOTE: Ajout du « Debugger for Chrome » dans Visual Studio Suite

Visual Studio Code ajouter l’installation de « Debugger for Chrome »

 

 

 

NOTA: Quelques copies d’écrans sont de la version Sprint Tool Suite 3 mais la version 4 est très similaire.

 

 

Etape 1/ utilisation de Spring Initializr

Allez sur https://start.spring.io/ pour fabriquer le fichier de configuration des jars compatibles pour réaliser nos actions. Les dépendances suivantes sont nécessaires :

  • Spring Web: inclus les composants MVC de Spring pour le Web et un serveur Tomcat
  • Mysql Driver: inclus le drivers JDBC pour la liaison de Spring avec l’outil de base de données Mysql
  • Spring Data JPA: inclus l’utilisation d’Hibernate pour la persistance des données

Il faut utiliser la version SNAPSHOT 2.3.6  (cette copie d’écran date de l’année dernière):

Télécharger le projet au format zip et le placer (en le dezippant et en évitant de faire un dossier C:\DEV\todo\todo\ mais bien un dossier c:\DEV\todo\ ) dans un dossier workspace par exemple c:\DEV\workspace-spring\.

 

Pour installer plus simplement l’outil Spring Tool Suite™ , téléchargez le et lancer son installation soit en associant les fichiers .java au programme de Java soit via une ligne de commande:

java -jar c:\DEV\spring\spring-tool-suite-4-4.7.1.RELEASE-e4.16.0-win32.win32.x86_64.self-extracting.jar

Importer le projet dans l’outil Spring Tool Suite™ avec une version d’eclipse spécialement configuré pour Spring.

Importer le projet trouvé dans le workspace:

Puis ouvrir le projet pour ajouter les réglages dans le fichier application.properties (ce fichier se trouve dans src/main/ressources ):

 

Ajouter ce contenu au fichier applications.properties (si vous utilisez Mysql sans installation attention de modifier le port 3306 par le port valide de cette installation):

# ===============================
# DATABASE
# ===============================
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.url=jdbc:mysql://localhost:3306/todo?zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=UTC
spring.datasource.username=todo
spring.datasource.password=todo

# ===============================
# JPA / HIBERNATE
# ===============================
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE

 

On peut noter que les 2 dernières lignes sur le logging permettra d’afficher les requêtes SQL avec les valeurs complètes:

org.hibernate.SQL: insert into Todo (actif, texte) values (?, ?)
Hibernate: insert into Todo (actif, texte) values (?, ?)
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BOOLEAN] - [false]
o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [todo-8]

 

 

Etape 2/ Utilisation de Maven

Il y a un bug majeur dans la version utilisé par Spring de sunfire. Il faut donc modifier le fichier pom.xml pour ajouter une version plus ancienne de sunfire:

dans le tag <build><plugins>, il faut ajouter ce code de <plugin> comme indiqué:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <version>2.5</version>
   <configuration>
	<skipTests>false</skipTests>
	<testFailureIgnore>true</testFailureIgnore>
	<forkMode>once</forkMode>
   </configuration>
</plugin>

Cela permet d’éviter le bug suivant avec l’intégration problématique de la version sunfire 2.22 qui n’arrive pas à récupérer les informations de sa fin d’exécution (de ce que j’ai compris)

 Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test

Pour les détails sur ce bug, vous pouvez consulter cette page: https://maven.apache.org/surefire/maven-surefire-plugin/examples/shutdown.html

 

Un fois le projet est importé, il faut lancer l’exécution sur le projet Maven click droit > Run As > Maven install :

Eclipse maven run maven install

Mais normalement vous pouvez avoir une erreur de configuration du JDK dans la console:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project todo: Compilation failure
[ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

Il faut faire l’ajout du JDK pour le projet, clic droit sur le Projet > Build Path > Configure Build Path >

Eclipse Spring erreur JDK Configure Build Path

Puis Onglet Library : choisir le JRE System puis bouton « Edit … »

Puis dans la nouvelle fenêtre choisir « Installed JRE »

Dans la nouvelle fenêtre faire « Add… », dans la nouvelle fenêtre faire « Standard VM » puis « Next » et indiquer le chemin du JDK sur votre ordinateur dans le champ « JRE Home » puis si le JDK indiqué est valide alors le bouton « Finish » ramène à la fenêtre précédente…

 

 

Nota: la version que des copies d’écrans est parfois un Java 8 mais pour ce TP je recommande un Java 15.

Validez le JDK installé par défaut en cochant la case à gauche comme sur cette copie d’écran:

Fermer les fenêtres avec « Apply and close » puis vérifier que le « bon » JDK est indiqué sur cette dernière fenêtre avant de faire « Finish »:

Eclipse maven run maven install

Normalement le « Maven install » doit indiquer que tout est opération sans rencontrer d’erreur:

[INFO] BUILD SUCCESS

 

Pour démarrer le programme spring, il suffit d’ouvrir la classe TodoApplication qui contient la méthode de démarrage du projet et de faire clic droit Menu Debug As > Java Application :

public static void main(String[] args) {
     SpringApplication.run(TodoApplication.class, args);
}

A la différence des projets précédents, Tomcat est inclus dans le projet Spring ce qui nous permet de démarrer le programme SpringApplication avec le serveur web. Si vous avez regarder le site start.spring.io en détail, vous avez noter qu’il est possible de déclarer un projet de type war qui dans ce cas peut être inclus dans un serveur Tomcat existant.

Par ailleurs, pourquoi faire un Debug As au lieu d’un Run As ? Via la fenêtre de Debug (cf copie d’écran ci-dessous), nous avons accès à un menu pour arréter le serveur et le relancer (Terminate ou Termiante and Relanuch) ce qui nous permet d’éviter que le serveur Tomcat ne reste en mémoire sur l’ordinateur bloquant le port 8080.

Le redémarrage du serveur est grandement simplifié en gérant son fonctionnement depuis Eclipse (Spring Tool Suite).

Vous pouvez constater le bon fonctionnement du serveur avec votre navigateur chrome en ouvrant l’URL http://127.0.0.1:8080/

Si vous avez un message d’erreur qui indique un problème d’accès à la base de données. Cela sera réglé par la création ensuite d’un utilisateur de base de données, en étape 3.

java.sql.SQLException: Access denied for user 'todo'@'localhost' (using password: YES)

 

 

Etape 3/ Fabrication d’une classe Todo entity et configuration BD

Faire une classe Todo dans le projet en ajoutant les getter et setter, constructor par défaut, toString, equals et hashcode (voir le Menu Source pour tout générer automatiquement):

package fr.ema.lgi2p.m2.todo;


import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Todo {

  @Id
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  private Long id;

  private String texte;
  private Boolean actif;

}

On notera la double annotation @Id et @GeneratedValue qui sous-traite la génération de l’ID à la base de données Mysql.

ATTENTION: si vous avez l’erreur suivante dans la console, c’est parce que votre Pojo Entity Todo n’a pas de constructeur par défaut:

Exception in thread "main" org.hibernate.InstantiationException: No default constructor for entity: com.web_dev_TP1.Web_dev_TP1.Todo

En fait, la couche de persistance JPA/Hibernate a besoin de savoir comment construire votre entité. Cette couche va commencer par créer une instance de Todo et appeler les Getter/Setter pour fabriquer l’instance ensuite. Donc il lui faut un constructeur par défaut…

 

 

Maintenant on doit créer une base de données avec un utilisateur de BD pour ce projet, dans mysql avec phpmyadmin, faite la création d’un utilisateur/MDP ayant tout les droits sur une base de données. Dans mon exemple, ces 2 valeurs seront todo.

On peut noter que dans l’onglet « Compte utilisateurs » on peut ajouter un compte utilisateur et une base de données portant le même nom en cochant comme ci-dessous » Créer une base de données portant son nom et donner à cet utilisateur tous les privileges sur cette base »:

PhpMyadmin configuration utilisateur et base de données

NOTA: dans le cas d’une utilisation de Mysql sans installation, il faut lancer en ligne de commande l’utilitaire mysql :

c:\DEV\mysql-5.7.17-winx64\bin\mysql.exe --port=55555 -u root -p

puis entrer ces commandes SQL pour créer un utilisateur todo (avec un mot de passe todo) avec une base de donnée todo:

CREATE DATABASE todo;
CREATE USER 'todo'@'localhost' IDENTIFIED WITH mysql_native_password BY 'todo';
GRANT all on todo.* TO 'todo'@'localhost';
flush privileges;

 

NOTA: En cas d’erreur suivante:

The server time zone value 'Paris, Madrid' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

fichier Application Version 0.1

Cela vient d’une veille configuration de mon serveur mysql qui a une TimeZone double, pour corriger, soit il faut changer le réglage dans le fichier de configuration de Mysql mais j’ai trouvé plus simple en forçant dans la connexion JDBC la TimeZone:

spring.datasource.url=jdbc:mysql://localhost:3306/todo?zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=UTC

Une dernière exécution du projet Maven > Debug > Maven install puis il faut exécuter la classe principale TodoApplication via clic droit Run > Java Application et accéder au service via un navigateur en allant sur http://127.0.0.1:8080/, par contre l’affichage est la page d’erreur générique « Whitelabel Error Page » que l’on pourra surcharger plus tard.

 

Run As TodoApplication

Il faut ajouter la dépendance de threetenbp dans le fichier pom.xml dans le bloc de tag <dependencies> , cette bibliothèque gère la conversion de date dans des formats compatibles avec Mysql :

<dependency>
  <groupId>org.threeten</groupId>
  <artifactId>threetenbp</artifactId>
  <version>1.3.3</version>
</dependency>

Vous pouvez vérifier que la table todo dans la base de données a été créée dans la base de données soit via phpMyAdmin soit via la commande desc <base de données>.<table>

desc todo.todo;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| actif | bit(1)       | YES  |     | NULL    |                |
| texte | varchar(255) | YES  |     | NULL   |                |
+-------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

 

Etape 4/ Fabrication d’une classe Controleur RESTful

Créer une nouvelle Classe TodoControleur:

Spring class TodoControleur

Avec ce code d’un TodoControleur, nous avont une méthode accessible via cette URL en méthode GET sur l’URL /todos:

package fr.ema.lgi2p.m2.todo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TodoControleur {

   @RequestMapping(value="/todos", method=RequestMethod.GET)
   public String listeTodos() {
     return "{todos:[]}";
   }
}

Testé l’appel via l’URL : http://127.0.0.1:8080/todos

La réponse est un morceau de json que l’on a bien sur compléter plus tard pour retourner tous les todos sous la forme suivante:

{"todos":[
{"id":1,"texte":"todo-1","actif": false}
,{"id":2,"texte":"todo-1","actif": false}
]}

On peut voir que par rapport à un Controleur de type Servlet appelé soit par une méthode GET ou POST, nous pouvons spécialiser des URLs et des méthodes plus simplement (les autres méthodes  de REST que GET & POST peuvent être aussi utilisées : « Relation entre URI et méthodes HTTP »)

Nous pouvons maintenant ajouter une méthode pour créer un todo qui aura comme texte un identifiant passé en paramètre {id}

 @RequestMapping(value = "/todo/{id}", method = RequestMethod.GET)
 public Todo getTodo(@PathVariable int id) {
     Todo todo = new Todo( "todo-" +id , false );
     return todo; 
 }

Appelons l’URL via : http://127.0.0.1:8080/todo/100, regardez dans la base de données le nouvel élément ajouté. Bien sur, on peut ajouter de multiples paramètres

On peut noter que la conversion en JSON de l’instance est réalisé automatiquement par Spring.

 

 

Etape 5/ Utilisation d’Hibernate au lieu de JPA pour voir un peu de code

Par défaut Spring utilise une couche de persistance appelée la couche JPA générique. Mais en utilisant Hiberante, nous allons pouvoir voir l’enchainement des opérations qui sont faites par cette couche de manière plus visible. Pour activer Hibernate, nous avons à modifier en étape 1 le fichier application.properties se trouvant dans le dossier src/main/ressources

# ===============================
# DATABASE
# ===============================

#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.url=jdbc:mysql://localhost:3306/todo?zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=UTC
spring.datasource.username=todo
spring.datasource.password=todo


# ===============================
# JPA / HIBERNATE
# ===============================

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
logging.level.org.hibernate.SQL=DEBUG 
logging.level.org.hibernate.type=TRACE

Voici la nouvelle version de la classe TodoApplication:

package fr.ema.lgi2p.m2.todo;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;

import java.util.Properties;

import javax.sql.DataSource;

@SpringBootApplication
@EnableAutoConfiguration(exclude = { 
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, 
HibernateJpaAutoConfiguration.class })
public class TodoApplication {

@Autowired
private Environment env;

public static void main(String[] args) {
SpringApplication.run(TodoApplication.class, args);
}

@Bean(name = "dataSource")
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();

dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));


return dataSource;
}

@Autowired
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
Properties properties = new Properties();

properties.put("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
properties.put("current_session_context_class",
env.getProperty("spring.jpa.properties.hibernate.current_session_context_class"));

LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();

factoryBean.setPackagesToScan(new String[] { "" });
factoryBean.setDataSource(dataSource);
factoryBean.setHibernateProperties(properties);
factoryBean.afterPropertiesSet();
SessionFactory sf = factoryBean.getObject();
System.out.println("## getSessionFactory: " + sf);
return sf;
}

@Autowired
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
   HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);
   return transactionManager;
}

}

Cette nouvelle version permet de déconnecter les méthodes classiques du JPA pour appeler une nouvelle classe TodoDao qui va assure les opérations classiques de persistence:

package fr.ema.lgi2p.m2.todo;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class TodoDao {

@Autowired
private SessionFactory sessionFactory;

public List<Todo> listTodo() {
  Session session = this.sessionFactory.getCurrentSession();
  Query<Todo> query = session.createQuery("From Todo", Todo.class);
  return query.getResultList();
}

public Todo newTodo(Todo newTodo) {
  Session session = this.sessionFactory.getCurrentSession();
  session.save(newTodo);
  return newTodo;
}


}

C’est cette classe TodoDao qui nous permet de vérifier/controler/modifier le fonctionnement classique et automatique de la couche de JPA.

 

Modification de la classe TodoControleur pour utiliser la classe TodoDao:

 @Autowired
private TodoDao todoDao;

 @RequestMapping(value = "/todo/{id}", method = RequestMethod.GET)
public Todo getTodo(@PathVariable int id) {
   Todo todo = new Todo("todo-" + id, false);
   todoDao.newTodo(todo);
   return todo;
}

Maintenant l’appel à l’URL suivante : http://127.0.0.1:8080/todo/100 fabrique un nouveau todo et le fait persister. Lancer une second fois en modifiant que la propriété actif du Todo soit true au lieu de false.

Regarder le résultat dans la base de données todo avec l’autoincrément de l’ID:

select * from todo.todo;
+----+-------+----------+
| id | actif | texte    |
+----+-------+----------+
| 1  |       | todo-100 |
| 2  | ☺    | todo-100 |
+----+-------+----------+
2 rows in set (0.00 sec)

La partie C du CRUD fonctionne maintenant, vous pouvez réaliser les autres opérations sur le CRUD dans le backoffice notamment en utilisation la méthode listTodo dans la classe TodoDao. je vous laisse la main pour rédiger les autres méthodes et l’interfaçage entre Controleur et Dao avec Hibernate.

 

Etape 6/ Static content pour Spring boot

Création (s’il n’existe pas) d’un dossier src/main/ressources/static pour le contenu static du service qui va contenir les développements en AngularJs. Le contenu static sera par exemple un fichier html, des fichiers css et images dans un premier temps.

L’objectif sera ensuite d’y placer du code html/css/javascript généré par un framework Javascript tel que /jquery-jquery-UI, Vue.js, React.js, Angulars, etc.

Pour afficher une page html, il faut créer une classe IndexController qui va envoyé le contenu de index.html :

package fr.ema.lgi2p.m2.todo;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {
@RequestMapping("/")
  public String welcome() {
    return "index.html";
  }
}

Puis avec la création d’un nouveau dossier src/main/ressources/static/img, pour y placer des images, il faut ajouter le code ci-dessous à la classe TodoApplication pour autoriser le contenu statique dans ce dossier:

 public void addResourceHandlers(ResourceHandlerRegistry registry) {
   registry.addResourceHandler("/img/**").addResourceLocations("classpath:/img/");
}

Il est possible d’ajouter des dossiers additionnels pour le reste des ressources comme du CSS.

Maintenant nous avons donc la possibilité d’ajouter du contenu statique dans le dossier src/main/ressources/static/ et ce contenu va provenir d’un développement avec Angular2 dans NodeJS.

Tester quand même la partie Spring static que tout fonctionne, c’est la partie serveur back qui doit être solide avant d’attaquer le frontend.

 

Etape 7/ Angular2 avec NodeJS

Pour le développement en javascript, le moteur de référence est le Javascript V8 de Google. Je vous recommande la lecture de cette bande dessiné qui explique les choix de Google dans la création de Chrome et particulièrement la partie sur le moteur Javascript V8 (https://www.google.com/googlebooks/chrome/small_00.html). Pour tout développeur WEB, cela donne des indications très utiles qu’il faut bien sur lire avec du recul. Par exemple quand un membre de Google indique « We are using precise garbage collection », il faut aussi comprendre que cela se fait grâce à une consommation de mémoire importante pour conserver les références sur les objets…

Installation de NodeJS 14 et ouvrir la ligne de commande dans un dossier dédié Workspace par exemple en créant ce dossier C:\DEV\workspace-nodejs.

NodeJs est utilisé comme serveur web de debug pour le code développé en Javascript avec le framework AngularJS qui utilise le langage de développement TypeScript. Mais au final la génération finale du projet est un ensemble de code Html/Css/Javascript qui sera embarqué comme contenu statique dans notre application Spring.

En premier lieu, nous allons utiliser ce dossier dans Visual Sutdio Code:

Et ajouter ensuite la fenêtre de terminal pour lancer les commandes de nodejs et d’angularjs:

Nous pourrons donc entrer les commandes directement dans ce terminal. Pour installer le client angular, il faut donc lancer cette commande:

npm install -g @angular/cli

Update npm on ne sait jamais (et update de nodejs peut être aussi?)

npm i npm

Maintenant nous allons créer enfin un projet todo pour angularjs.

Création du projet todo dans un dossier d’un workspace dédié aux projet node-js/angularjs

ng new todo

Répondre « yes » à la question « Would you line toi add Angular routing » et répondre CSS à la question « Which stylesheet format would you like to use (use arrow keys) » en appuyant sur la touche Entrée (oui c’est un menu pour cette option).

NOTA: je vous recommande à terme de tester les framework autour de CSS comme le SASS https://sass-lang.com/guide qui ajoute un système de variable au CSS mais ceci est une autre histoire…

La création du projet se fait par l’installation des différents packages dans le dossier de développement: C:\DEV\workspace-nodejs/todo/.

Il est à noter encore une fois que l’on compilera dans le dossier src/main/ressources/statics/ l’ensemble du projet une fois sa mise au point car l’appel d’un code installé dans NodeJS sur l’URL http://127.0.0.1:4200/ qui lancerait des commandes RESTfull sur des URLs de type http://127.0.0.1:8080/ serait bloquées. Nous verrons en debug comment contourner ce problème.

Nous avons 2 serveurs Web, NodeJS sur le port 4200 et Spring/Tomcat sur le 8080 chacun avec ses avantages et ses contraintes.Pour plus d’informations, vous pouvez consulter les sites traitant du « Cross-origin resource sharing  » par exemple https://developer.mozilla.org/fr/docs/Web/HTTP/CORS 

 

Entrer dans le dossier todo avec la commande cd (Change Directory) pour faire les manipulation dans le projet todo nouvellement créé.

cd todo

Puis pour voir l’application avec le serveur NodeJs, il faut entrer cette commande:

ng serve --sourceMap=true

Et une fois la conversion de l’application AngulArJs écrite en TypeScript faite en fichier Html/Css/Javascript, on peut via l’URL http://127.0.0.1:4200/ voir le résultat:

 

Etape 8/ Angular et TypeScript

TypeScript est un sur-langage de Javascript (wikipedia TypeScript), l’idée est d’écrire un code en langage TypeScript qui va être converti en Javascript avec des vérifications qui permettent d’éviter les erreurs classiques de javascript comme le « Object doesn’t support property »:

var todo = {"id":1,"texte":"lait","actif":false}
console.log( todo.Id );

NOTA: l’année précédent, vous avez peut être vu une démonstration d’AngularJS qui est une ancienne version d’AngularJS (ou Angular 1) utilisant le Javascript et non pas le TypeScript.

Avec la complexité des codes en constante augmentation, Javascript doit être renforcé de tests et de controle pour construire une architecture standardisé de type MVC côté Front-End vu que Spring propose les mêmes mécanisme côté Back-End.

Si on reprends l’application todo, on peut se concentrer pour la faire évoluer sur les 3 fichiers suivants dans le dossier src/app/ :

  1. app.component.ts— Le code du composant de base en TypeScript.
  2. app.component.html— La partie vue en HTML du composant de base en HTML.
  3. app.component.css— La feuille de styles du composant de base en CSS.

Le composant proposé par défaut par AngularJs est trop complexe pour notre application Todo. Remplaçons le code de app.component.html par ce code:

<div id="title">
  <h1>{{title}}</h1>
</div>

La modification de ce fichier fait automatiquement rechargé la page de votre navigateur car l’applicaiton ng serve --sourceMap=true fonctionne toujours sur votre ordinateur (à moins que vous n’ayez fermé ce programme et/ou le navigateur). Nous évitons ainsi tout ce qui est mécanisme de refresh du navigateur, tout est automatisé.

On peut ensuite modifier le fichier app.component.css pour y ajouter le centrer d’un tag h1 inclus dans un div ayant l’ID title:

#title > h1 {
    text-align: center;
}

L’étape suivante est de modifier le fichier app.component.ts qui contient la classe gérant le composant. Au début le composant n’inclus qu’une seule propriété par défaut title:

export class AppComponent {
  title = 'todo';
}

Nous pouvons ajouter une propriété lesTodos contenant une liste de valeurs qui sera initialisé par l’appel de la méthode ngOnInit qui se déclenche à la fabrication du composant (ne pas oublier de modifier la première ligne aussi avec OnInit) :

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

export interface Todo{
   id: number; 
   texte: string;
   actif: boolean;
}
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
  lesTodos = [];
  // si vous avez une erreur de type remplacer la ligne ci-dessus par
  // lesTodos: Array<Todo> = [];
  title = 'todo';

  ngOnInit(): void {
     this.lesTodos=[{"id":1,"texte":"lait","actif":false},{"id":2,"texte":"beurre","actif":false}];
  }
}

 

Côté application.html modifions pour afficher ce tableau JSON:

<ul>
  <li *ngFor="let todo of lesTodos">{{todo.texte}}</li>  
</ul>

Attention, ce n’est pas la « bonne » solution, il faut passer ensuite dans une structure avec Composant dans Angular que l’on verra plus loin. Tout mettre dans les fichiers applications n’est ici que dans un but d’apprentissage par étape.

 

Etape 9/ Intégration AngularJs avec Spring

La création des fichiers finaux dans le dossier src/ressources/static/ va permettre d’intégrer les codes ensembles et de faire un appel à l’URL http://127.0.0.1/todos/ pour obtenir la liste des todos.

Ouvrez un nouveau terminal via la même opération que dans l’étape 7 car pour mémoire le premier terminal est utilisé par le programme ng serve.

Créer les fichiers finaux d’angularjs dans le dossier du projet spring boot et plus précisement dans le dossier ressources/static/:

ng build todo --prod  --outputPath=C:\DEV\workspace-spring\todo\src\main\resources\static

Vous pouvez constater que l’ensemble des fichiers du projet Angular on été réduit en une collection de quelques fichiers Javascript, un fichier Html et un fichier CSS dans un format compacté et simplifié.

Le déploiement ensuite classiquement du projet spring nous permet de tester la solution dans Spring/Tomcat et de constater via les outils de développement Web du navigateur que l’on a juste oublié de créer la ressource favicon.ico (la seule erreur 404 dans cet onglet):

 

 

L’intégration est donc faite entre un Front-End développé avec le Framework Angular et le Back-End développé en Spring. Ce qui est important est que l’on peut remplacer des briques logicielles de cette architecture, par exemple remplacé le Front-End par le Framework React.js ou Vues.js ou un développement en iOs/Android et le Back-End peut être lui en technology Python, PHP, NodeJS, etc.

Il faut maintenant charger la liste des todos depuis l’URL http://127.0.0.1:8080/todos mais attention Angular est très sensible au formatage du fichier JSON provenant d’un serveur:

  • Evitez les objets contenant pour faire directement un tableau:
    • Oui: [{« id »:1, »texte »: »todo-1″, »actif »:false},{« id »:2, »texte »: »todo-1″, »actif »:false}]
    • Non: {todos:[{« id »:1, »texte »: »todo-1″, »actif »:false},{« id »:2, »texte »: »todo-1″, »actif »:false}]}
  • Simple quote n’est pas autorisé dans le formatage JSON:
    • Oui: [{« id »:1, »texte »: »todo-1″, »actif »:false},{« id »:2, »texte »: »todo-1″, »actif »:false}]
    • Non: [{‘id’:1,’texte’:’todo-1′,’actif’:false},{‘id’:2,’texte’:’todo-1′,’actif’:false}]
  • Element String non encadré de quote:
    • Oui: [{« id »:1, »texte »: »todo-1″, »actif »:false},{« id »:2, »texte »: »todo-1″, »actif »:false}]
    • Non: [{‘id’:1,’texte’:todo-1,’actif’:false},{id:2,’texte’:’todo-1′,’actif’:false}]

On peut exploiter par exemple la nouvelle fonctionnalité des block texte pour simplifier la fabrication de fichier JSON (attention cela ne fonctionne pas encore c’est trop tôt voir le contournement plus bas):

 public String toJson() {
     return """
       {"id":$id,
       "texte":"$texte",
       "actif":$actif}
       """
      .formatted("$id", this.id )
      .formatted("$texte",this.texte)
      .formatted("actif",this.actif);
}

La nouvelle version de Java 15 inclus ces structures de block texte pour permettre de fabriquer du contenu plus simplement que les anciennes concaténations assez peu lisible:

return "{\"id\":" + this.id + ",\"texte\":\"" + this.texte+ "\",\"actif\":" + this.actif.toString() +"}";

A voir http://blog.codefx.org/java/text-blocks/

NOTA: contournement de la méthode formatted qui est trop récente. En fait on va créer un string ( avec un objet TextBlock il y a un conflit cette feature est trop récente pour Spring) puis appeler la méthode static String.format qui fonctionne comme la fonction du langage C printf historique.

String returnString = "{\"id\":%d,\"texte\":\"%s\",\"actif\":%s}";

returnString = String.format(returnString, this.id, this.texte, this.actif);

Le remplacement des éléments %d (pour un nombre) ,%s (pour un string) se fait dans l’ordre d’apparition. Ce bout de code est en attente de solution élégante de chercher et remplacer dans les TextBlock à venir ou une autre solution (json-simple, Gson, etc.)

Plus élégant, on peut alors exploiter aussi les Stream appellant la méthode toJson sur chaque élément et en ajoutant un [ au début , un ] à la fin et des virgules entre les éléments:

lesTodos.stream().map(todo -> {return todo.toJson()}).collect(Collectors.joining(",", "[", "]"));

 

Il faut maintenant récupérer dans Angular la liste des Todos au lieu de l’avoir en dur dans le code. Alors l’ancienne version utilisait le module HttpClient qui a évolué en un nouveau module HttpClientModule. Donc attention, il peut y avoir confusion car il y a eu évolution de ce composant.

En premier lieu, ajoutons dans le fichier app.module.ts l’importaiton suivante:

import { HttpClientModule } from '@angular/common/http';

Et dans le même fichier, il faut l’ajouter au tableau des NgModule:

@NgModule({
   Imports: [
       HttpClientModule,
      ...
     ],...
})

 

NOTA: un problème avec ce nouveau module m’a obligé à lancer cette commande suivante et à relancer le serveur NodeJS:

npm cache verify

Il faut ajouter l’importation suivante en début de fichier app.component.ts:

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

Cet importation nous permet de fabriquer une instance d’HttpClient dans le composant AppComponent  via l’appel à la méthode constructor qui permet de fabriquer une propriété pour AppComponent qui est de nature privé, c’est l’équivalent en Java du constructeur. Je vous renvoie à cet article qui explique la notion d’initialisation et de classe entre Angular et TypeScript (http://pierreterrat.com/angular-ngoninit-et-constructor/).

 

Une fois que l’on dispose d’un client HttpClient, on peut l’utiliser pour faire une requête HTTP RESTFull, en première version avec création d’une constante temporaire:

export class AppComponent implements OnInit {
  lesTodos = [];
  title = 'todo';  

  constructor(private http: HttpClient) {
   const desTodos:Observable<[]> = this.http.get<[]>('http://127.0.0.1:8080/todos/');
   desTodos.subscribe(desTodos => {
     this.lesTodos = desTodos;
     console.log(this.lesTodos);
   });   
 }

 

Vous pouvez maintenant faire le déploiement de cette version du frontend dans Spring en redéployons la dans le dossier static:

ng build todo --prod  --outputPath=C:\DEV\workspace-spring\todo\src\main\resources\static

 

Mais pour tester, il faut outrepasser la protection la sécurité du CORS que l’on voit plus bas au chapitre Debug.

La liaison est faite entre le serveur Spring et le Fron-End Angular via cette opération.

Nous pouvons améliorer la récupération des informations via l’appel GET en spécifiant une structure de données via un interface dans le fichier app.component.ts en ajoutant l’export en tête du fichier (après les imports):

export interface Todo {   
  id: number;   
  texte: string;   
  actif: boolean; 
}

Conversion de l’appel GET, en indiquant la nature des données Todo[]:

const desTodos:Observable<Todo[]> = this.http.get<Todo[]>('http://127.0.0.1:8080/todos/'); 

Et en seconde version, on peut intégrer l’opération de conversion d’une instance de Observable<Todo[]> vers la propriété this.lesTodos en tableau de valeur:

this.http.get<Todo[]>('http://127.0.0.1:8080/todos/').subscribe(lesTodosJson => this.lesTodos = lesTodosJson);

 

 

Etape 10/ Debug et utilisation d’angular avec l’IDE ou sans IDE

Le débug du développement avec Angular suppose l’installation notamment d’un navigateur démarré avec des options. Personllement, j’utilise un Chromium (version opensource de Chrome) pour faire les opérations, je le lance dans le terminal avec ces réglages:

C:\Users\pierre.jean\AppData\Local\Chromium\Application\chrome.exe --disable-web-security --disable-gpu --user-data-dir=c:\DEV\worskpace-nodejs --auto-open-devtools-for-tabs --remote-debugging-port=9222 -incognito http://127.0.0.1:4200/
  • L’option –disable-web-security me permet d’outrepasser la sécurité du CORS et je peux donc débugger sur le serveur NodeJS (port 4200) qui appele le serveur Spring (port 8080). Il y a d’autres solutions possible pour contourner le CORS mais je trouve celle-ci simple d’installation
  • L’option –disable-gpu me permet d’éviter d’utiliser le rendu du GPU pour avoir le fonctionnement le plus simplifié possible de Chromium
  • –user-data-dir permet de créer un profil utilisateur spécifique pour le développement sans réglages venant d’une autre session de Chromium
  • –auto-open-devtools-for-tabs ouvre les Web Developper Tools par défaut
  • –remote-debugging-port ouvre un port de communication pour le débuggage depuis Visual Studio Code pour que les points d’arrêts placé dans l’IDE soit arrété dans Chromium
  • -incognito est l’option navigation privé de Chromium
  • http://127.0.0.1:4200/ est l’URL de NodeJs à remplacer par http://127.0.0.1:8080/ si on souhaite débugger sur Spring

Le démarrage de ng serve avec sourceMap permet de générer des fichiers qui font la correspondance entre le code Javascript et le code TypeScript pour le débuggage.

ng serve --sourceMap=true

L’utilisation des points d’arrêt dans le Visual Studio Code se fait en modifiant le fichier launch.json via le menu Executer > Ouvrir les configurations à modifier pour « attacher » le debugger de Visual Sutdio au Chromium démarré avec le port 9222 pour l’échange des points d’arrêt:

{
    // Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
    // Pointez pour afficher la description des attributs existants.
    // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "attach",
            "name": "Chromium Launch",
            "url": "http://127.0.0.1:4200/",            
            "port":9222,
            "sourceMaps": true,
            "webRoot": "${workspaceFolder}",
            "sourceMapPathOverrides": {
                "webpack:///./*":"${workspaceRoot}\\*" 
            }            
        }
    ]
}

Je peux donc mettre un point d’arrêt dans Visual Studio Code, « Executer > Démarrer le debogage » qui va se lier avec le Chromium démarré précédemment.

Une autre solution pratique aussi pour placer un point d’arrêt d’utiliser la commande « debugger; » dans une ligne du programme TypeScript pour permettre au programme de s’arrêter.

Exemple de point d’arrêt placé dans Chromium que l’on retrouve dans Visual Studio Code, notez la barre d’outil dans Visual Studio Code qui permet de faire les opérations classiques de débuggage, le dernier bouton en rouge permet de détacher le debugger de Visual Studio Code de Chromium:

Le debuggage depuis Visual Studio Code ne fonctionne pas toujours, je passe donc systématiquement par le debugger de Chromium et pour trouver le bon fichier, j’utilise le fameux mot clef debugger; .

Voici un exemple, de l’éxécution sur le Spring avec le code Angular intégré, l’appel à la requête todos/ qui retourne un fichier JSON et affiche dans la console du navigateur le retour d’information.

 

NOTA  sur le débugage:

Je vous laisse avec ce petit problème avec les fonctions d’asynchrones pour le debug:

const desTodos:Observable<Todo[]> = this.http.get<Todo[]>('http://127.0.0.1:8080/todos/');
desTodos.subscribe(desTodos => {
              this.lesTodos = desTodos;
              console.log( "Appel Asynchrone:" + this.lesTodos);
});
console.log("C'est vide: "+this.lesTodos);

En fait la dernière ligne avec le message « C’est vide » ne va pas contenir les todos car la requête HTTP RESTFull n’est pas terminée, c’est la ligne contenant « Appel Asynchrone » qui elle sera appelé plus tard quand la réponse à la requête HTTP RESTfull sera réalisée.

On peut donc retirer la dernière ligne qui ne sert à rien pour le débugage…

 

Etape 11/ Création d’un composant pour améliorer le code

La première opération que nous allons faire est de remplacer l’interface simple du Todo en un composant complet d’Angular via la ligne de commande:

ng generate component Todo

Le composant va se composer de 3 nouveaux fichiers classiques en Angular: todo.component.html, todo.component.css et todo.component.ts.

On ne touchera pas vraiment au fichier todo.component.css pour l’instant. Le contenu de todo.component.html va être de cette forme aussi simplifié (n’oublions pas que cela va être placé dans un tag <li></li> d’une liste HTML:

<span>( {{currentTodo.id}} ) ->  {{currentTodo.texte}} is {{currentTodo.actif}}</span>

Maintenant le nouveau composant doit recevoir une instance de Todo, que l’on appellera currentTodo de type Todo. Pour cela le composant TodoComponent a une propriété indiqué avec l’annotation @Input. On n’oubliera pas d’ajouter dans l’import la nouvelle annotation Input:

@Input() currentTodo:Todo;

Le code de todo.component.ts :

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

export interface Todo {
  id: number;
  texte: string;
  actif: boolean;
}

@Component({
  selector: 'app-todo',
  templateUrl: './todo.component.html',
  styleUrls: ['./todo.component.css']
})
export class TodoComponent implements OnInit {
  @Input() currentTodo:Todo;

  constructor() { }
  ngOnInit(): void {
  }
}

Il est à noter aussi que on définie pour la seconde fois l’interface Todo et que l’on devra bien le factoriser prochainement.

Maintenant, appelons ce nouveau composant dans le fichier app.component.html (j’ai laissé l’ancienne notation en commentaire HTML pour montrer la différence:

    <li *ngFor="let todo of lesTodos">
      <!-- <span>{{todo.id}}</span> {{todo.texte}} -->
      <app-todo [currentTodo]=todo></app-todo>
    </li>

La liaison se fait via le @Component et sa propriété selector: ‘app-todo’.

Bien sur maintenant on peut intervenir sur le todo.component.html pour faire le rendu du contenu du currentTodo:

<span id="checkbox_{{currentTodo.id}}"> {{currentTodo.texte}} is {{currentTodo.actif}}</span>

Vous pouvez modifier pour ajouter une classe CSS au span qui sera liéé à actif/non actif:

<span id="checkbox_{{currentTodo.id}}" class="todo_{{currentTodo.actif}}"> {{currentTodo.texte}} </span>

Un peu de CSS dans le fichier todo.component.css pour diférencié actif/non actif:

span.todo_false{
    text-decoration: line-through;
}

On pourrait fabriquer ce qui est formatage de type Pipe pour avoir un élément actif ou innactif. je vous renvoie sur ce tutoriel qui expliquera très bien comment cela fonctionne: https://fiyazhasan.me/angular-pipe-for-handling-boolean-types/

 

Etape 12/Formulaire avec binding des données et envoie des données

Création d’un évènement click sur le span dans le composant todo.component.html

<span (click)="onEdit()" id="checkbox_{{currentTodo.id}}" class="todo_{{currentTodo.actif}}"> {{currentTodo.texte}} </span>

Il faut donc créer la méthode onEdit dans todo.component.ts avec une propriété edit qui gère si le TodoComposant est en mode edition ou non:

export class TodoComponent implements OnInit {

  @Input() currentTodo:Todo;
  edit:boolean = false;

  onEdit(): void {
    this.edit = !this.edit;
  }
}

On va donc gérer dans le TodoComposant l’affichage soit de l’affichage déjà disponible soit d’un champ de formulaire avec un if à la façon Angular:

<span *ngIf="edit==false" (click)="onEdit()" id="checkbox_{{currentTodo.id}}" class="todo_{{currentTodo.actif}}"> {{currentTodo.texte}} </span>
<span   *ngIf="edit==true" 
        id="checkbox_{{currentTodo.id}}"> 
        <input value="{{currentTodo.texte}}" placeholder="Description"/>
</span>

Sauf que notre tag <input> n’a pas de liaison avec le composant TodoComposant pour reprendre les informations après modification.Nous allons ajouter à l’application le composant FormsModule en ajoutant l’import du formulaire dans app.module.ts:

import { FormsModule } from '@angular/forms';

et plus dans le tableau imports (bien sur s’il y a plusieurs imports dans le tableau ne les retirez pas) :

imports: [
  FormsModule,
],

Nous allons faire évoluer le TodoComposant pour lui ajouter une liaison avec le contenu du champ <input> via cet attribut [(ngModel)]= »currentTodo.texte »  tout modification du champ de formulaire sera effective sur la propriété currentTodo.texte et vise-versa (du coup plus besoin de l’attribut value ):

            <input   placeholder="Description"
                    [(ngModel)]="currentTodo.texte"
                    (focusout)="onValidation()" autofocus
            />

On notera que l’évènement focusout (perte de focus) permet de détecter la validation par l’utilisateur. Dans le composant TodoComposant, la méthode onValidation() ne fait que désactiver  la valeur edition sans gérér la valeur du champs car c’est le binding d’Angular qui fait le travail tout seul :

  onValidation(): void {
    this.edit = false;    
  }

Maintenant ajoutons le bouton checkbox et un bouton validé et envoyons sur le serveur la modification:

<input placeholder="Description"
   [(ngModel)]="currentTodo.texte"                    
/>
<input type="checkbox"  
   [(ngModel)]="currentTodo.actif"
/>
<input type="button" (click)="onValidation" value="Update" />

On retire la validation de la perte de focus du premier champs car sinon on valide avant d’avoir pu modifier le checkbox. J’avoue que la gestion des évènements pour éviter le bouton au bout de la ligne est complexe mais en fait ce code ne fonctionne que trop bien…

En effet, en cliquant sur le bouton Update on va aussi déclenche ensuite l’évènement sur le tag <span> qui repasse en mode édition. Comme dans beaucoup de framework javascript, il faut arréter la propagation de l’évènement click.

Dans todo.component.html:

 <input type="button" (click)="onValidation($event)" value="Update" />

Dans todo.component.ts:

  onValidation(event): void {
    event.stopPropagation();
    this.edit = false;
  }

 

L’envoie des données se fait avec des modifications côté Spring pour récupérer des données complexes. En premier lieu je donne la version détaillée où la conversion du fichier JSON en objet est visible pour simplifier le débuggage, ensuite on voit la version intégrée avec Spring.

Côté Spring, deux nouvelles méthodes:

Pour la couche TodoDao :

 public Todo updateTodo(Todo newTodo) {
   Session session = this.sessionFactory.getCurrentSession();
   session.update(newTodo);
   return newTodo;
}

 

Pour la fouche Controleur TodoControleur:

@PostMapping(value = "/updateOneTodo" )
public Todo updateTodo(@RequestBody String todo) { 
    ObjectMapper mapper = new ObjectMapper();
    // Petit bug qui permet de forcer le passage d'un int en long
    mapper.configure(DeserializationFeature.USE_LONG_FOR_INTS, true);
    try {
        Todo newTodo = mapper.readValue(todo, Todo.class);
        todoDao.updateTodo( newTodo );
        return ( newTodo );
    } catch (JsonProcessingException e) {
       e.printStackTrace();
    }
    return (null);
}

 

Côté Angular (n’oubliez pas d’importer le module http comme pour app.component.ts :

onValidation(event): void {
    event.stopPropagation();
    this.edit = false;
    this.updateTodo();
  }

  updateTodo():void{      
    const newTodo:Observable<Todo> = this.http.post<Todo>('http://127.0.0.1:8080/updateOneTodo' 
    , this.currentTodo );
    newTodo.subscribe(newTodo =>{
       this.currentTodo = newTodo;
       console.log(this.currentTodo);
    });
}

L’envoie d’un Todo se fait directement en passant l’objet Javascript qui va être converti en donnée JSON de la forme:

{id: 10, texte: "yaourt", actif: true}

On voit que l’on réalise la conversion de la chaine de caractère depuis le JSON en instance TODO avec le convertisseur JSON de Spring qui s’appelle Jackson.

Attention, il faut activer cette nouvelle option dans le fichier application.properties de Spring pour cause d’incompatibilité entre Angular et Spring sur le format du JSON:

#Jackson JSON parser
spring.jackson.parser.allow-unquoted-field-names=true

Car Jackson attend ceci comme fichier JSON par défaut:

{"id": 10, "texte": "yaourt", "actif": true}

 

Enfin la version plus simple côté Spring qui réalise la conversion directement:

 @PostMapping(value = "/updateTodo")
 public Todo updateTodo(@RequestBody Todo todo) { 
     todoDao.updateTodo(todo);
     return todo;
}

L’opération de conversion est réalisé avec Jackson mais je pense comme d’habitude qu’il est utile de pouvoir valider la conversion de JSON avec la première méthode pour gérer des cas plus variés. Côté Angular, la seule modification est dans l’URL de passer de /updateOneTodo en /updateTodo.


Les grandes bases de l’architecture Spring/Angular sont en place, à vous de jouer maintenant pour réaliser toutes les autres fonctionnalités du CRUD.

 

 

 

Pour revenir sur le problème de conversion avec Json, on peut ajouter la bibliothèque Gson à Spring, dans le fichier pom.xml à la fin du tag <dependecies>

    <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
       <version>2.8.5</version>
     </dependency>
</dependencies>

Du coup on peut créer une classe TodoHelper:

import com.google.gson.Gson;

public class TodoHelper {
   private static Gson gson = new Gson();
   public static String toJsonConverter(Todo todo){
       return gson.toJson( todo );
   }
}

Et appeler depuis notre Todo ce convertisseur:

public String toJson() { 
    return TodoHelper.toJsonConverter(this);
}

On pourrait même techniquement retirer Jackson comme serialiser/deserialiser de Json de Spring pour exploiter directement Gson.

spring.http.converters.preferred-json-mapper=gson

C’est une des forces de Java JEE de pouvoir permettre le remplacement d’un composant par un autre pour fabriquer un framework dont la structure peut évoluer doucement pour tirer partie d’une fonctionnalité ou d’une autre. Notre pile logicielle actuelle s’appuie sur Spring+Angular mais on pourrait avoir un remplacement d’un composant ou d’un autre, ou l’ajout de composants additionnels selon le besoin.

 

 

 

 

Publié dans IMT Mines Alès | Laisser un commentaire

X-Sens Dot Sensor

Dans le cadre d’un projet de recherche, j’ai testé un senseur de chez X-Sens: X-Sens Dot :

Ce capteur doit permettre de remonter des informations accélération pour l’expérience. Devant la documentation en ligne sur ce dispositif et avec l’accord du support très réactif de l’entreprise X-sens, je pense qu’un tutoriel plus complet sur ce dispositif peut être utile au plus grand nombre.

Des informations actuellement que je dispose, je n’ai pas trouvé de solution pour connecter mon Windows 10 sur le X-Sens, le développement se fait via mon smartphone android (un samsung S10+) et avec Android Studio.

Je ne peux que vous conseiller de télécharger l’application officielle (xsensdot-apk-v2020.0.apk en Avril 2020) de X-Sens pour les X-Sens Dot et le SDK X-Sens Dot dans la rubrique Software/Wearable Sensor: https://www.xsens.com/software-downloads

Le SDK contient une documentation PDF et .chm et un fichier XsensDotSdk.aar qui a servi de base à ce tutoriel.

 

1/ Démarrage d’Android Studio

En premier lieu créons dans Android Studio un nouveau projet se basant sur une Activity vide:

Configuration du projet avec un nom, un nom de package, un dossier de stockage et surtout une version de SDK minimale à API 22 selon les recommandations de la documentation:

En premier ajoutons les droits spécifiques et nécessaire sur cette application, il est à noter que je déploie sur un smartphone réel et non vers l’émulateur. Je trouve que c’est plus rapide et plus efficace de développer sur un smartphone réel en suivant ces recommandations sur developer.android.com.

Ajoutons donc ces permissions, qu’il faudra activer aussi sur le smartphone individuellement pour Storage et Position (voir plus bas dans le tutoriel):

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 

2/ Importation de XsensDotSdk.aar

L’importation d’un module aar se fait en plusieurs étapes que j’ai découvert avec ce projet.

En premier lieu, il faut indiquer l’importation de ce module via le Menu File > New > New Module … puis choisir « Import .JAR/.AAR Package » , faire Next:

 

Indiquer le chemin vers le module XsensDotSdk.aar (pour le nom du subproject le laisser par défaut):

Ce n’est pas parce que le module est importé en tant que subproject que notre projet a une dépendance envers lui.

Donc, Menu File > Project Structure … > puis Dependencies > app (notre projet par défaut) puis le petit bouton + (Add Depency) puis choisir « Module Depency » :

 

 

 

Indiquons que l’on veut une dépendance vers XsensDotSDK, Ok pour valider cette fenêtre et ensuite de nouveau OK pour valider la fenêtre précédente:

Une phase de build se déclenche plus ou moins longue selon la performance de son ordinateur…

 

3/ Utilisation des classes du  XsensDotSdk.aar

Nous allons travailler dans ce tutoriel sur la MainActivity, ce n’est pas l’idéal mais pour un développement de test nous pouvons réaliser un premier essai.

Ajoutons l’implémentation des classes XsensDotDeviceCv et XSensDotScannerCb:

Nous avons une erreur d’importation que l’on règle en laissant la souris sur les 2 classes problématiques, IntelliJ nous propose d’importer les packages manquants:

Nous pouvons maintenant aussi fabriquer les implémentations manquantes pour les méthodes nécessaires aux classes XsensDotDeviceCv et XSensDotScannerCb en survolant avec notre curseur ces dernières:

 

L’ajout de toutes les méthodes se fait rapidement:

 

 

4/ Développement des fonctions de connexion au X-sens DOT

Nous allons donc coder dans la méthode onCreate encore une fois par simplicité puis nous détecterons que le smartphone a bien trouvé le X-Sens Dot en mettant un point d’arrêt dans la méthode onXsensDotScanner:

public void onXsensDotScanned(BluetoothDevice bluetoothDevice) {

Donc on code une propriété mxScanner

private XsensDotScanner mXsScanner;

Puis dans la méthode onCreate :

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String version = XsensDotSdk.getSdkVersion();
    XsensDotSdk.setDebugEnabled(true);
    XsensDotSdk.setReconnectEnabled(true);
    mXsScanner = new XsensDotScanner(this.getApplicationContext(), this);
    mXsScanner.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
    mXsScanner.startScan();
}

 

Enfin un bout de code pour récupérer les informations sur le device:

@Override
public void onXsensDotScanned(BluetoothDevice bluetoothDevice) {
    String name = bluetoothDevice.getName();
    String address = bluetoothDevice.getAddress();
}

Choisissez ensuite votre smartphone (il faut que le débuggage soit possible sur ce smartphone d’ailleurs cf developer.android.com) puis le bouton « débug app » :

Voici les indications de débugage avec les adresses (factice sur cet écran) de réponse:

Ajoutons maintenant la récupération des données par le capteur en ajoutant une nouvelle propriété et  en modification la méthode onXsensDotScanned:

Nouvelle propriété: xsDevice pour gérer la connexion à notre Xsens Dot

private XsensDotDevice xsDevice = null;

 

Nouvelle version de onXsensDotScanned

@Override
public void onXsensDotScanned(BluetoothDevice bluetoothDevice) {
    String name = bluetoothDevice.getName();
    String address = bluetoothDevice.getAddress();

    xsDevice = new XsensDotDevice(this.getApplicationContext(), bluetoothDevice,MainActivity.this);
    xsDevice.connect();
    xsDevice.startMeasuring();
}

Notre X-Sens Dot devrait capture les données dans la méthode onXsensDotDataChanged et l’envoyer dans le loger LogCat d’Android:

@Override
public void onXsensDotDataChanged(String address, XsensDotData xsensDotData) {
    Log.i( "XsensDot", "onXsensDotDataChanged " + address + " " + xsensDotData );
}

 

Nous lançons le débugage avec un point d’arrêt sur l’évènement onXsensDotDataChanged et un regard sur le LogCat dans IntelliJ:

Aucune donnée n’arrive sur la méthode onXsensDotDataChanged….

 

5/ Ajout des droits dans le smartphone

Les données n’arrivent pas car il faut ajouter les droits sur l’application directement sur ce dernier. j’avais eu déjà le problème avec les IMU embarquées dans le smartphone.

Il faut donc aller sur l’application, faire un appuie long, puis choisir « Infos sur l’appli. » puis dans l’écran « informations sur l’application » choisir le menu « Autorisations » puis accepter les 2 autorisations « Localisation » et « Stockage » pour enfin pour relancer l’application avec les droits complets:

Et donc récupération des données sur un point d’arrêt du débug quand les données arrivent:

 

6/ Liaison Xsens DOT – Smartphone Android – Code JAVA

Pour la récupération des données de l’accélération  angulaire sur X du capteur Xsens DOT, j’ai utilisé une liaison bluetooth additionnel de type Port COM à 115200 bauds avec un programme en Java sur mon PC:

 

Vous pouvez constater sur la vidéo ci-dessous que le résultat est quand même assez impressionnant, la rotation de ma main déclenche bien le déplacement du point rouge sur le smartphone et l’envoie au PC de l’information Gauche/Droite/Centre pour faire réaliser le même déplacement au point vert.

Il y a un délais bien sur entre la modification d’orientation et le déplacement du point. L’algorithme doit être améliorer pour diminuer ce délais.

7/ Nouvelle version des SDK de Xsens

Suite à la conférence d’Avril 2020 de Xsens, j’ai la possibilité de récupérer les données directement depuis le PC. Donc la nouvelle version doit être directement développée sur l’ordinateur pour récupérer les données via le protocole Bluetooth BLE.

Pour simplifier le développement sur Windows, j’ai développé le code en C#. En effet, mes anciens développement avec le bluetooth m’ont montré que ce langage est le plus proche du système d’exploitation sur windows; aucune surprise le langage C# appartient à Microsoft. Du coup, je pense que les ouvertures/fermetures des canaux de communication bluetooth BLE seront simplifiées par ce langage de programmation.

Mon conseil est d’en premier lieu de travailler à partir du document « Xsens DOT BLE Services Specifications » proposé en téléchargement par Xsens sur son site internet. Ce document indique bien une évolution dans l’accès à certaines données envoyés par la nouvelle version (1.3) des Xsens. Personnellement, je vais continuer à utiliser la version 1.0.0 car moins de données = plus simple à interpréter.

Nota: attention au format big-endiant/little-endian des données, j’ai passé un peu de temps en lisant les octets dans le mauvais ordre.
Ce n’est pas encore standardisé, heureusement la documentation indique « All the big-endian members will be changed to little-endian in the next firmware release ».

Le développement a du être mis en stand-by pour cause de projet en parallèle, mais les premiers résultats sont encourageant. Le standard Bluetooth BLE est bien accepté par le xSens DOT comme montre la vidéo suivante qui affiche les accélérations du composant sur un seul axe.

Démonstration de la liaison bleutooth BLE du Xsens avec un développement C# sur un PC Windows 10 Pro version 18362 (Indiquer ma version n’est pas anodin pour le développement bluetooth BLE).

Publié dans Développement | Laisser un commentaire

git sourcesup

https://sourcesup.renater.fr/account/
Mettre un mot de passe du compte unix
Vérifier le mot de passe: https://sourcesup.renater.fr/account/change_pw.php

Trouver l’URL
URL : https://pierre.jean@git.renater.fr/authscm/pierre.jean/git/rearm/rearm.git cf copie d’écran en dessous pour le trouver
login UNIX pierre.jean
le BON MDP de SOurcesup

Ouvrir GitHub Desktop, faire clone a repository du smart https
https://pierre.jean@git.renater.fr/authscm/pierre.jean/git/rearm/rearm.git

—–
Ne fonctionne plus ?

Commande
git init

git clone ssh://git@git.renater.fr:2222/nom_projet.git

git clone https://pierre.jean@git.renater.fr/authscm/pierre.jean/git/rearm/rearm.git

Ouvre fenêtre authentification pour cloner sauf…

git config –global user.email « pierre.jean@mines-ales.fr »
git config –global user.name « pierre.jean »
git add rearm
git commit -m « Message de validation »

Publié dans Développement | Laisser un commentaire

Taiga Docker surprises

 

Pour une première étape avec Docker, j’ai essayé d’installer le logiciel taiga via cet outil de container. La solution la plus classique serait de prendre une image ubuntu et de suivre l’installation de docker (Setup development installation taiga).

Sauf qu’après avoir suivi une formation de Docker, j’ai compris que l’intérêt de Docker ou du moins un intéret est dans les micro service soit d’avoir 5 containers au lieu d’un seul.


NOTE: Vous avez un problème pour impoter votre projet taiga dans taiga (par exemple après une mise à jours) ?

Taiga contient un utilitaire qui se trouve dans le cotnaineur taiga-back et qui permet de faire l’importation suivant cette commande:

/usr/bin/python3 manage.py load_dump dump.json p.jean@mines-ales.fr

 

 

Taiga et Docker

Taiga est un logiciel de gestion de projet agile de type assez classique avec kanban et spring intégré. Ce que j’aime dans Taiga en plus qu’il soit open source est que l’on peut activer ou non les outils agile, par exemple commencé avec un simple kanban et ensuite rajouter des sprint et/ou un wiki et/ou un gestionnaire de bug.

Taiga n’a pas de version officielle de Docker. Plusieurs images sont disponibles mais j’avoue que parfois les personnes qui ont fait les images avaient des idées très précises de leur utilisation qui ne m’allait par.

Dans ma solution je souhaite que Docker puisse gérer les cinq containers avec l’avantage de pouvoir renforcer un container ou le remplacer au besoin :

  • taiga-db database postgreSQL
  • taiga-front pour la partie front web de Taiga
  • taiga-back pour la partie backoffice de Taiga
  • taiga-rabbit pour le gestionnaire de message dans Taiga
  • taga-events pour l’envoie des notifications dans Taiga via le navigateur
  • taiga-proxy pour le serveur front nginx dispatchant les requêtes.

L’image de docker de base

Je pars donc d’une image existante de docker. En fait, j’en essaye plusieurs avant de trouver une image qui correspond à ce que je souhaite soit avec une base de données et avec la partie notifications/messages.

La version suivante : https://github.com/docker-taiga/taiga semble être un bon compromis. Je télécharge donc le dépot github et je fais une installation sans problème sur un serveur linux de test.

Hors, cette installation ne fonctionne qu’une seule fois. Je n’arrive pas en relançant à récupérer le fonctionnement de mon serveur taiga. Après plusieurs essaies et avec l’obligation de devoir intégrer mes propres développements dans Taiga, je suis donc contraint de prépare une installation à partir du fichier docker-compose.yml.

 

Docker-taiga-pje

Pourquoi faire une version de taiga docker personnelles:

  • Je souhaite intégrer 1 fichier et une bibliothèque python en plus.
  • Je souhaite débugger avec un outil curl dans taiga-back et taiga-proxy
  • Je souhaite que le déploiement se fasse tout seul avec le minimum d’intervention de ma part
  • Le container taiga-back contient un serveur web nginx qui fait double emploie pour moi avec le serveur taiga-proxy en frontal
  • Monter en compétence avec Docker avec un exemple et des contraintes réelles
  • Docker sur Windows 10 avec tout les désavantages que l’on y trouve (et il y en a Docker est fait pour Linux et cela se voit)

La première étape que je vais faire est de créer un dossier pour le taiga-proxy et modifier le code de nginx.conf et nginx_ssl.conf pour que le nginx de ce container aille chercher le http://back:8000/. Cela suppose aussi la modificaiton du docker-compose.yml pour qu’il prenne en charge cette nouvelle image appelée taiga-proxy-pje.

Puis je faire la même modification pour le taiga-back pour qu’il prenne en charge de nouveau modules python et modifier le script de démarrage pour ne pas charger le serveur nginx. J’en profiterai pour que le port 8000 de ce container soit accessible pour faire le débogage avec curl installé dans ce container.

 

Etape 1 création de l’image taiga-proxy-pje

Téléchargement des fichiers du dépot git-hub depuis https://github.com/docker-taiga/proxy

 

Version initiale du fichier nginx.conf

server {
	server_name $TAIGA_HOST;
	listen 80;
	location ^~ /events {
		proxy_pass http://$EVENTS_HOST:8888/;
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";
		proxy_connect_timeout 7d;
		proxy_send_timeout 7d;
		proxy_read_timeout 7d;
	}
	location ^~ /api {
		include proxy_params;
		proxy_pass http://$TAIGA_BACK_HOST;
	}
	location ^~ /admin {
		include proxy_params;
		proxy_pass http://$TAIGA_BACK_HOST;
	}
	location ^~ /static {
		include proxy_params;
		proxy_pass http://$TAIGA_BACK_HOST;
	}
	location ^~ /media {
		include proxy_params;
		proxy_pass http://$TAIGA_BACK_HOST;
	}
	location / {
		include proxy_params;
		proxy_pass http://$TAIGA_FRONT_HOST;
	}
}

Version modifiée du fichier nginx.conf

server {
server_name $TAIGA_HOST;
listen 80;
location ^~ /events {
proxy_pass http://$EVENTS_HOST:8888/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection « upgrade »;
proxy_connect_timeout 7d;
proxy_send_timeout 7d;
proxy_read_timeout 7d;
}
location ^~ /api {
include proxy_params;
proxy_pass http://$TAIGA_BACK_HOST:8000;
}
location ^~ /admin {
include proxy_params;
proxy_pass http://$TAIGA_BACK_HOST;
}
location ^~ /static {
include proxy_params;
proxy_pass http://$TAIGA_BACK_HOST;
}
location ^~ /media {
include proxy_params;
proxy_pass http://$TAIGA_BACK_HOST;
}
location / {
include proxy_params;
proxy_pass http://$TAIGA_FRONT_HOST;
}
}

Maintenant dans le dossier taiga-pje/proxy en ligne de commande pour construire l’image taiga-proxy-pje :

docker build -t taiga-proxy-pje .

Il faut ensuite modifier le fichier docker-compose.yml pour ne plus appeler l’image taiga-proxy mais l’image taiga-proxy-pje, donc après avoir téléchargé tous les fichiers du dossier taiga via git

git clone –depth=1 -b latest https://github.com/docker-taiga/taiga.git

Nous obtenons le dossier suivant:

Nous pouvons donc ensuite modifier le fichier docker-compose.yml:

version: ‘3’

services:
back:
image: taiga-back
container_name: taiga-back
restart: unless-stopped
depends_on:
– db
– events
networks:
– default
volumes:
– ./data/media:/taiga-media
– ./conf/back:/taiga-conf
env_file:
– variables.env

front:
image: dockertaiga/front
container_name: taiga-front
restart: unless-stopped
networks:
– default
volumes:
– ./conf/front:/taiga-conf
env_file:
– variables.env

db:
image: postgres:11-alpine
container_name: taiga-db
restart: unless-stopped
networks:
– default
env_file:
– variables.env
volumes:
– ./data/db:/var/lib/postgresql/data

rabbit:
image: dockertaiga/rabbit
container_name: taiga-rabbit
restart: unless-stopped
networks:
– default
env_file:
– variables.env

events:
image: dockertaiga/events
container_name: taiga-events
restart: unless-stopped
depends_on:
– rabbit
networks:
– default
env_file:
– variables.env

proxy:
image: taiga-proxy-pje
container_name: taiga-proxy
restart: unless-stopped
depends_on:
– back
– front
– events
networks:
– default
ports:
– 80:80
– 443:443
volumes:
#- ./cert:/taiga-cert
– ./conf/proxy:/taiga-conf
env_file:
– variables.env

networks:
default:

 

Pour fabriquer l’ensemble des containers en allant chercher les images, la magie de docker est appeler avec

cd taiga
docker-compose.exe up -d

Pour mémoire, le dossier taiga/ contient le docker-compose.yml qui va faire l’assemblage des images et le dossier proxy contient l’image spéciale docker-proxy-pje.

Rapidement, vous allez faire un fichier go.bat avec:

cd proxy
docker build -t taiga-proxy-pje .
cd ..
cd taiga
docker-compose.exe up -d
cd ..

 

et un purge.bat qui fait plusieurs actions: retire les fichiers indiquant que ce démarrage n’est pas la version initiale, arrête l’option redémarrage des container pour pouvoir les arrêter :

  • retire les fichiers .initial_setup.lock qui indiquent que la configuration a déjà été faite (cf processus de création des fichiers conf ci-dessous)
  • mettre à jours le critères restart à no pour me permettre d’arrêter les containers car sinon docker les redémarre automatiquement, vous pouvez aussi faire docker update –restart=np $(docker ps -q) pour empecher tous les containers en fonctionnement de redémarrer
  • effacer les containeurs
  • effacer les images
  • effacer les volumes non utilisé par aucun container, attention cela pourrait retirer aussi d’autres volumes qui ne serait pas lié à des containers
rm taiga/conf/back/.initial_setup.lock
rm taiga/conf/front/.initial_setup.lock
rm taiga/conf/proxy/.initial_setup.lock
docker update –restart=no $(docker ps -a -q –filter « name=taiga-proxy » –filter « name=taiga-events » –filter « name=taiga-front » –filter « name=taiga-rabbit » –filter « name=taiga-db »)
docker rm taiga-proxy taiga-back taiga-events taiga-front taiga-rabbit taiga-db
docker rmi taiga-proxy-pje dockertaiga/front dockertaiga/events dockertaiga/rabbit dockertaiga/back
docker volume prune –force

Attention c’est assez violent de retirer tous les volumes non utilisé. Dans mon cas je n’avais que les containers et images liés à taiga.

Processus de créations des fichiers

J’ai eu beaucoup de problème pour comprendre qui fabrique les fichiers dans le dossier taiga/conf. En effet, au premier démarrage des containers taiga-back, taiga-proxy, taiga-front, le script appelé par le RUN (habituellement start.sh) de chaque Dockerfile va créer les dossiers et fichiers de la configuraton pour qu’au redémarrage du container, ces fichiers soient utilisés au lieu de les recréer à chaque fois. Le problème est de créer un processus complet de fabrication et non pas de bricoler dans les fichiers de taiga/conf/. On peut modifier ces fichiers pour tester quelqus réglages de nginx par exemple mais il faut bien qu’à la fin on ai la totalité du processus from scratch

Enfin, j’ai un taiga proxy qui appelle sur le port 8000, le serveur django. Maintenant, il faut configurer le taiga-back pour ne pas utiliser le nginx inclus mais directement le django

taiga-back-pje

Création du dossier back et modification du fichier go.sh

cd proxy
docker build -t taiga-proxy-pje .
cd ..
cd back
docker build -t taiga-back-pje .
cd ..

cd taiga
docker-compose.exe up -d
cd ..

 

et purge.bat:

rm taiga/conf/back/.initial_setup.lock
rm taiga/conf/front/.initial_setup.lock
rm taiga/conf/proxy/.initial_setup.lock
docker update –restart=no $(docker ps -a -q –filter « name=taiga-proxy » –filter « name=taiga-events » –filter « name=taiga-front » –filter « name=taiga-rabbit » –filter « name=taiga-db »)
docker rm taiga-proxy taiga-back taiga-events taiga-front taiga-rabbit taiga-db
docker rmi taiga-proxy-pje dockertaiga/front dockertaiga/events dockertaiga/rabbit taiga-back-pje
docker volume prune –force

 

Dans notre dossier back, nous allons trouver:

d—– 11/06/2019 11:04 users <— Le dossier contenant le nouveau fichier python pour l’OTP
-a—- 13/06/2019 18:43 1225 config.py <— Le fichier de configuration de taiga back
-a—- 08/06/2019 14:52 1956 Dockerfile <— Le fichier Dockerfile où le travail est le plus important
-a—- 02/06/2019 17:26 1466 Dockerfile.v0 <— Fichier Dockerfile initial, pour voir entre Linux et Windows
-a—- 08/06/2019 14:17 157 ntpd.conf <— Le container n’a pas accès à l’heure, cf plus bas
-a—- 13/02/2019 10:26 74 README.md <— Le fichier README de github
-a—- 10/06/2019 20:05 2015 start.sh <— Le nouveau fichier start.sh qui va bien changer

Il faut avec le terminal créer une nouvelle image docker-back que l’on va appeler docker-back-pje.

docker build -t taiga-back-pje .

Cette commande fabrique une nouvelle image de taiga-back. Sauf que sur windows, j’ai une erreur :

WARNING: Ignoring APKINDEX.b89edf6e.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.737f7e01.tar.gz: No such file or directory

Cette erreur vient d’un problème de dossier cache des packages d’alpine.

La solution est de modifier le dockerfile pour détruire ce cache et d’ajouter le package ca-certificates.
Je rajoute aussi le package « jq » pour avoir un outil d’affichage des données json lisible.

FROM alpine:latestENV TAIGA_HOST=taiga.lan \
TAIGA_SECRET=secret \
TAIGA_SCHEME=http \
POSTGRES_HOST=db \
POSTGRES_DB=taiga \
POSTGRES_USER=postgres \
POSTGRES_PASSWORD=password \
RABBIT_HOST=rabbit \
RABBIT_PORT=5672 \
RABBIT_USER=taiga \
RABBIT_PASSWORD=password \
RABBIT_VHOST=taiga \
STARTUP_TIMEOUT=15sWORKDIR /srv/taigaRUN rm -rf /var/cache/apk/* && rm -rf /tmp/* \
&& apk –no-cache add python3 gettext postgresql-dev libxslt-dev libxml2-dev libjpeg-turbo-dev zeromq-dev libffi-dev nginx \
&& apk add –no-cache –virtual .build-dependencies musl-dev python3-dev linux-headers git zlib-dev libjpeg-turbo-dev gcc ca-certificates jq \
&& mkdir logs \
&& git clone –depth=1 -b stable https://github.com/taigaio/taiga-back.git back && cd back \
&& sed -e ‘s/cryptography==.*/cryptography==2.3.1/’ -i requirements.txt \
&& pip3 install –upgrade pip \
&& pip3 install -r requirements.txt \
&& rm -rf /root/.cache \
&& apk del .build-dependencies \
&& rm /srv/taiga/back/settings/local.py.example \
&& rm /etc/nginx/conf.d/default.conf

EXPOSE 80

WORKDIR /srv/taiga/back

COPY config.py /tmp/taiga-conf/
COPY nginx.conf /etc/nginx/conf.d/
COPY start.sh /

VOLUME [« /taiga-conf », « /taiga-media »]

CMD [« /start.sh »]

Ok cela fabrique l’image, je peux modifier le fichier docker-compose.yml et recréer l’ensemble des images manquantes et des containers associés avec le script go.sh

version: ‘3’

services:
back:
image: taiga-back-pje
container_name: taiga-back
restart: unless-stopped
depends_on:
– db
– events
networks:
– default
volumes:
– ./data/media:/taiga-media
– ./conf/back:/taiga-conf
env_file:
– variables.env

front:
image: dockertaiga/front
container_name: taiga-front
restart: unless-stopped
networks:
– default
volumes:
– ./conf/front:/taiga-conf
env_file:
– variables.env

db:
image: postgres:11-alpine
container_name: taiga-db
restart: unless-stopped
networks:
– default
env_file:
– variables.env
volumes:
– ./data/db:/var/lib/postgresql/data

rabbit:
image: dockertaiga/rabbit
container_name: taiga-rabbit
restart: unless-stopped
networks:
– default
env_file:
– variables.env

events:
image: dockertaiga/events
container_name: taiga-events
restart: unless-stopped
depends_on:
– rabbit
networks:
– default
env_file:
– variables.env

proxy:
image: taiga-proxy-pje
container_name: taiga-proxy
restart: unless-stopped
depends_on:
– back
– front
– events
networks:
– default
ports:
– 80:80
– 443:443
volumes:
#- ./cert:/taiga-cert
– ./conf/proxy:/taiga-conf
env_file:
– variables.env

networks:
default:

Sauf que après un petit tour dans le container taiga-back fabriqué à partir de mon image taiga-back-pje

docker exec -it taiga-back sh

La date est complètement fausse sur Windows

En fait, docker windows ne peut accéder (avec la version que j’avais en mars 2019) à l’horloge système.
Il n’y a pas de problème sous Linux.

Comme j’ai besoins de cette date à jour pour la suite du projet. Je dois injecter un serveur de temps openntpd et le configurer dans l’image docker-back-pje

Nouveaux modifications du fichier Dockerfile

FROM alpine:latestENV TAIGA_HOST=taiga.lan \
TAIGA_SECRET=secret \
TAIGA_SCHEME=http \
POSTGRES_HOST=db \
POSTGRES_DB=taiga \
POSTGRES_USER=postgres \
POSTGRES_PASSWORD=password \
RABBIT_HOST=rabbit \
RABBIT_PORT=5672 \
RABBIT_USER=taiga \
RABBIT_PASSWORD=password \
RABBIT_VHOST=taiga \
STARTUP_TIMEOUT=15sWORKDIR /srv/taigaRUN rm -rf /var/cache/apk/* && rm -rf /tmp/* \
&& apk –no-cache add python3 gettext postgresql-dev libxslt-dev libxml2-dev libjpeg-turbo-dev zeromq-dev libffi-dev nginx \
&& apk add –no-cache –virtual .build-dependencies musl-dev python3-dev linux-headers git zlib-dev libjpeg-turbo-dev gcc ca-certificates jq openntpd \
&& mkdir logs \
&& cp /usr/share/zoneinfo/Europe/Paris /etc/localtime && echo « Europe/Paris » > /etc/timezone && renice -n-8 $(pidof ntpd -s) \
&& git clone –depth=1 -b stable https://github.com/taigaio/taiga-back.git back && cd back \
&& sed -e ‘s/cryptography==.*/cryptography==2.3.1/’ -i requirements.txt \
&& pip3 install –upgrade pip \
&& pip3 install -r requirements.txt \
&& rm -rf /root/.cache \
&& apk del .build-dependencies tzdata \
&& rm /srv/taiga/back/settings/local.py.example \
&& rm /etc/nginx/conf.d/default.conf

EXPOSE 80

WORKDIR /srv/taiga/back

COPY ntpd.conf /etc/ntpd.conf
COPY config.py /tmp/taiga-conf/
COPY nginx.conf /etc/nginx/conf.d/
COPY start.sh /

VOLUME [« /taiga-conf », « /taiga-media »]

CMD [« /start.sh »]

On note qu’il y a une injection de la timezone dans le fichier /etc/timezone pour indiquer le fuseau horaire

Bien sur le fichier ntpd.conf sur le disque dur a ces informations

# See ntpd.conf(5) and /etc/examples/ntpd.conf
listen on *server time1.google.com
server time2.google.com
server time3.google.com
server time4.google.com

On peut indiquer d’autres serveurs de temps dans le cas d’une structure qui aurait une politique locale des serveurs de temps

Je suis toujours dessus pour améliorer le processus…

Publié dans Développement | Laisser un commentaire

Accès manager-gui via Tomcat 8.5 dans Docker

Suite à l’installation de Tomcat 8.5 dans docker, je n’ai pas trouvé simplement comment accéder à l’interface de déploiement web dans Tomcat.

Il faut donc modifier les fichiers suivants:

/usr/local/tomcat/conf/tomcat-users.xml:

<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="admin" password="password" roles="manager-gui,manager-script" />

Puis aller dans les réglages de l’application manager dans /usr/local/tomcat/webapps/manager/META-INF/context.xml et modifier le tag suivant :

 <Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />

Par ceci:

 <Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="\d+\.\d+\.\d+.\d+|127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />

Merci à cet article :

https://stackoverflow.com/questions/42692206/docker-tomcat-users-configuration-not-working

 

 

 

 

 

Publié dans Développement | Laisser un commentaire

gvim et vimrc

Habituellement je n’utilise que la ligne suivante dans mon fichier vimrc qui gère la configuration par défaut de mon gvim/vim :

colorscheme slate

Juste le changement du thème et donc des couleurs par défaut de Gvim en choisissant un thème prédéfini.

J’avais besoin de disposer d’un Gvim ouvert au centre de mon écran de taille plutôt réduite déjà en mode édition avec un fichier vide par défaut. Du coup, j’ai installé le plugin wimproved.vim. Ce plugin a installer simplement, le fichier wimproved32.dll dans le dossier principal de vim, dans le dossier autoload le fichier autoload/wimproved.vim et dans le dossier plugin le fichier plugin/wimproved.vim.

Ensuite il faut configurer le fichier vimrc :

" Simplifier l'interface de gvim en retirant le menu et les icones
autocmd GUIEnter * silent! WToggleClean
" Centrer gvim avec une taille de 30% de l'écran
autocmd GUIEnter * silent! WCenter 30
" Degré de transparence de l'interface sur 255 niveau
autocmd GUIEnter * silent! WSetAlpha 220
" Couleur du thème
colorscheme slate

" test si c'est l'édition d'un nouveau fichier ou d'un fichier existant
" ces réglages ne sont appliqués qu'au nouveau fichier pas aux fichiers en éditon 
if argc()==0

  " cache les symboles ~ qui indiquent des lignes non existente
  hi NonText guifg=bg
  " fait une insertion vide par défaut pour retirer le message d'introduction 
  normal i 
  " mode insertion au lieu d'être mode commande comme habituellement
  start
endif


 

Vi / VIM / Gvim sont des outils très pratiques car disponiblent sur toutes les plateformes et les systèmes d’exploitations. Ils gèrent un nombre important type de format et ouvrent même des fichiers de tailles énormes sans sourciller. Je sais que l’apprentissage sur cet outil est compliqué (mode commande <-> mode édition) mais les manipulations de types expressions régulières et les plugins additionnels en font un outil extraordinaire.

Efface les lignes avec le mot profile quelque part:

:g/profile/d

Efface les lignes ne contenant par le mot profile quelque part:

:g!/profile/d

 

 

Publié dans Développement | Laisser un commentaire

Protégé : Tp4 IMT Mines Développement Web

Cette publication est protégée par un mot de passe. Pour la voir, veuillez saisir votre mot de passe ci-dessous :

Publié dans IMT Mines Alès | Commentaires fermés sur Protégé : Tp4 IMT Mines Développement Web

Résultat du sondage de Stackoverflow 2017 et Infographie de Chooseyourboss 2018

Le sondage 2017 du site web de support informatique stackoverflow vient de sortir. Le sondage est très/trop complet notamment sur des questions hors du domaine du développement (le développeur a t’il des enfants par exemple). Vous pouvez le trouver à cette URL.

Je sors quelques points que je trouve intéressant et donc ce n’est que mon regard personnel sur ce sondage, chacun est libre d’en sortir ses propres impressions.

Et blog de Choose Your Boss a ajouté une infographie pour 2018

 

 

Comment se définit le développeur:

Finalement on peut dire que les sondés sont globalement des développeurs qui font un peu de tout en Front/Back/Full, finalement c’est le « Desktop or entreprise applications » qui montre bien que ce type de développement est assez faible sur ce site. Peut être que les développeurs de ce genre d’applications sont expérimentés et n’ont plus besoin de poser des questions.

 

La bataille des IDEs:

Le Visual Studio payant et gratuit semble enfoncé les autres, le trio des éditeurs Sublime Text/Vim/Notepad++ semble être très utilisé au final, le reste est très classique au final.

Les langages des développeurs:

Beaucoup de développement web en Front, donc JS+HTML+CSS sontles premier. On trouve les inaltérables SQL/Shell en plus. La tendance reste Java/Python/C#/PHP/C++/C.  J’ai indiqué les langages ayant plus de 10%, vous trouverez surement votre langage dans le sondage.

 

Les Framework des développeurs:

Node.js / Angular /react indique bien que le développement des solutions javascript a le vent en poupe. Ce qui est surprenant encore c’est le .Net Core qui est très important, une information que je n’avais pas personnellement.

Base de données utilisées

 

La seconde place de SQL Server est pour moi une surprise, le reste me parait assez classique comme représentation.

Les plateformes cible des développeurs:

Attention, ce n’est pas avec quel OS ils développent, il y a une réponse spécifique sur ce point. On voit bien que le classique c’est Linux/Windows, un peu d’android, de cluster AWS, Mac OS. Rasberry Pi et WordPress sont présentés comme des cibles cela indique bien la force de leur spécificité.

 

Les regroupement  des technologies pour les développeurs:

Très utile cela indique bien les liaisons outils/technologies/plateformes pour comprendre qu’elles sont les compétences liées.

 

 

Publié dans Développement | Laisser un commentaire