Einfach Klasse:
Chuck Norris kann Klassen erstellen die sowohl abstract als auch final sind.
oder
Chuck Norris braucht keine Unit Tests sein Code funktioniert immer. IMMER.
Mehr davon gibt es bei ovisual.com
Einfach Klasse:
Chuck Norris kann Klassen erstellen die sowohl abstract als auch final sind.
oder
Chuck Norris braucht keine Unit Tests sein Code funktioniert immer. IMMER.
Mehr davon gibt es bei ovisual.com
Passend zu meinen letzten Artikeln über Clients für REST Webservices mit Jersey und Webservices mit Axis2 und Spring bin ich heute über den Artikel bei jars.de über die Generierung von Webservices mit dem Tool wsimport gestoßen.
Webservices Clients mit wsimport generieren
jars.de zeigt wie man auf der Kommandozeile Clients aus einer WSDL Url generieren kann.
Weiter Artikel:
Java Client für REST WebService (JAX-RS)
PHP Client für REST WebService
Nach dem Erstellen eines REST WebServices mit JAX-RS habe ich schon ein Beispiel für einen PHP Client eines WebServices gegeben. Natürlich lässt sich der REST WebService auch mit Java exzellent verarbeiten. Wie das geht werde ich in einem kleinen Beispiel demonstrieren. Der Client ruft den REST Web Service aus dem Tutorial für REST WebServices mit Jersey auf und benötigt auch die meisten JAR-Files aus diesem Beispiel. Zusätzlich wird noch das jersey-client-1.0.2.jar benötigt.
Jersey stellt uns für den einfachen Zugriff die Klassen Client und WebResource bereit.
Client client = Client.create(); WebResource wr = client.resource("http://localhost:8080/wstest/services/calculator/calc");
Mit Hilfe von WebResource können wir mit den HTTP Methoden post(), delete(), put() und natürlich get() unseren WebService aufrufen. Und mit der MultivaluedMap ist es uns möglich, dem WebService unsere Abfrageparameter mitzugeben.
package de.wstest.client; import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.GenericType; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.core.util.MultivaluedMapImpl; import de.wstest.MathResults; import de.wstest.ServiceResult; public class CalculatorClient { public static void main(String[] args) { Client client = Client.create(); //URL des WebService WebResource wr = client.resource("http://localhost:8080/wstest/services/calculator/calc"); //Parameter für WebService MultivaluedMap< String, String > params = new MultivaluedMapImpl(); params.add("a", "234"); params.add("b", "567"); ServiceResult sr = wr.queryParams(params).accept(MediaType.APPLICATION_XML_TYPE).get(new GenericType< ServiceResult >() {}); //Ergebnis ausgeben System.out.println(sr.getMessage()); List< MathResults > mathResults = sr.getErgebnisse(); for (MathResults mr : mathResults) { System.out.println(mr.getFormel()+" = "+mr.getErgebniss()); } } }
Die Ausgabe des WebServices ist wenig überraschend:
Results for Value a = 234, Value b = 567
a + b = 801
a - b = -333
a * b = 132678
FAZIT:
Wie man sieht, ist mit Hilfe der Jersey Klassen eine einfache Abfrage von REST WebServices möglich.
Ausführlichere Beispiele findet man auf den Enterprise Tech Tips Seiten von SUN, in welchem die Twitter Webservices benutzt werden. Dort gibt es dann auch Beispiele für das Benutzen der PUT, POST und DELETE Methoden.
Seit heute ist die neue Version 0.8 des Java Mass JPEG Resizer Tool veröffentlicht.
Die wichtigsten Änderungen sind folgende:
- Verbesserung der Performance
Version 0.7 hat auf meiner Dual Core Maschine bei 100 Bildern noch 2:26 Minuten gebraucht, mit der neuen Version wurden nur noch 1:21 Minuten benötigt.
- Eine neue Web Gallery
Die neue Web Gallerie “A Fancybox Slideshow” basiert auf dem JavaScript Framework jQuery und dem Plugin Fancybox.
- Und dann natürlich noch einige kleine Fehlerbehebungen
Für Webanwendungen die ich mit Java erstelle, verwende ich seit einigen Jahren Struts und seit einiger Zeit Struts2. Struts2 hat außer dem Namen nicht sehr viel mit dem älteren und weit verbreiteten Struts gemeinsam, sondern es basiert auf dem Framework Webworks. Das Tolle an Struts2 ist seine Flexibilität. So gibt es für verschiedenste Einsatzzwecke Plugins z.B. ein Rome Plugin zum Erzeugen von RSS Feeds oder eine JFreeChart Plugin, um Charts in die Webanwendung zu integrieren.
Da moderne Webanwendungen häufig sehr AJAX lastig sind, bei weinfreund.de verwende ich z.B. sehr viel AJAX im Backend und im Administrationsbereich, bringt Struts2 gleich ein Dojo Plugin von Haus aus mit. Mit dem Plugin ist es möglich, ohne Kenntnisse von JavaScript AJAX Funktionalität in die Anwendung einzubauen.
Folgendes Beispiel zeigt, wie man das Ergebnis eines Links per AJAX in ein DIV lädt.
< %@ taglib prefix="s" uri="/struts-tags" %> < %@ taglib prefix="sx" uri="/struts-dojo-tags" %> <head> <sx :head /> </head> <!-- Ein leeres Div in das unser Ergebnis geladen wird --> <div id="ziel" /> <!-- Unser Link, durch das Attribut targets wird das Ergebnis automatisch in unser oben definiertes DIV geladen. --> <sx :a targets="div" value="Google Startseite" href="http://www.google.de" />
Das Dojo Plugin bringt auch einige UI Elemente wie Tabs, Autocompleter, Kalender und mehr mit, die ähnlich einfach wie der Link zu benutzen gehen.
Warum jQuery?
Da ich mit dem Dojo Plugin an einige Grenzen gestoßen bin, z.B. bei Fileupload und JavaScript in AJAX-Results, und es auch viel Aufwand ist, die Optik an die eigene Webseite anzupassen, habe ich jQuery ausprobiert.
Leider gibt es noch kein Plugin was einem häufige Funktionen genauso erleichtern wie das Dojo Plugin. Bis jetzt gibt es nur Alpha Versionen und Entwicklerversionen eines solchen Plugins. Ich habe jQuery mit purem JavaScript benutzt. Das erfordert zwar einen erhöhten Programmieraufwand und Einarbeitung in JavaScript, aber jQuery hat einen leicht zu erlernenden Syntax, eine große Community und Plugins für fast jeden Einsatzzweck.
Mit jQuery sieht das gleiche Beispiel von oben so aus.
<head> <script type="text/javascript" src="scripts/jquery-1.3.2.min.js"></script> <script type="text/javascript"> $(document).ready(function() { $("#googlelink").click(function() { $("#ziel>").load("http://www.google.de"); }); }); </script> </head> <div id="ziel" /> <a id="googlelink" href="javascript:void(0)">Google Startseite</a>
Das Ganze ist zwar nicht so schick zu lesen wie mit dem Dojo Plugin, aber mit etwas Erfahrung hat man mit jQuery eine bessere Kontrolle über den Code und ist flexibler.
Auch jQuery bringt mit Hilfe von jQuery UI leicht zu benutzende Widgets wie Tabs, Dialogboxen und Kalender mit, welche auch noch mit dem Themeroller leicht an das eigene Layout anpassbar sind.
Fazit:
Mit jQuery hat man eine gute Alternative zum Struts2 Dojo Plugin, da man dieses flexibler an eigene Bedürfnisse anpassen und mit Plugins auch besser erweitern kann. Vielleicht gibt es ja für Struts2 auch bald ein brauchbares jQuery Plugin, so dass man es genauso einfach wie Dojo benutzen kann.
Ich kann den Einsatz von jQuery für AJAX basierte Webanwendungen nur empfehlen.
Durch das Jersey Projekt existieren Bibliotheken die es Java Entwicklern besonders einfach machen REST Web Services zu entwickeln. In diesem Tutorial werde ich zeigen wie einfach es ist eine Web Service zu schreiben der uns einfache Mathematische Berechnung zurückliefert.
1.)
Wir erstellen in unserer Entwicklungsumgebung, in meinem Beispiel Eclipse, ein Web Projekt. In das WEB-INF/lib Verzeichnis packen wir alle für Jersey benötigten JARs die es bei Jersey/Downloads runterzuladen gibt. Für dieses Tutorial benötigen wir folgende Bibliotheken: jersey-server.jar, jersey-core.jar, jsr311-api.jar, asm.jar, jaxb-impl.jar, jaxb-api.jar, activation.jar, stax-api.jar
2.)
In unserer WEB-INF/web.xml fügen wir folgendes hinzu:
<servlet> <display-name>JAX-RS REST Servlet</display-name> <servlet-name>REST-Servlet</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>REST-Servlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
3.)
Wir erstellen zwei Klassen die wir für unser Ergebniss benötigen.
Die erste Klasse MathResults kapselt unsere Mathematischen Ergebnisse.
package de.wstest; public class MathResults { private String formel; private Integer ergebniss; public String getFormel() { return formel; } public void setFormel(String formel) { this.formel = formel; } public Integer getErgebniss() { return ergebniss; } public void setErgebniss(Integer ergebniss) { this.ergebniss = ergebniss; } }
Und die zweite Klasse ServiceResult ist das Result unseres WebService
package de.wstest; import java.util.List; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class ServiceResult { private String message; private Integer returncode; private List<MathResults> ergebnisse; public Integer getReturncode() { return returncode; } public void setReturncode(Integer returncode) { this.returncode = returncode; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public List<MathResults> getErgebnisse() { return ergebnisse; } public void setErgebnisse(List<MathResults> ergebnisse) { this.ergebnisse = ergebnisse; } }
4.)
Jetzt erstellen wir eine weitere Klasse CalculatorService, diese ist unser eigentlicher Webservice und wird durch Annotions als dieser gekennzeichnet. Ein gute Übersicht über zulässige Annotions findet Ihr im Wiki von Jersey.
package de.wstest; import java.util.LinkedList; import java.util.List; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; @Produces("application/xml") @Path("calculator") public class CalculatorService { @GET @Path("calc") @Produces("application/xml") public ServiceResult add(@QueryParam("a") Integer a, @QueryParam("b") Integer b) { ServiceResult r = new ServiceResult(); List<MathResults> ergs = new LinkedList<MathResults>(); if(a == null || b == null) { r.setMessage("No Values!"); r.setReturncode(8); r.setErgebnisse(ergs); return r; } r.setMessage("Results for Value a = "+a+", Value b = "+b); r.setReturncode(0); MathResults e1 = new MathResults(); e1.setFormel("a + b"); e1.setErgebniss(a+b); MathResults e2 = new MathResults(); e2.setFormel("a - b"); e2.setErgebniss(a-b); MathResults e3 = new MathResults(); e3.setFormel("a * b"); e3.setErgebniss(a*b); ergs.add(e1); ergs.add(e2); ergs.add(e3); r.setErgebnisse(ergs); return r; } }
Fertig ist unsere RESTFull Webservice. Nach dem deployen in einem ServletContainer wie Tomcat erhalten wir nach einem Aufruf des Webservices im Browser
http://localhost:8080/wstest/services/calculator/calc?a=234&b=456
folgendes Ergebniss:
<serviceResult> <ergebnisse> <ergebniss>690</ergebniss> <formel>a + b</formel> </ergebnisse> <ergebnisse> <ergebniss>-222</ergebniss> <formel>a - b</formel> </ergebnisse> <ergebnisse> <ergebniss>106704</ergebniss> <formel>a * b</formel> </ergebnisse> <message>Value a = 234, Value b = 456</message> <returncode>0</returncode> </serviceResult>
Durch einen Aufruf der URL
http://localhost:8080/wstest/services/application.wadl
erhalten wir eine Übersicht über unsere Services und deren Parameter.
<application xmlns="http://research.sun.com/wadl/2006/10"> <doc xmlns:jersey="http://jersey.dev.java.net/" jersey:generatedBy="Jersey: 1.0 10/13/2008 12:27 PM"/> <resources base="http://localhost:8080/wstest/services/"> <resource path="calculator"> <resource path="calc"> <method name="GET" id="add"> <request> <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int" style="query" name="a"/> <param xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:int" style="query" name="b"/> </request> <response> <representation mediaType="application/xml"/> </response> </method> </resource> </resource> </resources> </application>
Fertig ist in wenigen Schritten unser REST Web Service der uns eine Liste von Berechnungen für einen Eingabe zurückliefert.
Mit Axis2 ist das Erstellen von Webservices für Java Programmierer noch einfacher geworden. Mit folgendem kleinen Beispiel will ich zeigen, wie man einen Webservice programmieren kann, der von Spring ein Bean injiziert bekommt.
Als Erstes erstellen wir unseren Webservice als einfache Java Klasse:
package com.jgeppert.services; import com.jgeppert.dao.MyDAO; private MyDAO myDAO; public class MyWebService { /* Die Funktion add() ist unsere Webservice Operation die * dann mit einem Client angesprochen werden kann. */ public String add(String text) { try { myDAO.save(text); return "insert successfully"; } catch(RuntimeException e) { return e.getMessage(); } } // Mit dieser Methode injiziert uns Spring unser DAO Objekt public String setMyDAO(MyDAO myDAO) { this.myDAO = myDAO; } }
Als Zweites brauchen wir für Aris2 eine service.xml mit folgendem Inhalt:
<service> <description>My First WebService</description> <parameter name="ServiceClass" locked="false"> com.jgeppert.services.MyWebService </parameter> <parameter name="ServiceObjectSupplier" locked="false">org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier</parameter> <parameter name="SpringBeanName" locked="false">myWebService</parameter> <operation name="add"> <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation> </service>
Für Spring sind die zwei Parameter ServiceObjectSupplier und SpringBeanName entscheidend, um uns das benötigte DAO zu übergeben.
Mit Hilfe eines Ant Scriptes oder manuell kann man sich den Webservice in das für Axis2 benötigte AAR Archiv packen. Das Archiv ist im Grunde eine normale JAR Datei mit der service.xml im META-INF Verzeichnis.
Die Struktur des AAR-Archives sollte so aus sehen:
- MyWebService - META-INF - services.xml - com - jgeppert - services - MyWebService.class
Damit Spring unser DAO in dem Service injizieren kann, brauchen wir noch folgenden Eintrag in unserer applicationContext.xml.
<bean id="applicationContext" class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" /> <bean id="myWebService" class="com.jgeppert.services.MyWebService"> <property name="myDAO" ref="MyDAO"/> </bean>
Nach dem deployen des AAR-Archives im services Folder der Axis2 Web Application steht der Service nun zur Verfügung.