Legacy WebApps mit AngularJS pimpen

901 views
832 views

Published on

Folien zu unserem Vortrag beim Java Forum Stuttgart 2014
Besuchen Sie uns unter http://www.thecodecampus.de

Müssen Sie auch noch alte servergetriebene Java-Webanwendungen weiterentwickeln und wollen Ihre Kunden dabei den Genuss der Usability moderner Webseiten bieten?
In unserem Talk beim JavaForum Stuttgart 2014 haben wir anhand von Codebeispielen und Erfahrungsberichten gezeigt wie man schrittweise AngularJS in bestehende Anwendungen integriert. Dieser agile Ansatz liefert schnelle Ergebnisse und reduziert die Kosten und Risiken im Vergleich zu einer kompletten Umstellung.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
901
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
1
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Legacy WebApps mit AngularJS pimpen

  1. 1. Legacy Web-Apps mit AngularJS pimpen
  2. 2. Über uns • Jan Blankenhorn und Philipp Burgmer • Software Developers • w11k.com / thecodecampus.de —> Esslingen / Stuttgart • Schulungen, Projekt-Kickoff • Consulting, Softwareentwicklung
  3. 3. Was ist dein Problem?
  4. 4. Probleme • Pflege und Weiterentwicklung alter Webanwendungen • Kunden verwöhnt von modernen Anwendungen
 —> wollen ähnliche Features • Entwickler genervt von alten Technologien • Zunehmend schwieriger Entwickler für alte Technologien zu finden
  5. 5. Beispiele Anforderungen • Autovervollständigung bei Suche • Schnelle Rückmeldung auf Eingaben / Validierung • Schnellere Reaktionszeiten der Anwendung • Website als Anwendung nicht als Website
  6. 6. Lösungsansatz • Neu Implementieren: Oft zu teuer und zu gefährlich • Bleibt nur: alte und neue Technologien verbinden
  7. 7. Architekturvergleich
  8. 8. Klassische Java Webanwendungen (JSP / JSF) ! • Rendering Template -> HTML geschieht auf dem Server • Zustand jedes Benutzers liegt auf dem Server 
 —> Skaliert schlecht • Komplette Page Requests pro Interaktion • JavaScript nur für kleine Aufgaben
  9. 9. Browser Servlet/Filter (Controller) JSP Pages (View) JavaBeans (Model) DB Server
  10. 10. JavaScript Apps • Client hat den Zustand und UI-Logik • Server hat keinen Zustand —> Bessere Skalierung • Server liefert • statische Ressourcen wie Templates und JavaScript Code • Daten via REST/JSON • Weniger Redundanz bei Übertragung
  11. 11. Controller (JS) View (HTML) Model (Json, Rest) REST API DB Server Client
  12. 12. Szenarien Nur Client Client + Server Rest Backend
  13. 13. Nur Client Szenario 1a
  14. 14. Ausgangssituation • Klassische Web-Anwendung z.B. mit Struts • Keine Änderungen an Server Architektur möglich • Server liefert weiterhin fertiges HTML
  15. 15. Lösungsansatz • Client per JavaScript erweitern • Direkte Interaktion bieten • HTML bzw. DOM nutzen • Höheres Level als jQuery
  16. 16. AngularJS • JavaScript-Framework zur Entwicklung von Rich Browser Applikationen • Bringt grundlegende UI Konzepte wie z.B. MVC in den Browser • Erweitert HTML anstatt zu abstrahieren • HTML kann nach den gegebenen Bedürfnissen erweitert werden
  17. 17. AngularJS • Eigentlich für Single-Page-Anwendungen gedacht • Leichtgewichtig, schnelle Initialisierung • Kann ruhig bei jedem Page-Reload geladen werden • JavaScript Code in Dateien auslagern -> Caching • Auch auf Teil des DOM anwendbar
  18. 18. Beispiel • Formular Validierung mit AngularJS • Server generiert HTML mit speziellen Attributen • AngularJS verwendet Attribute zum Validieren • Client zeigt Fehlermeldungen sofort an
 (mitgeliefert vom Server im HTML)
  19. 19. <div ng-app>! ! <form name="userForm" novalidate post="createUser.do">! ! <label for="userForm.email">E-Mail:</label>! ! <input type="email" id="userForm.email" ng-model="user.email" name="email" required>! <div ng-messages="userForm.email.$error">! <div ng-message="required">Please enter your email address</div>! <div ng-message="email">Please enter a valid email address</div>! </div>! ! ! <button type="submit" ng-disabled="userForm.$invalid"></button>! ! </form>! </div>!
  20. 20. Validatoren • Standard HTML Attribute • min, max, required • type mit email, date, time, number, url • AngularJS Attribute • ng-min-length und ng-max-length • ng-pattern • Eigene Validatoren per Attribut und JavaScript Code
  21. 21. Ajax mit DWR Szenario 1b
  22. 22. Ausgangssituation • Klassische Web-Anwendung z.B. mit Struts • Keine Änderungen an grundlegender Server Architektur möglich
  23. 23. Lösungsansatz • Server liefert weiterhin fertiges HTML • Beliebige JavaScript Frameworks oder VanillaJS im Client • Ajax Kommunikation mittels DWR
  24. 24. DWR • Servlet, dass Ajax-Requests verarbeitet • DWR erstellt JavaScript Stubs für Java Klassen und übernimmt Client - Server Kommunikation • Eine Art “Remote Procedure Call” • Spring / Guice / Struts Integration • http://directwebremoting.org/dwr/index.html
  25. 25. Beispiel • Dynamisches Anzeigen einer Liste • Klassisch: jeweils ein voller Page Request nötig • DWR Lösung: 1. AJAX Request zum Laden der Daten 2. JavaScript: Anzeige der Daten
  26. 26. Konfigurieren Auch per Annotations konfigurierbar <dwr> <!-- Nur Klassen in <allow> werden konvertiert --> <allow> <!-- Definieren der Klasse die freigegeben werden soll Erstellt wird die Klasse von Struts --> <create creator="struts" javascript="AjaxService"> <!-- auflisten der Methoden --> <include method="getAllElements"/> </create> </allow> </dwr>
  27. 27. Einbinden <script .. src="/lib/static/dwr/2.0/engine_and_util.min.js"/> <script .. src="/dwr/interface/AjaxService.js"/>
  28. 28. Benutzen Webbrowser Server /** * Java Script Code **/ AjaxService.getAllElements(populateList); ! function populateList(data) { //etwas mit den Daten machen console.log(data); } public List<String> getAllElements() { return elements; }
  29. 29. Client + Server Szenario 2a
  30. 30. Ausgangssituation • Klassische Web-Anwendung z.B. mit Struts • KEINE saubere Trennung zwischen Business-Logik und Web- Schnittstelle • Änderungen am Server in begrenztem Umfang möglich • Anwendung soll schrittweise erneuert werden
  31. 31. Lösungsansatz • Server liefert nur noch Daten und Templates (getrennt) • State kann im Server bleiben • AngularJS im Client setzt Daten und Templates zusammen
  32. 32. Probleme • Server ist eigentlich gedacht fertig gerenderte HTML-Seiten auszuliefern -> Hack ;) • Java Daten müssen serialisiert werden
  33. 33. Template & Daten • Laden der Seite in 2 Requests aufteilen • Normaler“ Struts Request liefert eine JSP Seite mit dem HTML Template und Code für AngularJS Anwendung • AngularJS Anwendung lädt dann die Daten als JSON über zusätzliche Requests vom Server
  34. 34. /* * Struts Action */ public ActionForward doExecute(...) throws Exception { final String acceptType = request.getHeader("Accept"); // Abfragen des Accept Types // 1. Call if (false == acceptType.startsWith("application/json")) { // JSP Seite zurückgeben. // Enthält die JavaScript Anwendung return mapping.findForward("template"); } // 2. Call else { // Daten erstellen und serialisieren final Object data = buildData(request, response, form); final String json = serializeData(data); request.setAttribute("jsonResponse", json); ! // antworten mit JSON return mapping.findForward("jsonResponse"); } }
  35. 35. https://code.google.com/p/google-gson/ /* * Beispiel: Daten mittels GSON zu JSON sterilisieren */ private String serializeData(final Object data) { final GsonBuilder builder = new GsonBuilder(); builder.serializeNulls(); final Gson gson = builder.create(); ! final String json = gson.toJson(data); ! return json; }
  36. 36. <!-- JsonResponse.jsp Minimale JSP Seite, in die das Json Eingebunden wird --> <%@ page contentType="application/json; charset=UTF-8" pageEncoding="UTF-8"%> ${jsonResponse}
  37. 37. <!-- JSP Seite mit AngularJS Anwendung -->! <script type="text/javascript">! angular.module("List", []);! ! angular.module('List').controller("ListCtrl", function ($scope) {! ! $scope.data = [];! ! $scope.search = function() {! var requestConfig = {! searchText: $scope.searchText! };! ! // Aufruf der Server REST Schnittstelle! $http.get('http://localhost/showData.do', requestConfig).then(function (response) {! // Verarbeitung der Daten! $scope.data = response.data;! });! };! ! $scope.search();! });! </script>
  38. 38. <div ng-app="List" ng-controller="ListCtrl">! <div class="header">! <input type="text" ng-model="searchText" placeholder="Full Text Search">! <button ng-click="search()">Search</button>! </div> ! ! <table>! <thead>! <tr>! <th ng-click="sortDataBy('name')">Name</th>! <th ng-click="sortDataBy('description')">Description</th>! </tr>! </thead>! <tbody>! <tr ng-repeat="entry in data">! <td><a ng-href="{{entry.link}}">{{entry.name}}</a></td>! <td>{{entry.description}}</td>! </tr>! </tbody>! </table>! </div>
  39. 39. Anwendungsfälle • Listen-Ansicht mit Sortierung, Filtern und Volltextsuche • Detail Ansicht mit dynamischem Nachladen von Daten (z.B. in Tabs oder Popups) • Mini-Single-Page-App auf einer Unterseite (CRUD)
  40. 40. Client + sauberer Server Szenario 2b
  41. 41. Ausgangssituation • Klassische Web-Anwendung mit z.B. Struts • Saubere Trennung zwischen Business-Logik und Web-Schnittstelle • Änderungen am Server in begrenztem Umfang möglich
  42. 42. Lösungsansätze • Ersetzen der Web-Schnittstelle durch REST API • Ausliefern der Templates als statisches HTML • Client wird wieder mit AngularJS umgesetzt
  43. 43. REST (Jersey) https://jersey.java.net/ /** * wird unter dem Pfad "resource" bereitgestellt */ @Path("resource") public class Resource { /** * * Methode verarbeitet HTTP GET requests. * Das Resultat wird als "text/plain" gesendet */ @GET @Produces(MediaType.TEXT_PLAIN) public String getIt() { return "Got it!"; } }
  44. 44. REST Backend Szenario 3
  45. 45. Ausgangssituation • Etwas modernere Web-Anwendung • REST Backend • Flex Client
  46. 46. Lösungsansatz • Client schrittweise portieren • Flex Anwendung anpassen und in neues HTML Grundgerüst integrieren • Flex nur bei Bedarf anzeigen • Kommunikation Flex <-> JavaScript
  47. 47. Probleme • Flash —> display: none —> display: block —> neue Initialisierung • JS Code ruft ActionScript zu früh auf • ActionScript ruft JS Code auf —> global, kein Angular Kontext
  48. 48. Lösung: w11k-flash • Open Source • Github: http://github.com/w11k/w11k-flash • Blog Artikel mit ausführlicher Erklärung:
 http://blog.thecodecampus.de/migration-von-flex-zu-angularjs
  49. 49. <div ng-controller="TestCtrl">! <div w11k-flash="flash.config"! w11k-select-visible="flash.visible"! >! </div>! </div>
  50. 50. angular.module('app').controller('TestCtrl', function ($scope) {! $scope.flash = {! config: {! swfUrl: 'assets/test.swf',! callback: function (readyPromise) {! $scope.flash.ready = readyPromise;! }! }! };! ! $scope.talkToMe = function (message) {! $scope.message = message;! $scope.response = 'Hello! My name is AngularJS.';! return $scope.response;! };! ! $scope.talkToFlex = function () {! if (angular.isDefined($scope.flash.ready)) {! $scope.flash.ready.then(function (flash) {! $scope.message = 'Hello! My name is AngularJS. What is your name?';! $scope.response = flash.talkToMe($scope.message);! });! }! };! });!
  51. 51. protected function application_creationCompleteHandler(event:FlexEvent) :void {! this.angularjs = AngularJSAdapter.getInstance();! ! // initialize flex application! this.currentState = defaultState.name;! ExternalInterface.addCallback("talkToMe", talkToMe);! ! this.angularjs.fireFlashReady();! }! ! protected function talkToMe(message :String) :String {! this.message = message;! response = 'Hello! My name is Flex.';! return response;! }! ! protected function talkToAngularJS() :void {! message = 'Hello! My name is Flex. What is your name?';! response = this.angularjs.call('talkToMe(message)', { message: message });! }
  52. 52. Fazit
  53. 53. Herausforderungen • Transaktionen, da asynchrone Kommunikation • Sicherheit: Client vs. Server • Validierung: Client + Server • Integration in bestehendes Build System • Sehr viele Technologien = Polyglott
  54. 54. Aber • Macht Spaß • Meist schnell und recht einfach möglich • Produktivitätsschub für neue Features • Generiert beim Kunden Lust auf mehr
  55. 55. Legacy Web-Apps mit AngularJS pimpen
  56. 56. Jan Blankenhorn blankenhorn@w11k.com ! Philipp Burgmer burgmer@w11k.com ! github.com/w11k blog.thecodecampus.de

×