Einfache Webservices unter Java 6 Mustang

Thomas Darimont

Erfahrenes Mitglied
Hallo,

hier mal ein kleines Beispiel für die Erstellung und Verwendung eines Webservices
unter Java 6:

Unser ICalculator interface:
Java:
package de.tutorials;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Use;

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
//@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = Use.ENCODED)
interface ICalculator {
  @WebMethod
  int computeSumOf(int a, int b);
}

Unsere Calculator Implementierung:
Java:
package de.tutorials;

import javax.jws.WebService;

/**
 * @author Tom
 */
@WebService(serviceName = "Calculator", portName = "Calculator", endpointInterface = "de.tutorials.ICalculator")
public class Calculator implements ICalculator {
  public int computeSumOf(int a, int b) {
    return a + b;
  }
}

Unser Exporter / Client:
Java:
/**
 * 
 */
package de.tutorials;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Endpoint;
import javax.xml.ws.Service;

/**
 * @author Tom
 */
public class SimpleWebServiceExample {
  public static void main(String[] args) throws Exception {
    Endpoint endpoint = null;
    try {
      endpoint = Endpoint.publish("http://localhost:44444/Calculator", new Calculator());
      System.out.println("Service Published!");
      Service service = Service.create(new URL("http://localhost:44444/Calculator?wsdl"), new QName(
        "http://tutorials.de/", "Calculator"));
      ICalculator simpleService = service.getPort(ICalculator.class);

      System.out.println(simpleService.computeSumOf(11, 12));
    } finally {
      //endpoint.stop();
    }
  }
}

Ausgabe:
Code:
Service Published!
23

Die Annotation
Java:
 @SOAPBinding(style = SOAPBinding.Style.RPC)
im ICalculator ist notwendig, da sonst als Default SOPABinding DocumentStyle verwendet wird
und die Laufzeit dann nach den entsprechenden Operations / Request / Response Wrapper Klassen sucht...
Deshalb bekommt man dann diese Exception:
Java:
...
@WebService
//@SOAPBinding(style = SOAPBinding.Style.RPC)
interface ICalculator {
Resultiert in:
Code:
Exception in thread "main" Server Runtime Error: class: de.tutorials.jaxws.ComputeSumOf could not be found
    at com.sun.xml.internal.ws.transport.http.server.HttpEndpoint.publish(HttpEndpoint.java:269)
    at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:87)
    at com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:59)
    at javax.xml.ws.Endpoint.publish(Endpoint.java:156)
    at de.tutorials.SimpleWebServiceExample.main(SimpleWebServiceExample.java:19)
Caused by: class: de.tutorials.jaxws.ComputeSumOf could not be found
    at com.sun.xml.internal.ws.modeler.RuntimeModeler.getClass(RuntimeModeler.java:271)
    at com.sun.xml.internal.ws.modeler.RuntimeModeler.processDocWrappedMethod(RuntimeModeler.java:562)
    at com.sun.xml.internal.ws.modeler.RuntimeModeler.processMethod(RuntimeModeler.java:509)
    at com.sun.xml.internal.ws.modeler.RuntimeModeler.processClass(RuntimeModeler.java:355)
    at com.sun.xml.internal.ws.modeler.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:251)
    at com.sun.xml.internal.ws.server.RuntimeEndpointInfo.createSEIModel(RuntimeEndpointInfo.java:170)
    at com.sun.xml.internal.ws.server.RuntimeEndpointInfo.init(RuntimeEndpointInfo.java:317)
    at com.sun.xml.internal.ws.transport.http.server.HttpEndpoint.publish(HttpEndpoint.java:298)
    at com.sun.xml.internal.ws.transport.http.server.HttpEndpoint.publish(HttpEndpoint.java:263)
    ... 4 more

Unser WSDL:
XML:
<definitions targetNamespace="http://tutorials.de/" name="Calculator">
<types/>
?
	<message name="computeSumOf">
<part name="arg0" type="xsd:int"/>
<part name="arg1" type="xsd:int"/>
</message>
?
	<message name="computeSumOfResponse">
<part name="return" type="xsd:int"/>
</message>
?
	<portType name="ICalculator">
?
	<operation name="computeSumOf" parameterOrder="arg0 arg1">
<input message="tns:computeSumOf"/>
<output message="tns:computeSumOfResponse"/>
</operation>
</portType>
?
	<binding name="CalculatorBinding" type="tns:ICalculator">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
?
	<operation name="computeSumOf">
<soap:operation soapAction=""/>
?
	<input>
<soap:body use="literal" namespace="http://tutorials.de/"/>
</input>
?
	<output>
<soap:body use="literal" namespace="http://tutorials.de/"/>
</output>
</operation>
</binding>
?
	<service name="Calculator">
?
	<port name="Calculator" binding="tns:CalculatorBinding">
<soap:address location="http://localhost:44444/Calculator"/>
</port>
</service>
</definitions>

Das Beispiel ist sogar so einfach, dass man sogar von einem C# Client aus den WebService ohne Probleme benutzen kann :)

Gruß Tom
 
Zuletzt bearbeitet von einem Moderator:
Hallo,

das soll ja auch der sinn eines webservices sein ;)

abstraktion des codes => dieser wird in XML beschrieben/gebettet

dadurch soll er sprachunabhängig, plattformunabhängig und typsicher sein
Nein... echt? ;-)

Das ist schon klar... wenn man den Contract First Ansatz wählt (man designed die Webservice Definition / die ausgetauschten Nachrichten in XML über WSDL) ist das mit der Interoperabilität in der Regel auch kein Problem. Da ich hier jedoch das WSDL (under the hood) on the fly generieren lasse ist das mit der Interoperabilität nicht so einfach, aber in diesem Fall (da hier nur primitive und Strings ausgetauscht werden) ist das kein Problem. Wenn ich jedoch versuche ein Datum (java.util.Date) auszutauschen wirds schon etwas früher knallen ;-)

Gruß Tom
 
Hallo,

bin gerade dabei mich in Client-Seite der Web Services unter JAVA einzuarbeiten und werde aus der Generierung des dynamischen Stubs nicht ganz schlau.

Ist es auf der Serverseite zwingend notwendig, die WebMethod innerhalb eines Interfaces zu deklarieren und worin liegt der Sinn eines dynamisch generierten Stubs wenn mein Client für den Aufruf der WebMethod das zugehörige Interface kennen muss ?
 
ich beschäftige mich ebenfalls mit dem thema webservice,

Momentan habe ich probleme meine Ausgabe dem Client zukommen zulassen. Bevor ich überhaupt noch weiter mache, könnte sich jmd meinen Code mal angucken, da ich nicht der überprofi in Java bin.
Code:
#Klasse AngebotsAufrufe()
package AngebotService;

import java.io.*;
import java.net.URI;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.awt.Desktop;




public class AngebotsAufrufe extends CopyAngebot
{
    String usr, pwd, host;
    String speicherort 	= 	null;
    String	verzeichnis = 	null;
  	String	bemerkung   = 	"test";
  	String	datum	    = 	"test";
  	String 	uhrzeit     = 	"test";
  	String response		=	null;
  	String angebotsnr 	= 	null;
	Connection con 		= 	null;
	Statement smt  		= 	null;
	Reader datei		= 	null;
	Desktop desk		= 	Desktop.getDesktop();
	
	

	public Desktop CreateAngebot(String pdffile)
	{
		angebotsnr = pdffile;
		usr  = "dewea083";
		pwd  = "";
		host = "jdbc:mysql://localhost:3306/Angebotsspeicher"; 						//Datenbank auf Server
		if(pdffile == null)
		{
			System.out.println("ERROR ANGEBOT CANNOT BE NULL!");
			return null;
		}
		else
		{ 
			try
			{					 	

				src 					= "/home/dewea083/Documents/1178526328411.pdf";		 	 																	//mkordner = new File("/usr/share/tomcat/webapps/pdf/"+angebotsnr).mkdir();		//erstelle einen Ordner der die AngebotsNummer hat
				CopyAngebot daten 	= new CopyAngebot();		 	 
		 	 	dest 					= "/srv/www/htdocs/pdf/"+pdffile+".pdf";							//gibt den Speicherort und den Dateinamen für das Angebot an
		 	 	daten.copyFile(src, dest); 										//Datei wird in das Verzeichnis kopiert		 	 

		 	 	verzeichnis = dest;
		 	 	Class.forName("com.mysql.jdbc.Driver");
		 	 	con 		 = DriverManager.getConnection(host, usr, pwd);																		//formatiert den Verzeichnisnamen so, dass er in der Datenbank gespeichert werden kann
		 	 	smt		 = con.createStatement();						
		 	 	String sql2 = "INSERT INTO Angebotverzeichnis(AngebotsNr,Verzeichnis,Bemerkung,Datum,Uhrzeit)" +
			 		       "VALUE(" +angebotsnr+ ",\"" +verzeichnis+ "\",\"" +bemerkung+"\",\"" +datum+ "\",\"" +uhrzeit+"\");";	
			 
		 	 	smt.executeUpdate(sql2);											//Daten vom Angebot werden in der DB gespeichert	 

		 	 	System.out.println("Angebot "+pdffile+".pdf"+" wurde erstellt");
		 	 	response = "Neues PDF erstellt, jetzt bitte anzeigen";
		 	 	con.close();
		 	 	smt.close();
		 	 	desk.browse(new URI("http://10.100.0.27/pdf/"+pdffile));
		 	 	return desk;
			}		
			catch(Exception ex)
			{						
			System.out.println(ex);
			return null;
			}
		}
	}	
	
	public String GetAngebot(String pangebot)
	{
		usr  = "dewea083";
		pwd  = "";
		host = "jdbc:mysql://localhost:3306/Angebotsspeicher"; //Datenbank auf Server
		if(pangebot == null)
		{
			System.out.println("ERROR ANGEBOT CANNOT BE NULL!");
			return null;
		}
		else
			{	
				try
				{	
				 System.out.println("Gesucht wird: "+pangebot);
				 Class.forName("com.mysql.jdbc.Driver");				//JDBC Treiber laden
				 con = DriverManager.getConnection(host, usr, pwd);		//Verbindung aufbauen
				 smt =con.createStatement();
				 String sql = "SELECT AngebotsNr From Angebotsspeicher.Angebotverzeichnis " +
				 			  "WHERE AngebotsNr ="+pangebot;
				 ResultSet rst = smt.executeQuery(sql);					//SQL Anweisung ausführen
				 System.out.println("Angebot wird gesucht");			//Es wird nach der Angebotsnummer gesucht
				 
				 
				 	while (rst.next())
				 	{
					 speicherort = rst.getString(1);				   //Gib mir das Verzeichnis wo die Datei liegt 
				 	}
					 con.close();
					 smt.close();
				}
				catch(Exception ex)
				{						
				System.out.println(ex);
				return null;
				}
				if (speicherort == null)
				{
					AngebotsAufrufe ca1 = new AngebotsAufrufe();
					ca1.CreateAngebot(pangebot);
					response = "Angebot nicht vorhanden. Erstelle es jetzt";	
				}
				else
				{
					System.out.println("Angebot "+pangebot +" bereits vorhanden");
					response = "Angebots vorhanden, ich zeige es dir jetzt an";
				}
				return response;
			}
	}
	
	public void pdfanzeigen(String pdf)
	{
		try {desk.browse(new URI("http://10.100.0.27/pdf/"+pdf)); }
		catch(Exception ex) {}
	}
}

#Klasse AngebotsService
package AngebotService;


import java.awt.Desktop;




public class AngebotsService 
{

	public String findeAngebot(String fangebot)
	{
		AngebotsAufrufe aa1 = new AngebotsAufrufe();
		return aa1.GetAngebot(fangebot);
	}

	public Desktop erstelleAngebot(String eangebot)
	{
		AngebotsAufrufe aa2 = new AngebotsAufrufe();
		return aa2.CreateAngebot(eangebot);
	}

}

Der Service soll später mal dem User eine PDF zurück geben, bzw. wenn diese noch nicht existiert soll er sie generieren und im Anschluss dem Benutzer schicken.
Ich hänge jedoch schon die gnaze zeit daran wie ich diese dem Benutzer senden kann

Wie man sieht habe ich es mit der awt.Destkop klasse versucht, jedoch t das nicht.
Ist also nur ein "TestCode"
 
Hallo,

bin gerade dabei mich in Client-Seite der Web Services unter JAVA einzuarbeiten und werde aus der Generierung des dynamischen Stubs nicht ganz schlau.

Ist es auf der Serverseite zwingend notwendig, die WebMethod innerhalb eines Interfaces zu deklarieren und worin liegt der Sinn eines dynamisch generierten Stubs wenn mein Client für den Aufruf der WebMethod das zugehörige Interface kennen muss ?

wenn du einen webservice erstellst z.bsp. in C# sieht das ja so aus...
[Webservice...]
class Service : System.Web.Services.WebService {
[WebMethod]
public String HelloWorld() {...}
}

wo soll hier das interface sein? das ist eine ganz normale klasse, nachdem du deinen web service server nicht in JAVA hast, nehme ich an, du hast in .NET entwickelt, wenn du dir ein neues WebService projekt anlegst sieht das so in etwa aus (wie gesagt, seh ich des net als interface)

die informationen dieser klasse werden in ein xml format gepackt, und ein client kann sich diese holen

wenn du unter java auf den webservice zugreifst, wir ein objekt WebServiceXY erstellt, welches als art proxy dient
dieses proxy bietet dann die selben methoden, die auch der webservice bietet und somit kannst du dann die methoden des webservices nutzen

der proxy/stub ist die verbindung zwischen client und server, und wenn dieser die methoden des webservices nicht kennen würde, dann könntest du die nicht aufrufen

so ungefähr, aber des macht für mich schon sinn, dass er ein objekt anlegt, dass die methoden des webservices aufruft,

dadurch wirds einfacher und du musst dich nicht mehr um die verbindung kümmern

mfg
 
Zuletzt bearbeitet:
ich beschäftige mich ebenfalls mit dem thema webservice,

Momentan habe ich probleme meine Ausgabe dem Client zukommen zulassen. Bevor ich überhaupt noch weiter mache, könnte sich jmd meinen Code mal angucken, da ich nicht der überprofi in Java bin.

Der Service soll später mal dem User eine PDF zurück geben, bzw. wenn diese noch nicht existiert soll er sie generieren und im Anschluss dem Benutzer schicken.
Ich hänge jedoch schon die gnaze zeit daran wie ich diese dem Benutzer senden kann

Wie man sieht habe ich es mit der awt.Destkop klasse versucht, jedoch t das nicht.
Ist also nur ein "TestCode"

also, ansich ist der code okay glaube ich, aber ein PDF in awt.desktop packen?
bei den webservices wird ja der datentyp in der WSDL beschrieben, hast du dir da schon mal spezifikationen angeschaut?

so auf die schnelle habe ich mal gefunden:
Webservices : unterstützte datentypen:
boolean, byte, short, int, long, float, double, die Wrapper Klassen Boolean, Integer, Double....
Arrays, div. Listen, Bäume etc
String, Date, Calendar, bigDecimal, BigInteger
Holder klassen
bei eigenen komplexen Klassen werden nur properties (setter+getter) serialisiert


vlt. gibt es ja die möglichkeit ein PDF in ein file zu wrappen und das zu serialisieren und rumschicken

falls es geht wird das sehr unperformant sein, würde ich nicht mit einem webservice machen

mfg
 
Zuletzt bearbeitet:
wenn du einen webservice erstellst z.bsp. in C# sieht das ja so aus...
[Webservice...]
class Service : System.Web.Services.WebService {
[WebMethod]
public String HelloWorld() {...}
}

wo soll hier das interface sein? das ist eine ganz normale klasse, nachdem du deinen web service server nicht in JAVA hast, nehme ich an, du hast in .NET entwickelt, wenn du dir ein neues WebService projekt anlegst sieht das so in etwa aus (wie gesagt, seh ich des net als interface)

die informationen dieser klasse werden in ein xml format gepackt, und ein client kann sich diese holen

wenn du unter java auf den webservice zugreifst, wir ein objekt WebServiceXY erstellt, welches als art proxy dient
dieses proxy bietet dann die selben methoden, die auch der webservice bietet und somit kannst du dann die methoden des webservices nutzen

der proxy/stub ist die verbindung zwischen client und server, und wenn dieser die methoden des webservices nicht kennen würde, dann könntest du die nicht aufrufen

so ungefähr, aber des macht für mich schon sinn, dass er ein objekt anlegt, dass die methoden des webservices aufruft,

dadurch wirds einfacher und du musst dich nicht mehr um die verbindung kümmern

mfg


Danke für die schnelle Antwort.

Mir ist schon klar, wie die Web Services im Prinzip funktionieren. Mein Problem liegt in den Zeilen

Service service = Service.create(new URL("http://localhost:44444/Calculator?wsdl"), new QName("http://tutorials.de/", "Calculator"));

ICalculator simpleService = service.getPort(ICalculator.class);


des obigen Beispiels. Die Generierung des Services mit Hilfe der WSDL URL sowie Servicename und Domain ist klar. Aber

ICalculator simpleService = service.getPort(ICalculator.class)

setzt doch die Kenntnis des Clients bezüglich des im Server beschriebenen Interfaces voraus, die WSDL-Beschreibung reicht da wohl nicht (die Methode aktzeptiert auch nur eine Interfacebeschreibung soweit ich weiss).
Wenn ich nun einen Webservice unter .NET implementiert habe, muss ich meinem Java Client ebenfalls dieses Interace bekannt machen ? (Oder ist der obige Code irgendwo nicht vollständig?)

mfg
 
Hallo,

das Interface auf Clientseite zu haben ist sehr sinnvoll, da du so getyped mit dem WebService interagieren kannst. Außerdem kannst du dann auch die Remoting-Implementierung Transparent halten (vielleicht willst du irgendwann mal, dass du RMI statt Webservices verwendest..., wenn du dann die entsprechenden Service Interfaces verwendet hast brauchst du hier keinen Code zu verändern) Wenn du den oben definierten Webservice über .Net ansprichst wird dir auch ein entsprechendes Client interface generiert... hier liefere ich dieses der Einfachheit halber jedoch mit, um den Schritt auf Java Client Seite ein zusätzliches Interface generieren zu müssen einzusparen.)

Gruß Tom
 
Hallo, vielen Dank.

Dann muss ich nur noch herausfinden, wo das entsprechende Interface generiert wird. Ich habe die entsprechenden Web Services bereits mit statisch generierten Stubs zum laufen gebracht - war kein Problem, hier bekomme ich ja das Interface - aber bei den dynamisch generierten sehe ich das einfach nicht (finde auch keine adequaten Beispiele im Netz).

mfg
 
Zurück