Slide 1

Slide 1 text

Schnelle und leichtgewichtige Anwendungsentwicklung mit HTML5 und JEE REST Alexander Schwartz Java User Group Frankfurt / 26. Juni 2013 1 © msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz

Slide 2

Slide 2 text

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, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz

Slide 3

Slide 3 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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 JavaScript • 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

Slide 4

Slide 4 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 4 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

Slide 5

Slide 5 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 5 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 272 gefundene Geocaches

Slide 6

Slide 6 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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

Slide 7

Slide 7 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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

Slide 8

Slide 8 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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; … }

Slide 11

Slide 11 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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 texts; … }

Slide 12

Slide 12 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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

Slide 13

Slide 13 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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; … }

Slide 14

Slide 14 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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 { } Client Server C @Produces({ "application/json", "text/xml" }) @Consumes({ "application/json", "text/xml" }) public abstract class DefaultRestEndpoint { < … 500 Zeilen Generics, Reflection, JPA Metamodel, JavaDoc … Einblick auf der nächsten Folie … > }

Slide 15

Slide 15 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 15 Blick durch Schlüsselloch in DefaultRestEndpoint Client Server C public abstract class DefaultRestEndpoint { … @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 { … @POST @Path("") public Response add(ENTITY entity) { bindReadOnlyEntities(entity); em.persist(entity); em.flush(); UriBuilder locationBuilder = uriInfo.getBaseUriBuilder(); locationBuilder.path(this.getClass()); PersistenceUnitUtil puu = em.getEntityManagerFactory() .getPersistenceUnitUtil(); URI childLocation = locationBuilder.path("{id}").build( puu.getIdentifier(entity)); return Response.status(Response.Status.CREATED).location(childLocation) .build(); } … public abstract class DefaultRestEndpoint { …. @POST @Path("/qbe") public List 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(); } } …

Slide 16

Slide 16 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 16 Object Graph Traversal Client Server C @Stateless @Path("/sighting") public class SightingEndpoint extends DefaultRestEndpoint { @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 { @GET @JsonView(ListView.class) public Response listAll() { … } public class Sighting extends AbstractEntity { … @JsonView(Extended.class) public String getSightingMemo() { return sightingMemo; } … }

Slide 17

Slide 17 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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"}

Slide 18

Slide 18 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 18 Erweiterungspunkt: Custom Serialisierer Client Server C public class DateTimeZoneDeserializer extends JsonDeserializer { @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 { @Override public void serialize(DateTimeZone value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString(value.getID()); } } • Ist kein Standardtyp • Eigener Serialisierer kann eingebunden werden

Slide 19

Slide 19 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 19 • Serialiserer für DateTimeZone und BigDecimal registrieren Erweiterungspunkt: Custom Serialisierer Client Server C @Provider public class CustomObjectMapper implements ContextResolver { @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

Slide 20

Slide 20 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 20 Exception Handler Client Server C @Provider public class EntityNotFoundExceptionMapper implements ExceptionMapper { @Inject private Localizer localizer; @Override public Response toResponse(EntityNotFoundException exception) { Map responseObj = new HashMap(); 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 + "}"; } } }

Slide 21

Slide 21 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 21 Validierung von Daten Client Server C 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 { @Override public Response toResponse(ConstraintViolationException exception) { Map responseObj = new HashMap(); for (ConstraintViolation violation : exception.getConstraintViolations()) { // … < 40 Zeilen Code > … } return Response.status(Response.Status.BAD_REQUEST).entity(responseObj) .build(); } P

Slide 22

Slide 22 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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 REST: JAX-RS P

Slide 23

Slide 23 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / 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 und direkter Einsprung Einstieg HTML Client Server HTML Single Page Apps – aber bitte strukturiert und mit Modularisierung V M

Slide 24

Slide 24 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 24 Beispiel: Eingabefelder mit Label und Eingabefeld HTML im View Client Server CSS-Frameworks wie Bootstrap erlauben schlankes HTML V Zeitzone bearbeiten
Name

Slide 25

Slide 25 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 25 • Reduktion der Information • Alternative Anordnung der Information HTML im View Client Server Responsive Design abhängig vom Endgerät/Bildschrimbreite V

Slide 26

Slide 26 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 26 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(); } M

Slide 27

Slide 27 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 27 Eine Texteingabe im Input-Feld aktualisiert das Modell – eine Änderung im Modell aktualisiert den View View-Model Client Server Bidirektionales Binding V self.deleteLanguage = function(language) { self.vessel().vesselName.remove(language); }; M

Slide 28

Slide 28 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 28 Eine Texteingabe im Input-Feld aktualisiert das Modell – eine Änderung im Modell aktualisiert den View Berechnete Elemente für Internationalisierung Client Server Wenn sich die Sprache ändert, ändern sich alle Übersetzungen V M /* knockout.i18n.js */ ko.i18n = function(key) { return ko.computed(function() { if (ko.language() != null) { return i18next.t(key, { lng : ko.language() }); } else { return ""; } }, key); };

Slide 29

Slide 29 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 29 Damit kann an jedem Use Case noch unabhängiger gearbeitet werden Modularisierte Resource-Dateien Client Server Jeder Use Case kann eine eigene Datei bekommen V …

Slide 30

Slide 30 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 30 • 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 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' ] },…

Slide 31

Slide 31 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 31 Modularisierung (Usecases) Client Server Modularisierung der Use-Cases V M übergreifende Module Bibliotheken ein Template pro Use Case eine JS Datei pro Use Case

Slide 32

Slide 32 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 32 • 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); }); });

Slide 33

Slide 33 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 33 • 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

Slide 34

Slide 34 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 34 • 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

Slide 35

Slide 35 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 35 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 oder echt? Mock oder echt? geringe Komplexität hohe Komplexität

Slide 36

Slide 36 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 36 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

Slide 37

Slide 37 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 37 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"); }); });

Slide 38

Slide 38 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 38 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

Slide 39

Slide 39 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 39 • 7 Tests • 760 ms Gesamtlaufzeit • Cross-Browser • Unabhängig vom Backend • Dokumentation aus fachlicher Sicht • Beliebige Schachtelung • Chrome etwas schneller als Firefox Jasmine ist schnell und einfach Client Server Ein Browser-Reload lässt die Tests erneut laufen C V M

Slide 40

Slide 40 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 40 • Integration in CI Server möglich • Jasmine Tests erstellen XML entsprechend JUnit (für Jenkins, Eclipse et al) $ phantomjs phantomjs-testrunner.js \ http://localhost:8080/rest-samples/?spec= Testen in der Dunkelverarbeitung Client Server Mit PhantomJS auf der Kommandozeile testen C V M

Slide 41

Slide 41 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 41 • Verbinden mit einer laufenden Browser-Instanz • Breakpoint setzen, Variablen sehen • Hot Code Replacement Debugging mit Chome Client Server Wie Java und ein bisschen mehr? V M

Slide 42

Slide 42 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 42 Debugging mit Chome

Slide 43

Slide 43 text

... © msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 43 Application Cache Client Server Resourcen werden vorab geladen und über eine Datei validiert V # cache.appcache CACHE: /rest-samples/index.html /rest-samples/js/main.js /rest-samples/js/libs/jquery.js /rest-samples/css/libs/bootstrap.css … NETWORK: * # hash:a0d1f5…eedd • Der Browser erfährt, welche Resourcen er vorab laden soll • Daten werden lokal gespeichert • Validierung via Manifest, ob Resourcen erneut geladen werden sollen (ggf. erst aktivieren, wenn Entwicklung abgeschlossen ist) M

Slide 44

Slide 44 text

© msg systems ag, 26. Juni 2013 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz 44 • 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 Application Cache 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

Slide 45

Slide 45 text

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 45 HTML5 und JEE REST / JUG Frankfurt / Alexander Schwartz © msg systems ag, 26. Juni 2013