Songs of Vaadin
Vaadin to demon pochodzący z fińskiej mitologii. Ma on postać renifera górskiego – boga przodka. Tyle tytułem wstępu.
Vaadin to też bardzo fajny framework UI oparty o GWT. Ważne słowo „opartu o” nie jest to nakładka na GWT, która tylko dostarcza komponentów, ale jest to całkowicie nowy pomysł, który zawiera to czego brakuje w GWT.
Jak dzielimy narzędzia
Pisząc aplikację zazwyczaj posiłkujemy się specjalnymi bibliotekami, zawierającymi różne komponenty, jak i gotowe rozwiązania pozwalające tworzyć aplikacje. Biblioteki te co do zasady nazywamy frameworkami. Nie jest to do końca słuszne dla wszystkich rozwiązań.
Frameworki to biblioteki takie jak np. Spring, które pozwalają na tworzenie aplikacji, ale pomimo najlepszych chęci twórców końcowy wynik jest silnie zintegrowany z frameworkiem. Można to porównać do obudowywania szkieletu naszą tkanką. Bez szkieletu wszystko się posypie.
Rusztowania to biblioteki wspomagające tworzenie aplikacji np. Grails, które po zakończeniu można w znacznej mierze usunąć z finalnego projektu i nie będzie to nas bolało. Zazwyczaj jedynym elementem wymaganym jest niewielka biblioteka dostarczająca klasy narzędziowe, ale można też obyć się bez niej.
GWT należy do trzeciej grupy. Nazywam ją „składem budowlanym a’la ikea”. W ramach biblioteki dostajemy stertę cegieł, desek, kilka worków cementu oraz instrukcję jak to wszystko można łączyć. Przypomina to wielkie pudło klocków Lego, z których możemy wybudować co nam się podoba. Niestety w IT oznacza to, że każdą trochę bardziej zaawansowaną funkcjonalność trzeba machać ręcznie lub szukać bibliotek.
Wady GWT
Najpoważniejszą wadą GWT jest jednak nieuwolnienie programistów od konieczności korzystania z elementów powiązanych z webem. Nadal musimy rzeźbić plik web.xml, nadal trzeba uważać co i jak przekazujemy do klienta. Do tego musimy użerać się z niekompatybilnością bibliotek. Na całe szczęście duża część kodu jest otwarta i można sobie poprawić to i owo.
Kolejną wadą jest kompilator Java2JavaScript. Gdy pojawił się na rynku to wszyscy byli nim zauroczeni. Pozwalał na uwolnienie się od grzebania w dziwnym języku jakim jest JS i przeniesienie zadań związanych z budową UI na programistów. Ci mając doświadczenie ze Swingiem mogli w naturalny sposób tworzyć interfejs użytkownika. Niestety szybko okazało się, że swoboda tworzenia jest mocno ograniczona. Nadal istniała separacja pomiędzy klientem i serwerem, najlepiej widoczna w postaci nazewnictwa pakietów. Do tego kompilator nie potrafił poradzić sobie z przeniesieniem wszystkich klas ze standardowego API Javy do przeglądarki. Dlaczego nie można było używać Calendar, a musieliśmy użerać się z Date? Czemu nie przeniesiono wszystkich wyjątków? Powodowało to konieczność namnażania bytów w ramach wzorców Value Object i DTO i to nie dla jakiś super skomplikowanych obiektów, ale dla standardowych elementów języka.
Gdzie jest Vaadin?
Vaadin jest oparty o GWT. Wykorzystuje tą bibliotekę ponieważ jest ona świetna do generowania elementów UI. Pozwala też na wykorzystanie już gotowych widgetów GWT w projekcie. Jeżeli jednak nie chcemy mieć nic wspólnego z GWT to nie zobaczymy ani linijki jego kodu.
Co to oznacza? Vaadin jest znacznie lepszym odpowiednikiem Swinga niż GWT. Separacja pomiędzy UI, a logiką jest bardziej naturalna, bliższa znanemu z okienek sposobowi zarządzania przepływem.
Prosta aplikacja
Przykładowa aplikacja będzie demonstrować główne założenie Vaadin, czyli zdjęcie z barków programisty konieczności dbania o plik web.xml. Zrobimy bardzo prostą rzecz. Formularz z jednym polem, którego zawartość będzie zapisywana do logu po stronie serwera.
Zaczniemy od wygenerowania prostego projektu Vaadin za pomocą Mavena. Jest to bardzo proste. Twórcy dostarczyli nawet klika różnych archetypów. Różnią się one szczegółami, ale na obecnym etapie nie jest to istotne. Użyję vaadin-archetype-clean. Poniżej skrypcik ułatwiający to zadanie. Pierwszy parametr grupa, drugi nazwa artefaktu.
Listing 1. Tworzenie aplikacji Vaadin – skrypt
#!/bin/bash
mvn archetype:generate -DarchetypeGroupId=com.vaadin -DarchetypeArtifactId=vaadin-archetype-clean -DarchetypeVersion=LATEST -DgroupId="$1" -DartifactId="$2" -Dversion=1.0 -Dpackaging=war
Po zaimportowaniu projektu do IDE mamy możliwość popatrzenia na plik pom.xml. Mój zawiera dodatkowe wpisy związane z JPA. Racz je zignorować.
Listing 2. Plik pom.xml
<?xml version="1.0" encoding="UTF-8"??><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelversion>4.0.0</modelversion><groupid>pl.koziolekweb.blog.vaadin</groupid><artifactid>first-vaadin-example</artifactid><packaging>war</packaging><version>1.0</version><name>Vaadin Web Application</name><properties><project.build.sourceencoding>UTF-8</project.build.sourceencoding></properties><build><plugins><plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-compiler-plugin</artifactid><configuration><source>1.5</source><target>1.5</target></configuration></plugin><plugin><groupid>org.mortbay.jetty</groupid><artifactid>maven-jetty-plugin</artifactid><version>6.1.19</version><configuration><systemproperties><systemproperty><name>jetty.port</name><value>23030</value></systemproperty></systemproperties><stopport>9966</stopport><stopkey>first-vaadin-example</stopkey><scanintervalseconds>0</scanintervalseconds><webappconfig><contextpath>/first-vaadin-example</contextpath><baseresource implementation="org.mortbay.resource.ResourceCollection"><resourcesascsv>src/main/webapp,${project.build.directory}/${project.build.finalName}
</resourcesascsv></baseresource></webappconfig></configuration></plugin><plugin><groupid>org.apache.maven.plugins</groupid><artifactid>maven-eclipse-plugin</artifactid><version>2.8</version><configuration><downloadjavadocs>true</downloadjavadocs><downloadsources>true</downloadsources></configuration><executions><execution><id>eclipse</id><phase>clean</phase><goals><goal>clean</goal><goal>eclipse</goal></goals></execution></executions></plugin></plugins></build><repositories><repository><id>vaadin-snapshots</id><url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/
</url><releases><enabled>false</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository><repository><id>jboss</id><url>http://repository.jboss.org/maven2</url></repository></repositories><dependencies><dependency><groupid>com.vaadin</groupid><artifactid>vaadin</artifactid><version>6.2.0</version></dependency><dependency><groupid>hibernate</groupid><artifactid>hibernate3</artifactid><version>3.2.4.SP1</version></dependency><dependency><groupid>hibernate-annotations</groupid><artifactid>hibernate-annotations</artifactid><version>3.3.0.GA</version></dependency><dependency><groupid>hibernate-commons-annotations</groupid><artifactid>hibernate-commons-annotations</artifactid><version>3.0.0.GA</version></dependency><dependency><groupid>hibernate-entitymanager</groupid><artifactid>hibernate-entitymanager</artifactid><version>3.3.1.GA</version></dependency><dependency><groupid>javax.persistence</groupid><artifactid>persistence-api</artifactid><version>1.0</version></dependency><dependency><groupid>javax.transaction</groupid><artifactid>jta</artifactid><version>1.1</version></dependency><dependency><groupid>hsqldb</groupid><artifactid>hsqldb</artifactid><version>1.8.0.10</version></dependency></dependencies></project>
Na koniec jeszcze plik aplikacji.
Listing 3. Aplikacja Vaadin
/*
* Copyright 2009 IT Mill Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package pl.koziolekweb.blog.vaadin;
import com.vaadin.Application;
import com.vaadin.ui.Button;
import com.vaadin.ui.Window;
/**
* The Application's "main" class
*/
@SuppressWarnings("serial")
public class MyVaadinApplication extends Application
{
private Window window;
@Override
public void init()
{
window = new Window("My Vaadin Application");
setMainWindow(window);
window.addComponent(new Button("Click Me"));
}
}
Odpalamy jettego w celach testowych. Domyślnie na porcie 8080 u mnie na 23030, bo na 8080 mam Tomcata. Sprawdzamy działa.
Teraz czas na nasz formularz. Vaadin dostarcza własny zestaw komponentów. Mają własną hierarchię, ale jak przejdziemy do kodu źródłowego to zobaczymy, że wykorzystywane są komponenty GWT. Dla własnego zdrowia psychicznego nie wnikajmy jednak jak Vaadin robi swoją magię. Ważne, że działa.
Nowa wersja klasy:
Listing 4. Wysyłamy informację
/*
* Copyright 2009 IT Mill Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package pl.koziolekweb.blog.vaadin;
import com.vaadin.Application;
import com.vaadin.ui.Button;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
/**
* The Application's "main" class
*/
public class MyVaadinApplication extends Application {
private static final long serialVersionUID = 1L;
private Window window;
@Override
public void init() {
window = new Window("My Vaadin Application");
setMainWindow(window);
final TextField messageTfd = new TextField("Message");
messageTfd.setColumns(25);
Button sendBtn = new Button("Click Me");
sendBtn.addListener(new ClickListener() {
private static final long serialVersionUID = 1L;
public void buttonClick(ClickEvent event) {
System.out.println(messageTfd.getValue());
}
});
window.addComponent(messageTfd);
window.addComponent(sendBtn);
}
}
Wygląda niewinnie. Odpalamy jettego wpisujemy wiadomość, klikamy i…
Listing 5. Zawartość logu
[INFO] Started Jetty Server
=================================================================
Vaadin is running in DEBUG MODE.
Add productionMode=true to web.xml to disable debug features.
To show debug window, add ?debug to your application URL.
=================================================================
Wiadomość
Działa!!!
Wow! Nie napisałem ani linijki jeśli chodzi o komunikację. Nie otworzyłem nawet pliku web.xml, a mam możliwość logowania informacji na serwer. Prawda, że bajer? Teraz czas na najbardziej widowiskowy bajer Vaadin. Nie będę opisywał co i jak, ale chyba załapiecie o co w tym chodzi:
Listing 6. Magia 😉
/*
* Copyright 2009 IT Mill Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package pl.koziolekweb.blog.vaadin;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import com.vaadin.Application;
import com.vaadin.terminal.StreamResource;
import com.vaadin.terminal.UserError;
import com.vaadin.terminal.StreamResource.StreamSource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
/**
* The Application's "main" class
*/
public class MyVaadinApplication extends Application {
private static final long serialVersionUID = 1L;
private Window window;
private Button sendBtn;
private TextField messageTfd;
private Embedded image;
@Override
public void init() {
window = new Window("My Vaadin Application");
setMainWindow(window);
messageTfd = new TextField("Message");
messageTfd.setColumns(5);
sendBtn = new Button("Click Me");
sendBtn.addListener(new ClickListener() {
private static final long serialVersionUID = 1L;
public void buttonClick(ClickEvent event) {
messageTfd.setComponentError(null);
if (!((String) messageTfd.getValue()).matches("^\\d*$")) {
messageTfd.setComponentError(new UserError("Digits only!"));
return;
}
else {
int rgb = 0;
try {
rgb = new Integer(((String) messageTfd.getValue())
.trim()).intValue();
if (rgb > 255 || rgb
<p>Podsumowując. Vaadin jest obecnie chyba najwygodniejszym znanym mi narzędziem pozwalającym na pracę przy webowym UI tak jak ze Swingiem. Zapraszam na moją prezentację o Vaadin w ramach WJUG 20 kwietnia o 18.00. Pokażę kilka innych elementów m.n. integrację ze Springiem.</p>