23. dubna 2009

Komponenta pro vyhledávání, třídění, stránkování, ...

Vyhledávání záznamů a jejich zobrazení je tak často se opakující věc, že by se zdálo, že už to má každý vyřešený. Bohužel tomu tak není, některé problémy se opakují pořád dokola - je nutné zobrazovat celkový počet záznamů? Je nutné mít možnost přejít na poslední stránku výpisu? Je možné, aby se v průběhu stránkování nebo třídění měnila data? Stačí parametrické vyhledávání nebo je nutný fulltext? Těch otázek je mnoho a co aplikace, tak to trochu jiné (specifické) požadavky zákazníka.

Ve firmě, kde nyní působím, se snažíme najít vhodné řešení na následující požadavky spojené s vyhledáváním:

  • řešení by ideálně mělo implementovat prezentační, tak i datovou vrstvu. Tedy zobrazení dat a i jejich načtení.
  • zobrazená data by mělo jít filtrovat, třídit, stránkovat
  • použitelné v JSP
  • nezávislé na zvoleném MVC řešení. Pokud závislé, tak pouze na Spring MVC
  • na datové vrstvě podpora JDBC a Hibernate

Takové řešení znám zatím pouze jedno a jmenuje se ValueList. Tento projekt (již přes dva roky neaktivní) vychází z implementace J2EE patternu ValueListHandler. Poslední verze je 0.1.8, ale i přesto je použitelná. Ve firmě to používají již nějaký pátek, ale pořád to není ono, pořád je nutné řešit nějaké problémy kvůli specifickým požadavkům té konkrétní aplikace. Super ale je, že se analytické, vývojářské a grafické oddělení bylo schopno domluvit na jednom řešení, které se používá a všichni o něm vědí.

Já osobně toto řešení nepovažuji za zcela šťastné. Když pominu to, že ValueList obchází standardní strukturu několika-vrstvé aplikace (data se načtou a pak se hned zobrazují), tak mi přijde, že mě to příliš svazuje. Jak jsem již naznačil, někdy potřebuji fulltext, někdy musím zaručit neměnnost dat při stránkování, někdy tahám data z více datových zdrojů atd. Chci tím tedy říci, že nevidím velkou přidanou hodnotu v jednotném řešení na datové vrstvě, ale zejména na prezentační vrstvě, protože tam je to pořád stejné (až na úpravy vzhledu pomocí stylů).

Pro čistě prezentační vrstvu se hodí DisplayTag, který se zdá být hodně zajímavý. Jako vhodnou cestu tedy vidím v použití nějaké komponenty jako DisplayTag s rozšířením o filtrování a podpoře na úrovni MVC (ať nemusím pořád řešit převod parametrů komponenty na interní datovou strukturu, podle které pak vyhledávám) a s tím, že datovou vrstvu si budu řešit dle potřeby. Pro časté scénáře mohu mít nějakou podporu v datové vrstvě, ať se vše nemusí řešit od nuly.

Rád bych se zeptal, jak tuto problematiku řešíte vy? Máte nějaké osvědčené interní řešení nebo to řešíte v každé aplikaci znovu a znovu?

8 komentářů:

Honza Novotný řekl(a)...

My máme v podstatě jen pevně vydefinované DTO, kterým se přenáší data z business do prezentační vrstvy. Na prezentační vrstvě pak máme několik komponent, které umí s tímto DTO pracovat, takže obvykle je nutné pouze implementovat rozhranní pro naplnění tohoto DTO obsahem. Tady jsme se nechtěli nijak limitovat a svazovat, takže se vždy od business dolů implementuje znova (ale řekl bych, že nám to vůbec nevadí - protože jsem potřebu reusu mezi projekty snad ani pořádně neviděl). Všechna rozhraní a DTO je custom made, ale nic extra sofistikovaného to není. Řekl bych, že tady se spíš držíme principu KISS.

Petr Jůza řekl(a)...

Jo, přesně takto bych si to nějak představoval. Dole flexibilita, nahoře jednotnost.

Pavel Müller řekl(a)...

My máme vlastně jen podobnou komponentu jako je DisplayTag. Jenom na prezentační vrsvu. Ta umí zacházet s jakoukoli kolekcí JavaBeans. Potom mame sadu tříd usnadňujících výběr z DB, stránkování a filtrování. Takže vlastně píšeme business metody pro každou tabulku znova, ale je to hodně jednoduché a myslím, že je to tak i správně. Mám potom standardní metody nepřeskakující vrstvy aplikace. Můžu aplikovat bezpečnost a další aspekty. Není to dokonalé, ale docela nám to funguje.

Slavek Tecl řekl(a)...

Co treba pouzit Javascript a nejaky framework, ktery resi gridy - ExtJS nebo YAHOO? Osobne mam dobrou zkusenost s Wicketem, ale to je cely framework, tak asi nespada do tveho filtru ;).

veselej řekl(a)...

Podobný problém řeším na JSF (ICEFaces) sadou vlastních komponent. Pro stránkování mám vlastní paginator, pro který je vždy nutné implementovat DataProvider. Implementace leží na managed beaně a jsou tam tuším metody pro vrácení záznamů od-do a pak zjištění počtu záznamů v tabulce. Další komponenta řeší vyhledávání nad každým sloupcem tabulky + komponenta na řazení záznamů. Univerzální je to hlavně na té View vrstvě. Na controlleru a modelu dělám většinou nové implementace. Celé je to propojeno přes objekt criteria a tak komponenty spolupracují :-) -> když vyhledáš něco ve sloupci automaticky se ajaxem změní počet stran. Nevím jestli Ti toto pomůže, ale já bych do něčeho "super" univerzálního nešel. Myslím, že nové implementace na controlleru a modelu jsou nutné.

kvas řekl(a)...

a co takto jmesa? (http://code.google.com/p/jmesa/) povodne sa volala extremecomponents a poskytuje vsetko co spominate v blogu (plus exporty do XLS, PDF) mam s nou skusenosti z niekolkych projektov a vsade sa osvedcila. rozhodne stoji za to ju skusit.

Vojtech Szocs řekl(a)...

Zdravim,

v nasej firme prave pracujeme na jednom vacsom Java projekte s pouzitim technology stacku GWT / SpringMVC / Hibernate.

Kazda aplikacna stranka je predpripravena na strane servera: potrebne komponenty su inicializovane cez stateless server-side widget model ktory pracuje nad DOM API. HTML response je vytvorena serializaciou vysledneho DOM-u do HTML plus:

- odkaz na "front controller" GWT entry point (deleguje klientsku logiku na konkretny entry point pre danu aplikacnu stranku)
- JSON / GWT-RPC serializovane objekty (stringy) dostupne cez JSNI (data pre inicializaciu daneho GWT entry pointu)

Na prezentacnej vrstve mame vlastny GWT grid widget, ktory robi asynchronne requesty na server cez GWT-RPC pre zobrazenie dat podla aktualnych poziadaviek. Grid definuje explicitne kriteria (filter, sort, paging) cez jednotne API ktore nazyvame "Criteria Transfer Object" (CTO). CTO sa pri requeste posle na server, kde nas SpringMVC @Controller (resp. RemoteServiceServlet) vykona:

- konverziu CTO do criteria objektu
- do tohto objektu prida implicitne kriteria pre dany grid (ak je to nutne)
- posle criteria objekt do DAO vrstvy ktora ziska entity / celkovy pocet

DAO vrstvu mame postavenu na DAO Fusion, ktory zaroven implementuje spominany CTO pattern. DAO Fusion za nas navyse riesi pripady ked chceme filtrovat / sortovat podla vnorenych properties pre danu perzistentnu entitu cez jednoduchu bodkovu notaciu.

Uvedeny technology stack sa nam velmi osvedcil pri nasom style vyvoja, ked HTML stranku nemusi nutne vytvorit web designer alebo programator - kludne to moze byt analytik s pouzitim HTML template toolov typu Dreamweaver. Z mojich skusenosti mozem povedat, ze riesit opakujuce sa patterny v DAO / biznis vrstve ma na vacsich projektoch jednoznacne zmysel, pokial ma byt aplikacia udrzatelna do buducnosti. Na druhej strane, vzdy zavisi od konkretnej situacie na projekte (KISS vs overengineering vs nieco rozumne medzi tym)..

Petr Jůza řekl(a)...

Čistě pro prezentační vrstvu jsem našel následující řešení:
displaytag, jMessa a Yahoo datatable.