Stronnice Chlebika – Newbie Java Blog

marzec 30, 2009

Użyszkodnicy, czyli o co walczymy w każdym projekcie cz.I

Zaszufladkowany do: Grails, HowToJava — Tagi:, , — chlebik @ 11:54 pm

Zgodnie z zapowiedziami przyszedł czas na bardziej zaawansowane rzeczy w Grails. Myślę, że HowToJava jest gotowe na przyjęcie pierwszych użytkowników.

Zagadnienie zarządzania uzytkownikami każdej aplikacji internetowej to tzw. core, czyli element należący do rdzenia aplikacji, który po napisaniu podlega raczej niewielkim modyfikacjom. Dlatego też tym bardziej trzeba ten temat przemyśleć. Z całą pewnością kwestię użytkowników trzeba wpierw podzielić na 2 ‘fronty’ – backend i frontend.

Backendem w tym przpadku nazywam zarządzanie użytkownikami poprzez administrację lub automatyczne działania kodu. Czyli po rejestracji takowy kod wyśle mejla aktywującego, albo też wyświetli moderatorowi dane delikwenta, który pragnie zarejestrować się w serwisie. Z kolei frontend to wszystko to, co może zrobić użytkownik ze sobą (zarówno ten niezarejstrowany, jak i z pełnią praw w serwisie). Nie jest to podział intuicyjny, ani też taki, który da się wyczytać w necie. Jednakże dobrze oddaje kroki, które po kolei będę wykonywał, aby zaimplementować funkcjonalność w serwisie.

Wyjdźmy od modelu. Bardzo to trąci DDD, o którym w kontekście całości Grailsów z pewnością kiedyś napiszę. Jednakże to, że trąci wcale nie oznacza, że to źle! Dobra, bo zabieram się jak do zabicia karpia :) Oto co trzeba na pewno w aplikacji:

  • proces rejestrowania uzytkowników, a w nim:
    • formularz rejestracji, jego walidacja oraz zapis do bazy
    • poinformowanie użytkownika o powodzeniu/niepowodzeniu procesu rejestracyjnego ( e-mail, komunikaty na stronie zaraz po rejestracji)
  • stworzenie namiastki panelu administracyjnego, który pozwoli na zarządzanie użytkownikiem (zarówno w procesie rejestracji jak i jego dalszej działalności)
  • napisanie kodu, który obsłuży użytkownika po zalogowaniu na stronie (do tego oczywiście oddzielna funkcjonalność oparta na formularzu rejestracji), a konkretnie:
    • rejestracja użytkownika w zasięgu sesji aplikacji
    • zbudowanie mniej lub bardziej rozbudowanego ACLa
    • stworzenie funkcjonalności, w której użytkownik będzie mógł się poruszać (czyli reszty serwisu)

Jak już wcześniej wspomniałem piszę kolejne notki na bieżąco, zatem powyższa lista z pewnością jest niekompletna i ulegnie modyfikacjom. Da się jednakże zauważyć oczywistą rzecz – potrzebujemy na pewno stworzyć kod, który będzie reprezentował naszego użytkownika (lub kandydata na niego). Nie zamierzam póki co bawić się w bardziej zaawansowane rzeczy – rejestracja zatem będzie przebiegała po prostu poprzez wpisanie nicku (unikatowego), a także hasła (plus potwierdzenie), dodamy także delikatną CAPTCHE, aby spamerzy nie mieli zbyt łatwo. Antycypując kolejne kroki nadamy też każdemu użytkownikowi jakąś rolę, którą będzie miał w serwisie – na szybko będą to role pod tytułem ‘czytacz’, ‘zwykły user’ i ‘admin’ (to ja :). Oto klasa dziedzinowa dla użytkownika:

class Htj_Users {

    static mapping = {
        id column: 'user_id'
    }

     static constraints = {
         nick( blank: false, size: 5..40, nullable: false, unique: true )
         passwd(blank: false, maxSize: 32, nullable: false, password: true )
         role( blank: false, nullable: false )
     }

    String nick;
    String passwd;
    Htj_User_Role role;
}

No i oczywiście mikroskopijna klasa dla typu roli:

class Htj_User_Role {

  static mapping = {
      id column: 'role_id'
  }

  String role_name;
}

Tworzymy kontroler o wdzięcznej nazwie UserController. Wpisujemy do niego taki kod:

def scaffold = Htj_Users;

i można już pobawić się dzięki scaffoldingowi. Ja do bazy przez PMA dodałem tylko trzy kategorie (wcześniej wymienione) i jak zawsze rusztowanie pozwala rozeznać się czy wszystko gra. Póki co gra zatem na dziś to koniec, późno trochę. Następnym razem zaimplementujemy cały CRUD ‘z palca’ plus zainstalujemy i wykorzystamy pierwszy raz plugin do frameworka.

marzec 29, 2009

A może SCJP?

Zaszufladkowany do: Blog, Java, Life — chlebik @ 11:34 pm

Ano może. Zaczynam się dość poważnie nad tym zastanawiać. Dlaczego? Już piszę…

Moje odczucia są przede wszystkim podyktowane moją dotychczasową ‘karierą’ (jak ja nie lubię tego słowa) jako programista PHP. Jak wygląda nauka tego języka raczej nie trzeba nikomu tłumaczyć – dynamiczne coś, które do tego działa nawet jeśli napisany kod woła o pomstę do nieba. Zasadniczo jest on również pierwszym językiem programowania dla wielu osób, co również nie dziwi zważywszy na ‘atrakcyjność wizualną’ (tzn. można stworzyć choćby stronkę swojej klasy czy osiedla, konsolowe komunikaty w czystym C są mniej porywające i nie da się na nie podrywać panienek :).

PHP jest też o tyle ciekawe, że wymaga zapoznania się (choćby podstawowym) z całą otoczką programowania dla WEB2.0, czyli (pomijając już HTML&CSS) frameworkami JavaScriptu (plus cała technologia AJAX), serwerami (choćby tym Apaczem w wersji minimalnej), konsolą linuxową (przydaje się czasem), a także bazami. I ta wiedza z początku rzecz jasna nikła, z czasem stale się zwiększa, oparta nie tylko o przeczytane lektury, ale głównie o doświadczenie zawodowe. I dobrze. Problem polega jednakże na tym, iż często język zostaje niejako w tyle. Bo kiedy już opanuje się słowa kluczowe, najczęściej używane konstrukcje, zapamięta się tak na oko ze 30 podstawowych funkcji języka, wówczas zasadniczo następuje zatrzymanie i brak bodźców do dalszej nauki. Nie każdy lubi czytać opasłe changelogi z kolejnego ‘dziesiętnego’ wydania kompilatora. Nie kazdy też chce spędzić kilka dni/tygodni/miesięcy na zapoznawaniu się z olbrzymią listą funkcji zaimplementowanych w języku. Nawet jeśli już nie funkcji, to nawet elementów języka, których się nie zna, a poznane na przykład przy nauce innego języka wydają się być szalenie genialne.

Nie chce się, cóż począć? Ano można począć tyle, iż na samym początku nauki nowego języka rozejrzeć się za możliwością poznania go właśnie poprzez certyfikat. Uprzedzając pytania i zarzuty – wiem, że istnieje ZCE, ale blog jest o Javie i w tej technologii zamierzam się dalej rozwijać. Dlatego też korzystając z doświadczenia zaczynam bardzo poważnie zastanawiać się nad podejściem do SCJP (w najnowszej wersji rzecz jasna). Oczywiście jak to w życiu wszystko ma swoje plusy i minusy, oto lista:

Plusy Minusy
‘zmuszenie’ do zapoznania się z całością języka, spojrzenie na niego z szerszej perspektywy tak naprawdę to zabawa ‘kto wynajdzie błąd w maksymalnie pokomplikowanym kodzie’
możliwość poznania zagadnień, z którymi na co dzień raczej się nie styka no i skoro się nie styka to po cholerę się nimi zajmować?
mile widziane w CV zależne tylko od widzimisię rekrutera
ale jak już masz to uznają to na całym świecie z drugiej strony jak idziesz robić za granicę to raczej pikuś nie jesteś i coś tam umiesz
zdobycie konkretnej wiedzy, lepsze to, niż granie w CSa z drugiej strony czy na pewno przydatnej?

Tyle mniej więcej można napisać – posiłkując się wujkiem Google. Jednakże mnie chyba najbardziej rusza w tym wszystkim aspekt motywacyjny – po prostu chciałbym udowodnić sobie, że jestem w stanie nauczyć się czegoś w dziedzinie programowania, a następnie poddać to obiektywnej ocenie. Nie kończyłem studiów kierunkowych – zatem byłby to całkiem niezły fun. Z drugiej strony – ileż to ciekawych technologii nie będzie mi dane przez te przygotowania poznać (no albo znacznie się to opóźni). Przy założeniu, że myślę o potencjalnym poszukiwaniu pracy w Java-landzie za kilkanaście miesięcy, nie wiem czy zysk z SCJP zrekompensuje mi poświęcony na niego czas.

Zdaję sobie sprawę, iż spora część z czytaczy posiada ten certyfikat, albo mocno o nim przemyśliwuje – poprosiłbym zatem o komentarz jakowyś, albo też mejla, czy warto w mojej sytuacji podejmować się tego wyzwania? Zobaczę co napiszą mądrzejsci ode mnie – może po zakończeniu przygody z Grailsami wezmę się za ‘powrót do korzeni’.

Dla zainteresowanych podaję kilka linków, pod którymi można znaleźć ciekawe informacje dotyczące egzaminu, a także materiały do nauki:

marzec 24, 2009

HowToJava w sieci!

Zaszufladkowany do: Grails, HowToJava — Tagi:, — chlebik @ 2:38 am

Tak to prawda. Myślałem na początku swojej przygody z Grails, że trochę trudno będzie pokazać cokolwiek szerszej publiczności – hosting Javy do tanich specjalnie nie należy, a ja szczerze powiem, iż wydawanie kilkuset (kilku tysięcy) złotych rocznie w celu quasi-hobbystycznym po prostu jest nieracjonalne. Na szczęście znowu Jacek Laskowski został moim bohaterem dnia.

Otóż istnieje coś tak miłego, jak serwis http://mor.ph, który umożliwia umieszczenie projektu Grailsowego (i nie tylko) na swoich serwerach, a także pozwala na sprawne zarządzanie nim. Cudownie! Od dziś zatem – postępy w pracach możecie śledzić na bieżąco pod adresem: http://howtojava.morphexchange.com. Proszę o wybaczenie jeśli coś nie działa lub się sypie – o to przecież chodzi, wszak wersja nawet nie alpha.

Dla tych, którzy chcieliby również skorzystać z serwisu podaję garść użytecznych informacji. Szybki tutorial jak wrzucić wszystko na serwer (wraz z deploymentem lokalnie) można wyczytać u Jacka. Raczej nie powinno być większych problemów (jakby były to piszcie – odpowiem). Ostrzegę tylko przed kilkoma pułapkami:

  • Należy uważać na plik z konfigiem do bazy. U mnie (MySQL) wygląda on tak i radzę go skopiować bezpośrednio i zmodyfikować. Literówki w deploymencie kosztowały mnie chyba godzinę wysyłania kolejnych wersji.
    production {
    dataSource {
    dbCreate = "update"
    url="jdbc:mysql://<NAZWA_HOSTA>/<NAZWA_BAZY>"
    username="<NAZWA_USERA>"
    password="<HASŁO_DO_BAZY>"
    }
    }

    Oczywiście loginy i hasło wraz z hostami dotyczą danych dla serwisu mor.ph. Wyczytać je można po zalogowaniu w odpowiedniej zakładce. Należy zwrócić uwagę a to, iż dbCreate to update, a także, że ja przeniosłem swój SQL ręcznie poprzez wklejenie kodu do PMA.
  • serwis działa wolno – obecnie (okolice 2-3 w nocy) wysyłanie kodu na serwer jak i deployment trochę trwa (a łącze mam 4MBit).
  • samo wysłanie na serwer nic nie gwarantuje – należy odczekać chwilkę, aż aplikacja nam “chwyci”.

To tyle na szybko. Zapraszam do krótkiej wizyty (zakładka Linki oraz Strona). Na razie to bardzo mało i niewiele, no ale i Google nie od razu napisali.

marzec 22, 2009

Koniec z linkami, czyli kontroler i widok pod kontrolą

Zaszufladkowany do: Grails, Groovy, HowToJava — chlebik @ 11:45 pm

Dziś ostateczne podsumowanie prac nad linkami w “How to Java”. Rzecz malutka, prosta, ale dająca dość obszerny obraz możliwości Grailsów. Na zakończenie szybki rzut oka na kontroler i troszeczkę większy na widok z użyciem GSP.

Jak pisałem w pierwszych postach o “How to Java” – statyczną zawartość umieszczę w jednym kontrolerze – StaticController, dodając ładne mapowanie adresów. Przyszedł czas by spełnić te obietnice. Oto kod kontrolera:


class StaticController {def defaultAction = 'linki'def linki = {[ linki: Htj_Links.list( sort: 'category') ]

}

def strona = { }

}

Jak widać definiujemy dwie akcje – strona oraz linki. Ta druga akcja będzie typowo statyczna – po prostu zostanie zaserwowany statyczny plik GSP. Sama definicja nie jest w tym przypadku konieczna – do tego jednakże wątku powrócę za chwilkę. Zastanowić się wypada co się stanie, kiedy w aplikacji odwołamy się do samego kontrolera, bez podania akcji. Standardowe mapowanie adresów w Grailsach nie wymaga podania akcji, konwencja przejmie tutaj sterowanie:

  • jeżeli w kontrolerze znajduje się tylko jedna akcja, wówczas domyślnie staje się ona podstawową akcją wywoływaną przy podaniu tylko nazwy kontrolera.
  • jeśli z kolei w kontrolerze mamy kilka akcji, domyślnie podstawową staje się ta o nazwie index
  • ostatecznie można tę akcję określić jawnie poprzez taki oto kod:
    def defaultAction = 'nazwaAkcji'

Zatem w kontrolerze dopisałem pro forma taką linijkę, choć docelowo kontroler Static nie będzie widoczny w aplikacji – jego użycie zostanie zakryte przez mapowanie. Teraz może kilka słów o akcji strona. Ma ona służyć wyświetleniu statycznego dokumentu HTML, w którym napisane byłoby kilka słów o stronce “How to Java”. Tak jak napisałem – jeżeli chodzi o wyrenderowanie widoku, bez konieczności jakichkolwiek działań w kontrolerze można ten przypadek obsłużyć inaczej. Należy dobrać się do pliku UrlMappings.groovy i dopisać tam następującą regułę:

"/strona" (view: "strona", controller: "static" )

I od dzisiaj przy wpisaniu po adresie: “/strona” nasze żądanie po prostu wyrenderuje wskazany widok, bez konieczności deklarowania akcji w kontrolerze. Możemy zatem na spokojnie usunąć linijkę z kontrolera.

Na sam koniec zostawiłem linki, gdyż tutaj sprawa jest poważniejsza. O przygodach z klasami domenowymi, które służą do obsługi tychże linków pisałem w poprzednich postach. Teraz zaś weźmiemy się za temat na poważnie:

[ linki: Htj_Links.list( sort: 'category') ]

Linijka ta robi tak wiele. Innymi słowy – wywołuje statycznie metodę list, która listuje wszystkie rekordy z tabeli. Do tego dorzucamy sortowanie po kategorii, a następnie to wszystko jest pakowane do widoku ( nawiasy kwadratowe na końcu akcji to po prostu zbiór zmiennych, które są przypisywane do widoku). Całkiem nieźle jak na krótką linijkę kodu.

Z kolei widok to w połowie otoczka związana z renderowaniem layoutu, zaś nas interesuje samo sedno:


<body><g:if test="${linki.size() > 0}" >
<ul>
<g:each in="${linki}" var="link"><g:if test="${link.category.category_name != poprzedniaKategoria}">
</ul>
<h2>${link.category.category_name}</h2>
<ul>
</g:if><li><a href="${link.address}">${link.title}</a> - ${link.description}</li>
<g:set scope="page" var="poprzedniaKategoria" value="${link.category.category_name}" />
</g:each>
</ul>
</g:if>

</body>

Po kolei. Na samym początku wykorzystujemy znacznik instrukcji warunkowej <g:if>, który sprawdza rozmiar przekazanego zbioru danych. Zasadniczo czynię to tylko po to, aby w razie pojawienia się pustego zbioru nie został wyrenderowany znacznik UL, który nie może być pusty jeśli chcemy pozostać w zgodzie z walidatorami HTML. Tworzymy listę, po czym przechodzimy po przekazanym nam zbiorze danych. I tutaj mała kwestia – kolejna instukcja IF. Rzecz w tym, iż w linkach są kategorie, głupotą zatem byłoby wrzucać wszystkie linki bez składu i rozkładu. Stąd instrukcja warunkowa, która sprawdza, czy poprzednia kategoria linku (zapisywana za pomocą znacznika <g:set>) była inna od obecnej. Jeśli była inna, wówczas zamykamy sobie listę, wyświetlamy nagłówek i tworzymy nową listę. Może i rozwiązanie to nie poraża geniuszem, ale swoją funkcję pełni wyśmienicie. W rezultacie po wprowadzeniu tego kodu (do bazy dodałem trochę danych przez PMA) u mnie przeglądarka wyświetliła coś takiego:

listalinkow

Piękne prawda? I to wszystko osiągnąłem dzięki relatywnie bardzo małej ilości kodu. Jedyne co może denerwować to brak porządku w nazwach linków w konkretnej kategorii – segregowanie językowe powinno na górę wypchnąć linki do Grailsów, zaś do mojego bloga na końcu. Dodamy zatem jeszcze jeden warunek do kontrolera:

[ linki: Htj_Links.list( [sort: 'category', sort: 'title' ]) ]

i możemy cieszyć się z ładniutkiej listy linków. Czysto, schludnie i bezpiecznie. Na dziś to tyle – w następnych wpisach zajmiemy się czymś bardziej dynamicznym – rejestracją użytkowników oraz ich autoryzacją.

marzec 19, 2009

Groovy in action, czyli to co tygrysy lubią najbardziej

Zaszufladkowany do: Groovy, Java — Tagi:, , , — chlebik @ 12:54 am

Zdałem sobie sprawę, iż powoli w swoich postach wychodzę poza klasy dziedzinowe/domenowe i z pola związanego z GORM wypada przejść do bardziej ‘programistycznych’ rzeczy, czyli do kontrolerów i widoków. I co z tego?

Ano to z tego, iż w tych elementach MVC przyda się kilka słów wyjaśnienia dotyczących języka Groovy. Prostota Grailsów umożliwia rozpoczęcie z nimi pracy bez lepszej znajomości języka Groovy. Jednakże jest to taka sama sytuacja jak w przypadku RoRa – pewnym momencie nieznajomość języka bazowego doprowadza do zatrzymania w rozwoju, ba, wręcz konieczności cofnięcia się w nauce. Dlatego też uprzedzając ten stan rzeczy dziś artykuł dotyczący kilku charakterystycznych dla Groovy’ego konstrukcji i rozwiązań.

Na pierwszy ogień idąc domknięcia (ang. closures). Jak piszą w mądrych książkach – “Domknięcia nie są trudne, są inne.” Myślę, że jest to najlepszy możliwy ich opis. Mówiąc zaś w skrócie – domknięcia są to obiekty, które zachowują się jak metody. Mogą przyjmować parametry, mogą zwracać wartość. Takie pomieszanie z poplątaniem, ale dzięki temu jest to konstrukcja kosmicznie wręcz skalowalna i efektowna (o efektywności pewnie kiedyś napiszę). Drugą definicją może być proste stwierdzenie, iż domknięcie to zwykły obiekt, który jest związany z pewnym fragmentem kodu. Jest to może mniej inticyjne, ale mam nadzieję, że przykłady pokażą o co chodzi.

Domknięcia można tworzyć tak:
- “w przelocie”
suma = 0
(1..10).each{ cyferka -> suma += cyferka }

- “z przypisaniem do zmiennej” (do tej pory używane przeze mnie w przykładach)
suma = 0
def domkniecie = { cyferka -> suma += cyferka }

Rozebrać należy ten temat na czyniki pierwsze. Otóż naturalnym odruchem dla programisty Groovy’ego powinno być myślenie – “nawiasy klamrowe, o, domknięcie”!!! Niezależnie od użytej formy ich tworzenia, zawsze jest to domknięcie. Konstrukcja ze strzałką przypomina PHP, ale jej znaczenie i istota jest daleka od odwoływania się do obiektu w PHP. Pewnie zresztą już jest jasne o co chodzi – wszystko, co jest po lewej stronie strzałki to parametry, które są przekazywane do domknięcia (jako parametry metody). To zaś, co znajduje się po prawej stronie strzałki to najzwyklejsze ciało metody. W przypadku domknięć do których przekazujemy tylko jeden parametr, nie wymaga on deklaracji, zaś w kodzie można odwoływać się do niego za pomocą domyślnej zmiennej it, np:

def domkniecie = { println it }
domkniecie("Tutaj chlebik");

Istnieje też trzecia możliwość stworzenia domknięcia. Wystarczy, że dysponujemy metodą w klasie, np:

class Rysowanko {

public void narysujCos( String tekst ) {
System.out.println( tekst );

}
}

To by potraktować tę metodę jako domknięcie wystarczy taka konstrukcja:

Rysowanko egzemplarzDoRysowania = new Rysowanko();
def rysujaceDomkniecie = egzemplarzDoRysowania.&narysujCos;
rysujaceDomkniecie( "Tutaj chlebik po raz drugi!" );

Czyli tworzymy domknięcie w formie pewnego typu wskaźnika do metody. Do czego to się może przydać? Ano na przykład mamy klasę taką jak powyższa, w której znajduje się kilka przeciążonych metod ( parametry to string, jakieś numerki, może jeszcze inne obiekty z własnymi metodami toString). Deklarujemy domknięcie dla tej przeciążonej metody i… i w zależności od przekazanych do domknięcia parametrów wywołuje ono konkretną metodę. Miłe, fajne i przyjemne. Zainteresowanych tematem odsyłam do dokumentacji Groovy, gdzie można sobie na ten temat poczytać więcej.

Innym dość ciekawym elementem języka są operatory specjalne. Znacząco potrafią ułatwić życie programiście, zwłaszcza w kontekście kontrolerów i widoków. Oto one:

  • spread operator ( *. ) – oznacza w skróconym zapisie, iż należy daną metodę/domknięcie wykonać na wszystkich elementach zbioru na rzecz którego została ona wywołana. Ufff, zamotałem. Oto kod:
    def lista = ["Chlebik ", "to ", "kiepski ", "programista."]
    print( lista*.toString() )

    Wyświetli on zgodnie z oczekiwaniami wszystkie elementy listy w formie ciągu wyrazów oddzielonych spacjami
  • Elvis operator ( ?: ) – bardzo przyjemna rzecz, która pozwala nadać zmiennej domyślną wartość na wypadek, gdyby przez przypadek z przypisania wyszły nici (zwrócona wartość to null lub jest po prostu pusta). Kod:
    tekst = jestemObiektem.wyciagnijMojaNazwe()?:"nie wiadomo"
  • Null-safe deference ( ?. ) – pamiętacie te wszytkie konstrukcje IF NOT NULL (lub coś w tym guście)? W Groovy istnieje operator, który wyręcza nas w tej brzydkiej czynności. Oto kod:
    println( zmiennaMogacaBycNullem?.jakiesJejPoleLubMetoda )"
    Jeżeli potencjalny obiekt, którego metodę chcielibyśmy wywołać okaże się być NULL to po prostu nic nie nastąpi. Tyle.

Na sam koniec zostawiłem tzw. Expando. Kolejna rzecz z ‘dynamicznej’ części Groovy, która jednakże może budzić pewne obawy. Zwrócił na to uwagę Jacek Laskowski w swojej prezentacji na WJUGu. Ale do rzeczy. Expando to po prostu obiekt, który zachowuje się w sposób, który określamy ‘na bieżąco’, bez konieczności tworzenia oddzielnej klasy lub pliku. Wkleję może przykład z książki:

def user = new Expando()

user.firstName = 'Christopher'
user.lastName = 'Judd'

user.greeting = { greeting ->
"${greeting} ${firstName} ${lastName}"
}

assert user.greeting("Hello") == 'Hello Christopher Judd'

Jak widać do takiego Expando możemy przypisać pewne wartości, zaś zachowanie (metody) deklarujemy poprzez domknięcia. Świetna sprawa, zwłaszcza by nie zaśmiecać kodu klasami wewnętrznymi.

To tyle jeśli chodzi o ten ciekawy język. Oczywiście rzecz jasna poruszyłem raptem trzy zagadnienia, jednakże uczyniłem tak tylko z powodu wyjaśnienia kilku rzeczy, które na 100% pojawią się w kolejnych wpisach, a wiedza o nich jest konieczna. Zainteresowanych poznaniem Groovy od podszewki zapraszam na oficjalne strony projektu. Można też zaopatrzyć się w literaturę poświęconą zagadnieniu, albo też skorzystać z masy linków, które prowadzą do miejsc związanych z Groovy.

marzec 17, 2009

Koniec sprzątania w modelu

Zaszufladkowany do: Grails, HowToJava, Java — Tagi:, , , , , — chlebik @ 12:38 am

Ostatnio posprzątaliśmy w modelu. I dobrze. Jednakże sprzątaliśmy malutki zaledwie modelik, taki naprawdę tyci tyci. Dzisiaj rozszerzymy go do wersji ostatecznej – gotowej do wdrożenia na serwer produkcyjny.

Mowa oczywiście o klasie Htj_Links(). Skończyłem na tym, iż posiada ona swoje ID (zmapowane za pomocą GORMa na kolumnę w tabeli bazy o nazwie ‘link_id’), adres oraz krótki opis. Dla ułatwienia poznawania frameworka zrezygnowałem w przykładach z odnoszenia się do kategorii linków, które miały być przechowywane w oddzielnej tabeli w bazie. Czas coś z tym zrobić.

Kod klasy domenowej, która opisywać będzie kategorię wygląda następująco:

class Htj_Links_Category {

static mapping = {
table 'htj_links_category'
id column: 'category_id'
}

String category_name;

}

Jak widać również zdefiniowałem nazwę tabeli (jakoś tak nie potrafię zostawić tego samej konwencji), a także kolumnę z kluczem głównym. I tak się teraz zastanawiam. W pliku DataSource.groovy zdefiniowałem typ interakcji z bazą (parametr dbCreate na update) – ciekawe co wyniknie z tego, że nie utworzyłem w bazie tabeli o nazwie zadeklarowanej w mapowaniu. Cóż, małe dopisanie linijki do pliku Htj_Links():

Htj_Links_Category category_id;

I uruchamiam aplikację. Błędem nie sypnęło, aplikacja uruchomiona. Pod adresem, gdzie zostawiłem wylistowanie wszystkich rekordów z bazy i owszem – wylistowało, ale… Tabela htj_links w bazie wzbogaciła się o kolumnę category_id_id (dlaczego tak???) o wartości NULL. Ciekawe. Tablica htj_links_category oczywiście nie została utworzona. No to teraz wracamy do pliku konfiguracyjnego i klepiem dbCreate na create. Mhhhhhmmmmmm, miodzio. Po ponownym rozruchu w bazie pojawiła się tabela htj_links_category z polami:

  • category_id
  • category_name (varchar(255))
  • version (automatycznie dodane przez GORMa

Całkiem całkiem jak widać. Ciekawi mnie tylko wciąż ta dziwna nazwa kolumny w tabeli htj_links. Po namyśle jednakże doszedłem do wniosku, iż skoro jest to egzemplarz klasy domenowej, to pewnie jest kluczem obcym, ergo, do podstawowej nazwy dodaje się suffix ID. Zatem dla ciekawości – usuwam z bazy htj_links_category, a także kolumnę z tabeli htj_links plus zmieniam nazwę pola w klasie Htj_Links na category. I ZONK…

ISTOTNE!!!

Po stworzeniu tabel i wspomnianej kolumny potworzone zostały automatycznie referery na kolumny z kluczami głównymi. Innymi słowy – tabela htj_links_category posiadała własny klucz główny, a oczywiście category_id_id zrefererowało do tegoż klucza, ale ZANIM TEN KLUCZ POWSTAŁ. Dlaczego o tym piszę? Ano dlatego, że próba ręcznego usunięcia tabeli htj_links_category lub kolumny category_id_id skutkowała błędami MySQL. W końcu tabelę usunąłem ręcznie z dysku, a po tej operacji kolumnę z kluczem obcym usunąłem poprzez wywołanie polecenia SQL:

ALTER TABLE htj_links DROP FOREIGN KEY FKDD69A9183B1B60E3;

Po ponownym rozruchu kolejny ZONK – tabela htj_links_category nie raczyła się utworzyć! Ciekawe… No nic – stworzyłem ją ręcznie (tylko klucz główny na category_id i kolumna VARCHAR dla category_name, zaś w DataSource.groovy powróciłem do opcji uaktualniania bazy danych. Rozruch – no i dało radę. Nie wiem czy to mój przypadek, niedoskonałość GORMa, czy jeszcze coś.

Idźmy jednakże dalej (i to pewnie też rozwiąże problem napotkany powyżej). Domyślam się, iż nasz piękny framework z góry założył, że chodzi o relację jeden-do-wielu (patrząc z perspektywy kategorii linku) i dlatego tak to wygląda (klucz obcy tylko w tabeli htj_links). Nie dodaję jakichkolwiek parametrów zawierania i przynależności (belongsTo lub hasMany, gdyż to nie jest tutaj potrzebne). Ręcznie dopisałem do tabeli htj_links_category rekord ( ‘nazwa’ to ‘java’, zaś id zostało wygenerowane automatycznie), po czym wpisałem również ręcznie odpowiedni ID do kolumny category_id w tabeli htj_links. I teraz w kontrolerze wystarczyło dodać taki oto kod:

def lineczki = Htj_Links.list()
lineczki.each{ println(it.category.category_name) }

I wykona się z automatu piękny JOIN i na konsoli powinniśmy otrzymać cudowny wynik w postaci: ‘java’. I o to chodziło! W następnym odcinku zajmę się ubraniem tego wszystkiego w ładniejszy widok.

marzec 14, 2009

Coś się chyba Helionowi pomyliło

Zaszufladkowany do: Java, JavaServerPages — Tagi:, — chlebik @ 12:34 pm

Dziś o czymś troszeczkę innym niż Grails. Odwiedziłem stronę wydawnictwa Helion, coby przepatrzyć jakieś promocje czy nowości. Jakie było moje zdziwienie, kiedy na stronie głównej pośród nowości zobaczyłem tę oto książkę.

Jasno i wyraźnie stoi napisane, iż jest to TOM 2. Hmmm, a gdzie tom pierwszy? W swojej naiwności liczyłem na to, że może chodzi o książkę o JSF, którą miałem okazję zakupić i leży u mnie na półce. Rzeczywistość okazała się jednakże inna – nasze cudowne wydawnictwo przetłumaczyło i wydrukowało tylko drugi tom! Z ciekawości zajrzałem do googla i co się okazuje? Że tom pierwszy tejże książki można sobie spokojnie ściągnąć z internetu spod tego adresu. Wiadomo, jest też jakieś “ale” – w treści książki mamy materiały reklamowe (niezbyt dokuczliwe), a także nie da się ściągnąć wersji all-in-one. Jednakże i to jest świetna gratka dla każdego, kto chciałby poznać tę technologię bliżej. Do tej pory pozostawało tylko “Head First”, a niekoniecznie każdemu forma tej serii wydawniczej pasuje. Jak widać i z pomyłek mogą narodzić się konkretne korzyści :)

marzec 12, 2009

Wiosna nadchodzi – sprzątamy w modelu

Zaszufladkowany do: Grails, Hibernate, HowToJava, Java — Tagi:, , , — chlebik @ 9:19 am

Odezwało się kilka głosów, iż sensowności wcielania w projekt Grailsowy rozwiązań opartych na Hibernate najtężsi filozofowie by się nie doszukali. Zgodnie zatem z zaleceniami czytelników bloga postanowiłem jasno rozgraniczyć Hibernate od rozwiązania oferowanego nam przez Grails – GORM.

W tym miejscu jeszcze tylko uprzedzę i przypomnę raz jeszcze, gdyż kilkunastokrotnie otrzymywałem mejle z pytaniami. Pisanie notek na blogu odbywa się równolegle z czytaniem odpowiedniej literatury (zarówno papierowej jak i online). Taką formułę bloga wybrałem dlatego, gdyż dopracowanych artykułów poświęconym konkretnym zagadnieniom w sieci można znaleźć masę. Najczęściej są one pisane przez praktyków, którzy daną technikę/technologię wykorzystują w codziennej pracy. Tym samym zapomnieli już dawno, z czym mieli problemy na początku. Dzięki mojemu podejściu (jednoczesnego pisania z poznawaniem omawianych zagadnień) z pewnością powtarzam się w niektórych miejsach, albo też piszę kod, który może pozostawiać sporo do życzenia. Ale to chyba najlepsza metoda nauki – obserwować popełniane błędy i wyciągać z nich wnioski. Dotyczy to zarówno mej skromnej osoby, jak i znacznego procenta czytelników.

Na początek może podstawowe wyjaśnienie – GORM to skrót od Grails Object-Relational Mapping. Pojęcie ORM myślę, że nie musi być rozjaśniane. Specyfiką rozwiązania zastosowanego we frameworku jest wykorzystanie sprawdzonego rozwiązania w tej dziedzinie jakim jest Hibernate z tym tylko, że w przypadku GORMa, framework po prostu wrappuje go w składnię groovy. Tak przynajmniej twierdzi mądra książka. W poprzednim wpisie chcąc, albo też nie chcąc zmieszałem te dwa rozwiązania (niepotrzebnie jak mi wskazano). Zatem bierzemy się za wiosenne porządki w kodzie.

Zaczniemy zatem od konfiguracji. GORM jest nadbudową na Hibernate, zatem proces konfiguracji jest w pełni obsługiwany przez mechanizmy frameworka. Czyli plik hibernate.cfg.xml jest zasadniczo niepotrzebny. Jedynym odnośnikiem dla korzystania z baz danych jest konfiguracyjny plik DataSource.groovy. Nie zmienił się on od czasu poprzedniego wpisu. Co więcej – zgodnie z radami komentujących poprzedni artykuł – wyrzuciłem katalogi z bibliotekami z folderu /lib i zostawiłem tam tylko connector do MySQLa (czysty plik JAR). Plik PreInit.groovy tym samym również poszedł w odstawkę.

Sam kod klas domenowych został rozszerzony poprzez jawne zadeklarowanie pola id, a także stworzenie konstruktora inicjalizującego wszystkie te wartości. To na pewno nie jest potrzebne!. Zmieniłem nazwę klasy na Htj_Links, dzięki czemu łatwiej będzie mi się orientować w kodzie (prefixy do nazw tabeli raczej nie ulegają zmianie). Kod mojej klasy domenowej po zmianach wygląda tak:

class Htj_Links {

static mapping = {
table 'htj_links'
id column: 'link_id'
}

String address;
String description;

I w kontrolerze (jakimkolwiek bądź) można sobie wklepać takie coś:

def lineczki = Htj_Links.list()
lineczki.each{ println(it.address) }

I na konsolce radosnie widac efekty wyciagniecia wszystkich elementów z bazy (słownie jednego testowego rekordu). Przyznaję jednakże – robi wrażenie. To tyle na razie – w następnym wpisie posprzątamy w kontrolerach i w widokach.

marzec 6, 2009

Grailsujemy z bazą, cz. II

Zaszufladkowany do: Grails, Hibernate, HowToJava, Java — Tagi:, , , , — chlebik @ 2:19 am

Nasze ostatnie spotkanie z Grails zakończyliśmy na wygenerowaniu za pomocą scaffoldingu gotowej funkcjonalności CRUD. Pobawiliśmy się trochę, ale…

… ale dalej nasza aplikacja nie ma za wiele funkcjonalności. Dane nie zapisują się w bazie danych, ich odczyt też nie bardzo bo i nie ma czego odczytywać. Tym razem postanowimy coś z tym zrobić. Postaramy się zaimplementować choć część funkcjonalności CRUD w oparciu o Hibernate. Do dzieła.

Scaffolding jest bardzo fajny, jednakże został on stworzony w jednym celu – by ułatwić tworzenie klasy domenowej (lub jak mówi Jacek Laskowski – dziedzinowej). To właśnie pisanie testów dla niej, sprawdzenie poprawności odwzorowań i tak dalej jest celem stosowania rusztowania w aplikacji Grails. Kiedy już mamy pewność, że klasa dziedzinowa jest w porządku, wówczas możemy zabrać się za implementację reszty. Przyjrzyjmy się jeszcze raz naszej klasie dziedzinowej:

class Linki {String adress;
String description;
Date addDate;
Integer category_id;

static constraints = {
adress(blank:false, maxSize: 256, nullable: false)
addDate()
description(blank:false, maxSize: 1024, nullable:false)
category_id(blank:false, nullable:false)
}

}

Tak zdefiniowana klasa daje dość duże pojęcie o tym jak powinna wyglądać tabela w bazie danych. Sama baza jeszcze nie istnieje fizycznie w jakimkolwiek RDBMie, ale to za chwilę się zmieni. By zaś pozostać w zgodzie ze wszystkimi prawidłami sztuki – oto jak będą wyglądały tabele dla linków:

htj_linki_baza1

Mamy zatem podstawową tabelę z linkami i pomocnicza, w której zapiszemy kategorię (dokładnie jedną) danego odnośnika. Pora zaprząc do pracy Hibernate. Zanim jednakże to zrobimy wypada powiedzieć parę słów o samej bazie danych. Otóż standardowo będzie to MySQL, wybrany dlatego, że akurat mam go zainstalowanego na dysku :) O swoich przygodach z driverem do JDBC pisałem wcześniej, zatem problemu być nie powinno. Jeżeli zaś chodzi o samego Hibernate, to nie zamierzam tutaj dawać jakiś rozbudowanych teoretyczych wykładów. Kod niech mówi za siebie. Do nauki używam bardzo fajnej książki, którą polecam każdemu.

Zanim zaczniemy pracę trzeba ściągnąć Hibernate i sterownik MySQLa dla JDBC (connector). Konkretne pliki JAR należy wypakować do katalogu /lib naszej aplikacji i jesteśmy gotowi do dalszej pracy (w przypadku Hibernate potrzebuje on też kilku innych bibliotek do pracy – zachęcam do sięgnięcia po książkę lub do dokumentacji). Plik /conf/DataSource.groovy wyglądał u mnie tak:

dataSource {
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
username = "root"
password = ""
}
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = "update" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost/chlebik"
}
}

Próbny rozruch (czy odnajduje klasy JDBC) i… zonk. ClassNotFoundException. Okazało się, że konwencja ponad konfigurację nie dała rady. I teraz zagwozdka – jak cholercia dodać do CLASSPATH Grailsów zewnętrzny plik JAR? Chwil kilka z guglem i cóż się okazuje – wymaga to małego hacka, który dobił mnie totalnie. W katalogu /conf należy utworzyć plik PreInit.groovy i tam wpisać taki oto twór (Update: W bugtrackerze frameworka znalazłem informację, że plik PreInit.groovy zmienia nazwę na BuildSettings.groovy, ale zmiana ta wywala u mnie błąd zatem zostaję przy starej nazwie):

grails.compiler.dependencies = { fileset(dir:'D:/Java/Howtojava/lib/mysql-connector-java-3.1.14/',includes:'*.jar');
fileset(dir:'D:/Java/Howtojava/lib/hibernate-distribution-3.3.1.GA/',includes:'*.jar')}

Tak to wygląda u mnie, ścieżki są bezwzględne (inaczej się jakoś nie dało). Domyślam się, że cała ta zabawa z CLASSPATH i tak dalej wiąże się mocno z wdrażaniem aplikacji, ale póki co nie za bardzo mi się chce zabawiać z meandrami Anta czy innego Mavena. Póki co takie rozwiązanie działa i do prac developerskich w zupełności wystarcza.

Oczywiście skoro mamy już zaimportowane biblioteki trzeba skonfigurować samego Hibernate. Tworzymy plik /conf/hibernate/hibernate.xfg.xml o takiej oto treści:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/chlebik</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.connection.pool_size">10</property>
<property name="show_sql">true</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- Mapping files -->
<mapping resource="grails-app/domain/Linki.hbm.xml"/>
</session-factory>
</hibernate-configuration>

Dane jak widać są zdublowane (występują w konfiguracji DataSource jak i dla Hibernate). Na razie nie wiem co z tych plików ma pierwszeństwo zatem zostawiam dane i tu i tu. Zgodnie z poleceniem z książki teraz wypadałoby stworzyć plik odwzorowań dla klasy Linki. Chwilowo dla jasności przykładu i łatwości zakomentowałem właściwość category_id oraz add_date. Oto kod:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="Linki" table="htj_links">

<id name="id" type="int" column="link_id">
<generator class="native" />
</id>

<property name="address" column="address" type="string" />
<property name="description" column="description" type="string" />

</class>

</hibernate-mapping>

Na szybko utworzona tabelka w bazie:

CREATE TABLE `htj_links` (
`link_id` int(11) NOT NULL auto_increment,
`address` varchar(255) character set utf8 collate utf8_polish_ci NOT NULL,
`description` varchar(255) character set utf8 collate utf8_polish_ci NOT NULL,
PRIMARY KEY (`link_id`)
) ENGINE=InnoDB;

I wrzucony jeden mały link. Do tego oczywiście naszą klasę dziedzinową trzeba przerobić na odpowiednią modłę, aby mogła występować wraz z Hibernate:

public class Linki {

String address;
String description;

static constraints = {
id(blank:false, nullable: false)
address(blank:false, maxSize: 255, nullable: false)
description(blank:false, maxSize: 1024, nullable:false)

}
Linki() {

}

public Linki( Integer id, String address, String description)
{
this.id = id;
this.address = address;
this.description = description;
}

public Integer getId()
{
return id;
}

public void setId( Integer link_id )
{
this.id = link_id;
}

public String getAddress()
{
return address;
}

public void setAddress( String address )
{
this.address = address;
}

public String getDescription()
{
return description;
}

public void setDescription( String description )
{
this.description = description;
}

}

Ufff, tyle roboty, a efektów wciąż nic. Teraz dopiszemy sobie taki oto kod do naszego kontrolera – LinkiController.groovy:

private static final SessionFactory sessionFactory;

static {
try {

sessionFactory = new Configuration ().configure ().buildSessionFactory ();
System.out.println("Identyfikator utworzonego obiektu: " + sessionFactory);
}
catch (Throwable ex) {
System.err.println("Inicjacja SessionFactory nie powiodła się." + ex);
throw new ExceptionInInitializerError (ex);
}
}

public static SessionFactory getSessionFactory () {
return sessionFactory;
}

No i teraz pozostaje tylko uruchomić naszą aplikację. Kiedy w standardowym wyjściu (konsoli) pojawi nam się coś na kształt:

Identyfikator utworzonego obiektu: org.hibernate.impl.SessionFactoryImpl@79404a

To znaczy, że odnieśliśmy sukces. Jak napisałem wcześniej – do istniejącej tabeli z linkami dodałem testowy rekord (wszystkie operacje na bazie dokonywane były przez PHPMyAdmin – nie jest to może podstawowe wyposażenie javowca, no ale ja ułatiwiam sobie życie i póki co pracuję z narzędziami, które wykorzystuję na co dzień). Skoro mamy rekord w bazie danych to wypadałoby na pewno go wyciągnąć. W tym samym kontrolerze pod linijką drukującą informację o naszym obiekcie należy umieścić taki oto kod:

Session session = sessionFactory.openSession();
List linki = session.createQuery("from Linki").list();
System.out.println("Pobrałem rekordów: " + linki.size());

Linki pojedynczyLink = linki.get(0);
System.out.println("Identyfikator rekordu to: " + pojedynczyLink.getId() );
System.out.println("Przypisany link to: " + pojedynczyLink.getAddress() );
System.out.println("Opis rekordu to: " + pojedynczyLink.getDescription() );

Zwrócić należy uwagę, że w naszym przypadku w klauzuli FROM mamy nazwę klasy, a nie tabeli! To dość istotne, inaczej otrzymalibyśmy komunikat mówiący o niemożności znalezienia tabeli. Jako, że rekord będziemy mieli raptem jeden, dostajemy się do niego bezopśrednio poprzez odwołanie się do pierwszego elementu zwróconej listy (oczywiście to tylko przykład, w normalnych aplikacjach takich rzeczy się nie robi). Ja w wyniku otrzymałem ostatecznie taki oto efekt (pogrubienia dodałem dla czytelności):

Identyfikator utworzonego obiektu: org.hibernate.impl.SessionFactoryImpl@1af7e68
Hibernate: select linki0_.link_id as link1_0_, linki0_.address as address0_, linki0_.description as descript3_0_ from htj_links linki0_

Pobrałem rekordów: 1
Identyfikator rekordu to: 1
Przypisany link to: http://www.chlebik.wordpress.com
Opis rekordu to: strona człowieka, który do końca nie wie o co chodzi w tym wszystkim.

I teraz by nie przedłużać (jest trzecia nad ranem) w tymże samym kontrolerze dopiszmy do naszego kodu takie oto coś:

pojedynczyLink.setDescription(" choć może autor i na czymś się zna....");
session.beginTransaction();
session.save(pojedynczyLink);
session.getTransaction().commit();
session.close();

Po uruchomieniu tego kodu zobaczmy efekt, po czym zrestartujmy aplikację. Co otrzymaliśmy z bazy? Może coś takiego:

Identyfikator rekordu to: 1
Przypisany link to: http://www.chlebik.wordpress.com
Opis rekordu to: choć może autor i na czymś się zna....

Cudnie. Jak widać początkowy wysiłek opłacił się i oto w kilku zaledwie linijkach możemy pobrać rekordy, zmienić jeden z nich (lub wszystkie), po czym zapisać je do bazy. Mam nadzieję, że przedstawiony powyżej kod daje choćby mgliste pojęcie o sile Hibernate, czy tez ORMów w ogólności. Następne boje z bazą (zrezygnujemy ze scaffoldingu – tak przy okazji można uruchomić sobie aplikację, przejść do sekcji z linkami i spróbować się pobawić) już niedługo, mam nadzieję, że nie stracicie cierpliwości.

marzec 5, 2009

Nowy layout

Zaszufladkowany do: Blog — Tagi:, — chlebik @ 3:08 pm

Tak przeglądałem ostatnio blog pod kątem możliwych usprawnień, ale jakoś nie znalazłem niczego ciekawego. WordPress z pewnością ma masę ciekawych rozszerzeń, no ale tylko wówczas, kiedy uruchamia się skrypt na własnym serwerze/hostingu.

Natomiast w przypadku domeny wordpress.com nie za wiele tego, ale postanowiłem choć trochę poprawić widoczność kodu, który publikuję na stronie. Poprzedni layout trochę nie do końca się z tym sprawdzał. Zatem oto nowy wygląd – ‘Regulus’.

Starsze wpisy »

Blog na WordPress.com.