Grailsów część trzecia – statyczna zawartość i mapowanie adresów

Grails w znaczącej mierze opierają się na zasadzie ‘konwencja ponad konfigurację’. Dlatego też tworzenie aplikacji działa w oparciu o tzw. scaffolding, co można przetłumaczyć jako ‘rusztowanie’. Nie byłbym rzecz jasna sobą, gdybym nie próbował tego tematu obejść 🙂

Choć to obejście przyszło mi dość łatwo. Otóż w myśl mądrych myśli autorów frameworka wpierw powinniśmy utworzyć klasę modelu (domain class), potem napisać do niej testy jednostkowe, uruchamiać je i zmieniać klasę, aż przejdzie ona wszystkie testy z powodzeniem i dopiero po tym napisać kontroler. Ciekawe podejście – z pewnością użytkownicy RoRa znają je o wiele lepiej niż prosty koder PHP. Domyślnie bowiem używając w pracy Zend Frameworka, wpierw tworzę sobie choćby namiastkę kontrolera, gdyż gdzieś trzeba uruchomić pisane klasy modelu. Jak widać w Grails temat został trochę przestawiony, ale co z tego wynika napiszę pewnie w kolejnych wpisach.

Teraz zaś postanowiłem rozejrzeć się trochę po projekcie pozostając wciąż blisko widoku, bez zagłębiania się specjalnie w szczegóły modelu. Poprawiłem trochę CSS (wygląda dobrze nawet pod Internet Explorerem), a także zreorganizowałem menu. Okazało się, że w serwisie będzie kilka miejsc, które będą miały charakter wybitnie statyczny, to znaczy, będzie to wyświetlenie 1 widoku, który to jednakże mógłby mieć swój unikalny adres, ale z drugiej strony, nie ma sensu wrzucać luźnych plików do głównego katalogu /web-app. Przykładem takich stron są choćby odnośniki ‘O serwisie’ czy ‘Linki’. Oczywiście w przypadku tej aplikacji problem jest trochę wydumany, ale w rzeczywistych aplikacjach ilość takich stron może już trochę wzrosnąć i tym samym dobrze byłoby od samego początku mieć dla nich oddzielne miejsce.

Oto jak wygląda obecnie główna strona serwisu:

stronaobecnie

Dobrze byłoby, aby pod linkami na górze kryły się ładne adresy w postaci /strona czy /linki. Jednakże tworzenie dla pojedynczych akcji oddzielnych kontrolerów mija się z celem. Wydumałem sobie zatem, że utworzę jeden kontroler, zaś poszczególne akcje będą odpowiadały za renderowanie tych stron. Konkretne pliki widoku (*.gsp) również znajdą się w jednym miejscu (katalogu).

Wpierw należy utworzyć kontroler, który zbierze to wszystko do kupy. Klikamy zatem prawym przyciskiem na folderze ‘Controlers’ i wybieramy New->Grails Controller. W okienku wpisujemy jego nazwę (u mnie będzie to static) i klikamy Finish. Netbeans przemieli magię frameworka i utworzy nie tylko kontroler, ale też odpowiedni katalog dla widoków w folderze Views and layouts wraz z testem integracji (katalog Integration Tests). Na razie jednakże zajrzyjmy do pliku StaticController.

class StaticController {
def index = { }
}

Rozbudowane, trzeba przyznać 🙂 Kontrukcja którą widać jest tzw. domknięciem. Jest to obiekt Javy, który jednakże wygląda i zachowuje się jak metoda. Jest to o tyle ciekawy element języka Groovy, iż nie potrzeba deklaracji zwracanego typu, a także jawnej specyfikacji parametrów. W przypadku Grailsów tak stworzone domknięcie odpowiada za to, co zostanie przetworzone podczas odwołania się do adresu w postaci /kontroler/akcja. By zaś nie pozostać gołosłownym wystarczy wpisać w adresie przeglądarki odpowiedni adres – http://127.0.0.1:8080/Howtojava/static/index – i co otrzymaliśmy?

Error 500: ServletContext must not be null

Śliczny komunikat o błędzie. Hmmmm, cóż to mogłem przegapić. ServletContext to pojęcie, które znam z JSP. Konkretnie jest to obiekt, który odpowiada za konfigurację całej aplikacji (można tam choćby umieścić dane dotyczące połączenia z bazą danych). Plikiem konfiguracyjnym aplikacji jeszcze się nie bawiłem, zatem może sprawdźmy jeszcze czy to może dlatego, że nie mamy pliku widoku. O dziwo po skopiowaniu pliku index.gsp do katalogu Views and layouts (podkatalog static) i ponownym uruchomieniu aplikacji – viola! Działa. Ciekawe… Zadanie na następny wpis – zapoznać się z konfigiem aplikacji. (PS. Okazało się, że to bug występujący w pewnych okolicznościach związany z pewnym kształtem UrlMappings.groovy. Zasadniczo nie przeszkadza i nie pojawił się więcej).

Plik kontrolera po małych zmianach wyglądał tak:

class StaticController {

def index = { }

def linki = {}

def strona = { }

}

Utworzyłem także 2 widoki – jeden to ‘linki.gsp’, a drugi to oczywiście ‘strona.gsp’. Oto jak wyglądają (zmienia się tylko napis na środku):

Informacje o stronie

Wpisuję adres http://127.0.0.1:8080/Howtojava/static/strona no i proszę. Jak ślicznie to wygląda:

linki

Wygląda całkiem ładnie, problem tylko z adresem, jemu trochę do ładnego wyglądu jeszcze brakuje. Należy zatem odwiedzić katalog Configuration i tam znaleźć plik UrlMappings.groovy. Świetny tutorial dotyczący mapowania adresów można znaleźć na stronie projektu Grails i tam odsyłam zainteresowanych tematem. Natomiast u mnie plik po edycji wygląda następująco:

class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}

"/strona" (controller: "static", action: "strona")
"/linki" (controller: "static", action: "linki")

"500"(view:'/error')
}
}

Zostawiłem domyślną ścieżkę, co mi tam 🙂 Ponownie odwiedzamy przeglądarkę, tym razem jednak wpisując adres http://127.0.0.1:8080/Howtojava/strona i… error 404. No i tu leży pies pogrzebany – należy zastopować serwer i uruchomić go ponownie, aby zmiany w kodzie aplikacji zostały wdrożone. Cóż, taka cena, którą póki co trzeba zapłacić (trzeba będzie poszukać na ten temat informacji). Po restarcie pod powyższym adresem ukaże się naszym oczom dokładnie taki sam widok jak na obrazku powyżej. Znowu sukces 🙂

Na koniec pomyślałem, że byłoby dobrze od razu zająć się stronami błędów. W pliku UrlMappings.groovy jak widać mamy regułę routingu dla kodu “500”. Przydałoby się jeszcze dla odróżnienia zdefiniować inny widok dla kodu “404” no i najlepiej stworzyć dla nich wspólny kontroler. Jeszcze nie wiem jak to wygląda w Grails, ale w takim kontrolerze możnaby dla przykładu podpiąć logowanie błędów, wyświetalnie wyrzuconych wyjątków, itp. Trzeba jednakże przyznać, iż renderowanie całości dotychczasowego layoutu na stronie o błędach mija się z celem. Dlatego też postanowiłem stworzyć odchudzoną wersję layoutu dla renderowania tylko dla komunikatów o błędach (choć może i przyda się później).

Chwilka pracy (myślę, że nie muszę wklejać listingów, wszystko odbywa się tak samo jak w tym i poprzednim wpisie) i powstał nowy lekki layout, a także stosowny kontroler Errors i widoki do niego. Domyślnie Grails tworzy widok, który jest odpowiedzialny za renderowanie błędów (error.gsp). Zostawiłem go, tylko zmieniłem nazwę na servererror, aby wyrzucał wyjątki w sposób ‘widoczny’ dla mnie (na serwerze produkcyjnym oczywiście takie coś należy wyłączyć). Dodałem też ładny widok dla kodu błędu 404. Restart, uruchom i znowu problem. Okazuje się, że przy błędzie 404 – Grails w dziwny sposób nie potrafi odwołać się do zewnętrznego pliku layoutu! Czyli mój piękny odchudzony plik z layoutem na niewiele mi się zda. Po prostu renderowany jest zwykły widok (nopageerror.gsp), ale tylko tyle! Nie jest w ogóle startowany plik layoutu. Grrr, posiedziałem nad tym, poklęłem no i nic – musiałem wrzucić zmiksowany kod layoutu i samej strony do jednego pliku. Pewnikiem gdzieś jest jakaś zagowzdka z obiektem renderującycm widok, no ale na razie nie za bardzo mam czas się w ten problem zagłębiać. Najważniejsze, że mam piękną stronę dla błędu 404.

stronabledu

Advertisements

One thought on “Grailsów część trzecia – statyczna zawartość i mapowanie adresów

  1. clondike

    Hej,

    Właśnie też odkryłem ten problem z brakiem renderowania layoutu na stronie błędu. Poradziłem sobie tak że stworzyłem ErrorController, w nim akcję def notfound = { render view:”/404″ }, no i dałem do tego mapping w konfiguracji – działa 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s