Andreas Hubmer/Markus Popp | Cenarion

GWT: Eintauchen in MVP und
Internationalisierung
•
•
•
•

Enterprise-Applikationen
Versicherungsbranche
Java
3 Jahre GWT

2
Ablauf
• MVP
– GWT & MVP
– Activities/Places

• Internationalisierung
• Client-Performance

3
MVP = Model View Presenter
Model View Presenter
• 1996
• Verwandt mit MVC
• Ziele
– Verantwortlichkeiten trennen
– Flexibilität von UIs bei Änderunge...
MVC - MVP
Model

Model

Presenter
Controller

View
View
6
Fragen
Data

UI

How do I manage
my data?

How does the user
interact with my data?

7
Data
What is my data?

8
Data
What is my data?

How do I specify my data?

9
Data
What is my data?

How do I specify my data?
How do I change my data?

10
UI
How do I display my data?

11
UI
How do I display my data?

How do events map into changes in my
data?

12
UI
How do I display my data?

How do events map into changes in my
data?
How do I put it all together?

13
How do I partition my application between
client and server?

Security

14
Vorteile von MVP
• Trennung von Model und View
→ mehr Flexibilität

• Ein Model – mehrere Views
• Testbarkeit
• Undo/Redo
...
MVP in GWT
Model

Datenanbindung,
Businesstransaktionen
Server

Client

Presenter

View

View mit Daten füttern,
Applikati...
Display-Logik vs.
Applikationslogik

Unit-Test → Applikationslogik
17
Warum MVP in GWT?
• Arbeitsteilung
– Lose Kopplung UI – Logik
– Struktur erleichtert Orientierung

• Testbarkeit

18
Warum MVP in GWT?
• Arbeitsteilung
• Testbarkeit
– UI-Komponenten in GWT:
• Schwer testbar
• Tests langsam

– Abgrenzung A...
Activities & Places
• Browser-History
• URL-Fragment = Place
– .../index.html#SearchPlace!bmw!pkw

• Place repräsentiert S...
State
Place

Session

Primitive Werte
Objekt-Ids

Authentifizierung
Sprache

21
Presenter = Activity
Place

initialisiert

Hält State für

Presenter
(Activity)
Model

aktualisiert

View

Kommuniziert

2...
Beispiel: Suche

23
Beispiel: SearchView.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM
"http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="...
Beispiel: SearchView
public class SearchView extends Composite {
@UiField TextBox vehicleId, brand;
@UiField ListBox type;...
Beispiel: Presenter
private DamagedVehicleRequest request;
private SearchView view;
public void searchOkClicked(String vin...
Klassen/Dateien
SearchPlace

Place

ActivityMapper

SearchPresenter

AbstractActivity

ClientFactory

SearchView

Composit...
Interfaces?

SearchPresenter

ISearchPresenter

SearchView

ISearchView

28
Testbarkeit?

29
Beispiel: Presenter
private DamagedVehicleRequest request;
private SearchView view;
public void searchOkClicked(String vin...
Beispiel: Presenter-Test
private SearchPresenter presenter;
private DamagedVehicleRequest request;
private SearchView view...
Beispiel: Presenter-Test
@Test
public void testSearch() {
presenter.searchOkClicked("", "bmw", "pkw");
Mockito.verify(requ...
GWTTestCase
• Für natives Javascript
• Langsam (HtmlUnit-Startup)
• Simulation von Usereingaben nicht
trivial
• JUnit 3

3...
Fragen zu MVP?

34
Eitrige
mit Buckel
und 16er Blech

35
messages_de_at.properties
sausage=Eitrige
breadEnd=Buckel
beer=16er Blech

messages_de_de.properties
sausage=Käsekrainer
b...
Internationalisierung
Internationalisierung
• .properties-Dateien
greeting = Hallo!

• Platzhalter für Parameter
greeting = Hallo {0}!

• UTF-8
...
Static String Internationalization
• Auflösung vom Compiler
– statische Werte in den generierten Dateien

• Überprüfungen ...
Permutationen
Englisch

Deutsch

Firefox

Internet
Explorer

FF
en

FF
de

IE
en

IE
de
40
Interfaces
greeting = Grüß euch! ☺
public interface UIMessages extends Messages {

String greeting();
}
UIMessages msgs = ...
Interfaces
gwtsample.greeting = Grüß euch! ☺
public interface UIMessages extends Messages {
@Key("gwtsample.greeting")
Str...
Constants Interface
• Konstanten ohne Parameter
• Typisierung der Konstanten
– Primitive Datentypen
– Strings
– String-Arr...
Constants Beispiel
digitsAfterDecimalPoint = 2
public interface UIConstants extends Constants {
@DefaultIntValue(3)
int di...
Messages Interface
• Parameter in Texten
• Rückgabewert String
permissionDenied = Error {0}: User {1} does not have
permis...
Messages Interface
• Parameter in Texten
• Rückgabewert String
permissionDenied = Error {0}: User {1} does not have
permis...
Messages ausgeben
• Java Code
ErrorMessages errorMsgs =
GWT.create(ErrorMessages.class);
Label errorLabel = new Label();
e...
Beispiel: Suche

48
Beispiel: SearchView.ui.xml
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user...
Beispiel: SearchView.ui.xml
<ui:with field="msgs" type="com.cenarion.client.UIMessages" />
<ui:UiBinder xmlns:ui="urn:ui:c...
Messages Features
•
•
•
•

Formatierung von Parametern
Pluralformen
Select Forms
HTML in den lokalisierten Texten

51
Formatierung
• Java-MessageFormat
• Bsp. Datumsformat
@DefaultMessage("{0,date,medium}")
String formatDate(Date date);

52
Pluralformen
• Deutsch/Englisch
– 1 Produkt (n=1)
– 2 Produkte (n=0, n>1)

• Französisch
– 0/1 produit (n=0, n=1)
– 2 prod...
Pluralformen Beispiel
products[one] = {0} Produkt
products = {0} Produkte

public interface I18nUIMessages extends Message...
Pluralformen Beispiel
products[one] = {0} Produkt
products = {0} Produkte

0 Produkte
1 Produkt
2 Produkte

products[one] ...
Select Forms
title[MALE] = Sehr geehrter Herr {0}!
title[FEMALE] = Sehr geehrte Frau {0}!
title = Sehr geehrte Damen und H...
HTML in Texten
greeting = Hallo <b>{0}</b>!
public interface I18nUIMessages extends Messages {
String greeting(String name...
SafeHtml
• Vermeiden von XSS
• Wrapper für Strings
– vertrauenswürdiges HTML-Markup
public interface SafeHtml extends Seri...
HTML in Texten
greeting = Hallo <b>{0}</b>!
public interface I18nUIMessages extends Messages {
SafeHtml greeting(String na...
Grenzen clientseitiger I18N
• Daten die vom Server kommen
– Werte aus einer Datenbank
– Serverseitige Validierungsfehler

...
Fragen zur I18N?

61
Client-Performance
Client-Performance

63
Client-Performance
• JavaScript
• IE8 
• GWT-Compiler: -style OBF/PRETTY

64
Repeating Commands
• Problem: Ausführungszeit und
#Statements
• Lösung: Pausen einlegen
Long-Running Task

Browser-Event-L...
Repeating Commands
List<Case> caseList = …
for (Case case : caseList) {
checkAndShow(case);
}

66
Repeating Commands
List<Case> caseList = …
final Iterator<T> caseIterator = caseList.iterator();
Scheduler.get().scheduleI...
Repeating Commands
Init
Init

Long-Running Task
RC

RC

Finish

RC

RC

RC

RC

RC

RC

Finish

Ausführungsreihenfolge:
In...
Server-Antwort parsen
• Problem: Große Antwort → Viel Zeit
• Lösung: Daten reduzieren
– Stück für Stück
– Encoding von Lis...
Encoding von Listen
• Beispiel: Postleitzahlen
class Plz { String plz; String name; }

• List<Plz>: 650KB
• List<String>: ...
Encoding von Listen
• List<Plz>

• List<String>

[ {"O": 2,
"D": {"plz": "4020",
"name": "Linz"}},
{"O": 1,
"D": {"plz": "...
Code-Splitting
• Problem: Startup-Zeit
• Lösung: JS-Code splitten
– Beispiel: UIs für spezielle Benutzergruppen
– GWT.runA...
Zusammenfassung
• MVP

• Internationalisierung

• Client-Performance
andreas.hubmer@cenarion.com
markus.popp@cenarion.com

http://www.cenarion.com/techblog
Upcoming SlideShare
Loading in …5
×

GWT: Eintauchen in MVP und Internationalisierung

2,364 views

Published on

Das Model-View-Presenter-Pattern (MVP) wurde von Google für GWT empfohlen. Es schreibt eine strenge Trennung von View und Presenter vor, die vor allem der Testbarkeit dient. Dieser Vorteil kann auch mit GWT genützt werden, um Logik im Presenter in schnellen Unit-Tests zu überprüfen. Activities und Places helfen in GWT-Applikationen die Browser-History zu verwenden, hängen aber nicht zwingend mit MVP zusammen, wie im Vortrag gezeigt wird.
Zur Internationalisierung von Anwendungen bietet GWT schnelle, typsichere Konzepte. Es wird ein praxisorientierter Einblick gegeben und auf Stolpersteine hingewiesen.
Außerdem wird im Vortrag gezeigt, wie Performance-Probleme des generierten JavaScript-Codes umgangen werden können.

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,364
On SlideShare
0
From Embeds
0
Number of Embeds
1,058
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

GWT: Eintauchen in MVP und Internationalisierung

  1. 1. Andreas Hubmer/Markus Popp | Cenarion GWT: Eintauchen in MVP und Internationalisierung
  2. 2. • • • • Enterprise-Applikationen Versicherungsbranche Java 3 Jahre GWT 2
  3. 3. Ablauf • MVP – GWT & MVP – Activities/Places • Internationalisierung • Client-Performance 3
  4. 4. MVP = Model View Presenter
  5. 5. Model View Presenter • 1996 • Verwandt mit MVC • Ziele – Verantwortlichkeiten trennen – Flexibilität von UIs bei Änderungen des Models erhöhen 5
  6. 6. MVC - MVP Model Model Presenter Controller View View 6
  7. 7. Fragen Data UI How do I manage my data? How does the user interact with my data? 7
  8. 8. Data What is my data? 8
  9. 9. Data What is my data? How do I specify my data? 9
  10. 10. Data What is my data? How do I specify my data? How do I change my data? 10
  11. 11. UI How do I display my data? 11
  12. 12. UI How do I display my data? How do events map into changes in my data? 12
  13. 13. UI How do I display my data? How do events map into changes in my data? How do I put it all together? 13
  14. 14. How do I partition my application between client and server? Security 14
  15. 15. Vorteile von MVP • Trennung von Model und View → mehr Flexibilität • Ein Model – mehrere Views • Testbarkeit • Undo/Redo 15
  16. 16. MVP in GWT Model Datenanbindung, Businesstransaktionen Server Client Presenter View View mit Daten füttern, Applikationslogik UI-Widgets, I18n, Event-Handling, Display-Logik 16
  17. 17. Display-Logik vs. Applikationslogik Unit-Test → Applikationslogik 17
  18. 18. Warum MVP in GWT? • Arbeitsteilung – Lose Kopplung UI – Logik – Struktur erleichtert Orientierung • Testbarkeit 18
  19. 19. Warum MVP in GWT? • Arbeitsteilung • Testbarkeit – UI-Komponenten in GWT: • Schwer testbar • Tests langsam – Abgrenzung Applikations-Logik von Display-Logik! 19
  20. 20. Activities & Places • Browser-History • URL-Fragment = Place – .../index.html#SearchPlace!bmw!pkw • Place repräsentiert State • Activity – Daten laden & UI initialisieren – Kommunikation mit Serverseite 20
  21. 21. State Place Session Primitive Werte Objekt-Ids Authentifizierung Sprache 21
  22. 22. Presenter = Activity Place initialisiert Hält State für Presenter (Activity) Model aktualisiert View Kommuniziert 22
  23. 23. Beispiel: Suche 23
  24. 24. Beispiel: SearchView.ui.xml <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <g:Label text="Beschädigtes Fahrzeug Suche" /> <g:Label text="Fahrgestell-Nr." horizontalAlignment="ALIGN_RIGHT" /> <g:TextBox ui:field="vehicleId" /> <g:Label text="Marke" /> <g:TextBox ui:field="brand" /> <g:Label text="Fahrzeugtyp"/> <g:ListBox ui:field="type" /> <g:Button text="OK" /> <g:Button text="Zurücksetzen" /> <g:VerticalPanel ui:field="tblSearchResults" /> </ui:UiBinder> 24
  25. 25. Beispiel: SearchView public class SearchView extends Composite { @UiField TextBox vehicleId, brand; @UiField ListBox type; private SearchPresenter presenter; @UiHandler("btnOk") public void onOkClick(ClickEvent event) { presenter.searchOkClicked( vehicleId.getText(), brand.getText(), type.getValue()); } } 25
  26. 26. Beispiel: Presenter private DamagedVehicleRequest request; private SearchView view; public void searchOkClicked(String vin, String brand, String type) { if (! validVehicleId(vin)) view.setErrorText("Fehlermeldung …"); else request.search(vin, brand, type). fire(new Receiver …); } 26
  27. 27. Klassen/Dateien SearchPlace Place ActivityMapper SearchPresenter AbstractActivity ClientFactory SearchView Composite UiBinder SearchView.ui.xml 27
  28. 28. Interfaces? SearchPresenter ISearchPresenter SearchView ISearchView 28
  29. 29. Testbarkeit? 29
  30. 30. Beispiel: Presenter private DamagedVehicleRequest request; private SearchView view; public void searchOkClicked(String vin, String brand, String type) { if (! validVehicleId(vin)) view.setErrorText("Fehlermeldung …"); else request.search(vin, brand, type). fire(new Receiver …); } 30
  31. 31. Beispiel: Presenter-Test private SearchPresenter presenter; private DamagedVehicleRequest request; private SearchView view; @Before public void setup() { view = Mockito.mock(SearchView.class); request = Mockito.mock(DamagedVehicleRequest.class); presenter = new SearchPresenter(view, request, …); } 31
  32. 32. Beispiel: Presenter-Test @Test public void testSearch() { presenter.searchOkClicked("", "bmw", "pkw"); Mockito.verify(request).search("", "bmw", "pkw"); } @Test public void testSearchInvalidVin() { presenter.searchOkClicked("1", "bmw", "pkw"); Mockito.verify(view).setErrorText("Fehlermeldung …"); Mockito.verifyZeroInteractions(request); } 32
  33. 33. GWTTestCase • Für natives Javascript • Langsam (HtmlUnit-Startup) • Simulation von Usereingaben nicht trivial • JUnit 3 33
  34. 34. Fragen zu MVP? 34
  35. 35. Eitrige mit Buckel und 16er Blech 35
  36. 36. messages_de_at.properties sausage=Eitrige breadEnd=Buckel beer=16er Blech messages_de_de.properties sausage=Käsekrainer breadEnd=Brotendstück beer=Ottakringer 36
  37. 37. Internationalisierung
  38. 38. Internationalisierung • .properties-Dateien greeting = Hallo! • Platzhalter für Parameter greeting = Hallo {0}! • UTF-8 greeting = Grüß euch! ☺ 38
  39. 39. Static String Internationalization • Auflösung vom Compiler – statische Werte in den generierten Dateien • Überprüfungen vom Compiler • Typisierung durch Interfaces 39
  40. 40. Permutationen Englisch Deutsch Firefox Internet Explorer FF en FF de IE en IE de 40
  41. 41. Interfaces greeting = Grüß euch! ☺ public interface UIMessages extends Messages { String greeting(); } UIMessages msgs = GWT.create(UIMessages.class); String text = msgs.greeting(); 41
  42. 42. Interfaces gwtsample.greeting = Grüß euch! ☺ public interface UIMessages extends Messages { @Key("gwtsample.greeting") String greeting(); } UIMessages msgs = GWT.create(UIMessages.class); String text = msgs.greeting(); • Constants Interface • Messages Interface 42
  43. 43. Constants Interface • Konstanten ohne Parameter • Typisierung der Konstanten – Primitive Datentypen – Strings – String-Arrays – String-Maps 43
  44. 44. Constants Beispiel digitsAfterDecimalPoint = 2 public interface UIConstants extends Constants { @DefaultIntValue(3) int digitsAfterDecimalPoint(); } UIConstants constants = GWT.create(UIConstants.class); int digits = constants.digitsAfterDecimalPoint(); 44
  45. 45. Messages Interface • Parameter in Texten • Rückgabewert String permissionDenied = Error {0}: User {1} does not have permission to access {2} public interface ErrorMessages extends Messages { String permissionDenied(int errorCode, String username, String resourceName); } 45
  46. 46. Messages Interface • Parameter in Texten • Rückgabewert String permissionDenied = Error {0}: User {1} does not have permission to access {2} Kompilierfehler public interface ErrorMessages extends Messages { String permissionDenied(int errorCode, String username); } 46
  47. 47. Messages ausgeben • Java Code ErrorMessages errorMsgs = GWT.create(ErrorMessages.class); Label errorLabel = new Label(); errorLabel.setText(errorMsgs.permissionDenied( 550, "username", "file.txt")); • UIBinder XML 47
  48. 48. Beispiel: Suche 48
  49. 49. Beispiel: SearchView.ui.xml <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <g:Label text="Beschädigtes Fahrzeug Suche" /> <g:Label text="Fahrgestell-Nr." /> <g:TextBox ui:field="vehicleId" /> <g:Label text="Marke" /> <g:TextBox ui:field="brand" /> <g:Label text="Fahrzeugtyp" /> <g:ListBox ui:field="type" /> <g:Button text="OK" /> <g:Button text="Zurücksetzen" /> <g:VerticalPanel ui:field="tblSearchResults" /> </ui:UiBinder> 49
  50. 50. Beispiel: SearchView.ui.xml <ui:with field="msgs" type="com.cenarion.client.UIMessages" /> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <g:Label text="{msgs.damagedVehicleSearch}" /> <g:Label text="{msgs.vehicleIdNo}" /> <g:TextBox ui:field="vehicleId" /> <g:Label text="{msgs.brand}" /> <g:TextBox ui:field="brand" /> <g:Label text="{msgs.type}" /> <g:ListBox ui:field="type" /> <g:Button text="{msgs.ok}" /> <g:Button text="{msgs.reset}" /> <g:VerticalPanel ui:field="tblSearchResults" /> </ui:UiBinder> 50
  51. 51. Messages Features • • • • Formatierung von Parametern Pluralformen Select Forms HTML in den lokalisierten Texten 51
  52. 52. Formatierung • Java-MessageFormat • Bsp. Datumsformat @DefaultMessage("{0,date,medium}") String formatDate(Date date); 52
  53. 53. Pluralformen • Deutsch/Englisch – 1 Produkt (n=1) – 2 Produkte (n=0, n>1) • Französisch – 0/1 produit (n=0, n=1) – 2 produits (n>1) • Arabisch: 0, 1, 2, wenige, viele 53
  54. 54. Pluralformen Beispiel products[one] = {0} Produkt products = {0} Produkte public interface I18nUIMessages extends Messages { String products(@PluralCount int numProducts); } I18nUIMessages messages = GWT.create(I18nUIMessages.class); lblProducts0.setText(messages.products(0)); lblProducts1.setText(messages.products(1)); lblProducts2.setText(messages.products(2)); 54
  55. 55. Pluralformen Beispiel products[one] = {0} Produkt products = {0} Produkte 0 Produkte 1 Produkt 2 Produkte products[one] = {0} produit products = {0} produits 0 produit 1 produit 2 produits 55
  56. 56. Select Forms title[MALE] = Sehr geehrter Herr {0}! title[FEMALE] = Sehr geehrte Frau {0}! title = Sehr geehrte Damen und Herren! public enum Gender { MALE, FEMALE, UNKNOWN } public interface I18nUIMessages extends Messages { String title(String name, @Select Gender gender); } msgs.title("Max Mustermann", Gender.MALE); Sehr geehrter Herr Max Mustermann! 56
  57. 57. HTML in Texten greeting = Hallo <b>{0}</b>! public interface I18nUIMessages extends Messages { String greeting(String name); } String name = "<i>XSS-Attacke</i>"; htmlGreeting.setHTML(messages.greeting(name)); Hallo XSS-Attacke! 57
  58. 58. SafeHtml • Vermeiden von XSS • Wrapper für Strings – vertrauenswürdiges HTML-Markup public interface SafeHtml extends Serializable { String asString(); } • Zusätzliche Typsicherheit 58
  59. 59. HTML in Texten greeting = Hallo <b>{0}</b>! public interface I18nUIMessages extends Messages { SafeHtml greeting(String name); } String name = "<i>XSS-Attacke</i>"; htmlGreeting.setHTML(messages.greeting(name)); Hallo <i>XSS-Attacke</i>! 59
  60. 60. Grenzen clientseitiger I18N • Daten die vom Server kommen – Werte aus einer Datenbank – Serverseitige Validierungsfehler 60
  61. 61. Fragen zur I18N? 61
  62. 62. Client-Performance
  63. 63. Client-Performance 63
  64. 64. Client-Performance • JavaScript • IE8  • GWT-Compiler: -style OBF/PRETTY 64
  65. 65. Repeating Commands • Problem: Ausführungszeit und #Statements • Lösung: Pausen einlegen Long-Running Task Browser-Event-Loop 65
  66. 66. Repeating Commands List<Case> caseList = … for (Case case : caseList) { checkAndShow(case); } 66
  67. 67. Repeating Commands List<Case> caseList = … final Iterator<T> caseIterator = caseList.iterator(); Scheduler.get().scheduleIncremental(new RepeatingCommand() { @Override public boolean execute() { int counter = 0; while (caseIterator.hasNext()) { if (counter++ == 50) return true; // execute again checkAndShow(caseIterator.next()); } return false; } }); 67
  68. 68. Repeating Commands Init Init Long-Running Task RC RC Finish RC RC RC RC RC RC Finish Ausführungsreihenfolge: Init Finish RC RC Scheduler.scheduleIncremental 68
  69. 69. Server-Antwort parsen • Problem: Große Antwort → Viel Zeit • Lösung: Daten reduzieren – Stück für Stück – Encoding von Listen 69
  70. 70. Encoding von Listen • Beispiel: Postleitzahlen class Plz { String plz; String name; } • List<Plz>: 650KB • List<String>: 50KB String plzString = plz + " " + name; 70
  71. 71. Encoding von Listen • List<Plz> • List<String> [ {"O": 2, "D": {"plz": "4020", "name": "Linz"}}, {"O": 1, "D": {"plz": "1040", "name": "Wien"}}, … ], [ {"O": 1}, {"O": 2}, … ] [], [ "1040 Wien", "4020 Linz", … ] 71
  72. 72. Code-Splitting • Problem: Startup-Zeit • Lösung: JS-Code splitten – Beispiel: UIs für spezielle Benutzergruppen – GWT.runAsync( new RunAsyncCallback(…)) 72
  73. 73. Zusammenfassung • MVP • Internationalisierung • Client-Performance
  74. 74. andreas.hubmer@cenarion.com markus.popp@cenarion.com http://www.cenarion.com/techblog

×