Monthly Archives: October 2010

Kilka sztuczek w Struts 1

W nowej pracy mam okazję na co dzień pracować z frameworkiem Struts. W moich dotychczasowych projektach nie miałem do tej pory okazji zapoznać się z tym frameworkiem, jednakże p0 kilku tygodniach pisania w nim kodu mam o nim jakieś tam pojęcie. Napotkałem po drodze kilka dość frustrujących “wpadek” i dlatego postanowiłem je opisać na blogu.

1. Tagi z dynamicznymi wartościami.

Podstawą internetu jest magiczny znacznik HTMLa o nazwie FORM. Zasadniczo dość często zdarza się, iż adres akcji, która zostanie wywołana jest zależny od przekazanego parametru. W Strustach zaleca się do takich operacji używanie tagu <bean:write> – w sumie można się z tym nawet zgodzić, problemem jest to, iż nie da się umieścić tego tagu wewnątrz treści innego tagu. Czyli takie coś nie przejdzie:

<html:form action="<bean:write [...] />"  ></html:form>

Wpisanie czegoś takiego do treści strony JSP spowoduje wyrzucenie wyjątku. O dziwo użycie składni skrypletowej ze znacznikami również nie zadziała;

<html:form action="<%=(String)request.getAtrtribute("cost")%>"  ></html:form>

Problem ten można obejść sposobem “niejavowym”. A mianowicie tak:

<html:form action='<%=(String)request.getAtrtribute("cost")%>'  ></html:form>

Widać różnicę? Zamieniamy po prostu cudzysłów na apostrof. I nagle dziwnym trafem wszystko działa.

2. Checkboxy w checkboxie czyli o tagu html:multibox

Załóżmy taką sytuację. Piszemy aplikację do rezerwacji pokoi w hotelu. Jako użytkownik wybieramy sobie kilka opcji spośród dostępnych w hotelu ( np. sejf w pokoju, wypożyczenie auta). I te informacje przechowujemy dla każdej rezerwacji. Z drugiej strony mamy rzecz jasna również wszystkie możliwe opcje – ich lista może być długa. I teraz – jak przy edycji/podglądzie formularza szybko i łatwo zaznaczyć na liście te, które użytkownik wybrał dla swojej rezerwacji?

Rzecz jasna możemy przeiterować po całej kolekcji ze wszystkimi opcjami i następnie iteracyjnie przechodzić po opcjach, które wybrał użytkownik. Jeśli obecnie przetwarzana wartość znajduje się pośród tych, które wybrał użytkownik renderujemy atrybut checked. Jednakże jest to troszeczkę nieefektywne i dlatego też twórcy Strutsa wymyślili tag o nazwie html:multibox. W skrócie – iterujemy po liście wszystkich możliwych opcji, ale zamiast porównywać cokolwiek (skrypletami choćby) wstawiamy do tej pętli ww. znacznik i powinno być dobrze. Dlaczego o tym piszę? Ano rzućmy okiem na dokumentację tagu:

Renders an HTML <input> element of type checkbox, whose “checked” status is initialized based on whether the specified value matches one of the elements of the underlying property’s array of current values.

Co pomyśli sobie programista? Świetnie – iterujemy po liście obiektów i potem do tagu wrzucamy drugą listę tego samego typu obiektów i jest OK. Czyli wystarczy dokonać trochę magii z przesłonięciem metod equals oraz hashCode i jesteśmy w domu. No i nie do końca…

Okazuje się (po 3h mojego rzucania mięsem przed komputerem), iż w tym przypadku jednym rozwiązaniem jest to, że obydwie kolekcje będą zawierały obiekty typu String!. Zapomnijcie o dobrach tego taga w przypadku własnych klas. Ostatecznie może wyglądać to tak:

<logic:iterate id="lancuch" name="BeanFormularza" property="listaLancuchow" >

         <html:multibox property="listaLancuchowDoZaznaczenia">
             <bean:write name="lancuch" />
        </html:multibox>

</logic:iterate>

3. Sprawdzanie parametrów żądania

Generalnie sprawa jest prosta. W akcji zapisujemy zmienną w obiekcie żądania i chcemy dobrać się do niej w widoku. Robimy tak:

request.setAttribute( "klucz", wartoscPodTymKluczem );

Wiadomo jednakże, iż czasami wartoscPodTymKluczem może przyjąć wartość NULL, albo co gorsza w ogóle nie zostać ustawiona (co może, choć nie do końca, znaczyć to samo co NULL). Dobrą praktyką byłoby tym samym sprawdzenie w widoku, czy aby interesująca nas zmienna nie jest właśnie NULLem. I tutaj mała niespodzianka w przypadku tagu logic:present. Tag ten sprawdza, czy podana zmienna istnieje. Jednakże należy uważać, gdyż dokumentacja może być myląca – przyzwyczajeni bowiem jesteśmy do tego, iż atrybuty name oraz property oznaczają to samo w każdym tagu – name zawiera nazwę beana, zaś property to konkretna własność obiektu (choć nie do końca, tak naprawdę liczy się istnienie metody dostępowej). Natomiast w przypadku atrybutów żądania jest odwrotnie! By powyższy przykład zadziałał z ww. tagiem musi to wyglądać następująco:

<logic:present name="klucz" >
  tutaj jest miejsce na nasz kod i wszystko inne jeśli wartość istnieje i nie jest pusta
</logic:present>

Zapominamy o property. Tak to ma wyglądać.

4. Podsumowanie
Duperelki, ale ileż potrafią napsuć zdrowia i dobrego samopoczucia. Rzecz jasna wszystko dotyczy frameworka Struts w wersji 1. Jak wygląda ten temat obecnie nie wiem i raczej niezbyt prędko będę miał okazję poznać drugą odsłonę tego frameworka. Jednakże komentarze na ten temat jak najmilej widziane.