GET

Werbung
5. RESTful Web Services
•
•
•
•
•
•
•
•
•
•
•
•
•
JavaScript Object Notation
JSONP
Idee: Web-Services
Idee: RESTful
erste Services
GET, POST
Clients
Response
Path-Parameter
Aufrufparameter
Architektur von REST-Applikationen
Fallstudie (GET, POST, PUT, DELETE)
Ausblick
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
476
Ausblick auf weitere Themen
Browser
3
JSF
Scope
Bean
Validation
1
RESTful
WebService
Web
Sockets
2
CDI
EJB
JPA
Datenbank
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
477
Einstieg JSON
• JavaScript Object Notation (http://json.org/)
• textuelles Austauschformat, abgeleitet aus JavaScript
{ "name": "Tony Stark",
"alter": 42,
"firma": { "name": "Stark Industries",
"ort": "New York, N.Y"
},
"freunde":["Steve Rogers", "Bruce Banner"]
}
• Sammlung von
– (Name: Wert)-Paaren
– Arrays von Werten
• Werte können wieder aus beiden Elementen bestehen
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
478
Vereinheitlichung von JSON in Java
in JEE 7 ergänzt:
• JSR 353: JavaTM API for JSON Processing (23.5.2013),
https://jcp.org/en/jsr/detail?id=353
• Referenzimplementierung jsonp https://jsonp.java.net/
• in Glassfish 4.0 enthalten
zwei zentrale APIs
• Object Model API; sehr analog zum DOM API für XML
parsing
• Streaming API; sehr analog zum StAX API
• unabhängig von Programmiersprachen nutzbar
• kompakter als XML (ähnlich gut/schlecht menschenlesbar)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
479
Beispiel: JSON-Object lesen (1/2)
public static void main(String[] args) {
String daten =
"{ \"name\": \"Tony Stark\","
+ " \"alter\": 42,"
+ " \"firma\": { \"name\": \"Stark Industries\","
+ " \"ort\": \"New York, N.Y\""
+ "},"
+ "\"freunde\":[\"Steve Rogers\", \"Bruce Banner\", 42]"
+ "}";
JsonReader reader = Json.createReader(new StringReader(daten));
JsonObject tony = reader.readObject();
reader.close();
//Set<String> namen = tony.keySet(); // geht auch
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
480
Beispiel: JSON-Objekt lesen (2/2)
System.out.println("Name
: " + tony.getString("name"));
System.out.println("Alter
: " + tony.getInt("alter"));
JsonObject firma = tony.getJsonObject("firma");
System.out.println("Firmenname : " + firma.getString("name"));
System.out.println("Umsatz
: " + firma.getInt("umsatz", 20));
JsonArray freunde = tony.getJsonArray("freunde");
Default, wenn
for (JsonValue freund : freunde) {
nicht da
System.out.println(freund + " * " + freund.getValueType());
}
Name
: Tony Stark
Alter
: 42
}
Firmenname : Stark Industries
Umsatz
: 20
Steve Rogers * STRING
Bruce Banner * STRING
42 * NUMBER
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
481
Beispiel: JSON-Objekt von Hand erstellen
public static void main(String[] args) {
JsonObject personObject = Json.createObjectBuilder()
.add("name", "Bruce Banner")
.add("alter", 44)
.add("firma",
Json.createObjectBuilder()
Object:
.add("name", "Shield")
{"name":"Bruce
Banner","alter":44,"f
.add("ort", "unbekannt")
irma":{"name":"Shield
.build())
","ort":"unbekannt"},
.add("freunde",
"freunde":["James
Json.createArrayBuilder()
Howlett","Ben
.add("James Howlett")
Grimm"]}
.add("Ben Grimm")
.build())
.build();
System.out.println("Object: " + personObject);
Komponentenbasierte
Software}
Entwicklung
Prof. Dr.
Stephan Kleuker
482
Ausschnitt Klassendiagramm
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
483
Beispiel: Stream-Bearbeitung von JSON
START_OBJECT:
// daten: siehe JSON lesen
KEY_NAME: name
JsonParser parser = Json
VALUE_STRING:
.createParser(new StringReader(daten)); KEY_NAME: alter
while (parser.hasNext()) {
VALUE_NUMBER: 42
Event event = parser.next();
KEY_NAME: firma
System.out.print(event + ": ");
START_OBJECT:
switch (event) {
KEY_NAME: name
VALUE_STRING:
case KEY_NAME:
System.out.print(parser.getString()); KEY_NAME: ort
VALUE_STRING:
break;
END_OBJECT:
case VALUE_NUMBER:
KEY_NAME: freunde
System.out.print(parser.getInt());
START_ARRAY:
break;
VALUE_STRING:
}
VALUE_STRING:
System.out.println("");
VALUE_NUMBER: 42
}
END_ARRAY:
Komponentenbasierte SoftwareProf. Dr.
484
END_OBJECT:
Entwicklung
Stephan Kleuker
Binding
• Binding schafft automatische Umwandlungsmöglichkeit von
A nach B und von B nach A
• ohne Binding muss die Umwandlung (marshalling) manuell
erfolgen, bei Netztransport ggfls. Rückumwandlung
notwendig (unmarshalling)
• Java-Objekt von und nach XML löst JAXB
• JSR 222: JavaTM Architecture for XML Binding (JAXB) 2.0,
https://jcp.org/en/jsr/detail?id=222
• wichtig Umwandlungsprozess konfigurierbar
• Java-Objekt von und nach JSON noch nicht standardisiert
(für JEE 8 angekündigt)
• Referenzimplementierung für Glassfish (Stand Ende 2013)
ist MOXy (übersetzt JAXB-Annotationen nach JSON)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
485
Beispiel: Vorbereitung einer Entitäts-Klasse für JSON
@XmlRootElement
public class Punkt implements Serializable {
private int x;
private int y;
public Punkt() {} // wichtig
public Punkt(int x, int y) {this.x = x; this.y = y;}
public int getX() {return x;}
public int getY() {return y;}
public void setX(int x) {this.x = x;}
public void setY(int y) {this.y = y;}
@Override
public String toString() {return "[" + x + "," + y + "]";}
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
486
Annotationen zur Steuerung der Übersetzung
@XmlElement(name=“rufname") // Key-Umbenennung
public String name;
@XmlTransient // nicht übertragen
public int alter;
• man beachte, dass man erhaltenes Objekt auch noch mit
vorherigen Methoden modifizieren kann
• Übersetzung noch nicht standardisiert (aktuell MOXy, Teil
von EclipseLink)
• da manuelle JsonObject-Erzeugung nicht sehr aufwändig
und sehr flexibel, wird es gute Alternative bleiben
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
487
Hintergrund Web Services
• zentraler Wunsch: einfache Nutzung von Software über das
Netz
• unabhängig wo sich ein Rechner befindet
• unabhängig von der Programmiersprache
SOAP-basierte WebServices
• jeder Service hat eindeutige Kennung (URI, Uniform
Resource Identifier)
• Schnittstellenbeschreibung WSDL
• typisch: XML-basierte Kommunikationsprotokolle
• typisch: Verbindung mit SOA
• hier nicht wichtig, aber SOA ≠ SOAP ≠ Web Service
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
488
Hintergrund: Service Oriented Architecture
UDDI
ServiceVerzeichnis
WSDL
ServiceNutzer
3. Anfragen
SOAP
4. Antworten
ServiceAnbieter
HTTP
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
489
Zwischenfazit SOA
• Vision: auf Grundlage von Geschäftsprozessmodellierungen
kann individuelle Software für ein Unternehmen entstehen
• Realität: machbar, wenn alles auf einem Hersteller basiert
• Realität: UDDI hat in fast allen Projekten nicht
stattgefunden (SOA ist auch Super Overhyped Acronym)
• aber: WebServices basierend auf SOAP haben als
Kommunikationskonzept zentrale Bedeutung bekommen
• gilt als relativ langsam
• aber: Unternehmen nutzen es um MS-basierte Oberfläche
mit JEE-realisiertem Server zu verbinden
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
490
RESTful (Representational State Transfer)
• Idee von der Interaktion zwischen Rechnern bleibt
• REST ist ein Architekturstil für verteilte HypermediaSysteme
• Protokoll: nutze Möglichkeiten von HTTP
– GET: lese Information (SELECT)
– POST: neue Information (INSERT)
– PUT: ändere Information (UPDATE)
– DELETE: lösche Information (DELETE)
• Klammern deuten Ähnlichkeit zu Datenbankoperationen an
• Grundlage: Dissertation Roy Fielding „Architectural Styles
and the Design of Network-based Software Architectures “
• http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
491
Woher kommt „ Representational State Transfer“
http://www.scrumsprinter.de/sprint/42
Resource
Client
{ “id”: 42,
“name”: “Prototyp”,
“elemente”: [ …
Client fordert Information mit Hilfe einer URL an.
Eine Repräsentation der Information wird als Ergebnis
zurückgegeben (z. B. in Form eines JSON-Objekts), Client hat
Informationszustand.
Client nutzt Hyperlink in Ergebnis um weitere Informationen
anzufordern.
Neues Ergebnis versetzt Client in einen neuen Informationszustand.
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
492
HATEOAS – saubere REST-Architektur
„Hypermedia as the Engine of Application State“
• Client kennt nur die Basis-URI des Dienstes
• Server leitet durch Informationszustände der Anwendung
durch Bekanntgabe von Wahlmöglichkeiten (Hyperlinks)
• Der vollständige Informationszustand kann beim Client oder
beim Server liegen, oder auch über beide verteilt sein
• HTTP-Kommunikationsprotokoll selbst bleibt zustandslos
• Grundregel: GET, PUT, DELETE sind idempotent; führen zum
gleichen Ergebnis, egal wie oft sie im gleichen
Informationszustand aufgerufen werden
• häufig genutzter Trick: POST auch zur partiellen Aktualisierung
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
493
Wer nutzt es (Beispiele)?
• Hinweis: Öfter wird gegen die geforderte Reinform von
RESTful WebServices verstoßen, und normale
Anfragemöglichkeit mit GET als RESTful bezeichnet
•
•
•
•
Google Maps
Google AJAX Search API
Yahoo Search API
Amazon WebServices
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
494
Standardisierung in Java
viele Implementierungen
• Restlet http://www.restlet.org/
• Apache CXF http://cxf.apache.org/
• Project Zero http://www.projectzero.org
• GlassFish Jersey https://jersey.dev.java.net/ (Referenz)
• JBoss RESTeasy http://www.jboss.org/resteasy/
Standardisierung für Java:
• JSR 311: JAX-RS: The JavaTM API for RESTful Web Services,
https://jcp.org/en/jsr/detail?id=311 (10.10.2008)
• JSR 339: JAX-RS 2.0: The Java API for RESTful Web Services,
https://jcp.org/en/jsr/detail?id=339 (24.5.2013)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
495
JAX-RS aktivieren
• in JEE-aware Servern reicht theoretisch folgendes aus
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("resources")
public class ApplicationConfig extends Application {
}
• ist generell im .war-File
• sonst Konfiguration als Servlet nötig
• Beschreibung in web.xml
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
496
JAX-RS aktivieren (Alternative)
@ApplicationPath("resources")
public class ApplicationConfig extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
try {
// customize Jersey 2.0 JSON provider:
Class jsonProvider = Class
.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");
resources.add(jsonProvider);
} catch (ClassNotFoundException ex) {}
addRestResourceClasses(resources);
return resources;
}
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(hello.HelloWorld.class);
Anbieter von
}
Services
} Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
497
erste RESTful-WebServices
@Path("/helloworld")
public class HelloWorld {
public HelloWorld() { }
@GET
@Produces("text/html")
public String getHtml() {
return "<html><body><h1>Hello, World!!</h1></body></html>";
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getText() {
return "Tach Welt";
}
}
Komponentenbasierte
SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
498
detaillierte Analyse
@Path("/helloworld")
• Gibt Aufrufpfad an, hier resources/helloworld
• könnte auch nur an einzelnen Methoden stehen
• kann auch zusätzlich an Methoden stehen, so dass sich der
Pfad verlängert
@GET
@Produces("text/html")
• Annotationen aus javax.ws.rs
• HTTP-Befehl und Ergebnistyp (mögliche Ergebnistypen,
mehrere MIME-Typen [Multipurpose Internet Mail
Extension])
• nachfolgender Methodenname spielt keine Rolle!
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
499
direkter Aufruf
• bei GET ist direkter Aufruf im Browser möglich
• aber, das ist ein sehr sehr untypisches Szenario
• typisch:
– Aufruf direkt aus einer Web-Seite, meist mit JavaScript
– Aufruf aus anderer Software heraus mit Mitteln der
jeweiligen Programmiersprache (z. B. java.net.URL)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
500
Detaillierte Analyse mit cURL
• generell jedes Programm zur Erzeugung von HTTP-Aufrufen
und Analyse der Ergebnisse geeignet
• Kommando-Zeile mit cURL
http://curl.haxx.se/download.html
• Für etwaige Parameter muss auch URL in
Anführungsstrichen stehen
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
501
Nutzung automatischen Marshallings - GET
• verschiedene Rückgabetypen bedienbar (praktisch
sinnvoll?)
@GET
@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_JSON})
public Punkt getJSon2() {
return new Punkt(42,43); // war @XMLRootElement annotiert
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
502
Nutzung automatischen Unmarshallings - POST
@POST
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_JSON)
public String postit(Punkt p){
System.out.println(p);
return "ok";
}
• weitere Parameter im JSON-Objekt führen zu Fehlern
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
503
zentrale Klassen Client und Response
• RESTful Web Services werden typischerweise aus anderer
Software aufgerufen
• dies ist natürlich auch in Java möglich; vor JAX-RS 2.0 aber
proprietäre Lösungen der Anbieter
• jetzt Klasse javax.ws.rs.client.Client
• Bei der Nutzung von RESTful Web Services können
verschiedene Klassen als Typen für Parameter und
Rückgabe genutzt werden
• Hilfreich ist Klasse javax.ws.rs.core.Response
• Server erzeugt Response-Objekt
• Client kann problemlos Response-Objekt lesen
• Response ist ein Stream, muss auch geschlossen werden
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
504
Hilfsmethode zur genaueren Analyse von Response
private void details(Response res) {
System.out.println("-----------------\n"
+ "AllowedMethods : " + res.getAllowedMethods() + "\n"
+ "Entity Class: " + res.getEntity().getClass() + "\n"
+ "Language : " + res.getLanguage() + "\n"
+ "Location : " + res.getLocation() + "\n"
+ "Mediatype : " + res.getMediaType() + "\n"
+ "Links : " + res.getLinks() + "\n"
+ "Status : " + res.getStatus() + "\n"
+ "Date : " + res.getDate() + "\n"
+ "Class : " + res.getClass() + "\n"
+ "Inhalt : " + res.readEntity(String.class));
res.close();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
505
Kleine Beispiele (1/7)
• Anmerkung: Zeigt Service-Nutzung, zeigt nichts von REST
public class ClientAnalyse {
private Client client;
private WebTarget userTarget;
public ClientAnalyse() {
Client client = ClientBuilder.newClient();
userTarget = client
.target("http://localhost:8080/resources/helloworld");
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
506
Kleine Beispiele (2/7)
public void analyse1() {
Response res = userTarget.request("text/html").get();
details(res);
}
AllowedMethods : []
Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1
Language : null
Location : null
Mediatype : text/html
Links : []
Status : 200
Date : Wed May 14 18:55:35 CEST 2014
Class : class org.glassfish.jersey.client.ScopedJaxrsResponse
Inhalt : <html lang="en"><body><h1>Hello, World!!</h1></body></html>
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
507
Kleine Beispiele (3/7)
public void analyse1() {
Response res = userTarget.request(MediaType.TEXT_PLAIN).get();
details(res);
}
AllowedMethods : []
Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1
Language : null
Location : null
Mediatype : text/plain
Links : []
Status : 200
Date : Wed May 14 18:55:35 CEST 2014
Class : class org.glassfish.jersey.client.ScopedJaxrsResponse
Inhalt : <html lang="en"><body><h1>Hello, World!!</h1></body></html>
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
508
Kleine Beispiele (4/7)
public void analyse3() {
Response res = userTarget
.request(MediaType.APPLICATION_JSON).get();
details(res);
}
AllowedMethods : []
Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1
Language : null
Location : null
Mediatype : application/json
Links : []
Status : 200
Date : Wed May 14 18:55:35 CEST 2014
Class : class org.glassfish.jersey.client.ScopedJaxrsResponse
Inhalt : {"x":42,"y":43}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
509
Kleine Beispiele (5/7)
public void analyse4() {
Response res = userTarget.request(MediaType.TEXT_XML).get();
details(res);
}
AllowedMethods : []
Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1
Language : null
Location : null
Mediatype : text/xml
Links : []
Status : 200
Date : Wed May 14 19:08:13 CEST 2014
Class : class org.glassfish.jersey.client.ScopedJaxrsResponse
Inhalt : <?xml version="1.0" encoding="UTF-8"
standalone="yes"?><punkt><x>42</x><y>43</y></punkt>
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
510
Kleine Beispiele (6/7)
public void analyse5() {
Builder buil = this.userTarget.request(MediaType.TEXT_PLAIN);
Entity e = Entity.entity(new Punk(3, 4)
, MediaType.APPLICATION_JSON);
System.out.println(e + " : " + e.getEntity());
String res = buil.post(e, String.class);
System.out.println(res);
}
javax.ws.rs.client.Entity@52aa911c : [3,4]
ok
• Anmerkung: Klasse Punk wie Punkt, sogar ohne
XMLRootElement-Annotation , aber Serializable
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
511
Kleine Beispiele (7/7)
public void analyse5() {
Builder buil = this.userTarget.request(MediaType.TEXT_PLAIN);
Entity e = Entity.json(new Punk(2,3));
System.out.println(e + " : " + e.getEntity());
String res = buil.post(e, String.class);
System.out.println(res);
}
javax.ws.rs.client.Entity@49fa424c : [2,3]
ok
• Klasse Entity bietet einige Marshalling-Methoden
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
512
flexible Dienststrukturen
• generell soll man aus Antworten auf weitere
Abfragemöglichkeiten schließen können
• /helloworld/kunden/
Frage nach Kunden: Sammlung der Namen aller Kunden
• /helloworld/kunden/Hoeness/
Frage nach Kunden mit Namen: alle Eigenschaften des
Kunden
• /helloworld/kunden/Hoeness/konten
Frage nach Konten eines benannten Kunden: Sammlung
aller Konten des Kunden
• /helloworld/kunden/Hoeness/konten/42
Frage nach Kontonummer eines benannten Kunden: alle
Eigenschaften des Kontos dieses Kunden
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
513
Beispiel: Umsetzung von Pfaden (1/4)
@Path("helloworld")
public class HelloWorld {
// Kundenname, Sammlung von Konten (Nummer, Betrag)
private Map<String, Map<Integer, Long> > kunden;
public HelloWorld() {
// zufaellige Beispieldaten
Map<Integer,Long> tmp = new HashMap<>();
tmp.put(42,32000000L);
kunden = new HashMap<>();
kunden.put("Hoeness", tmp);
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
514
Beispiel: Umsetzung von Pfaden (2/4)
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/kunden/{user}/konten/{id}")
public JsonObject getKontostand(
@PathParam("user") String user
, @PathParam("id") int id) {
JsonObjectBuilder erg = Json.createObjectBuilder();
Map<Integer,Long> kunde = kunden.get(user);
if(kunde == null){
return erg.add("fehler", "kein Kunde").build();
}
Long summe = kunde.get(id);
if(summe == null){
return erg.add("fehler", "kein Konto").build();
}
return erg.add("summe", summe).build();
Komponentenbasierte
SoftwareProf. Dr.
}
Entwicklung
Stephan Kleuker
515
Beispiel: Umsetzung von Pfaden (3/4)
public static void main(String[] a){
String[] verdaechtig = {"Rummenigge", "Hoeness"};
int[] nummern = {42,43};
Client client = ClientBuilder.newClient();
for(String v:verdaechtig){
for (int n:nummern){
WebTarget target = client.target(
"http://localhost:8080/resources/helloworld/kunden/"
+ v + "/konten/" + n);
JsonObject erg = target
.request(MediaType.APPLICATION_JSON)
.get(JsonObject.class);
System.out.println(erg);
}
}
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
516
Beispiel: Umsetzung von Pfaden (4/4)
{"fehler":"kein Kunde"}
{"fehler":"kein Kunde"}
{"summe":32000000}
{"fehler":"kein Konto"}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
517
Umsetzung von Pfaden
@Path("/kunden/{user}/konten/{id}")
• Einbau von Pfadvariablen, auf die in Parameterliste mit
@PathParam("user") zugegriffen werden kann
• einfache Java-Typen, typischerweise int, long, String
nutzbar; Konvertierung automatisch
• Pfadvariablen in der Klassenannotation können dann in
jedem Methodenkopf genutzt werden
• Pfadvariablen können in @Path doppelt vorkommen und
müssen dann gleichen Wert bei Nutzung haben
• im Hinterkopf: wenn HTTPS, dann auch User-Token so
übertrag- und später prüfbar (Sicherheit)
• im Hinterkopf: individueller Wert für jeden Nutzer, der EMail mit so einem Link erhält
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
518
Externer Service zur Analyse von IPs (1/4)
private static void zeigeJsonObjekt(JsonObject js){
for(String key:js.keySet()){
System.out.println(key+ ": " + js.get(key));
}
}
public static void main(String[] s){
String SERVICE = "http://freegeoip.net/json";
Client client = ClientBuilder.newClient();
WebTarget wt = client.target(SERVICE);
Invocation.Builder invoc = wt.request();
JsonObject ergebnis = invoc.get(JsonObject.class);
zeigeJsonObjekt(ergebnis);
zeigeJsonObjekt(client.target(SERVICE+"/www.bild.de")
.request().get(JsonObject.class));
}
Komponentenbasierte
SoftwareProf. Dr.
Entwicklung
Stephan Kleuker
519
Externer Service zur Analyse von IPs (2/4)
ip: 93.196.192.46
country_code: DE
country_name: Germany
region_code: 07
region_name: Nordrhein-Westfalen
city: Hopsten
zipcode:
latitude: 52.3833
longitude: 7.6167
metro_code:
area_code:
Komponentenbasierte SoftwareEntwicklung
ip: 209.8.115.88
country_code: US
country_name: United States
region_code: TX
region_name: Texas
city: Dallas
zipcode:
latitude: 32.7831
longitude: -96.8067
metro_code: 623
area_code: 214
Prof. Dr.
Stephan Kleuker
520
Externer Service zur Analyse von IPs (3/4)
public static void main(String[] st){
Client client = ClientBuilder.newClient();
WebTarget wt = client.target("http://freegeoip.net/json");
Invocation.Builder invoc = wt.request();
Response ergebnis = invoc.get();
System.out.println(ergebnis);
ergebnis.bufferEntity(); // sonst Fehler bei 42
System.out.println(ergebnis.getEntity());
for(String s:ergebnis.getHeaders().keySet()){
System.out.println(s +": " + ergebnis.getHeaders().get(s));
}
System.out.println(ergebnis.readEntity(JsonObject.class));
System.out.println(ergebnis.getEntity().getClass()); //42
ergebnis.close();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
521
Externer Service zur Analyse von IPs (4/4)
ScopedJaxrsResponse{ClientResponse{method=GET,
uri=http://freegeoip.net/json, status=200, reason=OK}}
java.io.ByteArrayInputStream@6d420a24
Date: [Wed, 14 May 2014 17:48:10 GMT]
Access-Control-Allow-Origin: [*]
Content-Length: [222]
Content-Type: [application/json]
{"ip":"93.196.192.46","country_code":"DE","country_name":"Germany","
region_code":"07","region_name":"NordrheinWestfalen","city":"Hopsten","zipcode":"","latitude":52.3833,"longitu
de":7.6167,"metro_code":"","area_code":""}
class java.io.ByteArrayInputStream
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
522
Übergabe von Aufrufparametern (1/2)
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/rechnen")
public JsonObject machMathe(
@QueryParam("op1") int op1,
@QueryParam("op2") int op2,
@DefaultValue("plus")
@QueryParam("operator") String operator) {
JsonObjectBuilder erg = Json.createObjectBuilder();
if(operator.equals("minus")){
return erg.add("operator", operator)
.add("ergebnis", (op1-op2)).build();
}
return erg.add("operator", "plus")
.add("ergebnis", (op1+op2)).build();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
523
Übergabe von Aufrufparametern (2/2)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
524
Dienstnutzung mit Aufrufparametern (1/2)
public static void main(String[] s) {
String SERVICE
= "http://maps.googleapis.com/maps/api/geocode/json";
Client client = ClientBuilder.newClient();
WebTarget wt = client.target(SERVICE +
"?address=Quakenbrueck&sensor=false");
Invocation.Builder invoc = wt.request();
JsonObject ergebnis = invoc.get(JsonObject.class);
System.out.println(ergebnis);
JsonObject details = ((JsonArray)ergebnis.get("results"))
.getJsonObject(0);
JsonObject position= (JsonObject)
((JsonObject)details.get("geometry")).get("location");
System.out.println(position);
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
525
Dienstnutzung mit Aufrufparametern (2/2)
{"results":[{"address_components":[{"long_name":"Quakenbrück","
short_name":"Quakenbrück","types":["locality","political"]},{"l
ong_name":"Osnabrück","short_name":"OS","types":["administrativ
e_area_level_3","political"]},{"long_name":"Lower
Saxony","short_name":"NDS","types":["administrative_area_level_
1","political"]},{"long_name":"Germany","short_name":"DE","type
s":["country","political"]}],"formatted_address":"Quakenbrück,
Germany","geometry":{"bounds":{"northeast":{"lat":52.6967289,"l
ng":8.0344312},"southwest":{"lat":52.65917049999999,"lng":7.903
767999999999}},"location":{"lat":52.675599,"lng":7.950777699999
999},"location_type":"APPROXIMATE","viewport":{"northeast":{"la
t":52.6967289,"lng":8.0344312},"southwest":{"lat":52.6591704999
9999,"lng":7.903767999999999}}},"types":["locality","political"
]}],"status":"OK"}
{"lat":52.675599,"lng":7.950777699999999}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
526
Aufgabe
Sprinter soll um eine RESTful-Schnittstelle ergänzt werden,
• mit der von außen auf Sprints zugegriffen werden kann,
• die nur eine Teilmenge der Daten der Sprints sieht,
• die neue Sprints anlegen kann,
• die Sprints editieren kann,
• die Sprints löschen kann
• Entscheidung: Ergänze Programm um RESTful Webservices
• Schnittstelle wird in neuem Projekt genutzt (das zum
einfacheren Verständnis eine JSF-Oberfläche bekommt)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
527
Nutzungsszenario
• Links nicht ausimplementiert
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
528
Architektur: hierarchischer Aufbau
Resource
POST
GET
(CREATE) (READ)
PUT
(UPDATE)
DELETE
(DELETE)
/sprints
erzeugt
neuen
Sprint
Aktualisiere
alle Sprints
(oder
weglassen)
alle Sprints
löschen
/sprints/42 Fehler!
Übersicht
über alle
Sprints
Zeige Sprint wenn Sprint
mit id 42
mit id 42
existiert, dann
aktualisieren,
sonst Fehler
Lösche den
Sprint mit id
42
Hinweise: noch sauberer wäre /sprint/42 (Einzahl)
graue Felder nicht realisiert
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
529
Einordnung SprintRestController (Server)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
530
Client (minimal)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
SprinterRESTClient
531
Vorbereitung im Server
@Stateless // oder @Singleton
@Path("")
public class SprintRestController implements Serializable{
@Inject
private PersistenzService pers;
@Context
private UriInfo uriInfo; // später genauer
private SimpleDateFormat formatter
= new SimpleDateFormat("dd.MM.yyyy");
public SprintRestController() {
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
532
Hilfsmethode zum Sprint einpacken
private JsonObject jsonSprint(Sprint s, boolean einzeln) {
String idzeigen = (einzeln) ? "" : "" + s.getId();
JsonObjectBuilder js = Json.createObjectBuilder();
js.add("id", s.getId())
.add("motto", s.getMotto())
.add("starttermin", formatter.format(s.getStarttermin()))
.add("endtermin", formatter.format(s.getEndtermin()))
.add("geplanterAufwand", s.getGeplanterAufwand())
.add("farbe", s.color())
.add("link", uriInfo.getAbsolutePathBuilder()
.path(idzeigen + "/backlogElemente")
.build().getPath());
return js.build();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
533
GET /sprints (1/2)
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/sprints")
public JsonObject getSprints(
@DefaultValue("-1") @QueryParam("von") int von,
@DefaultValue("-1") @QueryParam("bis") int bis) {
List<Sprint> alle = pers.findAllSprint();
if (von < 0 || von >= alle.size()) {
von = 0;
}
if (bis < 0 || bis >= alle.size()) {
bis = alle.size() - 1;
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
534
GET /sprints (2/2)
JsonArrayBuilder elemente = Json.createArrayBuilder();
for (int i = von; i <= bis; i++) {
elemente.add(jsonSprint(alle.get(i), false));
}
return Json.createObjectBuilder()
.add("sprints", elemente)
.build();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
535
Client – Vorbereitung (1/2)
• Client braucht keine echte Datenhaltung
• Ansatz: Daten lokal in SessionScope halten (für kleinere
Datenmengen ok
@Named
@SessionScoped
public class SprintController implements Serializable {
private Client client;
private List<Map<String, Object>> sprints;
private final static String[] keys = {"id", "motto"
, "starttermin", "endtermin", "geplanterAufwand"
, "link", "farbe"};
private final static String SPRINTS
= "http://localhost:8080/Sprinter/resources/sprints";
private final static String HOME = "index";
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
536
Client – Vorbereitung (2/2)
•
eine Variable pro Eigenschaft mit get und set
enum Status {BASIC, EDIT;}
private long id;
private String motto;
private Date starttermin;
private Date endtermin;
private int geplanterAufwand;
private Status modus;
private String meldung = ""; // Statusmeldung ohne Voodoo
SimpleDateFormat formatter
= new SimpleDateFormat("dd.MM.yyyy");
public SprintController() {
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
537
Client – Initialisierung (1/2)
@PostConstruct
public void init() {
this.modus = Status.BASIC;
this.client = ClientBuilder.newClient();
WebTarget wt = client.target(SPRINTS);
Invocation.Builder buil = wt
.request(MediaType.APPLICATION_JSON);
JsonObject ergebnis = buil.get(JsonObject.class);
JsonArray array = ergebnis.getJsonArray("sprints");
this.sprints = new ArrayList<Map<String, Object>>();
for (JsonValue val : array) {
JsonObject js = (JsonObject) val;
// speichert einen String als Attribut/Wert-Paar
Map<String, Object> werte = new HashMap<String, Object>();
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
538
Client – Initialisierung (2/2)
for (String k : keys) {
werte.put(k, js.get(k));
}
this.sprints.add(werte);
}
this.motto = "";
this.starttermin = null;
this.endtermin = null;
this.geplanterAufwand = 0;
} in älteren Versionen (Übung !), überflüssige " entfernen
for (String k : keys) {
Object tmp = js.get(k);
String txt = tmp.toString();
if(txt.startsWith("\"") && txt.endsWith("\"") && txt.length() > 1){
tmp = txt.substring(1, txt.length()-1);
}
werte.put(k, tmp);
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
539
Erfolgloses Löschen möglich
• vom anderen Nutzer gelöscht oder modifiziert
• Idempotent wäre, diesen Fehler zu ignorieren (ist gelöscht)
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
540
Server Action loeschen
@DELETE
@Path("/sprints/{id}")
public JsonObject loeschen(@PathParam("id") long id) {
pers.removeSprint(id);
JsonObjectBuilder js = Json.createObjectBuilder();
js.add("status", "geloescht");
return js.build();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
541
Client löschen
public String loeschen(Object sid) {
System.out.println("loeschen: " + sid);
WebTarget wb = client.target(SPRINTS + "/" + sid);
Invocation.Builder build = wb
.request(MediaType.APPLICATION_JSON);
try {
JsonObject ergebnis = build.delete(JsonObject.class);
this.meldung = "loeschen erfolgreich: " + ergebnis;
} catch (Exception e) {
this.meldung = "loeschen gescheitert: " + e;
}
init();
this.modus = Status.BASIC;
return HOME;
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
542
Neuer Sprint – Server (1/2)
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/sprints")
public JsonObject hinzufuegen(JsonObject jo) {
Sprint sprint = new Sprint();
sprint.setMotto(jo.getString("motto"));
sprint.setGeplanterAufwand(jo.getInt("geplanterAufwand"));
SimpleDateFormat formatter
= new SimpleDateFormat("dd.MM.yyyy");
try {
sprint.setStarttermin(formatter
.parse(jo.getString("starttermin")));
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
543
Neuer Sprint – Server (2/2)
sprint.setEndtermin(formatter
.parse(jo.getString("endtermin")));
} catch (ParseException ex) {
return null;
}
pers.persist(sprint);
JsonObjectBuilder js = Json.createObjectBuilder();
js.add("link"
, uriInfo.getAbsolutePathBuilder()
.path(sprint.getId() + "/backlogElemente")
.build().getPath());
return js.build();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
544
Neuer Sprint – Client Aktion uebernehmen (1/4)
public String uebernehmen() {
// Validerung des Clients muss dieser regeln
if (this.starttermin == null || this.endtermin == null){
this.meldung = "Start- und Endtermin angeben!";
return HOME;
}
if (this.starttermin.compareTo(this.endtermin) > 0){
this.meldung = "Endtermin nicht vor Starttermin";
return HOME;
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
545
Neuer Sprint – Client Aktion uebernehmen (2/4)
JsonObjectBuilder js = Json.createObjectBuilder();
js.add("motto", this.motto)
.add("starttermin", formatter.format(this.starttermin))
.add("endtermin", formatter.format(this.endtermin))
.add("geplanterAufwand", this.geplanterAufwand);
if (this.modus.equals(Status.BASIC)) {
neuerSprint(js);
}
if (this.modus.equals(Status.EDIT)) {
editiereSprint(js);
}
init();
this.modus = Status.BASIC;
return HOME;
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
546
Neuer Sprint – Client Aktion uebernehmen (3/4)
private void neuerSprint(JsonObjectBuilder js){
WebTarget wb = client.target(SPRINTS);
Invocation.Builder build = wb
.request(MediaType.APPLICATION_JSON);
Entity entity = Entity.entity(js.build()
, MediaType.APPLICATION_JSON);
try {
JsonObject ergebnis = build.post(entity, JsonObject.class);
this.meldung = "einfuegen erfolgreich: " + ergebnis;
} catch (Exception e) {
this.meldung = "einfuegen gescheitert: " + e;
}
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
547
Sprint editieren – Server (1/2)
@PUT
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/sprints/{id}")
public JsonObject aktualisieren( @PathParam("id") long id
, JsonObject jo) {
Sprint sprint = pers.findSprint(id);
sprint.setMotto(jo.getString("motto"));
sprint.setGeplanterAufwand(jo.getInt("geplanterAufwand"));
try {
sprint.setStarttermin(formatter
.parse(jo.getString("starttermin")));
sprint.setEndtermin(formatter
.parse(jo.getString("endtermin")));
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
548
Sprint editieren – Server (2/2)
} catch (ParseException ex) {
return null;
}
pers.merge(sprint);
JsonObjectBuilder js = Json.createObjectBuilder();
js.add("link"
, uriInfo.getAbsolutePathBuilder()
.path("/backlogElemente").build().getPath());
return js.build();
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
549
Editiere Sprint – Client Aktion uebernehmen (4/4)
private void editiereSprint(JsonObjectBuilder js) {
WebTarget wb = client.target(SPRINTS + "/" + this.id);
Invocation.Builder build = wb
.request(MediaType.APPLICATION_JSON);
js.add("id", id);
Entity entity = Entity.entity(js.build()
, MediaType.APPLICATION_JSON);
try {
JsonObject ergebnis = build.put(entity, JsonObject.class);
this.meldung = "aktualisieren erfolgreich: " + ergebnis;
} catch (Exception e) {
this.meldung = "aktualisieren gescheitert: " + e;
}
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
550
UriInfo (1/2)
@Path("ana")
@Stateless
public class Analyse {
@Context
private UriInfo uriInfo;
private final static Logger LOGGER = Logger
.getLogger(Analyse.class.getSimpleName());
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getText() {
LOGGER.info("in getText");
LOGGER.info(this.uriInfo.getAbsolutePath().toString());
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
551
UriInfo (2/2)
LOGGER.info(this.uriInfo.getPath());
LOGGER.info(this.uriInfo.getRequestUri().toString());
for (String s:this.uriInfo.getQueryParameters().keySet()){
LOGGER.info(s+ ": "
+ this.uriInfo.getQueryParameters().get(s));
}
return "hai";
}
INFO:
INFO:
INFO:
INFO:
INFO:
INFO:
in getText
http://localhost:8080/resources/ana
/ana
http://localhost:8080/resources/ana?x=Hai&text=42
text: [42]
x: [Hai]
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
552
WADL (1/3)
• Web Application Description Language
• XML-basierte Beschreibung angebotener Dienste
• generell soll HTTP-Befehl OPTIONS genutzt werden, um
Übersicht zu erhalten
• Alle möglichen Dienste mit Parametern werden aufgeführt
• Dienstbeschreibungen können aus Annotation generiert
werden
• Alternativ kann @OPTIONS-annotierte Methode realisiert
werden (z. B. um Ausgabe zu verhindern)
• Bedeutung eher gering, für Werkzeuge basierend auf
WADL-Services interessant; erkennen so Aktualisierungen
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
553
WADL (2/3) - Beispielmethode
@GET
@Produces("text/html")
public String getHtml() {
return "<html><body>Hello, World!!</body></html>";
}
<resources base="http://localhost:8080/resources/">
<resource path="helloworld">
<method id="getHtml" name="GET">
<response>
<representation mediaType="text/html"/>
</response>
</method>
...
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
554
WADL (3/3) – Beispiel aus Sprinter
<resources base="http://localhost:8080/Sprinter/resources/">
<resource path="sprints">
<method id="getSprints" name="GET">
<request>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema"
name="von"
style="query" type="xs:int" default="-1"/>
<param xmlns:xs="http://www.w3.org/2001/XMLSchema"
name="bis"
style="query" type="xs:int" default="-1"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
<method id="hinzufuegen" name="POST">
<request>
<representation mediaType="application/json"/>
</request>
<response>
Komponentenbasierte
SoftwareProf. Dr.
<representation mediaType="application/json"/>
Entwicklung
Stephan Kleuker
555
@FormParam
<form action="http://vfl.de/mitglieder" method="post">
<p>
Vorname: <input type="text" name="vorname"><br>
Nachname: <input type="text" name="nachname"><br>
<input type="submit" value="Send">
</p>
ermöglicht die Übernahme
</form>
von Parametern einer POSTAnfrage eines HTML@Path("/mitglieder")
Formulars
@Consumes(Mediatype.APPLICATION_FORM_URLENCODED)
public class CustomerResource {
@POST
public void createCustomer(
@FormParam(“vorname") String vorname
, @FormParam(“nachname") String nachname) {
...
}
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
556
Response.Status (gibt evtl. passende Exceptions)
public enum Status {
OK(200, "OK"),
CREATED(201, "Created"),
ACCEPTED(202, "Accepted"),
NO_CONTENT(204, "No Content"),
MOVED_PERMANENTLY(301, "Moved Permanently"),
SEE_OTHER(303, "See Other"),
NOT_MODIFIED(304, "Not Modified"),
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
BAD_REQUEST(400, "Bad Request"),
UNAUTHORIZED(401, "Unauthorized"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
NOT_ACCEPTABLE(406, "Not Acceptable"),
CONFLICT(409, "Conflict"),
GONE(410, "Gone"),
PRECONDITION_FAILED(412, "Precondition Failed"),
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
SERVICE_UNAVAILABLE(503, "Service Unavailable");
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
557
Weiterführend (1/2)
• asynchron
@POST
@Asynchronous public void bearbeite(
@Suspended AsyncResponse ar, Daten daten)
• reguläre Ausdrücke in Path, @Path("{id : .+}")
komplexe Auswertungsregeln, was, wenn mehrere
Möglichkeiten an Pfaden existieren
• HEAD: nimmt typischerweise erste GET und gibt statt
Ergebnis nur Header und Response-Code zurück
• MIME-Types können sehr detailliert sein, generell
type/subtype;name=value;name=value...
@Consumes("application/xml;charset=utf-8")
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
558
Weiterführend (2/2)
• JAX-RS-Annotationen können auch nur in Interfaces
ausgelagert werden
• Matrix-Parameter (Attribute) behandelbar
http://beispiel.spieler.de/vfl;typ=Sturm/2015
• Nutzung von Header-Parametern @HeaderParam
public String get(@HeaderParam("Referrer") String
aufrufer) {
public String get(@Context HttpHeaders headers) {
• Cookie-Nutzung
public String get(@CookieParam(“minr") int minr)
• genauere Analyse vom ResponseBuilder.status(.)
• Einbindung von Bean Validation
• …
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
559
Literatur
• (Standard-Links sind im Text)
• [Bur14] B. Burke, RESTful Java with JAX-RS 2.0, O‘Reilly,
Sebastopol (CA), USA, 2014
• http://www.oracle.com/technetwork/articles/java/jaxrs201929352.html
Komponentenbasierte SoftwareEntwicklung
Prof. Dr.
Stephan Kleuker
560
Herunterladen