Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Schnelle und leichtgewichtige Anwendungsentwicklung mit HTML5 und JEE/REST

Schnelle und leichtgewichtige Anwendungsentwicklung mit HTML5 und JEE/REST

Über die Jahre haben sich HTML und JEE stark gewandelt. Mit den heute vorliegenden Versionen ist eine effektive und effiziente Anwendungsentwicklung möglich.
Bei HTML wurde aus einer reinen Seitenbeschreibungssprache durch JavaScript, DOM und CSS eine vollwertige Client-Plattform, die nicht nur auf Effekte und Komponenten wie z.B. jQuery und jQuery UI setzt, sondern auch zusehends durch MV*-Frameworks strukturiert wird.
In der letzten Iteration brachte JEE neben den vorher schon starken Bereichen wie z.B. Persistenz zum ersten Mal Context Dependency Injection (CDI), Validierung von Werten mittels Annotationen (Bean Validation) und REST-Schnittstellen (JAX-RS) mit.
Im Laufe des Vortrags wird Schritt für Schritt eine strukturiere HTML5-Anwendung entwickelt, mit der ein leichtgewichtiges JEE REST-Backend mit Persistenz und Validierung alle seine Vorteile ausspielen kann. Außerdem wird gezeigt, wie diese Anwendung inkrementell erweitert und automatisiert getestet werden kann.

Alexander Schwartz

April 04, 2013
Tweet

More Decks by Alexander Schwartz

Other Decks in Technology

Transcript

  1. Schnelle und leichtgewichtige Anwendungsentwicklung mit HTML5 und JEE REST Alexander

    Schwartz Berlin Expert Days (BedCon) 2013 / 4. April 2013 1 © msg systems ag, 4. April 2013 HTML5 und JEE REST / BedCon 2013 / Alexander Schwartz
  2. 2 Was ich vorhabe 1. Worum es geht 2. Fachlicher

    Einstieg in das Beispiel 3. JEE Stack für REST auf dem Server 4. HTTP + JavaScript Stack auf dem Client 5. Testen der Anwendung 6. Detaillierung Server-Tests 7. Detaillierung Client-Tests 8. Zusammenfassung © msg systems ag, 4. April 2013 HTML5 und JEE REST / BedCon 2013 / Alexander Schwartz
  3. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 3 Worum es hier geht • HTML als Seitenbeschreibung • CSS für ansprechendes (responsive) Design • Widget z.B. via jQueryUI + Plugins • Clientlogik via JavaScript • Strukturierung mit Javascript MV*-Frameworks (z. B. KnockoutJS) • Modularisierung und Nachladen von Resourcen (z. B. requireJS) • JAX-RS 1.0/2.0 als Teil von JEE 6/7 • Kommunikation via REST/JSON ideal für JavasScript • Persistenz via JPA • Validierung von Daten mit Bean Validation • CDI für Erweiterungspunkte • Integration in Enterprise IT dank vieler Java-Bibliotheken Browser als Client-Plattform JEE REST für serverseitige Services HTML+JavaScript und JEE+REST als Plattform
  4. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 4 Wer ich bin Alexander Schwartz Lead IT Consultant im GB Travel und Logistics 10 Jahre Java 7 Jahre PL/SQL 7 Jahre Absatzfinanzierung 3,5 Jahre Direktbank 1 Frau 2 Kinder 216 gefundene Geocaches
  5. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 5 Mein Sponsor und Arbeitgeber 1980 gegründet mehr als 4000 Kollegen 8 Branchen 540 Mio € Umsatz 2012 22 Länder 16 deutsche Standorte msg systems ag
  6. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 6 User Story: „Nutzer möchte die Sichtung eines Schiffes erfassen, um später sehen zu können, ob auch andere dieses Schiff gesehen haben. Hierzu erfasst er Schifftstyp, Datum, Zeitzone und eine Notiz.“ Die heutige Aufgabe Online-Datenbank für (Raum-)Schiffsichtungen Garantiert kein Bezug zu einem Kundenprojekt! https://github.com/ ahus1/rest- samples
  7. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 7 Unser Wegweiser • Darstellung User-Interface • Interaktion mit dem Nutzer V View • Datenhaltung im Client • Bindung an den View M View Model • Kommunikation zwischen Server/Client • Besteht aus server- und clientseitigem Teil C Communication • Fachliche Business-Logik • Greift auf Persistenz zu B Business Services • Datenhaltung und Persistenz P Persistence Eine klare Schichtentrennung hilft als Wegweiser durch die Architektur Client Server
  8. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 8 Was es im Inneren zusammenhält Sichtung Schiffstyp Zeitzone Domain-Model für Struktur hilft Fachabteilung und Entwicklern M C P Client Server
  9. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 9 Wie´s für den Kunden aussieht Mockups klären früh das Maskenlayout und verringern Nacharbeiten P Client Server V
  10. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 10 • IDs werden automatisch generiert • Validierung über Bean-Validation • Basis-Klasse AbstractEntity für Optimistic Locking Los geht‘s – die erste Entität Standard-JPA-Entität für „Zeitzone“ P Client Server @Entity public class Timezone extends AbstractEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long timezoneId; @NotEmpty private String timezoneName; … } @MappedSuperclass public class AbstractEntity { @Version private Integer version; … }
  11. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 11 • Übersetzbares Element als Entität Translation • CascadeType.ALL für gemeinsame Speicherung • Orphan Removal für Housekeeping • Translation enthält eine Map mit Übersetzungen Entität mit Übersetzung Komplexe Entität „Schiffstyp“ P Client Server @Entity public class Vessel extends AbstractEntity { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long vesselId; @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "vesselName") private Translation vesselName; … } @Entity public class Translation extends AbstractEntity { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long translationId; @ElementCollection @CollectionTable(name = "Text", joinColumns = @JoinColumn(name = "translationId")) @MapKeyColumn(name = "textLanguage") @Column(name = "textString") private Map<Locale, String> texts; … }
  12. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 12 Vorsicht beim (Daten-Model) Bau Abbildung fachlicher Datentypen auf technische Datentypen Fachlich Java JSON JavaScript Zeichenkette String String String Ganzzahl Long Number Number Dezimalbruch BigDecimal String * String * Datum LocalDateTime String ** String ** * JavaScript Number-Type unterstützt nur Fließkommazahlen, aber keine Dezimalzahlen. Es können dadurch Rundungsdifferenzen auftreten, die fachlich nicht gewünscht sind. Daher Fallback auf String. ** „Standard“ bei JSON ist für Datumsangaben Sekunden seit 1970 und Zeit UTC. LocalDateTime lässt sich so nicht abbilden; Date in JavaScript wird in der Zeitzone des Browser dargestellt => keine Kontrolle durch Anwendung möglich möglich. Daher Fallback auf Datum als String im ISO-Format M C P Client Server
  13. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 13 • ManyToOne-Relation für Selectbox Vessel – ohne Cascade! • Joda-Elemente für Zeiten; usertype für Joda-Persistenz Datum in JPA Komplexe Entität „Sichtung“ P Client Server @Entity public class Sighting extends AbstractEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long sightingId; private String sightingMemo; @ManyToOne @JoinColumn(name = "vesselId") private Vessel vessel; @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTimeZoneAsString") private DateTimeZone sightingTimezone; @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime") private LocalDateTime sightingDate; … }
  14. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 14 • DefaultRestEndpoint liefert CRUD Funktionalität • Genug „Platz“ im Endpoint für spezifische Funktionalität (z.B. Aufruf von Business Services) • Sicherstellung „Don‘t Repeat Yourself“ Erster REST Endpoint Java-Generics sind gut! @Stateless @Path("/timezone") public class TimezoneEndpoint extends DefaultRestEndpoint<Timezone> { } Client Server C @Produces({ "application/json", "text/xml" }) @Consumes({ "application/json", "text/xml" }) public abstract class DefaultRestEndpoint<ENTITY extends HasId> { < … 500 Zeilen Generics, Reflection, JPA Metamodel, JavaDoc … Einblick auf der nächsten Folie … > }
  15. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 15 Blick durch Schlüsselloch in DefaultRestEndpoint Client Server C public abstract class DefaultRestEndpoint<ENTITY extends HasId> { … @GET @Path("/{id:.+}") public Response findById(@PathParam("id") String id, @Context Request request) { ENTITY result = em.find(getEntityClass(), constructPK(id)); if (result == null) { throw new EntityNotFoundException(); } pullByJsonView(result, getExtendedView()); return Response.ok(result).build(); } … public abstract class DefaultRestEndpoint<ENTITY extends HasId> { … @POST @Path("") public Response add(ENTITY entity) { bindReadOnlyEntities(entity); em.persist(entity); em.flush(); UriBuilder locationBuilder = uriInfo.getBaseUriBuilder(); locationBuilder.path(this.getClass()); URI childLocation = locationBuilder.path("{id}").build(entity.getId()); return Response.status(Response.Status.CREATED).location(childLocation) .build(); } … public abstract class DefaultRestEndpoint<ENTITY extends HasId> { …. @POST @Path("/qbe") public List<ENTITY> queryByExample(ENTITY entity) { Session session = (Session) em.getDelegate(); Example example = Example.create(entity).enableLike(MatchMode.ANYWHERE) .ignoreCase(); Criteria criteria = session.createCriteria(entity.getClass()).add(example); addSubCriteria(criteria, entity); if (criteria.list().isEmpty()) { return null; } else { pullByJsonView(criteria.list(), getExtendedView()); return criteria.list(); } } …
  16. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 16 Object Graph Traversal Client Server C @Stateless @Path("/sighting") public class SightingEndpoint extends DefaultRestEndpoint<Sighting> { @Override protected Class<?> getExtendedView() { return Sighting.Extended.class; } @Override @GET @Path("/{id:.+}") @JsonView(Sighting.Extended.class) public Response findById(@PathParam("id") String id, @Context Request request) { return super.findById(id, request); } … } Mit @JsonView-Annotationen kann die Sichtbarkeit eingeschränkt werden public abstract class DefaultRestEndpoint<ENTITY extends HasId> { @GET @JsonView(ListView.class) public Response listAll() { … } public class Sighting extends AbstractEntity { … @JsonView(Extended.class) public String getSightingMemo() { return sightingMemo; } … }
  17. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 17 • Fachliche Überlegung: kein sightingMemo in der Übersicht notwendig • Technische Überlegung: kein version in der Übersicht notwendig • ABER: @JsonView gibt‘s nur bei Jackson (nicht JEE Standard) Object Graph Traversal Output Client Server C GET http://localhost:8080/rest-samples/rest/sighting [{"sightingId":1, "vessel":{"vesselId":1,"vesselName":"Klingonischer Jäger"}, "sightingTimezone":"Europe/Berlin", "sightingDate":"2013-04-11T11:00:00.000"}, {"sightingId":2, "vessel":{"vesselId":1,"vesselName":"Klingonischer Jäger"}, "sightingTimezone":"Europe/London", "sightingDate":"2013-04-11T22:00:00.000"}] In der Liste sind weniger Attribute angezeigt, in der Einzelansicht mehr GET http://localhost:8080/rest-samples/rest/sighting/-1 {"version":1, "sightingId":1, "sightingMemo":"unheimlich!", "vessel":{"version":0,"vesselId":-1,"vesselName":"Klingonischer Jäger"}, "sightingTimezone":"Europe/Berlin", "sightingDate":"2013-04-11T11:00:00.000"}
  18. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 18 Erweiterungspunkt: Custom Serialisierer Client Server C public class DateTimeZoneDeserializer extends JsonDeserializer<DateTimeZone> { @Override public DateTimeZone deserialize(JsonParser jparse, DeserializationContext context) throws IOException { String text = jparse.getText(); if (text == null || text.trim().length() == 0) { return null; } else { return DateTimeZone.forID(text); } } } DateTimeZone serialisieren (da kein Standardtyp) public class DateTimeZoneSerializer extends JsonSerializer<DateTimeZone> { @Override public void serialize(DateTimeZone value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString(value.getID()); } }
  19. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 19 • Serialiserer für DateTimeZone und BigDecimal registrieren Erweiterungspunkt: Custom Serialisierer Client Server C @Provider public class CustomObjectMapper implements ContextResolver<ObjectMapper> { @Override public ObjectMapper getContext(Class<?> type) { final ObjectMapper result = new ObjectMapper(); SimpleModule module = new SimpleModule(getClass().getName(), new Version(1, 0, 0, null)) .addDeserializer(BigDecimal.class, new BigDecimalAmountDeserializer()) .addSerializer(BigDecimal.class, new BigDecimalAmountSerializer()) .addDeserializer(DateTimeZone.class, new DateTimeZoneDeserializer()) .addSerializer(DateTimeZone.class, new DateTimeZoneSerializer()); result.registerModule(module); result.configure(Feature.WRITE_DATES_AS_TIMESTAMPS, false); return result; } } Registrieren der Serialisierer / De-Serialisierer
  20. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 20 Exception Handler Client Server C @Provider public class EntityNotFoundExceptionMapper implements ExceptionMapper<EntityNotFoundException> { @Inject private Localizer localizer; @Override public Response toResponse(EntityNotFoundException exception) { Map<String, String> responseObj = new HashMap<String, String>(); responseObj.put("general", localizer.localize("error.entityNotFound")); return Response.status(Response.Status.NOT_FOUND).entity(responseObj) .build(); } } Für jede Exception kann (muss) ein eigener Handler definiert werden public class Localizer { @Inject private HttpServletRequest httpServletRequest; public String localize(String key) { try { ResourceBundle rb = ResourceBundle.getBundle("messages", httpServletRequest.getLocale()); return rb.getString(key); } catch (MissingResourceException e) { return "{" + key + "}"; } } }
  21. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 21 Validierung von Daten Client Server C @Entity public class Sighting extends AbstractEntity { … @NotNull @Size(min = 2, message = "{sighting.memo.minLength}") private String sightingMemo; … } Bean Validation plus Exception-Handler #ValidationMessages_de.properties sighting.memo.minLength=Muss mindestens {min} Zeichen lang sein @Entity public class Sighting extends AbstractEntity { … @NotNull @Size(min = 2, message = "{sighting.memo.minLength}") private String sightingMemo; … } @Provider public class ConstraintViolationExceptionMapper implements ExceptionMapper<ConstraintViolationException> { @Override public Response toResponse(ConstraintViolationException exception) { Map<String, Object> responseObj = new HashMap<String, Object>(); for (ConstraintViolation<?> violation : exception.getConstraintViolations()) { // … < 40 Zeilen Code > … } return Response.status(Response.Status.BAD_REQUEST).entity(responseObj) .build(); } P
  22. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 22 • Querschnittsfunktionen lassen sich einfach von domänenspezifischen Elementen trennen • APIs und Erweiterungspunkte für spezifische Implementierungen sind vorhanden • JSON Serialisierung ist nicht in JEE 6.0 standardisiert • Durch Generics, JPA Metamodel und Reflection gelingt es, das DRY Prinzip durchzuhalten JEE Zwischenfazit Client Server C JEE kann REST! P
  23. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 23 Anforderungen: • HTML für den View • View-Model für Datenhaltung • Bi-direktionales Datenbinding View / View-Model • Modularisierung von JavaScript-Bibliotheken, aber auch Templates und JavaScript-Code für Usecases der Anwendung • Stateful-URLs innerhalb der Anwendung; Vor-/Zurück-Navigation Einstieg HTML Client Server HTML Single Page Apps – aber bitte strukturiert und mit Modularisierung V M
  24. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 24 Beispiel: Eingabefelder mit Label und Eingabefeld HTML im View Client Server CSS-Frameworks wie Bootstrap erlauben ein schlankes HTML V <form class="form-horizontal" > <fieldset> <legend>Zeitzone bearbeiten</legend> <div class="row-fluid"> <div class="control-group"> <label class="control-label" for="bezeichnung">Name</label> <div class="controls"> <input type="text" id="timezoneName" class="input-large" /> </div> </div> </div> </fieldset> </form>
  25. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 25 Umgesetzt mit KnockoutJS View-Model Client Server Ein Menü anzeigen – Trennung View vom View Model V // menu.js var Menu = function() { // Data var self = this; self.folders = ko.observableArray([ { name : 'Schiffstypen', link : '#/vessel/main' }, { name : 'Sichtungen', link : '#/sighting/main' }, { name : 'Zeitzonen', link : '#/timezone/main' } ]); self.folder = ko.observable(); } <!-- index.html --> <ul class="nav" data-bind="foreach: menu.folders"> <li data-bind="css: { active: $data.link == $parent.menu.folder() }, attr: {id: $data.link} "><a data-bind="text: $data.name, attr: {href: $data.link}"></a></li> </ul> M
  26. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 26 Eine Texteingabe im Input-Feld aktualisiert das Modell – eine Änderung im Modell aktualisiert den View View-Model Client Server Bidirektionales Binding V <!-- vessel.js --> self.deleteLanguage = function(language) { self.vessel().vesselName.remove(language); }; M <!-- vessel.html --> <a class="btn btn-small“ data-bind="click: $parents[2].deleteLanguage"> <i class="icon-trash"></i> </a>
  27. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 27 • Jedes Modul erhält einen „Header“ mit Abhängigkeiten • Für 3rd-Party-Bibliotheken werden im der Startprozedur Abhängigkeiten definiert • requireJS sorgt für parallelen Download der JS-Module Modularisierung (Model) Client Server Modularisierung der Anwendung (Model) mit requireJS V <!-- vessel.js --> define( [ 'knockout', 'jquery', 'mapping', 'hasher', 'crossroads', 'menu' ], function(ko, $, mapping, hasher, crossroads, menu) { // logik… }); M //main.js require.config({ shim : { jquery : { exports : "jQuery" }, knockout : { deps : [ 'jquery' ] }, 'knockout.validation' : { deps : [ 'knockout' ] },… <!– index.html --> <script data-main="js/main" src="js/libs/require.js"></script>
  28. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 28 Modularisierung (Usecases) Client Server Modularisierung der Use-Cases V M übergreifende Module Bibliotheken ein Template pro Use Case eine JS Datei pro Use Case
  29. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 29 • HTML5 unterstützt das „History“ API, bei dem URLs sich ändern können, auch wenn die Seite gleich bleibt • Zusatzinformationen zu einer Seite können per JavaScript in der Browser-Historie abgelegt werden Ohne History-API: • Workaround: URL hinter dem Hash-Tag http://localhost:8080/rest-samples/#/vessel/edit/1 http://localhost:8080/rest-samples/#/vessel/main http://localhost:8080/rest-samples/#/timezone/edit/1 • Unterstützt z.B. durch Crossroads.js Stateful URLs Client Server URLs für den direkten Einstieg – und Vor-/Zurücknavigation V crossroads.addRoute(/vessel\/edit\/(.+)$/, function(id) { $.get("rest/vessel/" + id, function(data) { self.vessel(mapping.fromJS(toViewModel(data))); self.vesselList(null); }); });
  30. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 30 • Laden eines Elements • Das Model kann ggf. für den View punktuell transformiert werden, z.B. HashMap als Array REST-Anbindung in JavaScript Client Server Das Model im Backend kann weitgehend beibehalten werden $.get("rest/vessel/" + id, function(data) { self.vessel(mapping.fromJS(toViewModel(data))); self.vesselList(null); }); function toViewModel(data) { data = jQuery.extend(true, {}, data); var text = []; $.each(data.vesselName, function(key, value) { text.push({ textLanguage : key, textString : value }); }); data.vesselName = text; return data; } C M M
  31. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 31 • Querschnittsfunktionen lassen sich einfach von domänenspezifischen Elementen trennen • APIs und Erweiterungspunkte für spezifische Implementierungen sind vorhanden • Die Zahl der Bibliotheken und APIs ist deutlich größer als im JEE Bereich • Ist der Rahmen vorbereitet, können einfach neue Use Cases dazuentwickelt werden (je eine JS + HTML Datei pro Use Case) • Code-Änderungen sind nach einem Browser-Refresh sofort sichtbar HTML/JS Zwischenfazit Client Server HTML + JavaScript können strukturiert werden! V M C
  32. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 32 Automatisiertes Testen Client Server Verschiedene Testframeworks decken verschiedene Bereiche ab V M C B P Jasmine, Sinon Selenium IDE Selenium RC Junit Arquillian Arquillian + REST- assured Mock? Mock? geringe Komplexität hohe Komplexität
  33. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 33 Arquillian: • Automatisiertes Deployment von Teilen der Server-Anwendung (ggf. ergänzt um Mock-Komponenten) REST-assured: • Testen der REST-services mit Fluent API Arquillian + REST assured Client Server Test-Anwendungen automatisiert packen und laufen lassen @RunWith(Arquillian.class) public class MesseEndpointTest { @Deployment public static WebArchive createArchiveAndDeploy() { WebArchive war = ShrinkWrap.create(WebArchive.class, "arquillian-rest-demo.war"); war.addPackages(…); war.addAsLibraries(…); return war; } @Test public void testReturnFilledList() throws Exception { Response r = given().log().all() .contentType(ContentType.JSON).expect() .body("[0].meBezeichnung", equalTo("Vessel 1")) .statusCode(Status.OK.getStatusCode()).when() .get("/rest-samples/rest/vessel"); assertThat("only one element exists", r.body().jsonPath().getList("").size(), equalTo(1)); } B P C
  34. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 34 Kleine Tests: • Unit-Tests für JavaScript-Code-Bibliotheken • Ergänzt durch HTML-Fragmente • DOM-Interaktion möglich durch jQuery Integration Große Tests: • Tests der vollständigen Use Cases Jasmine BDD Testframework Client Server Anforderungen beschreiben und Tests automatisieren auf dem Client V M describe("Manage Vessels", function() { it("shows a list of two vessels at the start", function() { expect($("#vesselList")).toBeVisible(); expect($("#vesselList > tbody > tr")[0]).toContainHtml("Vessel 1"); expect($("#vesselList > tbody > tr")[1]).toContainHtml("Vessel 2"); }); });
  35. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 35 Frontend-Entwickler ist unabhängig vom Backend – und kann selber Testen Sinon.JS für Mocks Client Server Backend kann via JavaScript simuliert werden describe("Manage Vessels", function() { beforeEach(function() { server = sinon.fakeServer.create(); server.respondWith("GET", "rest/vessel", [ 200, { "Content-Type" : "application/json" }, vesselList ]); server.respondWith("DELETE", "rest/vessel/1", [ 204, null, "" ]); server.respondWith("GET", "rest/vessel/1", [ 200, { "Content-Type" : "application/json" }, vessel ]); afterEach(function() { // disable fake server server.restore(); }); ); C
  36. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 36 • 7 Tests • 760 ms Gesamtlaufzeit • Cross-Browser • Unabhängig vom Backend • Dokumentation aus fachlicher Sicht • Beliebige Schachtelung Jasmine ist schnell und einfach Client Server Ein Browser-Reload lässt die Tests erneut laufen C V M
  37. © msg systems ag, 4. April 2013 HTML5 und JEE

    REST / BedCon 2013 / Alexander Schwartz 37 • Backend und Frontend können fachliche Komponenten und technische Komponenten von einander getrennt werden • Steht der Rahmen, so können Entwickler an unabhängig an verschiedenen Use Cases arbeiten • Steht der Rahmen, so können Entwickler mit geringen Vorkenntnissen in die Entwicklung einsteigen • Frontend und Backend können separat entwickelt werden • HTML+JS bietet schnelle Turnaround-Zeiten in der Entwicklung • JEE REST bietet Integration in Enterprise IT und stabile Laufzeitumgebung • Sowohl Frontend als auch Backend können einfach skalieren • Durch neue HTML5 Features wie Local Storage und kann die Skalierung weiter erhöht werden Zusammenfassung Client Server JEE REST Backend ergänzt sich mit HTML/JS Frontend V M C B P
  38. www.msg-systems.com Vielen Dank für Ihre Aufmerksamkeit msg systems ag Mergenthalerallee

    73 - 75 65760 Eschborn Telefon: +49 (171) 5 62 57 67 E-Mail: [email protected] www.msg-systems.com 38 HTML5 und JEE REST / BedCon 2013 / Alexander Schwartz © msg systems ag, 4. April 2013