Nachdem ich im vorigen Teil die grundsätzliche Vorgehensweise zum Erstellen eines REST-Services auf Tomcat mit der Jersey-Bibliothek erläutert habe, will ich diesem Teil noch zeigen, wie man Klassen für Ressourcen definiert, CRUD anwendet und einen REST-Service JSON sprechen läßt. Dazu verwende ich die generierte „Kontakte“-Klasse aus dem Artikel „JAXB mit Eclipse nutzen“ im REST-Jargon als Ressource. Die Server-Klasse kann sowohl XML, als auch JSON zurückgeben.
Wer mehr zu Rest und dessen Vokabular erfahren will, dem seien u. a. folgendeArtikel empfohlen: „OData: die Daten API des Webs„, „JSON Provider erstellen. Part 4: Mit Tomcat und Jersey REST Services erstellen“ und „Representational state transfer (REST)„.
Die Server Klasse um JSON und JAXB erweitern
Im letzten Teil habe ich mehr oder weniger sinnlosen Text über REST ausgegeben. Das soll sich nun ändern, die Texte sind nicht unbedingt sinnvoller ;-), aber immerhin erfolgt die Ausgabe nicht mehr direkt, sondern über das Einlesen und Schreiben einer XML Datei („Kontakte.xml“), die als Datenbank dient. Alle Kontakte werden auf dem Server von ihr gelesen bzw. in sie geschrieben – mit JAXB sollte das kein Problem darstellen. Bei der Anwendung von CRUD bietet es sich an diese Datei entsprechend zu synchronisieren, also neue Kontakte hinzuzufügen (C = Create), alle oder einzelne Kontakte zu lesen (R = Read), Kontakte zu verändern (U = Update) und schließlich auch Kontakte zu löschen (D = Delete).
Die Schnittstelle zwischen der Server-Klasse und der XML-Datei, stellt die Klasse „KontakteHandler“ dar. Mit ihr kann man die CRUD Operationen durchführen.
Man kann das vorhandene Projekt weiterverwenden, oder ein Neues erstellen.
1. Erstellen Sie ein “Dynamic Web Project” mit Eclipse
2. Kopieren der Jersey-Jars und die JAXB-Jars in das Verzeichnis WebContent/WEB-INF/lib des Projektes. Kopieren der generierten JAXB-Klassen (aus dem Artikel „JAXB mit Eclipse nutzen„) in das „src/generated“ Unterverzeichnis des Projektes. Kopieren der Datei „Kontakte.xml“ in das „WebContent“ Verzeichnis.
4. Source-Code für die Klasse „KontakteHandler“ erstellen:
package org.jkhofmann.dyndns;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Writer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import generated.*;
// Klasse (Singleton) zur Verwaltung der "Kontakte" Ressource
public class KontakteHandler {
private String xmlFileName = "Kontakte.xml";
private static KontakteHandler instance = null;
private Kontakte kontakte = null;
private boolean isSyncedWithFile = false;
private KontakteHandler() {
}
public static KontakteHandler getInstance() {
if (instance == null) {
instance = new KontakteHandler();
}
return instance;
}
private void readKontakte() {
Kontakte kontakteRet = null;
try {
// create JAXB context and instantiate unmarshaller
JAXBContext context = JAXBContext.newInstance(Kontakte.class);
Unmarshaller um = context.createUnmarshaller();
this.kontakte = (Kontakte) um.unmarshal(new FileReader(xmlFileName));
isSyncedWithFile = true;
} catch (Exception e) {
e.printStackTrace();
}
}
private void writeKontakte() {
try {
// create JAXB context and instantiate marshaller
JAXBContext context = JAXBContext.newInstance(Kontakte.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Writer w = null;
try {
w = new FileWriter(xmlFileName);
m.marshal(this.kontakte, w);
} finally {
try {
w.close();
} catch (Exception e) {
}
}
isSyncedWithFile = true;
} catch (Exception e) {
e.printStackTrace();
}
}
public Kontakte getKontakte() {
if (!isSyncedWithFile) {
this.readKontakte();
}
return this.kontakte;
}
public Kontakte searchKontakte(String nameArg) {
Kontakte kontakteRet = null;
boolean isContactFound = false;
if (!isSyncedWithFile) {
this.readKontakte();
}
for (int i = 0; i < this.kontakte.getKontakt().toArray().length; i++) {
Kontakte.Kontakt k = kontakte.getKontakt().get(i);
if (k.getName().equals(nameArg)) {
if (!isContactFound) {
kontakteRet = new Kontakte();
isContactFound = true;
}
kontakteRet.getKontakt().add(k);
}
}
return kontakteRet;
}
public void setKontakte(Kontakte kontakte) {
this.kontakte = kontakte;
this.writeKontakte();
}
public void setXmlFileName(String xmlFileName) {
this.xmlFileName = xmlFileName;
}
}
5. Erweitern der Server Klasse um die Repräsentation JSON und die Verwendung der Klasse „KontakteHandler“:
package org.jkhofmann.dyndns;
import java.io.File;
import javax.servlet.ServletContext;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import generated.*;
@Path("/kontakte")
public class HelloRestService {
@Context UriInfo uriInfo;
@Context Request request;
@Context ServletContext context;
// This method is called if JSON is requested. If QueryParam is empty, all contacs will be
// returned. Otherwise the contact will be searched in the contact list and if it exists it
// will be returned.
@GET
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Kontakte getJSON(@QueryParam("name") String name) {
Kontakte kontakteRet = null;
// Set path to the contacts xml source file (it is the real path on the tomcat server):
String strBas = context.getRealPath("/") + "Kontakte.xml";
KontakteHandler.getInstance().setXmlFileName(strBas);
// Depending on if QueryParam is set, select the right handler method
if ((name != null) && name.trim().length() > 0) {
// if QueryParam is set, it will be searched for it:
kontakteRet = KontakteHandler.getInstance().searchKontakte(name);
} else {
// if QueryParam is NOT set, return all contacts:
kontakteRet = KontakteHandler.getInstance().getKontakte();
}
return kontakteRet;
}
// This can be used to test the integration with the browser
@GET
@Produces( { MediaType.TEXT_XML })
public Kontakte getXML(@QueryParam("name") String name) {
Kontakte kontakteRet = null;
// Set path to the contacts xml source file (it is the real path on the tomcat server):
String strBas = context.getRealPath("/") + "Kontakte.xml";
KontakteHandler.getInstance().setXmlFileName(strBas);
// Depending on if QueryParam is set, select the right handler method
if ((name != null) && name.trim().length() > 0) {
// if QueryParam is set, it will be searched for it:
kontakteRet = KontakteHandler.getInstance().searchKontakte(name);
} else {
// if QueryParam is NOT set, return all contacts:
kontakteRet = KontakteHandler.getInstance().getKontakte();
}
return kontakteRet;
}
}
6. Erstellen und Anpassen der „web.xml“ Datei
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>HelloRestService</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>HelloRestService</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>org.jkhofmann.dyndns</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>HelloRestService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
7. Erstellen und Deployen des WAR-Archives, z.B. „JerseyJAXBRestTest1.war“
Parameter: PathParam, QueryParam, FormParam etc.
Will man auf eine bestimmte Ressource zugreifen, kann dies u.a. über eine Parametrisierung des URI-Pfades geschehen (PathParam), z.B. „GET /artikel/123„, oder durch einen oder mehrere Aufrufparameter (QueryParam), z.B. „GET /artikel?id=123“ geschehen. QueryParam lässt sich relativ einfach anwenden, wie das Beispiel der Server Klasse zeigt, hier wird er Parameter „name“ ausgewertet, ist er angegeben, wird nach einem Kontakt mit diesem Namen gesucht. Ist das nicht der Fall, werden alle Kontakte ausgegeben. Mit FormParam lassen sich Formular-Parameter abfragen, wie sie in HTML-Formularen übergeben werden.
Weitere Informationen und Parameter sind u.a. in http://jsr311.java.net/nonav/releases/1.0/index.html zu finden.
Die Anwendung von QueryParam wurde bereits im vorigen Beispiel veranschaulicht. FormParam kommt in einem späteren Beispiel zur Anwendung. Im folgenden Beispiel wird die Verwendung von PathParam gezeigt:
@Path("/users/{username}")
public class UserResource {
@GET
@Produces("text/xml")
public String getUser(@PathParam("username") String userName) {
...
}
}
Testen
Direkt im Browser
Man kann sich die Ergebnisse direkt in einem Browser anschauen, der Link (ohne QueryParam) lautet: http://localhost:8080/JerseyJAXBRestTest1/kontakte
Sollen nur die Kontakte mit einem bestimmten Namen angezeigt werden, lautet die URL beispielsweise: http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1
Advanced Rest Client
Google Chrome Nutzer können auch die Erweiterung „Advanced Rest Client“ verwenden, sie bietet u.a. den Vorteil, dass man sich den JSON-Response direkt anschauen kann. Dazu erweitert man den Header um „Accept“ mit dem Inhalt „application/json“ und drückt anschliessend den „Send request“ Knopf.
Ohne QueryParam: http://localhost:8080/JerseyJAXBRestTest1/kontakte
Ergebnis:
Mit QueryParam: http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1
Ergebnis:
Java Client
Zum Testen des Services kann man beispielsweise folgenden Java-Client implementieren:
package org.jkhofmann.dyndns;
import java.net.URI;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.representation.Form;
public class JerseyJAXBRestTest1Client {
public static void main(String[] args) {
ClientConfig config = new DefaultClientConfig();
Client client = com.sun.jersey.api.client.Client.create(config);
WebResource service = client.resource(getBaseURI());
// Get XML
System.out.println(service.path("kontakte").accept(
MediaType.TEXT_XML).get(String.class));
// Get XML for application
System.out.println(service.path("kontakte").accept(
MediaType.APPLICATION_JSON).get(String.class));
// Get JSON for application
System.out.println(service.path("kontakte").accept(
MediaType.APPLICATION_XML).get(String.class));
// Testen von @QueryParam, Methode queryParam baut URL entsprechend zusammen,
// z.B. GET http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1:
System.out.println(service.queryParam("name", "Name1").path("kontakte").accept(
MediaType.APPLICATION_XML).get(String.class));
}
private static URI getBaseURI() {
return UriBuilder.fromUri(
"http://localhost:8080/JerseyJAXBRestTest1").build();
}
}
Das Ergebnis:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Kontakte><Kontakt><Name>Name1</Name><Vorname>Vorname1</Vorname><eMail>eMail1</eMail></Kontakt><Kontakt><Name>Name2Neu</Name><Vorname>Vorname2Neu</Vorname><eMail>eMail2Neu</eMail></Kontakt><Kontakt><Name>Name3Neu</Name><Vorname>Vorname3Neu</Vorname><eMail>eMail3Neu</eMail></Kontakt></Kontakte>
{"Kontakt":[{"Name":"Name1","Vorname":"Vorname1","eMail":"eMail1"},{"Name":"Name2Neu","Vorname":"Vorname2Neu","eMail":"eMail2Neu"},{"Name":"Name3Neu","Vorname":"Vorname3Neu","eMail":"eMail3Neu"}]}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Kontakte><Kontakt><Name>Name1</Name><Vorname>Vorname1</Vorname><eMail>eMail1</eMail></Kontakt><Kontakt><Name>Name2Neu</Name><Vorname>Vorname2Neu</Vorname><eMail>eMail2Neu</eMail></Kontakt><Kontakt><Name>Name3Neu</Name><Vorname>Vorname3Neu</Vorname><eMail>eMail3Neu</eMail></Kontakt></Kontakte>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Kontakte><Kontakt><Name>Name1</Name><Vorname>Vorname1</Vorname><eMail>eMail1</eMail></Kontakt></Kontakte>
In der zweiten Zeile ist der JSON Response und in der vierten Zeile die Rückgabe mit @QueryParam.
Jetzt aber: CRUD
Das R(Read) in CRUD haben wir jetzt ausreichend getestet, bleiben noch C (Create), U(Update) und D(Delete). Im folgenden Beispiel wird die Server Klasse entsprechend erweitert und mit unserer Datenbank „Kontakte.xml“ synchronisiert.
Folgende HTTP Operationen werden in diesem Zusammenhang verwendet:
| HTTP Operation | CRUD |
| POST | Create |
| GET | Read |
| PUT | Update |
| DELETE | Delete |
PUT – Update
Die folgende Methode dient der Server Klasse dazu, einen Kontakt zu verändern. Hier wird der @FormParam benutzt, wie er beispielsweise in einem HTML Formular verwendet wird.
Die KontakteHandler Klasse wird wie folgt erweitert:
public void updateKontakte() {
this.writeKontakte();
}
Die Server Klasse muss dazu wie folgt erweitert werden:
...
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
...
// PUT operation to update data. Accepts parameters as form parameters like they usually used
// in HTML pages. Shows the usage of @FormParam.
@PUT
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response putContact(@FormParam("name") String nameArg,
@FormParam("nameNeu") String neunameArg,
@FormParam("vnameNeu") String neuvnameArg,
@FormParam("emailNeu") String neuemailArg,
@Context HttpServletResponse servletResponse) {
Response resRet = Response.noContent().build();;
// Set path to the contacts xml source file (it is the real path on the tomcat server):
String strBas = context.getRealPath("/") + "Kontakte.xml";
KontakteHandler.getInstance().setXmlFileName(strBas);
// Depending on if QueryParam is set, select the right handler method
if ((nameArg != null) && nameArg.trim().length() > 0) {
// if QueryParam is set, it will be searched for it:
Kontakte kontakte = KontakteHandler.getInstance().searchKontakte(nameArg);
// Check if kontakt was found:
if (kontakte != null) {
Kontakte.Kontakt kontakt = kontakte.getKontakt().get(0);
if ((neunameArg != null) && nameArg.trim().length() > 0)
kontakt.setName(neunameArg);
if ((neuvnameArg != null) && nameArg.trim().length() > 0)
kontakt.setVorname(neuvnameArg);
if ((neuemailArg != null) && nameArg.trim().length() > 0)
kontakt.setEMail(neuemailArg);
KontakteHandler.getInstance().updateKontakte();
resRet = Response.created(uriInfo.getAbsolutePath()).build();
}
}
return resRet;
}
Zum Testen kann die Java Client Klasse wie folgt erweitert werden:
package org.jkhofmann.dyndns;
import java.net.URI;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.representation.Form;
public class JerseyJAXBRestTest1Client {
public static void main(String[] args) {
ClientConfig config = new DefaultClientConfig();
Client client = com.sun.jersey.api.client.Client.create(config);
WebResource service = client.resource(getBaseURI());
// Get XML
System.out.println(service.path("kontakte").accept(
MediaType.TEXT_XML).get(String.class));
// Get XML for application
System.out.println(service.path("kontakte").accept(
MediaType.APPLICATION_JSON).get(String.class));
// Get JSON for application
System.out.println(service.path("kontakte").accept(
MediaType.APPLICATION_XML).get(String.class));
// Testen von @QueryParam, Methode queryParam baut URL entsprechend zusammen,
// z.B. GET http://localhost:8080/JerseyJAXBRestTest1/kontakte?name=Name1:
System.out.println(service.queryParam("name", "Name1").path("kontakte").accept(
MediaType.APPLICATION_XML).get(String.class));
// Check PUT operation:
// Simulate a HTML form and send PUT request to server to update existing resource:
Form form = new Form();
form.add("name", "Name2");
form.add("nameNeu", "Name2Neu");
form.add("vnameNeu", "Vorname2Neu");
form.add("emailNeu", "eMail2Neu");
ClientResponse response = service.path("kontakte").type(MediaType.APPLICATION_FORM_URLENCODED)
.put(ClientResponse.class, form);
System.out.println( response.getStatus() + " " + response.getClientResponseStatus() );
System.out.println( response.getEntity( String.class ) );
}
private static URI getBaseURI() {
return UriBuilder.fromUri(
"http://localhost:8080/JerseyJAXBRestTest1").build();
}
}
Schaut man sich anschließend die „Kontakte.xml“ Datei im Root Verzeichnis der Web-Applikation an, sieht sie so aus:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Kontakte>
<Kontakt>
<Name>Name1</Name>
<Vorname>Vorname1</Vorname>
<eMail>eMail1</eMail>
</Kontakt>
<Kontakt>
<Name>Name2Neu</Name>
<Vorname>Vorname2Neu</Vorname>
<eMail>email2Neu</eMail>
</Kontakt>
<Kontakt>
<Name>Name3</Name>
<Vorname>Vorname3</Vorname>
<eMail>eMail3</eMail>
</Kontakt>
</Kontakte>
Man erkennt, dass der zweite Eintrag verändert wurde.
Mit dem Advanced Rest Client von Google, kann man beispielsweise folgende Werte testen:
Das Ergebnis:
Schaut man sich anschließend die „Kontakte.xml“ Datei im Root Verzeichnis der Web-Applikation an, sieht sie so aus:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Kontakte>
<Kontakt>
<Name>Name1</Name>
<Vorname>Vorname1</Vorname>
<eMail>eMail1</eMail>
</Kontakt>
<Kontakt>
<Name>Name2Neu</Name>
<Vorname>Vorname2Neu</Vorname>
<eMail>eMail2Neu</eMail>
</Kontakt>
<Kontakt>
<Name>Name3Neu</Name>
<Vorname>Vorname3Neu</Vorname>
<eMail>eMail3Neu</eMail>
</Kontakt>
</Kontakte>
Jetzt wurde der dritte Eintrag verändert.
Anstelle des @FormParam Parameters kann man auch direkt JAXB Klassen übergeben. Zu diesem Zweck muss die Server Klasse um folgende Methode erweitert werden:
...
import javax.xml.bind.JAXBElement;
...
@PUT
@Consumes(MediaType.APPLICATION_XML)
public Response putContact(JAXBElement<Kontakte> kontakteArg) {
Response resRet = Response.noContent().build();
// Set path to the contacts xml source file (it is the real path on the
// tomcat server):
String strBas = context.getRealPath("/") + "Kontakte.xml";
KontakteHandler.getInstance().setXmlFileName(strBas);
// extract the name to search for:
String searchName = kontakteArg.getValue().getKontakt().get(0).getName();
// extract the remaining attributes:
String newVName = kontakteArg.getValue().getKontakt().get(0).getVorname();
String newEMail = kontakteArg.getValue().getKontakt().get(0).getEMail();
Kontakte kontakte = KontakteHandler.getInstance().searchKontakte(
searchName);
// Check if kontakt was found:
if (kontakte != null) {
Kontakte.Kontakt kontakt = kontakte.getKontakt().get(0);
// if ((neunameArg != null) && nameArg.trim().length() > 0)
// kontakt.setName(neunameArg);
if ((newVName != null) && newVName.trim().length() > 0)
kontakt.setVorname(newVName);
if ((newEMail != null) && newEMail.trim().length() > 0)
kontakt.setEMail(newEMail);
KontakteHandler.getInstance().updateKontakte();
resRet = Response.created(uriInfo.getAbsolutePath()).build();
}
return resRet;
}
Der Client kann folgenden Aufruf verwenden:
// Check PUT Operation with JAXB class:
Kontakte kontakteUpdate = new Kontakte();
Kontakte.Kontakt kontaktUpdate = new Kontakte.Kontakt();
kontaktUpdate.setName("Name1");
kontaktUpdate.setVorname("NeuVorname1");
kontaktUpdate.setEMail("NeuEMail1");
kontakteUpdate.getKontakt().add(kontaktUpdate);
ClientResponse response2 = service.path("kontakte")
.type(MediaType.APPLICATION_XML)
.put(ClientResponse.class, kontakteUpdate);
System.out.println(response2.getStatus() + " "
+ response2.getClientResponseStatus());
System.out.println(response2.getEntity(String.class));
Man beachte, dass sich der Name nicht ändern läßt, weil er gleichzeitig als Suchargument verwendet wird. Würde man für jeden Kontakt noch ein weiteres, eindeutiges Attribut definieren, beispielsweise eine ID, dann könnte man das als Suchargument verwenden und auch den Namen ändern.
POST – Create
Um die POST Operation zu implementieren, also um einen neuen Kontakt zu erstellen, kann man im Prinzip ähnlich wie bei der PUT Operation vorgehen. Im Beispiel wird wieder der @FormParam verwendet, um die Attribute des neuen Kontaktes festzulegen. Beim PUT habe ich „Response“ als Rückgabetyp gewählt, hier werde ich einmal „text/plain“, also String und einmal „MediaType.APPLICATION_XML“, also XML als Rückgabetyp wählen. Man kann natürlich auch andere Möglichkeiten der Parameterübergabe wählen (z.B. @QueryParam, etc.), das Gleiche gilt für den Response.
Die Server Klasse (mit „text/plain“ als Rückgabetyp):
@POST
@Produces("text/plain")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String postContact(@FormParam("nameNeu") String neunameArg,
@FormParam("vnameNeu") String neuvnameArg,
@FormParam("emailNeu") String neuemailArg,
@Context HttpServletResponse servletResponse) {
// Set path to the contacts xml source file (it is the real path on the
// tomcat server):
String strBas = context.getRealPath("/") + "Kontakte.xml";
KontakteHandler.getInstance().setXmlFileName(strBas);
Kontakte kontakte = KontakteHandler.getInstance().getKontakte();
Kontakte.Kontakt kontakt = new Kontakte.Kontakt();
// Check if there is something to create:
if ((neunameArg != null) && neunameArg.trim().length() > 0) {
if ((neunameArg != null) && neunameArg.trim().length() > 0)
kontakt.setName(neunameArg);
if ((neuvnameArg != null) && neuvnameArg.trim().length() > 0)
kontakt.setVorname(neuvnameArg);
if ((neuemailArg != null) && neuemailArg.trim().length() > 0)
kontakt.setEMail(neuemailArg);
kontakte.getKontakt().add(kontakt);
KontakteHandler.getInstance().updateKontakte();
}
return "Customer " + kontakt.getName() + " added !";
}
Die Server Klasse (mit „MediaType.APPLICATION_XML“ als Rückgabetyp):
@POST
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Kontakte postContact(@FormParam("nameNeu") String neunameArg,
@FormParam("vnameNeu") String neuvnameArg,
@FormParam("emailNeu") String neuemailArg,
@Context HttpServletResponse servletResponse) {
// Set path to the contacts xml source file (it is the real path on the
// tomcat server):
String strBas = context.getRealPath("/") + "Kontakte.xml";
KontakteHandler.getInstance().setXmlFileName(strBas);
Kontakte kontakte = KontakteHandler.getInstance().getKontakte();
Kontakte.Kontakt kontakt = new Kontakte.Kontakt();
// Check if there is something to create:
if ((neunameArg != null) && neunameArg.trim().length() > 0) {
if ((neunameArg != null) && neunameArg.trim().length() > 0)
kontakt.setName(neunameArg);
if ((neuvnameArg != null) && neuvnameArg.trim().length() > 0)
kontakt.setVorname(neuvnameArg);
if ((neuemailArg != null) && neuemailArg.trim().length() > 0)
kontakt.setEMail(neuemailArg);
kontakte.getKontakt().add(kontakt);
KontakteHandler.getInstance().updateKontakte();
}
// create a "Kontakte" class with one "Kontakt" (the created one),
// and use it for the response (in XML format):
Kontakte kontakteRet = new Kontakte();
kontakteRet.getKontakt().add(kontakt);
return kontakteRet;
}
Als Client verwende ich wieder den Advanced Rest Client:
Der Response (in der XML Version der Server Methode):
DELETE – Delete
Für die Operation Löschen werde ich wieder mit @QueryParam arbeiten und JSON zurückgeben. Auch hier gilt wieder, dass man andere Möglichkeiten der Parameterübergabe wählen könnte (Klasse direkt übergeben, @FormParam etc.), das Gleiche gilt für den Response.
Die Server Klasse wie folgt erweitern:
@DELETE
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Kontakte deleteContact(@QueryParam("name") String nameArg) {
// Set path to the contacts xml source file (it is the real path on the
// tomcat server):
String strBas = context.getRealPath("/") + "Kontakte.xml";
KontakteHandler.getInstance().setXmlFileName(strBas);
Kontakte.Kontakt kontaktRet = new Kontakte.Kontakt();
if ((nameArg != null) && nameArg.trim().length() > 0) {
// if QueryParam is set, it will be searched for it:
Kontakte kontakte = KontakteHandler.getInstance().searchKontakte(
nameArg);
// Check if kontakt was found:
if (kontakte != null) {
// save attributes for return value:
kontaktRet.setName(new String(kontakte.getKontakt().get(0)
.getName()));
kontaktRet.setVorname(new String(kontakte.getKontakt().get(0)
.getVorname()));
kontaktRet.setEMail(new String(kontakte.getKontakt().get(0)
.getEMail()));
// delete contact:
Kontakte.Kontakt kontakt = kontakte.getKontakt().remove(0);
KontakteHandler.getInstance().updateKontakte();
}
}
// create a "Kontakte" class with one "Kontakt" (the created one),
// and use it for the response (in XML format):
Kontakte kontakteRet = new Kontakte();
kontakteRet.getKontakt().add(kontaktRet);
return kontakteRet;
}
Test mit dem Advanced Rest Client:
Das Ergebnis:
Links:
vogella: REST with Java (JAX-RS) using Jersey – Tutorial
IBM developerWorks: Build a RESTful Web service using Jersey and Apache Tomcat
Thorsten Horn: RESTful Web Services mit JAX-RS und Jersey
devx.com: JAX-RS: Developing RESTful Web Services in Java















