morosystems na ostravském czjugu o apache wicket
DESCRIPTION
Pavel Klobása si pro posluchače ostravského CZJUGu připravil přednášku o Apache Wicket.TRANSCRIPT
Apache Wicket
MoroSystems, s.r.o.Pavel KlobásaSenior Java [email protected]
MoroSystems, s.r.o.• Pobočky Brno a Hradec Králové• Firma s českými vlastníky• 26 zaměstnanců a externistů• Na trhu od roku 2005
MoroSystems, s.r.o.• Odborný weblog VsadNaJavu.cz• Zakázkový vývoj webových aplikací,
informačních systémů a portálových řešení• Outsourcing vývoje SW nad Java/J2EE• Implementace a customizace Atlassian JIRA• Internetový startup Hráči.info
Obsah
Porovnání s jinými frameworky
Komponenty
Modely
Podpora JavaScriptu a Ajaxu
Jak vytvořit RIA
Část první: porovnání s jinými frameworky
Principy webových frameworků
MVC Klientský fw Komponentový fwStruts, Spring MVC... Flex, GWT JSF, Tapestry, WicketServer: celá aplikaceKlient: statické HTML
Server: REST APIKlient: celá aplikace
Server: celá aplikaceKlient: statické HTML
Stav v URL Stav na klientu Stav v komponentáchInternet Intranet IntranetVelká zatěž Velká zatěž Střední zatěž
Principy frameworků vs. AJAXMVCImplementace AJAXu jde proti principu MVC. Musíme implementovat vykreslení celé stránky a vykreslení fragmentu stránky zvlášť. Vzniká duplicita kódů...
Klientský fwKlient stáhne data přes REST API = základní vlastnost frameworku.
Komponentový fwKomponenty „žijí“ na serveru – můžeme je požádat o vykreslení do AJAXové odpovědi – dojde k aktualizaci fragmentu HTML stránky. Pokud fw podporuje AJAX, je jeho použití snadné.
Umí tohle váš framework?● pracuje s POJO daty● lze využít generické datové typy● šablony editovatelné v běžném HTML editoru● oddělení kódu a šablon● snadné použití JavaScriptu/AJAXu● „hezké“ URL, tlačítko Zpět● podpora pro clustering● testovatelnost pomocí jednotkových testů
...tak trochu jako Swing...
● Anonymní třídy● Model oddělený od komponenty● Dědičnost● Kompozice komponent● (Generické datové typy)
Část druhá: O komponentách
Hierarchie komponent
Component
WebComponent
WebMarkupContainer
FormBorder
Link
Panel
TreeGrid
DataGrid
TabbedPanel
FormComponent
Button
FileUpload
CheckBox
TextField
Label Image
Další komponenty viz téžhttp://wicket.sourceforge.net/wicket-extensions/
Grid
AddressPanel.html<html xmlns:wicket="http://wicket.apache.org/"><body><table class="edit-form"><wicket:panel><tr><th>Adresát:</th><td><input wicket:id="name" type="text" class="adr"/></td>
</tr><tr><th>Ulice:</th><td><input wicket:id="street" type="text"/></td>
</tr><tr><th>Město:</th><td><input wicket:id="city" type="text"/></td>
</tr><tr><th>Země:</th><td><select wicket:id="country"></select></td>
</tr></wicket:panel>
</table></body></html>
Ukázka šablonyID komponenty
Ukázka kódupublic class AddressPanel extends Panel { private static final long serialVersionUID = 1L;
public AddressFragmentPanel(String id, IModel<Address> model) { super(id, new CompoundPropertyModel<Address>(model)); add(new TextField<String>("name").setRequired(true)); add(new TextField<String>("street")); add(new TextField<String>("city").add(new IValidator(){
public void validate(IValidatable<T> validatable){String city = (String)getDefaultModelObject();if (city == null || city.length()<2) {
ValidationError error = new ValidationError();error.setMessage("Bad city name");validatable.error(error);
}}
}); add(new CountryDropDown("country")); }}
Je to znovupoužitelná komponta,vzniklá jako kompozice komponent
Název komponenty odpovídá názvu atributu modelu
Anonymní třída není problém
public interface IBehavior { void beforeRender(Component component); void afterRender(Component component); void onComponentTag(Component comp,ComponentTag tag); boolean isEnabled(Component component); …a několik dalších metod...}
IBehavior – modifikace komponenty
Dědičnost komponent umožňuje totéž, ale IBehavior je často elegantnější...
public class Highlighter extends AbstractBehavior {@Overridepublic void onComponentTag(Component comp,ComponentTag tag) {
if (isHighlighted(component)) {tag.getAttributes().put("class","hglt");
}}private boolean isHighlighted(component){
// TODO: implement it}
}
IBehavior – ukázka
public class HighlighterUtils {public static void prepareForms(MarkupContainer parent) {
parent.visitChildren(FormComponent.class, new IVisitor<FormComponent>(){
public Object component(FormComponent comp){comp.add(new Highlighter());return IVisitor.CONTINUE_TRAVERSAL;
}});
}}
IVisitor
- IBehavior lze opakovaně využít- jedna komponenta může mít více IBehavior
public class MyComponent extends Component{@SpringBeanProductDAO productDAO;...
}public class MyApplication extends WebApplication {
public void init() {super.init();addComponentInstantiationListener(
new SpringComponentInjector(this));}
}
Spring Dependency Injection
<dependency><groupId>org.apache.wicket</groupId><artifactId>wicket-spring</artifactId><version>${wicket.version}</version>
</dependency>
Část druhá: O modelech
public interface IModel<T> extends IDetachable{T getObject();void setObject(final T object);
}
Model
Pro srovnání:Model v MVC = mapa objektůModel ve Swingu = ad hoc interface dle komponenty
AbstractReadOnlyModel – jen pro čteníResourceModel – lokalizace textůCompoundPropertyModel – jméno atributu=jméno
komponentyIChainingModel – zřetězení modelůLoadableDetachableModel – odpojení
neserializovatelných objektů
Některé modely Wicketu
public class Model<T extends Serializable> implements IModel<T> {private static final long serialVersionUID = 1L;private T object;public T getObject() {
return object;}public void setObject(final T object) {
this.object = object;}
}
Triviální modelTato implementace je součástí Wicketu:
ALE:Model musí být serializovatelný – entity serializované být nesmí
(ukládají se pouze do databáze, ne kamsi na disk/síť/cache...)Jak zajístíme vzájemnou aktualizaci dat v modelech více komponent?Jak zajistíme aktualizaci dat při změně v dB?
public class CurrentTimeModel extends AbstractReadOnlyModel<String> {
public String getObject() {SimpleDateFormat fmt=new SimpleDateFormat("d.M. hh:mm");return fmt.format(new Date());
}}
Volat metodu je často výhodnější, než uchovávat datový obsah.Můžeme takto rovnou volat DAO...
„Počítaný“ model
public class OrderListModel extends AbstractReadOnlyModel<List<Order>> { @SpringBean transient OrderDAO dao; public LoggedUserModel(){ InjectorHolder.getInjector().inject(this); } public List<Order> getObject() { return dao.getLoggedUserOrders(); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); InjectorHolder.getInjector().inject(this); }}
Metoda vrátí vždy čerstvá data
Model napojený na DAO
Část třetí: JavaScript a AJAX
public class HTMLEditor extends TextArea<String>{ @Override protected void onAfterRender() { super.onAfterRender(); getResponse().write(JavascriptUtils.SCRIPT_OPEN_TAG); getResponse().write("makeTinyMCE('" + getMarkupId() + "');"); getResponse().write(JavascriptUtils.SCRIPT_CLOSE_TAG); }}
Upozornění: toto je jen ilustrační příklad...
JavaScript v komponentě
Label clockLabel=new Label("clock", new AbstractReadOnlyModel<String>() {private static final long serialVersionUID = 1L;public String getObject() {
SimpleDateFormat fmt=new SimpleDateFormat("d.M. hh:mm:ss");return fmt.format(new Date());
}};add(clockLabel);
add(new AjaxLink<Void>("refresh") {private static final long serialVersionUID = 1L;@Overridepublic void onClick(AjaxRequestTarget target) {
target.addComponent(clockLabel);target.addJavascript("window.defaultStatus='"
+Runtime.getRuntime().freeMemory()+"'");}
};
Aktualizace komponenty AJAXem
požadavek vznikl na klientu, ale o tom, co se bude dít,
rozhodne server.
Část pátá: RIA
Aplikace běží v prohlížeči a na webovém serveru (=nulové náklady na instalaci na klientech)
Napodobuje GUI klient-server aplikace● ovládání: drag&drop, kontextové menu, ukládání stavu
GUI mezi sezeními...● pokročilé komponenty: datový grid, pulldown menu,
autocomplete...● složitý, často dynamický, layout aplikace
Rich Internet Application
Jak na to? Wicket na serveru a JS komponenty na klientu.
Unobtrusive javascript
Nevtíravý javascript ● chceme, aby javascript byl „přidanou
hodnotou“ a aplikace fungovala i bez něj● je to best practice pro klasické webové stránky● užitečný koncept pro napojení serverového
komponentového frameworku a klientských javascriptových komponent
Unobtrusive javascript - ukázkaHTML<div id="tabs"> <ul> <li><a href="#foo">foo</a></li> <li><a href="#bar">bar</a></li> <li><a href="#baz">baz</a></li> </ul> <div> <div id="foo"> <p>foo content</p> </div> <div id="bar"> <p>bar content</p> </div> <div id="baz"> <p>baz content</p> </div> </div></div>
JSvar tabview = new Y.TabView({srcNode:'#tabs'});tabview.render();
Toto je ukázkový kód ze stránek YUI3.
Porovnání jQuery a YUIjQuery– populární a známý v ČR– krátké, čitelné, elegatní kódy
Komponenty v jQuery od různých autorů– rozdílné API, rozdílné licence, nejednotná grafika
YUI – používají též velké firmy (eBay, Yahoo)– „nudné“ API
Komponenty v YUI jsou součástí fw– podobné API, stejná grafika
http://wicket.apache.orghttp://wicket.sourceforge.net/wicket-extensionshttp://wicketstuff.org/wicket14http://wicketstuff.org/grid-example https://cwiki.apache.org/WICKET/spring.htmlhttp://developer.yahoo.com/yui/3/examples/
Další informace: