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
Principy webových frameworků
MVC Klientský fw Komponentový fw
Struts, Spring MVC... Flex, GWT JSF, Tapestry, Wicket
Server: celá aplikace Server: REST API Server: celá aplikace
Klient: statické HTML Klient: celá aplikace Klient: statické HTML
Stav v URL Stav na klientu Stav v komponentách
Internet Intranet Intranet
Velká zatěž Velká zatěž Střední zatěž
Principy frameworků vs. AJAX
MVC
Implementace AJAXu jde proti principu MVC. Musíme implementovat
vykreslení celé stránky a vykreslení fragmentu stránky zvlášť. Vzniká
duplicita kódů...
Klientský fw
Klient stáhne data přes REST API = základní vlastnost frameworku.
Komponentový fw
Komponenty „ž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)
Component
WebComponent
Hierarchie Label Image
komponent WebMarkupContainer
Link
Border Form
Panel FormComponent
TreeGrid Button
DataGrid CheckBox
TabbedPanel FileUpload
Další komponenty viz též
http://wicket.sourceforge.net/wicket-extensions/ TextField
Je to znovupoužitelná komponta,
Ukázka kódu vzniklá jako kompozice komponent
public 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")); Název komponenty odpovídá
add(new TextField<String>("city").add(new IValidator(){ názvu atributu modelu
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); Anonymní třída není problém
}
}
});
add(new CountryDropDown("country"));
}
}
IBehavior – modifikace komponenty
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...
}
Dědičnost komponent umožňuje totéž,
ale IBehavior je často elegantnější...
IBehavior – ukázka
public class Highlighter extends AbstractBehavior {
@Override
public void onComponentTag(Component comp,ComponentTag tag) {
if (isHighlighted(component)) {
tag.getAttributes().put("class","hglt");
}
}
private boolean isHighlighted(component){
// TODO: implement it
}
}
IVisitor
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;
}
});
}
}
- IBehavior lze opakovaně využít
- jedna komponenta může mít více IBehavior
Spring Dependency Injection
public class MyComponent extends Component{
@SpringBean
ProductDAO productDAO;
...
}
public class MyApplication extends WebApplication {
public void init() {
super.init();
addComponentInstantiationListener(
new SpringComponentInjector(this));
}
<dependency>
} <groupId>org.apache.wicket</groupId>
<artifactId>wicket-spring</artifactId>
<version>${wicket.version}</version>
</dependency>
Model
public interface IModel<T> extends IDetachable{
T getObject();
void setObject(final T object);
}
Pro srovnání:
Model v MVC = mapa objektů
Model ve Swingu = ad hoc interface dle komponenty
Některé modely Wicketu
AbstractReadOnlyModel – jen pro čtení
ResourceModel – lokalizace textů
CompoundPropertyModel – jméno atributu=jméno
komponenty
IChainingModel – zřetězení modelů
LoadableDetachableModel – odpojení
neserializovatelných objektů
Triviální model
Tato implementace je součástí 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;
}
}
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?
„Počítaný“ model
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...
Model napojený na DAO
public class OrderListModel extends AbstractReadOnlyModel<List<Order>> {
@SpringBean transient OrderDAO dao;
public LoggedUserModel(){
InjectorHolder.getInjector().inject(this); Metoda vrátí
} vždy čerstvá data
public List<Order> getObject() {
return dao.getLoggedUserOrders();
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
InjectorHolder.getInjector().inject(this);
}
}
JavaScript v komponentě
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...
Aktualizace komponenty AJAXem
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());
}
};
požadavek vznikl na klientu,
add(clockLabel);
ale o tom, co se bude dít,
add(new AjaxLink<Void>("refresh") { rozhodne server.
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
target.addComponent(clockLabel);
target.addJavascript("window.defaultStatus='"
+Runtime.getRuntime().freeMemory()+"'");
}
};
Rich Internet Application
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
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ázka
HTML JS
<div id="tabs"> var tabview = new Y.TabView({srcNode:'#tabs'});
<ul> tabview.render();
<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> Toto je ukázkový kód ze stránek YUI3.
<div id="baz">
<p>baz content</p>
</div>
</div>
</div>
Porovnání jQuery a YUI
jQuery
– 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