Bonjour,
Voici un exemple très simple de création d'un serveur de Web services sous Windev, dans une configuration de projet de type "Archive Java", avec JAX-WS (Java API for XML Web Services).
Dans Windev, je crée un nouveau projet.
A l'étape 1, je choisis le type de projet "Archive Java".
Ensuite, je crée une nouvelle collection de procédures globales.
Dans mon exemple, je l'ai nommée "ServeurWs".
Dans le code de déclaration de la collection de procédures, j'ajoute les variables globales suivantes :
Je crée maintenant une nouvelle procédure "init" dans "ServeurWs", qui permettra par la suite de passer au code Java l'ip et le port du serveur de Web services.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 sServeurIp est une chaîne iServeurPort est un entier
Je crée deux nouvelles procédures "get_sServeurIp" et "get_iServeurPort" dans "ServeurWs" :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 PROCEDURE GLOBALE init(LOCAL _sServeurIp est une chaîne,LOCAL _iServeurPort est un entier) sServeurIp = _sServeurIp iServeurPort = _iServeurPort
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 PROCEDURE GLOBALE get_sServeurIp() RENVOYER sServeurIpJe crée maintenant une nouvelle procédure "start" dans "ServeurWs".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 PROCEDURE GLOBALE get_iServeurPort() RENVOYER iServeurPort
Dans l'entête de cette procédure "start", je clique sur le libellé "WS", pour la transformer en procédure Java.
J'écrase ensuite l'ensemble du code généré, qui ressemble à cela :
par le code suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 public static void start() { }
Je crée ensuite une nouvelle procédure "javaDeclarations" dans "ServeurWs".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 public static void start() { //Publication des Web services try { String sServeurIp = appelProcedureWL_String("get_sServeurIp"); int iServeurPort = appelProcedureWL_int("get_iServeurPort"); String sWsdl = "http://"+sServeurIp+":"+iServeurPort+"/ws/MonWebService?wsdl"; Endpoint.publish(sWsdl, new MonWebServiceImpl()); /* Pour un lancement en tant que Service Windows (sans fenêtre) while(true){ Thread.sleep(10); } */ } catch (Exception e) { System.err.println(e.getMessage()); } }
Cette procédure permettra de déclarer l'ensemble des classes Java utilisées par le serveur de Web services.
Comme pour la procédure "start", je clique sur le libellé "WS", pour la transformer en procédure Java.
Je supprime le code créé automatiquement par Windev, pour y coller ce code :
Il ne me reste plus désormais qu'à implémenter la procédure "wsHelloWorld" dans "ServeurWs".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 import javax.jws.WebService; import javax.annotation.Resource; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.ws.Endpoint; import javax.xml.ws.WebServiceContext; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @WebService(targetNamespace="http://MonWebService.com/wsdl") public static class MonWebServiceImpl { @Resource WebServiceContext webServiceContext; //================================================================================================== @WebMethod @WebResult(name="ClaHelloWorldRes") public ClaHelloWorldRes helloWorld(@WebParam(name="nom", targetNamespace="http://MonWebService.com/wsdl") final String sNom, @WebParam(name="age", targetNamespace="http://MonWebService.com/wsdl") int iAge) throws Exception { //Appel à la procédure Windev wsHelloWorld écrite en WLangage String sRes = appelProcedureWL_String("wsHelloWorld",sNom,iAge); //La procédure renvoie une chaine débutant par <ERR> en cas d'exception dans le code WLangage if (sRes.startsWith("<ERR>")){ sRes = sRes.substring(5); throw (new Exception(sRes)); } ClaHelloWorldRes res = new ClaHelloWorldRes(); res.setNom(sNom); res.setAge(iAge); return res; } } //------------------------------------------------------------------------ //Classe de réponse pour le retour du Web service @XmlAccessorType(XmlAccessType.NONE) public static class ClaHelloWorldRes { @XmlElement(name = "Nom", required = true) private String nom; @XmlElement(name = "Age") private int age; public String getNom() { return nom; } public void setNom(String value) { this.nom = value; } public int getAge() { return age; } public void setAge(int value) { this.age = value; } }
C'est cette procédure qui va traiter les paramètres envoyés par le client du Web Service, directement en WLangage :
Ceci fait, je crée une fenêtre Windev pour tester le Web service.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 PROCEDURE wsHelloWorld(_sNom est une chaîne,_iAge est un entier) Trace("Bonjour "+_sNom+", vous avez "+_iAge+" ans") //ExceptionDéclenche(1,"Erreur fatale !!!") RENVOYER "" CAS EXCEPTION: RENVOYER "<ERR>"+ExceptionInfo(errComplet)
Dans cette fenêtre, j'ajoute un bouton, dans lequel j'écris ce code :
C'est fini !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 LOCAL sServeurIp est une chaîne iServeurPort est un entier sServeurIp = "localhost"//NetAdresseIP() iServeurPort = 8090 //Définir les globales init(sServeurIp,iServeurPort) //Démarrer le serveur start() Trace("Le serveur de Web services est démarré. La description des Web services est accessible ici : ") Trace("http://"+sServeurIp+":"+iServeurPort+"/ws/MonWebService?wsdl")
je n'ai plus qu'à générer l'archive Java en cliquant le le bouton de génération Java dans Windev.
Attention, lors de la création de l'archive, à la 4ième étape "Autres fichiers de l'archive" il est IMPERATIF d'ajouter les librairies Java JAXB suivantes :
"jaxb-api.jar", "jaxb-core.jar", "jaxb-impl.jar", "jaxb-jxc.jar" et "jaxb-xjc.jar".
Les librairies que j'ai utilisé pour cet exemple peuvent être téléchargées ici : https://mon-partage.fr/f/fiWSrA6N/
Les dernières versions du site officiel se trouvent ici : https://jaxb.java.net/
L'archive générée <NomDeMonProjetWindev>.jar se trouve dans le répertoire <RepDeMonProjetWindev>\Exe\Archive Java.
Une fois l'archive lancée par le biais du fichier <NomDeMonProjetWindev>.bat, je clique sur le bouton pour lancer le serveur.
Je peux alors ouvrir un navigateur internet à cette adresse pour voir le fichier de description wsdl du Web service :
http://localhost:8090/ws/MonWebService?wsdl
Pour tester le Web service, il est possible d'utiliser l'outil gratuit SoapUI : https://www.soapui.org/.
Sinon, voici le code Windev à utiliser :
Ou plus simplement :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 sSoap est une chaîne = [ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://MonWebService.com/wsdl"> <soapenv:Header/> <soapenv:Body> <wsdl:helloWorld> <!--Optional:--> <wsdl:nom>%1</wsdl:nom> <wsdl:age>%2</wsdl:age> </wsdl:helloWorld> </soapenv:Body> </soapenv:Envelope> ] sSoap = ChaîneConstruit(sSoap,"bastiencb",37) LOCAL sServeurIp est une chaîne iServeurPort est un entier sServeurIp = "localhost"//NetAdresseIP() iServeurPort = 8090 cMaRequête est un httpRequête cMaRequête..URL = "http://"+sServeurIp+":"+iServeurPort+"/ws/MonWebService?wsdl" cMaRequête..Entête["Accept-Encoding"] = "gzip,deflate" cMaRequête..ContentType = "text/xml;charset=UTF-8" cMaRequête..Entête["SOAPAction"] = "" cMaRequête..Entête["Connection"] = "Keep-Alive" cMaRequête..Entête["User-Agent"] = "Apache-HttpClient/4.1.1 (java 1.5)" cMaRequête.Contenu = sSoap cMaRéponse est un httpRéponse = HTTPEnvoie(cMaRequête) SI ErreurDétectée ALORS Erreur(ErreurInfo(errComplet)) RENVOYER Faux SINON Info(cMaRéponse..Contenu) FIN
Pour aller plus loin :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 sSoap est une chaîne = [ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://MonWebService.com/wsdl"> <soapenv:Header/> <soapenv:Body> <wsdl:helloWorld> <!--Optional:--> <wsdl:nom>%1</wsdl:nom> <wsdl:age>%2</wsdl:age> </wsdl:helloWorld> </soapenv:Body> </soapenv:Envelope> ] sSoap = ChaîneConstruit(sSoap,"bastiencb",37) LOCAL sServeurIp est une chaîne iServeurPort est un entier sServeurIp = "localhost"//NetAdresseIP() iServeurPort = 8090 SI PAS WL.SOAPExécuteXML("http://"+sServeurIp+":"+iServeurPort+"/ws/MonWebService?wsdl",sSoap) Erreur(ErreurInfo(errComplet)+RC+RC+SOAPErreur(SOAPErrMessage)) SINON Info(SOAPDonneRésultat(SOAPRésultat)) FIN
On voit dans cet exemple que la procédure WLangage appellée par le Web service ne peut renvoyer que des chaines et en aucun cas des objets complexes.
Cela limite l'intérêt de ce code d'exemple.
Pour aller plus loin, je dois donc faire en sorte que la chaine en sortie de la procédure WLangage "wsHelloWorld" soit du code JSON (https://fr.wikipedia.org/wiki/JavaSc...bject_Notation).
De cette manière, je pourrais reconstituer l'objet de résultat à partir de cette chaine, en la désérialisant à l'aide de la librairie JSON pour Java "jackson" par exemple.
Cf https://github.com/FasterXML/jackson.
Voici le code de la procédure "start" modifié :
Et le code de la procédure "wsHelloWorld" :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 import javax.jws.WebService; import javax.annotation.Resource; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.ws.Endpoint; import javax.xml.ws.WebServiceContext; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; @WebService(targetNamespace="http://MonWebService.com/wsdl") public static class MonWebServiceImpl { @Resource WebServiceContext webServiceContext; //================================================================================================== @WebMethod @WebResult(name="ClaHelloWorldRes") public ClaHelloWorldRes helloWorld(@WebParam(name="nom", targetNamespace="http://MonWebService.com/wsdl") final String sNom, @WebParam(name="age", targetNamespace="http://MonWebService.com/wsdl") int iAge) throws Exception { //Appel à la procédure Windev wsHelloWorld écrite en WLangage String sRes = appelProcedureWL_String("wsHelloWorld",sNom,iAge); //La procédure renvoie une chaine débutant par <ERR> en cas d'exception dans le code WLangage if (sRes.startsWith("<ERR>")){ sRes = sRes.substring(5); throw (new Exception(sRes)); } //ClaHelloWorldRes res = new ClaHelloWorldRes(); //res.setNom(sNom); //res.setAge(iAge); //Désérialisation JSON avec Jackson ClaHelloWorldRes res = null; ObjectMapper mapper = new ObjectMapper(); res = mapper.readValue(sRes, ClaHelloWorldRes.class); return res; } } //------------------------------------------------------------------------ //Classe de réponse pour le retour du Web service @XmlAccessorType(XmlAccessType.NONE) public static class ClaHelloWorldRes { @XmlElement(name = "Nom", required = true) private String nom; @XmlElement(name = "Age") private int age; public String getNom() { return nom; } public void setNom(String value) { this.nom = value; } public int getAge() { return age; } public void setAge(int value) { this.age = value; } }
Attention, lors de la création de l'archive, à la 4ième étape "Autres fichiers de l'archive" il sera IMPERATIF d'ajouter en plus les librairies jackson suivantes :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 PROCEDURE wsHelloWorld(_sNom est une chaîne,_iAge est un entier) sJson est une chaîne sJson = [ { "nom":"%1", "age":%2 } ] sJson = ChaîneConstruit(sJson,_sNom,_iAge) //ExceptionDéclenche(1,"Erreur fatale !!!") RENVOYER sJson CAS EXCEPTION: RENVOYER "<ERR>"+ExceptionInfo(errComplet)
"jackson-databind-2.8.1.jar", "jackson-annotations-2.8.0.jar" et "jackson-core-2.8.1.jar"
Les librairies que j'ai utilisé pour cet exemple peuvent être téléchargées ici : https://mon-partage.fr/f/WWd6Oxw7/
Les dernières versions du site officiel se trouvent ici : https://github.com/FasterXML/jackson
Pour aller encore plus loin, et outrepasser les limitations d'utilisation de certaines fonctionnalités WLangage en configuration de projet Java, on pourrait imaginer que la procédure "wsHelloWorld" communique par sockets avec un exécutable Windev en pur WLangage... Ou encore faire tourner le serveur de web services en tant que service Windows avec JavaService par exemple ...
Bonne prog
Partager