Exercices - Création d'un client Rest⚓︎
Toujours dans notre application de locations, on peut imaginer rajouter une page Web permettant l'ajout d'un nouveau logement. Pour cela, il faudrait pouvoir saisir son adresse. Lorsque vous remplissez un tel formulaire sur une page Web, il y a souvent des propositions d'adresses qui apparaîssent lorsqu'on commence la saisie. Nous allons mettre en place cela (en partie).
Nous allons donc utiliser un Web Service (externe à notre application) comme source de données. Nous allons donc rajouter une couche DAO, qui ne se connecte pas à une base de données cette fois, mais à ce Web Service.
Exercice 1 - Prise en main de l'API⚓︎
Prise en main de l'API
Pour cela, nous allons utiliser l'API nationale permettant de chercher une adresse en France.
Vous pouvez effectuer quelques tests, avec Postman par exemple, pour la prendre en main.
Elle est disponible ici : https://adresse.data.gouv.fr/api-doc/adresse
Nous allons utiliser l'URI /search
avec le verbe HTTP GET
et deux paramètres de requête (c'est-à-dire des "query parameters") :
q
: Permet d'indiquer l'adresse recherchée.limit
: Le nombre (maximum) de résultats renvoyés.
Il y a d'autres paramètres possibles, mais ils ne nous sont pas nécessaires ici.
Par exemple, vous pouvez effectuer un test avec https://api-adresse.data.gouv.fr/search/?q=64%20avenue%20jean%20portalis&limit=15, qui renvoie, à l'heure où ceci est écrit, 4 résultats.
Remarque : Comme nous n'utilisons que le verbe HTTP GET
, que nous ne modifions ni l'en-tête, ni le corps de la requête, et que le résultat est par défaut envoyé au format JSON, il est possible d'effectuer la requête directement dans un navigateur, sans passer par Postman. Je vous conseille cependant tout de même de l'utiliser, afin de bien prendre l'habitude de l'utiliser.
Exercice 2 - Génération du modèle⚓︎
Génération du modèle
Il nous faut transformer ce résultat JSON en Java Beans. Nous pourrions créer la couche modèle correspondante à la main, puisque le format du résultat est indiqué ici, mais ce serait fastidieux. Il est possible de générer automatiquement ce code.
On peut pour cela par exemple utiliser le site https://www.jsonschema2pojo.org/. Pour cela :
- Copier le résultat (le fichier JSON) de la requête dans la partie gauche.
- Dans le champ Package, indiquer le package dans lequels les Java Beans (la couche modèle) va être générée. Ici, on peut par exemple indiquer
fr.univtours.polytech.locationapp.model.address
- Dans le champ Class name, indiquer le nom de la classe principale. Ici, on peut par exemple indiquer
WsAddressResult
- Dans Source type, sélectionner JSON.
- Cliquer sur
Zip , télécharger le résultat et le placer dans le dossier 📂src/main/java
(le dossier contenant les sources Java) du projet Web.
Ca y est, notre modèle est généré !
Depuis notre application Java, lorsque nous exécuterons le Web Service, nous récupérerons un objet WsAddressResult
, contenant lui même une liste de Feature
. Cet objet Feature
correspond à une adresse.
Il contient lui-même un objet Properties
qui permettra d'accéder aux informations sur chacune des adresses renvoyées.
Exercice 3 - Création du client Rest⚓︎
Création du client Rest
Il nous reste maintenant à appeler ce Web Service, depuis notre application Java et non plus depuis un navigateur ou depuis Postman uniquement. Plus précisément, il nous reste à appeler ce Web Service depuis la couche DAO de notre application Java.
Commençons donc par créer la couche DAO. Elle ne contient ici qu'une seule méthode, qui renvoie une liste d'adresse (c'est-à-dire une liste de Feature
), et qui prend en paramètre une chaîne de caractère : l'adresse recherchée.
Voici donc l'interface fr.univtours.polytech.locationapp.dao.AddressDao
:
public List<Feature> getAddresses(String search);
Et son implémentation, la classe fr.univtours.polytech.locationapp.dao.AddressDaoImpl
. Pour cela, nous allons utiliser les classes fournies par JaxRS :
private static String URL = "https://api-adresse.data.gouv.fr";
@Override
public List<Feature> getAddresses(String search) {
// Instanciation du client.
Client client = ClientBuilder.newClient();
// On indique l'URL du Web Service.
WebTarget target = client.target(URL);
// On indique le "end point" (on aurait aussi pu directement le mettre dans
// l'URL).
// C'est également avec cette méthode qu'on pourrait ajouter des "path
// parameters" si besoin.
target = target.path("search");
// On précise (lorsqu'il y en a) les "query parameters".
target = target.queryParam("q", search);
target = target.queryParam("limit", 15);
// On appelle le WS en précisant le type de l'objet renvoyé, ici un
// WsAddressResult.
System.out.println(target.getUri());
WsAddressResult wsResult = target.request(MediaType.APPLICATION_JSON).get(WsAddressResult.class);
return wsResult.getFeatures();
}
Remarque sur le code
On pourrait écrire tout cela de manière condensée :
private static String URI = "https://api-adresse.data.gouv.fr/search";
@Override
public List<Feature> getAddresses(String search) {
Client client = ClientBuilder.newClient();
Result result = client.target(URI).queryParam("q", search).queryParam("limit", 15)
.request(MediaType.APPLICATION_JSON).get(WsAddressResult.class);
return result.getFeatures();
}
Exercice 4 - Les couches métier et présentation⚓︎
Les couches métier et présentation
Nous allons ajouter une petite couche présentation, pour utiliser ce que nous avons fait :
-
Commençons par créer le service métier appelant ce DAO. Pour cela, créer l'EJB
fr.univtours.polytech.locationapp.business.AddressBusinessLocal
(nous n'allons pas créer deRemote
ici), contenant une méthode :☕ Code Javapublic List<Feature> searchAddresses(String search);
:warning: Ne pas oublier d'utiliser l'annotation
@Local
. -
Créer l'implémentation de cet EJB, qui appelle la couche DAO.
:warning: Ne pas oublier d'utiliser l'annotation
@Stateless
. -
Créer une servlet, qui sera appelée via l'URI
/searchAddress
, contenant l'implémentation dedoGet
et dedoPost
:doGet
redirige l'utilisateur vers une JSPaddresses.jsp
contenant un champ pour saisir une adresse.doPost
récupère cette adresse saisie, appelle l'EJB effectuant la recherche, et redirige l'utilisateur versaddresses.jsp
qui affiche cette liste.
☕ Code Java - La servlet@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // On place une liste vide dans la requête. request.setAttribute("ADDRESSES", new ArrayList<Feature>()); // On redirige vers la JSP. request.getRequestDispatcher("addresses.jsp").forward(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // On récupère ce que l'utilisateur à saisi. String search = request.getParameter("search"); // On exécute la requête correspondante. List<Feature> addresses = this.addressBusiness.searchAddresses(search); // On place le résultat de la recherche dans la requête. request.setAttribute("ADDRESSES", addresses); // On redirige vers la JSP. request.getRequestDispatcher("addresses.jsp").forward(request, response); }
☕ La JSP<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html> <html> <head> <title>Rechercher une adresse</title> </head> <body> <form action="searchAddress" method="post"> <input type="text" name="search"/> <input type="submit" value="Rechercher"/> </form> <table> <tr> <th>Adresse</th> <th>Ville</th> <th>Code postal</th> </tr> <c:forEach var="address" items="${requestScope.ADDRESSES}"> <tr> <td> ${address.properties.name} </td> <td> ${address.properties.city} </td> <td> ${address.properties.postcode} </td> </tr> </c:forEach> </table> </body> </html>
La page de recherche est maintenant accessible depuis l'URL http://localhost:8080/LocationApp/searchAddress (il faut penser à mettre à jour le nom de l'application Web et du port).