Web Service sous Spring Boot (java)
Langage : Java sous Spring Boot
La partie Web service développée dans les plateformes sert d’intermédiaire entre les frontaux et le ou les backends. Objectif est de mutualiser les fonctionnalités développées, d’éviter d’avoir des liens trop importants antre les frontaux et le backend , de permettre des accès externes aux backends.
Plusieurs vocations pour ces web services :
- servir d’intermédiaire entre les frontaux et les backends de stockage de données
- servir d’intermédiaire entre les frontaux et les moyens de calculs
- servir d’accès à des plateformes extérieures avec Token.
Illustrations par plateforme
Plateforme passy : dictionnaire phonétique français et ses variations. Contexte MongoDB.
/***
* Retourne que la liste des mots trouvés selon le filtre sur la phonétique
* {"ilfo":{"phonetique":"^car"}}
* @param body
* @return
*/
@RequestMapping(value = "/phono", method = POST)
public Map<String, List<atilf>> find_dico_phono(@RequestBody Map<String, Map<String, String>> body) {
Map<String, List<atilf>> liste_trouves = new HashMap<>();
Query query_ = new Query();
query_.addCriteria(Criteria.where("phonetique").regex(body.get("ilfo").get("phonetique")));
liste_trouves.put("ilfo", mongoTemplate.find(query_, atilf.class, "lexique"));
System.out.println("Extraction des mots demandés");
return liste_trouves;
}
Dans cet appel on passe par un mapping objet à l’aide de la classe atilf.class
package fr.ilfo.passy;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import com.fasterxml.jackson.annotation.JsonProperty;
public class atilf implements Serializable{
private static final long serialVersionUID = 1L;
@Id
private String _id;
@JsonProperty("id")
private String id;
@JsonProperty("graphie")
private String graphie;
@JsonProperty("categ")
private String categ;
@JsonProperty("genre")
private String genre;
@JsonProperty("phonetique")
private String phonetique;
}
Plateforme EMOLGINE : Web service devant la base de données CHEMBL — Contexte MYSQL
(réf : https://mkyong.com/spring-boot/spring-boot-spring-data-jpa-mysql-example/)
Objectif de ce web service est de servir d’intermédiaire pour la plateforme EMOLGINE et le site SPGoO avec la base de données de la Chembl. L’expérimentation au sein du site de SPGoO permet de mettre au point les fonctionnalités avec les utilisateurs avant leur intégration dans EMOLGINE.
Plusieurs étapes pour la mise en place de ce web service :
- Constituer le projet Spring boot sous Eclipse
- Ajouter les packages nécessaires
- Développer les éléments d’interrogation
Configuration actuelle est une version 2.5.0 de Spring boot et la version 11 de java.
Contenu du fichier pom.xml :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>fr.spgoo</groupId>
<artifactId>chembl</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spgoo-chembl</name>
<description>service d'exploration de cible</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Structuration du projet avec un exemple sur la table compound_structures

Entity
package fr.spgoo.chembl;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Compound_structures {
@Id
private Long molregno;
private String molfile;
@Column(name = "standard_inchi", nullable = false)
private String standardinchi;
@Column(name = "standard_inchi_key", nullable = false)
private String standardinchikey;
@Column(name = "canonical_smiles", nullable = false)
private String canonicalsmiles;
public Compound_structures() {
}
public Long getMolregno() {
return molregno;
}
public void setMolregno(Long molregno) {
this.molregno = molregno;
}
public String getMolfile() {
return molfile;
}
public void setMolfile(String molfile) {
this.molfile = molfile;
}
public String getStandardinchikey() {
return standardinchikey;
}
public void setStandardinchikey(String standardinchikey) {
this.standardinchikey = standardinchikey;
}
public String getStandardinchi() {
return standardinchi;
}
public void setStandardinchi(String standardinchi) {
this.standardinchi = standardinchi;
}
public String getCanonicalsmiles() {
return canonicalsmiles;
}
public void setCanonicalsmiles(String canonicalsmiles) {
this.canonicalsmiles = canonicalsmiles;
}
}
Interface
package fr.spgoo.chembl;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface Repository_Compound_structures extends JpaRepository<Compound_structures, Long> {
List<Compound_structures> findByMolregno(Long molregno);
List<Compound_structures> findByStandardinchikey(String inchikey);
}
Service
package fr.spgoo.chembl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class Serv_compound_structures {
@Autowired
private Repository_Compound_structures Repository;
public List<Compound_structures> findByMolregno(Long inchikey) {
return Repository.findByMolregno(inchikey);
}
public List<Compound_structures> findByStandardinchikey(String inchikey) {
return Repository.findByStandardinchikey(inchikey);
}
}
DataController
package fr.spgoo.chembl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin("*")
@RestController
@RequestMapping("/chembl")
public class DataController {
@Autowired
private Serv_compound_structures SRV_compound_structures;
@GetMapping("/find/molregno/{molregno}")
public List<Compound_structures> findByTitle(@PathVariable Long molregno) {
return SRV_compound_structures.findByMolregno(molregno);
}
@GetMapping("/find/inchikey/{inchikey}")
public List<Compound_structures> findByStandardinchikey(@PathVariable String inchikey) {
return SRV_compound_structures.findByStandardinchikey(inchikey);
}
}
Exemples d’appel et affichage des résultats :
http://localhost:9999/chembl/find/inchikey/PSOPUAQFGCRDIP-UHFFFAOYSA-N
Résultats
[
{
"molregno": 4,
"molfile": "\n RDKit 2D\n\n 23 25 0 0 0 0 0 0 0 0999 V2000\n 6.3417 -2.4250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8542 -2.7250 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3417 -1.8250 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3750 -2.4250 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3750 -1.8250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8542 -1.5250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8500 -5.1167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8542 -3.3250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.8167 -2.7167 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8500 -4.5167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3667 -5.4167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8542 -0.9250 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3292 -5.4167 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3667 -3.6167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3292 -3.6167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3292 -4.2167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3667 -4.2167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3667 -6.0167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 7.8792 -5.1167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 8.4042 -5.4167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 7.8875 -6.3167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 8.4042 -6.0167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 8.9250 -6.3167 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2 1 1 0\n 3 1 1 0\n 4 2 1 0\n 5 6 1 0\n 6 3 1 0\n 7 10 1 0\n 8 2 1 0\n 9 1 2 0\n 10 16 2 0\n 11 7 1 0\n 12 6 2 0\n 13 7 2 0\n 14 8 1 0\n 15 8 2 0\n 16 15 1 0\n 17 14 2 0\n 18 11 2 0\n 19 11 1 0\n 20 19 2 0\n 21 18 1 0\n 22 20 1 0\n 23 22 1 0\n 4 5 2 0\n 10 17 1 0\n 21 22 2 0\nM END",
"standardinchi": "InChI=1S/C17H13N3O3/c1-11-2-4-12(5-3-11)16(22)13-6-8-14(9-7-13)20-17(23)19-15(21)10-18-20/h2-10H,1H3,(H,19,21,23)",
"standardinchikey": "PSOPUAQFGCRDIP-UHFFFAOYSA-N",
"canonicalsmiles": "Cc1ccc(C(=O)c2ccc(-n3ncc(=O)[nH]c3=O)cc2)cc1"
}
]
http://localhost:9999/chembl/find/molregno/1
Résultat
[
{
"molregno": 1,
"molfile": "\n RDKit 2D\n\n 24 26 0 0 0 0 0 0 0 0999 V2000\n 5.2792 -2.0500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7917 -2.3500 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 5.2792 -1.4500 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3125 -2.0500 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7875 -4.7417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7875 -4.1417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3125 -1.4500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3042 -5.0417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7917 -1.1500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7917 -2.9500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.2667 -3.8417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.2667 -3.2417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3042 -3.8417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 4.7542 -2.3417 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3042 -5.6417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.2667 -5.0417 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3042 -3.2417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7917 -0.5500 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7792 -5.9417 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8167 -4.7417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 4.7417 -4.1417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.8250 -5.9417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3417 -5.0417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 7.3417 -5.6417 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2 1 1 0\n 3 1 1 0\n 4 2 1 0\n 5 6 1 0\n 6 13 1 0\n 7 9 1 0\n 8 5 1 0\n 9 3 1 0\n 10 2 1 0\n 11 12 1 0\n 12 10 2 0\n 13 17 2 0\n 14 1 2 0\n 15 8 2 0\n 16 5 2 0\n 17 10 1 0\n 18 9 2 0\n 19 15 1 0\n 20 8 1 0\n 21 11 1 0\n 22 15 1 0\n 23 20 2 0\n 24 23 1 0\n 4 7 2 0\n 11 6 2 0\n 22 24 2 0\nM END",
"standardinchi": "InChI=1S/C17H12ClN3O3/c1-10-8-11(21-17(24)20-15(22)9-19-21)6-7-12(10)16(23)13-4-2-3-5-14(13)18/h2-9H,1H3,(H,20,22,24)",
"standardinchikey": "OWRSAHYFSSNENM-UHFFFAOYSA-N",
"canonicalsmiles": "Cc1cc(-n2ncc(=O)[nH]c2=O)ccc1C(=O)c1ccccc1Cl"
}
]
Retour d’expérience de cette mise en place :
Quelques recommandations à prendre en compte : attention aux noms d’attributs avec des caractères spéciaux (_), dans ce cas il faut utiliser la directive column pour associer l’attribut de la table avec un nom de variable sans ces caractères spéciaux.
Vous aurez observer que dans le service il n’y a pas d’indication de requête SQL correspondant à l’extraction des données de la base, on a juste indiquer l’instruction suivante:
List<Compound_structures> findByMolregno(Long molregno);
C’est la partie JPA qui prend en charge de façon implicite lors du chargement par l’Autowired de la résolution correspondante. Dans cette exemple, l’ORM interprète le nom de la fonction Molregno comme une demande d’extraction d’un attribut molregno d’une classe Compound_structures. Classe dans laquelle on doit retrouver l’attribut molregno de type Long.
Prise en compte du NULL dans les attributs
Dans la définition de la classe de l’Entity faire attention aux types utilisés . Ne pas utiliser les types de bases (Primitive types are not nullable) qui n’acceptent pas la valeur NULL lors de l’affectation il faut préférer les types “objet” String, Long, Integer ….. qui eux acceptent la valeur NULL. donc dans ce cas l’ORM est bien en mesure d’instancier un objet correctement.