pondělí 29. prosince 2008

Apache Wicket - Znovupoužitelné komponenty

Tvorba vlastních komponent je u komponentově orientovaného web frameworku, důležitá vlastnost. Jen težko bych hledal projekt, který by si vystačil s existujícími vlastnostmi a komponenty daného rámce a nesnažil se o vlastní tvorbu.

Pokud bych Wicket srovnával s JSF na této úrovni, musel bych více podrobněji znát tvorbu komponent v JSF. Ať jsem se snažil sebevíc, nikdy jsem úplně neodhalil výhody vlastních komponent v JSF. Ten postup mi přišel natolik složitý a nesmyslný, že v tomto případě jsem vždy sáhnul po něčem existujícím (RichFaces, Tomahawk, atd.). V JSF mám v tomto ohledu jen teoretickou znalost, která mi ovšem stačí k tomu, abych se do nečeho takového, jako je tvorba vlastních komponent, vůbec nepouštěl.

Ve Wicketu je situace naprosto rozdílná. Samotný framework mě v podstatě nutí rozsekávat danou prezentaci do několika menších celků, které se později dají znovu použít. Navíc je situace o to snažší, že není potřeba se učit či používat nové věci. Bohatě stačí znalost základních komponent a jejich využití. Vše ostatní vyplyne samo.

Pro tvorbu nové komponenty je nejčastěji používán "org.apache.wicket.markup.html.panel.Panel", od kterého má vlastní komponenta dědí. Díky tomu získám základní vlastnosti, které bych musel jinak znovu tvořit. Podobnost lze najít u Swingu, kde vlastní komponenty nejčastěji dědí od JPanelu.

Na malém příkladu ukážu, jak vytvořit komponenu, která bude obsahovat základní informace o zaměstnanci. Tuto komponentu poté budu moci využít např. při kliknutí na detail zaměstnance, při výpisu zaměstnanců, apod. Všude, kde budu chtít znát základní informace o daném zaměstnanci.

Nejprve doménový model:
public class Zamestnanec { 
private String idCislo;
private String prijmeni;
private String jmeno;
// set, get
}

Nyní vytvořím wicket komponentu:
<wicket:panel>
<span wicket:id="prijmeni"></span> <span wicket:id="jmeno"></span> (<span wicket:id="idCislo"></span>)
</wicket:panel>

A k danému HTML i Java kod:
public class ZamestnanecPanel extends Panel {
  public ZamestnanecPanel(String id, Zamestnanec z) {
  super(id);
  add(new Label("prijmeni", z.getPrijmeni());
  add(new Label("jmeno", z.getJmeno());
add(new Label("idCislo", z.getIdCislo());
  }
}

Tím mám vlastní komponentu hotovou.

Nyní ji stačí využít. Například při zobrazení detailu zaměstnance:
... hlavicka html stranky ....
<div class="detail">
<span wicket:id="zakladni"></span>
.... další vlasnosti
</div>
... paticka html stranky.....

K danému HTML i Java kod:
public class DetailPage extends WebPage {
  public DetailPage(String idCislo) {
  super();
  add(new ZamestnanecPanel("zakladni", service.findById(idCislo)));
  // dalsi vlastnosti
  }
}

I když je daný příklad triviální, jasně znázorňuje to, že tvorba vlastních komponent je v Apache Wicket velice jednoduchá a hlavně dobře použitelná. Způsob jak navrhovat takové komponenty je stejný jako v případě tvorby objektově orientovaného kódu. Třídy jsou malé a obsahují jen jednu jasně specifikovanou funkcionalitu. Stejné je to i zde.
*Myslím, že tohle je ta nejzásadnější věc, která dělá z Apache Wicketu dobrý framework, ve kterém je radost něco psát. Vytvořit komponenty a pak je skládat jako lego :)*

6 komentářů:

  1. Chci se zeptat jak je to s vytavernim znovupouzitelnych komponent skrze vice projektu?

    Chapejte vice projektu, vice naprosto odlisnych grafik.

    Kdybych upravil Vas priklad. Neslo by o komponentu zobrazujici zamestnance, ale cloveka jako takoveho.

    1) pro jden projekt, jde o zobrazeni zamestnance:
    Jmeno, Prijmeni, Tituly, Datum narozeni, kontaktni informace, pracovni zarazeni, odkaz na stranku s posudky.
    2) pro druhy projekt, jde o lektora:
    Jmeno, Prijmeni, Tituly, rozsirujici informace (na jeden radek textu), odkaz na publikace
    3) pro dalsi projekt, jde o clena zajmove organizace:
    Jmeno, Prijmeni, Tituly, Datum narozeni, rodne cislo, clenske cislo, checkbox s informaci o zaplacenych clenskych prispevcich, kontaktni udaje a poznamka

    V beznem MVC mi na to vsechno staci jeden Controller, ktery vytahne objekt IPerson, ktery ma ale v databazi pokazde jinou reprezentaci a pak v kazdem projektu mam vlastni JSP stranku, ktera popisuje co se ma zobrazit v jakem poradi a rozlozeni.

    V realu pak do XML napisu, ze rozhrani IPerson je reprezentovano clasou bud Employee nebo Lecurer, nebo Member, ktera je v Hibernate spravne mapovana a jedna JSP stranka (kterou udela designer se znalosti properties dane tridy).

    OdpovědětVymazat
  2. Však ani zde není třeba řešit něco složitého.

    Pokud chcete například použít komponentu ve více projektech, kde vstupem bude vzdy jiný objekt, ale bude obsahovat stejné vlastnosti, stačí vstup zabalit do CompoundPropertyModel a dane vlastnosti poté vytahovat bez znalosti typu.

    Další vlastností je použití dědičnosti, která při tvorbě Wicket komponent také hezky funguje. Není problém poté tvořit od jednoduchých až po složitější komponenty na zobrazení informací o zaměstnanci.

    Co se týče grafika(y), view je reprezentováno pomocí čistého html s malým přídavkem atributu wicket:id="". Navíc není problém napsat si vlastní "path resolver" a dané html soubory, k třídám, tahat z jiného místa, než je package, ve kterém se nachází i java wicket komponenta. O zbytek designu by se vždy měly postarat kaskádové styly, které jsou k projektu přiřazeny.

    OdpovědětVymazat
  3. Problem nastava, kdyz vlastnosti stejne nebudou, k cemuz byla otazka smerovana.
    Jednoducha bude situace, pokud budu zobrazovat vsechny vlastnosti, to bych asi sahl po reflexi a RepeatingView, ktere umoznuje generovani opakujicich se tagu.
    Pokud bude potreba jen nektere, a v kazdem pripade jine, bude muset mit kazda stranka dany tag a prislusna javovska class odpovidajici objekt.

    OdpovědětVymazat
  4. 4Slavek Tecl: Ano o to mi jde, podle vyse uvedene ukazky je totiz potreba (jestli to dobre chapu) v Java kodu provest "add(new Label(„prijme­ni“, z.getPrijmeni())" resp. podobnou "opicarnu" (cimz, ale jiz v Java kodu omezuju GUI, protoze tvrdim ze tanhle polozka bude Label a nic jineho).

    Navic kdyz objekt ziska nejakou novou vlastnost, neni mozne predelat jenom HTML kod (coz by v JSP nebyl problem), ale musim prislusne upravit i Java kod, aby pridal tuto vlastnost pomoci "add(new Label(„novaVlastnost“, z.getNovaVlasnost())".

    Kdyz to srovnam se Spring MVC, tak tam mi controller soupne do modelu beanu a ja pak z ni vytahnu v JSP libovolnou vlastnost a nadesignuji si ji jak chci. Treba chci seznam autoru:
    controller:
    model.setAutorList( getDao().getAutorList() );
    Jsp 1:


    ${autor.firstname}.....


    Jsp 2:
    Editace Knihy
    ...


    ${autor.surname} ${autor.firstname}



    A dalsi a dalsi stranky, pritom k pripraveni dat mi staci porad jeden jediny controller a vyuziti techto dat je pak v rukou JSP stranky.

    Z ukazky v blogu vyplyva ze takto pruzne pouziti to nema.

    OdpovědětVymazat
  5. Daný kód nůže být nějak takto:
    public ZamestnanecPa­nel(String id, CompoundProper­tyModel model) {
    super(id, model);
    add(new Label("prijmeni");
    add(new Label("pozice.nazev"); // zamestnanec.getPozice().getNazev();
    }

    Existence html souboru a java kódu je dost často vytýkána. Na druhou stranu, definovat web layout pomocí java kódu (ala swing) by bylo dosti složité.

    Co se týče samotných komponent, tak lze využít Label v různých html prvcích. Rozdíl lze poté najít pouze u formulářových prvků či odkazech.

    OdpovědětVymazat
  6. Hmm z prispevku jsou odmazany vskere tagy :( bez upozorneni. Tak to zkusim jeste jednou s html entitama.

    Jsp 1:
    <tabule name="seznam vsech autoru">
    <c:forEach items="${model.autorList}" var="autor" >
    <tr><td>${autor.firstname}.....</tr>
    </c:forEach>

    Jsp 2:
    Editace Knihy
    ...
    <form:select name="autor">
    <form:options items="${model.autorList}" key="id" var="autor">
    ${autor.surname} ${autor.firstname}
    </form:options>
    <form:select>

    OdpovědětVymazat

React a hrátky s TypeScriptem

V minulosti jsem se již několikrát zmiňoval, že používat JavaScript bez statických typů, je stejné jako jezdit na kole poslepu. Nemusí se...