WebService amb wsgen/wsimport i Maven

WebServices amb Maven

1 Crear un webservice a partir d’una classe java

1.1 Preparació

Aquest és un post que tenia ganes d’escriure de feia temps: Com fer un webservice amb java, i com invocar-lo.

El entorn que faré servir per a desenvolupar el webservice és:

Comencem. És una bona pràctica encetar el desenvolupament a partir d’un archetype Maven. Trio l’archetype d’aplicació webapp-javaee6.

mvn archetype:generate \ 
   -DgroupId=cat.apuntstecnologia.proves \
   -DartifactId=jeews \
   -DarchetypeGroupId=org.codehaus.mojo.archetypes \
   -DarchetypeArtifactId=webapp-javaee6

Que genera la següent estructura:

project
|-- pom.xml
`-- src
    `-- main
        |-- java
        `-- webapp
            |-- WEB-INF
            |   `-- web.xml
            `-- index.jsp

Tanmateix també hauria estat una bona tria començar amb l’archetype de webapp. Mancaria afegir la carpeta java i modificar el pom.xml.

mvn archetype:generate \
    -DgroupId=cat.apuntstecnologia.proves \
    -DartifactId=warws \
    -DarchetypeArtifactId=maven-archetype-webapp

Un projecte de webapp simple genera l’estructura següent:

project
|-- pom.xml
`-- src
    `-- main
        `-- webapp
            |-- WEB-INF
            |   `-- web.xml
            `-- index.jsp

O fins i tot un simple projecte estàndard de java. Aleshores hauria d’afegir encara més modificacions:

mvn archetype:generate -DgroupId=cat.apuntstecnologia.proves \
                       -DartifactId=jarws \
                       -DarchetypeArtifactId=maven-archetype-quickstart

que és equivalent l’archetype per defecte i és el mateix que:

mvn archetype:generate -DgroupId=cat.apuntstecnologia.proves \
                       -DartifactId=jarws \

Si ho prefereixo, puc treballar amb Eclipse. El projecte Maven es pot convertir a Eclipse amb:

mvn eclipse:eclipse

I, a continuació, puc importar el projecte creat al workspace de l’Eclipse.

1.2 La classe java del servei

Ja sigui amb Eclipse o amb un altre editor, creo la classe del servei web:

package cat.apuntstecnologia.proves;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public class ServeiProva {
    public ServeiProva() {
    }
    
    @WebMethod
    public int suma(int a, int b) {
    	return a + b;
    } 
    
    @WebMethod
    public String concatena(String a, String b) {
    	return a + b;
    }
    
    @WebMethod
    public String quinDiaEsAvui() {
    	SimpleDateFormat sdf = new SimpleDateFormat("DD/MM/YYYY");
    	return sdf.format(new Date());
    }
}

Un cop tinc el font, compilo la classe:

mvn compile

1.3 wsgen per a generar els objectes del servei

Ara faig servir wsgen sobre la classe per a generar els objectes del web service. wsgen és una eina estàndard que es proporciona amb el JDK.

Primer creo la carpeta src/main/resources. un cop he creat la carpeta em situo a l’arrel del projecte i faig:

wsgen -cp target/classes cat.apuntstecnologia.proves.ServeiProva \ 
      -s src/main/java/ \
      -r src/main/resources/ \
      -d target/classes \
      -wsdl

Amb l’instrucció anterior, ha generat la carpeta

{workspace}/jeews/src/main/java/cat/apuntstecnologia/proves/jaxws

Amb el següent contingut

Concatena.java
ConcatenaResponse.java
QuinDiaEsAvui.java
QuinDiaEsAvuiResponse.java
Suma.java
SumaResponse.java

i també el package amb els .class corresponent a la carpeta target/classes

A més, ha generat el wsdl i l’schema xsd a la carpeta src/main/resources

1.4 Generar el war

En aquest punt ja només queda preparar el paquet war per al seu desplegament com a webservice

Per això a la carpeta src/main/webapp/ creo la subcarpeta WEB-INF i el fitxer web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, 
Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">

<web-app>
    <display-name>ServeiProva</display-name>
</web-app>

i genero el war

mvn package

Que obté, finalment, el war:

/home/albert/workspace/java/jeews/target/jeews-1.0-SNAPSHOT.war

1.5 Deploy al WildFly 9

El renombro a jeews.war i, finalment, faig el desplegament. En el meu cas estic utilitzant el servidor WildFly 9. Per a desplegar en aquest servidor nomes he de deixar el jeews.war a la carpeta

/home/albert/wildfly-9.0.2/standalone/deployments

i fa el deploy automàticament:

17:19:48,943 INFO  [org.jboss.ws.cxf.metadata] (MSC service thread 1-3)
 JBWS024061: Adding service endpoint metadata: 
 id=cat.apuntstecnologia.proves.ServeiProva
 address=http://localhost:8080/jeews/ServeiProva
 implementor=cat.apuntstecnologia.proves.ServeiProva
 serviceName={http://proves.apuntstecnologia.cat/}ServeiProvaService
 portName={http://proves.apuntstecnologia.cat/}ServeiProvaPort
 annotationWsdlLocation=null
 wsdlLocationOverride=null
 mtomEnabled=false

17:19:53,876 INFO  
[org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean] 
(MSC service thread 1-3) 
Creating Service {http://proves.apuntstecnologia.cat/}ServeiProvaService 
from class cat.apuntstecnologia.proves.ServeiProva

17:19:56,321 INFO  [org.apache.cxf.endpoint.ServerImpl] 
(MSC service thread 1-3) 
Setting the server's publish address to be 
http://localhost:8080/jeews/ServeiProva

17:19:56,912 INFO  [org.jboss.ws.cxf.deployment] (MSC service thread 1-3)
 JBWS024074: WSDL published to:
file:/wildfly-9.0.2/standalone/data/wsdl/jeews.war/ServeiProvaService.wsdl

I ara provo el meu web service. Obro un navegador i accedeixo a la URL http://localhost:8080/jeews/ServeiProva?wsdl

i obtinc el wsdl.

1.6 Provar el servei amb SoapUI

Si faig servir aquesta URL amb una eina com SoapUI puc provar els diferents mètodes que exposa el servei.

A la imatge adjunta, veig com s’ha executat l’operació de suma.

 

Figure 1: Prova del webservice amb SoapUI

web-service-soap-ui

2 Crear un client de webservice a partir d’un WSDL

2.1 Preparació

Al punt anterior he fet la prova del servei amb l’aplicació Soap UI. Soap UI és capaç de generar un client del servei web a partir de l’URI del WSDL. El que faré a continuació és això mateix: generar un client del servei web a partir del WSDL.

Com abans, el primer pas és crear un projecte de webapp. Faig servir el mateix archetype que al punt 1.1, el webapp-javaee6.

mvn archetype:generate \ 
   -DgroupId=cat.apuntstecnologia.proves \
   -DartifactId=jeeclientws \
   -DarchetypeGroupId=org.codehaus.mojo.archetypes \
   -DarchetypeArtifactId=webapp-javaee6

2.2 wsimport per a generar les classes del client.

Ara he de generar les classes del client. Faig servir wsimport. Igual que wsgen, wsimport és una eina estàndard del jdk.

wsimport -s src/main/java/ \
         -d target/classes \
         -p cat.apuntstecnologia.proves.jeeclientws \
         http://localhost:8080/jeews/ServeiProva?wsdl

La instrucció anterior ha creat a la carpeta src/main/java el package cat.apuntstecnologia.proves.jeeclientws on ha desat les fonts de les classes java de la implementació del client:

Concatena.java
ConcatenaResponse.java
ObjectFactory.java
package-info.java
QuinDiaEsAvui.java
QuinDiaEsAvuiResponse.java
ServeiProva.java
ServeiProvaService.java
Suma.java
SumaResponse.java

A la carpeta target/classes, per la seva banda, hi són els fitxers .class i l’estructura de carpetes corresponents al package.

En aquest punt ja tinc la implementació de les classes del client. Ara preparo una pàgina jsp per invocar els diferents mètodes del servei, i una pàgina de resposta.

Es tracta dels tres mètodes

int suma(int a, int b);
String concatena(String a, String b);
String quinDiaEsAvui();

Vet aquí el formulari (index.jsp)

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>jeeclientws</title>
	
        function sendRequest(arg) {
            f1.methodInvoked.value = arg;    
            f1.submit();
        }
        
    </head>
    <body>
        <h1>WebService ServeiProva Client</h1>
	<form name="f1" method="post" action="response.jsp">
	    <input type="hidden" name="methodInvoked" />
	    <table>
	        <thead>
		    <tr><td>method</td><td>arg1</td><td>arg2</td><td>&nbsp</td></tr>
		</thead>
		<tbody>
		    <tr>
		        <td>Suma</td>
			<td><input type="text" name="sumArg1" /></td>
			<td><input type="text" name="sumArg2" /></td>
			<td><input type="button" value="send"
			           onclick="javascript:sendRequest('suma');">
		        </td>
		    </tr>
		    <tr>
		        <td>Concatena</td>  
			<td><input type="text" name="concatArg1" /></td>
			<td><input type="text" name="concatArg2" /></td>
			<td><input type="button" value="send"
			           onclick="javascript:sendRequest('concatena');">
		        </td>
		    </tr>
		    <tr>
		        <td colspan="3">Quin dia és avui?</td>
			<td><input type="button" value="send"
			           onclick="javascript:sendRequest('quindia');">			
		    </tr>
		</tbody>
		<tfoot>
		    <tr>
		        <td colspan="4"><input type="reset" value="reset" />
		    </tr>
		</tfoot>
            </table>
	</form>
    </body>
</html>

i el més interessant response.jsp, que és on es fa la invocació propiament dita al webservice

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page import="cat.apuntstecnologia.proves.jeeclientws.*"%>
<%
String methodInvoked = request.getParameter("methodInvoked");
String sumArg1 = request.getParameter("sumArg1");
String sumArg2 = request.getParameter("sumArg2");
String concatArg1 = request.getParameter("concatArg1");
String concatArg2 = request.getParameter("concatArg2");
String result = "";

ServeiProvaService serveiProvaService = new ServeiProvaService();
ServeiProva serveiProva = serveiProvaService.getServeiProvaPort();

if ("suma".equals(methodInvoked))  {
    result = "" + serveiProva.suma(Integer.parseInt(sumArg1), 
                                   Integer.parseInt(sumArg2));      
}

if ("concatena".equals(methodInvoked))  {
    result = serveiProva.concatena(concatArg1, concatArg2);      
}

if ("quindia".equals(methodInvoked))  {
    result = serveiProva.quinDiaEsAvui();      
}
%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>jeeclientws response</title>
    </head>
    <body>
        <h1>WebService ServeiProva Client - Response</h1>
	<table>
	    <thead>
	        <tr><td>method invoked</td><td>response</td></tr>
	    </thead>
	    <tbody>
                <tr><td><%= methodInvoked%></td><td><%= result%></td></tr>
	    </tbody>
            <tfoot>
                <tr><td colspan="2"><a href="index.jsp">back</a></td></tr>
            </tfoot>
        </table>
    </body>
</html>

I l’execució:

request

Figure 2: Prova del mètode ‘concatena’

response

Figure 3: Resposta del webservice

3 Conclusió. Repositoris GitHub

He creat un web service, i el corresponent client, a partir d’una classe java fent servir les eines wsgen i wsimport que proporciona el jdk; i archetytpes de Maven per a generar les aplicacions.

La generació del codi java del webservice i del client amb les eines ha estat directa i em permet centrar-me en el desenvolupament de les funcionalitats del webservice, més que no pas en la “lampisteria” per posar el webservice en funcionament.

El codi del webservice i del client es pot trobar al meu github, a les adreces:

Webservice (projecte jeews): https://github.com/abaranguer/jeews.git

Client del Webservice (projecte jeeclientws): https://github.com/abaranguer/jeeclientws.git

Aquest article es pot descarregar en format PDF des de http://abaranguer.eresmas.com/webservices.pdf

Author: Albert Baranguer Codina

Created: 2016-01-31 dg 20:54

Emacs 24.5.1 (Org mode 8.2.10)

Validate