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 :

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 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
4
5
 
PROCEDURE GLOBALE init(LOCAL _sServeurIp est une chaîne,LOCAL _iServeurPort est un entier)
 
sServeurIp	= _sServeurIp
iServeurPort = _iServeurPort
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
 
PROCEDURE GLOBALE get_sServeurIp()
 
RENVOYER sServeurIp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
PROCEDURE GLOBALE get_iServeurPort()
 
RENVOYER iServeurPort
Je crée maintenant une nouvelle procédure "start" dans "ServeurWs".
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 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
public static void start()
{
}
par le code suivant :

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());
	}
}
Je crée ensuite une nouvelle procédure "javaDeclarations" dans "ServeurWs".
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 :

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;
	}
}
Il ne me reste plus désormais qu'à implémenter la procédure "wsHelloWorld" dans "ServeurWs".
C'est cette procédure qui va traiter les paramètres envoyés par le client du Web Service, directement en WLangage :

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)
Ceci fait, je crée une fenêtre Windev pour tester le Web service.
Dans cette fenêtre, j'ajoute un bouton, dans lequel j'écris ce code :

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")
C'est fini !

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 :

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
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
 
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
Pour aller plus loin :

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é :

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;
	}
}
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
 
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)
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 :
"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