Category Archives: SCJPTester

SCJPTester wyświetla newsy – podstawy Springa w praktyce

Dziś przyszedł czas na coś większego. Mam nadzieję, że ilość kodu nie będzie odstraszająca. Ponieważ dziś zaimplementujemy coś z pomocą tandemu Spring + Hibernate. Konkretnie przebudujemy troszeczkę widok strony głównej po to, aby móc wyświetlić ostatnie informacje o aplikacji (podobną rzecz robiliśmy z ProgramBash). Jest to o tyle ciekawe, iż użyjemy Springa w całej jego krasie, stworzymy pierwszą tabelę w naszej bazie, nauczymy się czegoś więcej o kontrolerach, używaniu Hibernate poprzez klasy Springa, a ostatecznie troszeczkę podlejemy to sosem od FreeMarkera. Do dzieła.

Zaczniemy od bazy. Zainstalowałem ją jakiś czas temu, a do naszej aplikacji podpiąłem chwilkę później. W ten sposób wyposażeni możemy stworzyć pierwszą tabelę w bazie danych – konkretnie news:

CREATE TABLE news (
id serial PRIMARY KEY,
title varchar(127) NOT NULL,
content text NOT NULL,
data date NOT NULL
) WITHOUT OIDS ;

Co zaowocuje takim komunikatem:

NOTICE: CREATE TABLE will create implicit sequence "news_id_seq" for serial column "news.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "news_pkey" for table "news"
Zapytanie zostało wykonane w 454 ms i nie zwróciło żadnych wyników.

Mówiąc krótko – została utworzona sekwencja, która została przypisana do kolumny z naszym kluczem głównym (ten też został zresztą utworzony jak widać). Mamy zatem tabelę, na której będziemy pracować – dodałem do niej też 2 rekordy, aby mieć jakieś dane do pracy. Zajmiemy się teraz samym Springiem. Na czym bowiem polega jego zajefajność? Otóż podstawą jest właśnie wstrzykiwanie zależności – mamy obiekt, którego składową jest inny obiekt. Konfigurujemy te 2 obiekty w pliku XML, a Spring zajmie się utworzeniem obiektu, jego przekazaniem i wszystkim po drodze. Jest to o tyle praktyczne, iż redukuje ilość kodu, który trzeba za każdym razem napisać. Deklarujemy po prostu, że potrzebujemy w danym obiekcie innego obiektu i viola – działa. Suchy opis jednakże niewiele znaczy, zatem lepiej przerobić rzecz w praktyce.

Zaczniemy od klasy domenowej dla naszego newsa. Dla tej i pozostałych klas domenowych utworzymy oddzielny pakiet com.wordpress.chlebik.domain. Kod wygląda tak:

package com.wordpress.chlebik.domain;

import java.io.Serializable;
import java.sql.Date;

/**
 * Klasa domenowa dla newsa w serwisie
 *
 * @author chlebik
 */
public class News implements Serializable {

 private    long      id;
 private    String   title;
 private    String   content;
 private    Date     data;

 /**
 * Konstruktor
 *
 * @author chlebik
 */
 public News() {}

 // Gettery
 public long getId() {
 return id;
 }

 public String getTitle() {
 return title;
 }

 public String getContent() {
 return content;
 }

 public Date getData() {
 return data;
 }

 // Settery
 public void setId( int id ) {
 this.id = id;
 }

 public void setTitle( String title ) {
 this.title = title;
 }

 public void setContent( String content ) {
 this.content = content;
 }

 public void setData( Date data ) {
 this.data = data;
 }

}

Nihil novi sub sole. Klasa jest prosta i sztampowa do bólu. Mapowanie:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.wordpress.chlebik.domain.News" table="news">
 <id column="id" name="id" type="int">
 <generator/>
 </id>
 <!--  zwykle kolumny -->
 <property column="content" name="content" type="string"/>
 <property column="title" name="title" type="string"/>
 <property column="data" name="data" type="date"/>
 </class>
</hibernate-mapping>

Należy pamiętać o dopisaniu mapowania do pliku konfiguracyjnego Hibernate. Teraz wypadałoby zaimplementować klasę dostępu do naszej klasy domenowej, czyli mówiąc krótko piszemy DAO. Rzecz jasna wychodzimy od interfejsu, który zdefiniuje kontrakt jaki chcemy by spełniały ew. klasy implementujące. Uwaga! Dla tych co nie wiedzą dlaczego używamy interfejsów ważne wskazanie – posiadając interfejs korzystamy przy ewentualnej pracy z polimorfizmu. Zatem nagłe przepisanie aplikacji z MySQLa na PostgreSQL i na odwrót nie stanowi problemu, gdyż ew. obiekty przekazujemy rzutując w górę na interfejs.

Rzecz jasna w przypadku newsów na stronie głównej problemu nie ma – będzie tam póki co jedna metoda, która będzie nam wyciągała nasze newsy w określonej ilości. Może i dla takiego zastosowania możnaby od razu sklepać klasę, ale ani to profesjonalne, ani nie wykształca dobrych zachowań. Zatem tworzymy prosty interfejs w pakiecie com.wordpress.chlebik.dao.interfaces.

package com.wordpress.chlebik.dao.interfaces;

import com.wordpress.chlebik.domain.News;
import java.util.List;

/**
 * Interfejs specyfikujacy kontrakt dla klas DAO newsow w serwisie
 *
 * @author chlebik
 */
public interface NewsDaoInterface {
 public List<News> getNews( int counter );
}

Interfejs mamy – teraz przyszedł czas na klasę go implementującą. I tutaj pierwszy styk Springa z Hibernate. Ten pierwszy posiada gotowe klasy, które służą obsłudze zapytań SQLa poprzez Hibernate. Oczywiście skorzystamy z tej możliwości, tym bardziej, że ułatwia to pisanie kodu. Jak bowiem wyglądałaby nasza klasa DAO? Zaimplementowalibyśmy metodę, w której wyciągalibyśmy sesję, potem ją zamykali, obsługa wyjątków, blech, coś brzydkiego, prawie jak JDBC. Zaczniemy od konfiguracji – musimy poinformować Springa, że używać będziemy Hibernate. Jednakże wprowadzimy pewien porządek, coby nie mieszać niepotrzebnie w dotychczasowym pliku konfiguracyjnym. Stworzymy oddzielny plik XMLa z konfiguracją bazy danych, a następnie zaimportujemy go do obecnie już istniejącego frontcontroller-servlet.xml. Nasz plik nazwiemy database-config.xml i wrzucamy do katalogu WEB-INF:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 <bean id="dataSource">

 <property name="driverClassName">
 <value>org.postgresql.Driver</value>
 </property>
 <property name="url">
 <value>jdbc:postgresql://88.198.31.169/chlebik</value>
 </property>

 <property name="username"><value>MOJ_USER</value></property>
 <property name="password"><value>MOJE_HASLO</value></property>
 </bean>

 <bean id="mySessionFactory">

 <property name="mappingResources">
 <list>
 <value>News.hbm.xml</value>
 </list>
 </property>

 <property name="hibernateProperties">
 <props>
 <prop key="hibernate.dialect">
 org.hibernate.dialect.PostgreSQLDialect
 </prop>
 </props>

 </property>
 <property name="dataSource">
 <ref bean="dataSource"/>
 </property>

 </bean>
</beans>

Zaś do pliku frontcontroller-servlet.xml dopisujemy taki kod (dotyczy bazy danych jak i naszego beana z newsami):

<import resource="database-config.xml"/>

  <bean id="newsDao" class="com.wordpress.chlebik.dao.implementation.NewsDao">
        <property name="sessionFactory" ref="mySessionFactory" />
     </bean>

  <bean name="/index.html" class="com.wordpress.chlebik.controllers.IndexController">
       <property name="newsDao" ref="newsDao" />
  </bean>

Mamy pokonfigurowane stosowne beany by ogarnąć połączenie z bazą danych. W ten sposób wstępnie poinformowaliśmy Springa (zdefiniowaliśmy bean) o istnieniu fabryki sesji Hibernate. Ślicznie. Dzięki temu możemy teraz zastanowić się nad implementacją klasy DAO dla newsów. Mamy tutaj kilka możliwości:

  • HibernateDaoSupport – jest to klasa, którą powinny rozszerzać nasze klasy implementujące interfejs DAO konkretnej encji. Dzięki jej użyciu uzyskujemy o wiele łatwiejszy dostęp do sesji (po to właśnie skonfigurowaliśmy session factory), co prawda może to momentami być problematyczne ( o tym pewnie kiedy indziej napiszę ), dla obecnego przykładu powinno być OK.
  • HibernateDaoSupport wraz z obiektem pomocniczym HibernateTemplate – jest pokłosiem powyższego – również rozszerzamy klasę HibernateDaoSupport, ale za to odowłujemy się również do obiektu pomocniczego HibernateTemplate, co znacznie skraca kod.

Jako, że jedno wynika z drugiego pokażę obie implementacje. W wersji pierwszej po prostu rozszerzymy klasę HibernateDaoSupport:


package com.wordpress.chlebik.dao.implementation;

import com.wordpress.chlebik.dao.interfaces.NewsDaoInterface;
import com.wordpress.chlebik.domain.News;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * Klasa DAO dla newsów
 *
 * @author chlebik
 */
public class NewsDao extends HibernateDaoSupport implements NewsDaoInterface {

 List<News> newsy;
 SessionFactory sessionFactory;

 /**
 * Bezargumentowy konstruktor
 */
 public NewsDao() {}

 /**
 * Wyciaga newsy w zadanej ilosci
 *
 * @param   int    counter
 * @return  List<News>
 */
 public List<News> getNews(int counter) {

 try {

 Session session = getSession();
 newsy = (List<News>)session.createQuery( "from News order by data desc limit " + counter ).list();
 releaseSession( session );
 return newsy;

 } catch ( Exception e ) {
 System.out.println( e.toString() );
 }

 return newsy;

 }

 public List<News> getNewsy()  {
 return newsy;
 }

 public void  setNewsy( List<News> lista )  {
 newsy = lista;
 }
}

Jak widać łatwiej dostać się do sesji, łatwiej ją uwolnić i w ogóle jest zawsze czysto, zawsze sucho i powiedzmy, że zazwyczaj pewnie. Jednakże kod ten można jeszcze bardziej uprościć i doprowadzić do takiej oto postaci (sama metoda getNews()):

public List<News> getNews(int counter) {
         return (List<News>) getHibernateTemplate().find( "from News order by data desc limit " + counter );
}

Obiekt pomocniczny HibernateTemplate udostępnia kilka najbardziej popularnych metod używanych przy pracach z bazami danych, dlatego też w tak prostych przypadkach jego użycie jest jak najbardziej wskazane. Po więcej informacji na temat tej klasy odsyłam do dokumentacji. Ja użyłem metody find, która jak widać wyciąga rekordy pasujące do zapytania. Uwaga! Używanie tego podejścia jest bardzo szybkie i przyjemne, ale automatycznie mocno skazuje nas na integrację ze Springiem. W przypadku gdybyśmy chcieli zmienić coś w samym kodzie aplikacji i ewentualnie przemigrować jego kawałek na inny framework mielibyśmy trochę roboty. Polecam odnośnik z jednego z komentarzy do tutoriala Darka Zonia ( mały link ).

Cóż nam teraz zostało? Sprawdzić czy w ogóle coś działa! Odwołamy się do istniejącego już kontrolera – IndexController. Tam w metodzie handleRequest do tej pory zwracaliśmy prostą instancję ModelandView. Na razie zostawimy ten temat sam sobie, natomiast stworzymy obiekt DAO i zobaczymy czy na pewno zwrócił to, co powinien zwrócić. Modyfikujemy zatem ww. metodę i dodajemy taki oto kod:


newsy = newsDao.getNews(MAIN_PAGE_NEWS_COUNTER);
System.out.println( "Zwroconych newsow " + newsy.size() );

Jak widać do kontrolera dodałem też stałą, która będzie nam wskazywała ile newsów pobrać na główną stronę. W codziennej praktyce rzeczy związane z konkretnym kontrolerem/akcją umieszczam najbliżej jak się da – do tego jako stałą. Jakoś tak bardziej to elegancko wygląda. Choć pewnie w komercyjnym projekcie dla zewnętrznego klienta takie rzeczy powinno się trzymać w zewnętrznym pliku, a konto łatwiejszego utrzymania. Uruchamiamy nasz projekt. I w konsoli wyskakuje krótkie:


Zwroconych newsow 2

Czyli coś poszło tak jak powinno 😉  Oczywiście kwestia jest teraz taka, że wypadałoby owe newsy przedstawić w odpowiedni sposób. Rzecz jasna wpierw trzeba listę z newsami przekazać do widoku. W kontrolerze zatem zamieniamy linijkę z instrukcją zwrotu obiektu ModelandView na następującą:


return new ModelAndView( "index", "newsList", newsy );

I po kilku zabawach z CSSem oraz z modyfikacją widoku:

  <#list newsList as News>
                  <div class="col">
                      <h4 style="color: #FFF2B3;">${News.title}</h4>
                      <h5>${News.data}</h5>
                      <p style="font-size: 10px; line-height: 1.2em;">${News.content}</p>

                  </div>
    </#list>

Znaczniki są dość samo-opisujące. Mamy zwykłą iterację po liście i ostateczny efekt wygląda w taki oto sposób:

Wakacje w pełni, a Chlebik wraca do gry

Witam serdecznie. Po kilku tygodniach ciszy merytorycznej na blogu dziś oficjalnie oznajmiam, że w środku okresu wakacyjnego powracam do gry 🙂

Co prawda wciąż próbuję zgrać pracę w nowym miejscu z dotychczasowymi przyzwyczajeniami, ale powoli osiągam na tym polu sukcesy i nawet deszcz za oknem nie jest w stanie zniszczyć mojego opanowania i ładu wewnętrznego 😉  Co zatem na dniach? Na pewno powrót do zabawy ze Springiem w postaci projektu SCJPTester.  Już samo to wiele znaczy, ale na pewno też spróbuję czasem przemycić coś z zupełnie innej beczki, ale nie chcę niczego obiecywać, aby nie narzucać sobie czegokolwiek. Zresztą urlop na horyzoncie zatem i wolnego czasu dla bloga ciutkę mniej, ale pocieszam się, że dłużej jeżdżę pociągiem teraz, a internet mobilny w komórce działa bez zarzutu. Wpisy z pociągu… ciekawe.

SCJPTester w wersji HelloWorld!

Dzisiaj zrobimy coś poważniejszego. Konkretnie postaramy się sprawić, że nasz SCJPTester zaistnieje w sieci, a także sprawimy by owo zaistnienie było czymś więcej niż wyświetleniem zwykłej strony JSP z napisem “Hello World!”. Do roboty.

W tym momencie jednakże nie wiem od czego tak naprawdę zacząć. Może od samego Spring MVC, gdyż to w jego strukturze będziemy się poruszać. Już po nazwie widać, iż realizujemy wzorzec MVC, co jest bardzo dobre, ale co więcej – Spring MVC implenentuje również wzorzec Front Controllera, to znaczy, iż wszystkie żądania skierowane do aplikacji przechodzą przez jedno miejsce (niezależnie od requestu). Poniżej ładny schemat zaczerpnięty ze stron Spring MVC:

Jest mi to wszystko o tyle bliskie, że w codziennej pracy z PHP korzystam z tych samych wzorców. Podoba mi się to również z tego powodu, iż wiadomo gdzie przychodzi nasze żądanie, można z nim po drodze zrobić jeszcze wiele ciekawych rzeczy. O wiele bardziej to przejrzyste niż JSF. Lecimy dalej. Nasz front controller jest najzwyklejszym serwletem, który dziedziczy po klasie HttpServlet i jako taki powinien być zdefiniowany w pliku web.xml. Podstawowa konfiguracja wyglądałaby na przykład tak:


    <servlet>
        <servlet-name>frontcontroller</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>frontcontroller</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

Domyślnie Spring MVC załaduje wszystkie ustawienia z pliku web.xml, jednakże przy każdym requeście (w powyższym przykładzie do zasobów kończących się na .html) zostanie uruchomiony serwlet o nazwie frontController. W tym momencie mechanizm ładujący spróbuje znaleźć w katalogu WEB-INF dodatkowy plik z konfiguracją, według wzoru:

[nazwa-serwletu]-servlet.xml

Dzięki czemu możemy mieć wyspecjalizowany plik kontekstu dla konkretnego typu żądań (np. do takich, które wymagają zwrotu nie HTMLa, ale np. pliku PDF). Generalnie w myśl mojego zamysłu aplikacja będzie posługiwała się rozszerzeniami *.html. Samych stron jakoś specjalnie wiele to nie będzie, dlatego też poprzestaniemy na opisowych nazwach “niby-routingu”, czyli np. login.html czy testuj.html. Request do konkretnego zasobu jest podpinany pod klasę kontrolera, która go obsłuży. Spring dostarcza szereg bazowych klas, które powinny być użyte do obsługi żądań (w sensie – należy po nich dziedziczyć). Dlatego też w pliku frontcontroller-servlet.xml pojawi się taki kod:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <!-- the application context definition for the springapp DispatcherServlet -->

  <bean name="/index.html" class="com.wordpress.chlebik.controllers.IndexController" />

</beans>

I teraz trzeba napisać nasz kontroler. Generalnie jego zadaniem będzie serwowanie zwykłej statycznej strony, zatem nie ma potrzeby korzystać z jakiś bardziej zaawansowanych klas Springa – zaimplementujemy po prostu interfejs Controller, który jest bazowym dla wszystkich klas kontrolerów. O innych klasach implementujących ten interfejs napiszę później przy tworzeniu bardziej zaawansowanej użyteczności:

package com.wordpress.chlebik.controllers;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

/**
 *  Klasa kontrolera dla strony glownej
 *
 * @author chlebik
 */
public class IndexController implements Controller {

 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    return new ModelAndView("index.jsp");
  }

}

Na razie odnosimy się do prostej strony index.jsp, która została utworzona wraz z całym projektem. Jest ona też wpisana w pliku web.xml na liście plików powitalnych dla aplikacji. Po małych przeróbkach z mojej strony plik ten wygląda tak:


<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>SCJPTester</title>
    </head>
    <body>
        <h1>Bardziej rozbudowane Hello World!</h1>
    </body>
</html>

No i po uruchomieniu aplikacji widzimy taki ekran:

Rzecz jasna jest to domyślny start poprzez odwołanie się do domeny localhost:8084, sprawdźmy zaś, czy nasz kontroler daje sobie radę. Odwiedzamy adres localhost:8084/index.html i widok nam się nie zmienił – czyli jesteśmy w domu, kontroler działa. Jednakże jak na razie jest to dość słabe HelloWorld. Dorzucimy do tego przykładu ładny widok – czyli podepniemy FreeMakera wraz z całym layoutem. Na pewno będzie się przyjemniej z tym wszystkim pracowało.

Wpierw zatem trzeba się zatroszczyć o same źródła biblioteki FreeMarker. Odwiedzamy starego znajomego POM.xml i w zależnościach projektu dopisujemy:

 <dependency>
   <groupId>org.freemarker</groupId>
   <artifactId>freemarker</artifactId>
   <version>2.3.16</version>
 </dependency>

I dociągamy tę zależność. Kiedy FreeMarker pojawi się nam na liście bibliotek jesteśmy w domu. Tak w ogóle to zdecydowałem się na tę bibliotekę, gdyż jest ponoć bardzo podobna do Velocity (czyli poznaję prawie 2 rzeczy za cenę 1:) ), a do tego Spring posiada do tego wyprowadzenie (w sensie integracji widoku), ale do tego jeszcze dojdziemy. Co konkretnie robi FreeMarker? Organizuje nam widok – jest to w zasadzie system szablonów – czyli dzięki niemu stworzymy sobie cały layout strony, a także będziemy dzięki niemu operować w widoku na danych, które dostaniemy z modelu. Problem z FreeMarkerem jest taki, że w sieci jest masa tutoriali na temat jego połączenia ze Springiem, jednakże najczęściej na przykładzie 1 statycznej strony się kończy. Takie zaś rozwiązania były dobre przy HTMLu 3 jakieś 10 lat temu, jak nie lepiej. Dlatego też ja pokażę jak przygotować projekt do życia – czyli zbudujemy sobie cały layout, który będzie dynamicznie wypełniany w zależności od wywołanego zasobu. Do dzieła!

FreeMarker jest już w naszej bibliotece. Teraz należy poinformować Springa o jego istnieniu, a także ustawić, że wyświetlamy widok inaczej niż za pomocą czystych stron HTMLa. Zatem odwiedzamy web.xml i klepiemy tam takie coś:

<servlet>
    <servlet-name>freemarker</servlet-name>
    <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>

    <!-- FreemarkerServlet settings: -->
    <init-param>
      <param-name>TemplatePath</param-name>
      <param-value>/WEB-INF</param-value>
    </init-param>
    <init-param>
      <param-name>NoCache</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>ContentType</param-name>
      <param-value>text/html</param-value>
    </init-param>

    <!-- FreeMarker settings: -->
    <init-param>
      <param-name>template_update_delay</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>default_encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>number_format</param-name>
      <param-value>0.##########</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>
  </servlet>

To na początek kilka podstawowych ustawień servletu FreeMarkera. Wartości są dość jasne – warto tylko zwrócić uwagę na parametr template_update_delay – ustawienie tam wartości 0 jest dobre dla środowiska developerskiego. Dla oddzielnych pików layoutu rzecz jasna utworzymy specjalny katalog w folderze WEB-INF, dzięki czemu nie da się otworzyć poszczególnych składowych w przeglądarce. Dla swojej aplikacji jak zawsze skorzystałem z darmowego szabloniku, który można podejrzeć w tym miejscu. Szablonik rzecz jasna posiada coś takiego jak nagłówek, menu, główną treść i content. Dlatego też naturalnie rozbijemy go na kilka oddzielnych części
i ładować potrzebne nam części. FreeMarker składuje szablony w plikach z rozszerzeniem *.ftl. Tworzymy katalog layout w folderze WEB-INF i wrzucamy tam plik layout.ftl:

<#macro scjptesterLayout>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>SCJPTester</title>
        <meta http-equiv="Content-Language" content="Polish" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link href="/css/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <div id="header">
          <h1><a href="/index.html">SCJPTester</a></h1>
          <ul id="menu">
            <li class="active"><a href="/index.html">główna</a></li>
            <li><a href="/start.html">zarejestruj/zaloguj</a></li>
            <li><a href="#">demo</a></li>
            <li><a href="#">kontakt</a></li> 
          </ul>
        </div>
    
        
      <div class="wrap">

       <#nested />
          

        </div>
        <div id="footer">
          <p class="right">Design: <a href="http://www.solucija.com/">Luka Cvrk</a></p>
          <p>&copy; Nazwa 'SCJPTester' &middot; jest własnością Michała 'Chlebika' Piotrowskiego</p>
        </div>
    </body>
</html>
</#macro>

Jest to zwykły layout (na razie większość linków i menu są dość umowne), w którym jednakże widać kilka nowości. Pierwsza linijka kodu mówi już wiele – tworzymy własne makro, któremu nadajemy określoną nazwę. Całość HTMLa musi być zawarta w treści tegoż makra. W środku do tego, konkretnie w miejscu gdzie będziemy chcieli, aby wyświetlana zawartość zmieniała się w zależności od wybranego zasobu – wrzuciliśmy znacznik: #nested. W tym miejscy FreeMarker wrzuci nam stosowny widok. Pliki z obrazkami oraz CSSem należy wrzucić bezpośrednio do katalogu webapp, dzięki czemu będzie on dostępny z poziomu przeglądarki – bez tego nic ładnego nam się nie pokaże. W katalogu WEB-INF tworzymy także podkatalog views, gdzie będziemy składować poszczególne widoki dla konkretnych akcji. Taki podział wprowadza trochę czystości do widoków, od razu wiadomo gdzie i czego szukać. Teraz do tego musimy poddać edycji plik frontcontroller-servlet.xml i wrzucić tam taki oto kod (zwróć uwagę na zapisy o kodowaniu – mi zeszło na rozkminienie tego 2h):

<bean id="freemarkerConfig"
  class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath"
   value="/WEB-INF" />

  <!-- To jest niemozliwie wrecz wazne - bez tego bedziemy mieli krzaki w widoku zamiast UTF-8  -->
 <property name="freemarkerSettings"> 
    <props>
         <prop key="default_encoding">UTF-8</prop>
    </props>
 </property>

 </bean>


 <bean id="viewResolver"
  class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
      <property name="cache" value="true" />
      <property name="prefix" value="/views/" />
      <property name="suffix" value=".ftl" />

      <!-- if you want to use the Spring FreeMarker macros, set this property to true -->
      <property name="exposeSpringMacroHelpers" value="true" />

       <!-- To jest niemozliwie wrecz wazne - bez tego bedziemy mieli krzaki w widoku zamiast UTF-8  -->
      <property name="contentType" value="text/html;charset=UTF-8"></property>

 </bean>

Powiadamiamy w ten sposób FreeMarkera gdzie ma szukać plików z szablonami, a także w jakim formacie się to odbędzie (określenia prefix i suffix dla ViewResolvera). W związku z takim określeniem reguł, kod w kontrolerze musimy zmienić na:

 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {


    return new ModelAndView("index");
  }

Dzięki takiemu podejściu przy ewentualnej zmianie koncepcji widoku wystarczy, że zmienimy dane w pliku XML i możemy zmienić katalog, gdzie nasze pliki leżą, że o i ich rozszerzeniu nie wspomnę. Teraz na koniec wystarczy stworzyć plik index.ftl w katalogu views:

<#import "../layout/layout.ftl" as layout>
<@layout.scjptesterLayout>

  <div id="teaser">
      <div class="wrap">
       
        <div class="box">
          <h2>Witaj na stronach aplikacji <em title="SCJPTester">SCJPTester</em></h2>
          <p>Aplikacja ta powstała jako projekt edukacyjny Michała 'Chlebika' Piotrowskiego, w celu praktycznego poznania frameworka <strong>Spring</strong>, a także szeregu innych
          technologii. Projekt powstał niedawno zatem jego funkcjonalność jest na razie znikoma, jednakże stan ten zmienia się bardzo szybko. Więcej informacji na temat aplikacji
          moża znaleźć <a href="https://chlebik.wordpress.com">na blogu autora.</a></p>
        </div>
      </div>
    </div>


      <div class="col">
        <h3>Zarejestruj <span class="red"> się!</span></h3>
        <p>Bardzo szybki i prosty proces rejestracji pozwoli Ci od razu rozpocząć przygotowania do egzaminu.</p>
      </div>
      <div class="col">
        <h3>Kontroluj <span class="red">postępy</span></h3>
        <p>Dzięki panelowi statystyk będziesz mógł sprawdzić swoje postępy w nauce. Wyniki poprzednich testów zostaną zapisane i w każdej chwili można je przejrzeć.</p>
      </div>
      <div class="col last">
        <h3>Zgłaszaj <span class="red">własne pomysły</span></h3>
        <p>Jeżeli zaproponowane pytania nie są dla Ciebie wyzwaniem - stwórz swoje własne i podziel się nimi z innymi użytkownikami serwisu!</p>
      </div>



</@layout.scjptesterLayout>

I jesteśmy w domu. W pierwszej linijce importujemy nasz layout (wskazujemy konkretny plik) do konkretnej przestrzeni nazw, w tym przypadku layout. Niestety tak to wygląda, gdyż próby podpięcia automatycznego wgrywania pliku layoutu poprzez edycję web.xml nie powiodły się. Gdyby ktoś wiedział jak to osiągnąć byłbym wdzięczny. Uruchamiamy aplikację i przechodzimy pod adres http://localhost:8084/index.html i viola – mamy stronkę główną (poniosło mnie trochę przy marketingowych zwrotach, zatem wybaczcie :).

Teraz przyszedł czas na poprawienie naszej strony startowej. Należy przypomnieć, iż określiliśmy kontroler, który jest odpowiedzialny za obsługę żądań do zasobów kończących się na *.html. Jednakże wypadałoby zrobić coś z faktem, iż nasza główna strona będzie wyświetlana również w sytuacji, kiedy w pasku adresu wpiszemy tylko nazwę domeny. Tutaj w przypadku ProgramBash stosowałem zwykły plik HTML z redirectem. Jednakże nie jest to potrzebne. Do pliku web.xml dopisaliśmy regułę, iż wszystkie requesty kończące się na HTML są przechwytywane przez FreeMarkera. W takim razie w katalogu webapp tworzymy PUSTY plik index.html i dopisujemy go do listy plików powitalnych w web.xml

 <welcome-file-list>
        <welcome-file>index.html</welcome-file>
 </welcome-file-list> 

I teraz już bez konieczności zabaw w jakiekolwiek przenoszenie – wszystkie requesty, które pójdą na naszą domenę (jednakże te “całościowe” z prośbą o stronę główną) zostaną obsłużone w ten sam sposób co requesty przychodzące na adres http://domena.pl/index.html. Proste jak konstrukcja gwoździa, szkoda, że dopiero po tym jak się wyczyta o tym u wujka Google. To tyle na dziś – przyznam, że pomijając przygodę z kodowaniem stron w FreeMarkerze i nieudaną próbę podpięcia domyślnego layoutu poznawanie Springa jest całkiem przyjemne. Szybki rzut oka na klasy kontrolerów dostarczane wraz ze Springiem utwierdził mnie w przekonaniu, że ktoś wiedział co robi projektując te narzędzie.

Mavenizacji ciąg dalszy – dlaczego tym razem wyszło

Dziś znów na tapecie Maven. Nie tak dawno pisałem jak poszły moje pierwsze boje z tym narzędziem. W skrócie – nie poszły.

Zakończyłem jednakże prace z szkieletem projektu i po chwili namysłu (plus fakt, że poszedłem spać przed 3) stwierdziłem, że może to i dobrze. Jak wspominałem w poprzednim wpisie w dokumentacji Springa jest opisane tworzenie projektu krok po kroku, wraz z dodawaniem katalogów i takich tam. Stwierdziłem zatem, że jeśli już poznawać nowe narzędzie to od samych podstaw, a do takowych na pewno będzie należało klepanie wszystkiego z palca. Przypomina to trochę poznawanie linuxa od instalowania Gentoo, ale co tam. Utworzony projekt wygląda na razie bardzo skromnie:

Nie ma tego wiele. Podpięte mamy tylko API do serwletów oraz JUnit i to jeszcze nie w wersji 4. Widok w IDE rzecz jasna nie odzwierciedla sytuacji na dysku – tak projekt wygląda od strony plików i katalogów:

Tutaj wiemy już coś więcej. W katalogu src będzie trzymany kod – zarówno ten “podstawowy”, jak i pliki związane z prezentacją w sieci jak np. CSS czy obrazki. Znajdziemy też wstępnie katalog do trzymania testów, a także przygotowany katalog dla plików wygenerowanych i gotowych do wdrożenia na serwerze. Sugeruję zajrzeć do pliku POM.xml, który jest podstawowym plikiem dla Mavena. Na razie jest on dość prosty i krótki:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.wordpress.chlebik</groupId>
 <artifactId>scjpsym</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>scjpsym</name>
 <url>http://maven.apache.org</url>

 <dependencies>

 <dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>servlet-api</artifactId>
 <version>2.5</version>
 <scope>provided</scope>
 </dependency>

 <dependency>
 <groupId>javax.servlet.jsp</groupId>
 <artifactId>jsp-api</artifactId>
 <version>2.1</version>
 <scope>provided</scope>
 </dependency>

 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>3.8.1</version>
 <scope>test</scope>
 </dependency>

 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>2.0.2</version>
 <configuration>
 <source>1.5</source>
 <target>1.5</target>
 </configuration>
 </plugin>
 </plugins>
 <finalName>scjpsym</finalName>
 </build>
 <properties>
 <netbeans.hint.deploy.server>Tomcat60</netbeans.hint.deploy.server>
 </properties>
</project>

Dość istotna jest ostatnia część pliku, a mianowicie plugin maven-compiler-plugin. Domyśłnie Maven kompiluje kod zgodny z Javą w wersji bodajże 1.3, co jest zasadniczo prehistorią. Dlatego też określenie docelowej wersji na 1.5. Powiedzmy, że na razie taki plik nam starcza. Jednakże aplikacja ma za zadanie działać ze Springiem, Hibernate i Spring MVC. Tutaj dochodzimy do sedna sprawy – zależności. W powyższym przykładzie element dependencies zawiera w sobie opisy pojedynczych bibliotek wraz z ich wersjami. Co więcej – dodanie bibliotek spowoduje przy budowaniu projektu próbę zainstalowania (w sensie dodania do projektu) bibliotek potrzebnych by pracowały te wskazane przez nas. Są to tzw. zależności przechodnie i każdy kto swego czasu pracował z linuxami opartymi na pakietach RPM doceni jak miłą rzeczą jest brak konieczności martwienia się o zależności.

Mała uwaga! Standardowo aplikacje tworzę w środowisku Windows. Zakładam rzecz jasna, że czytelnicy mojego bloga wiedzą, że kiedy napiszę dla przykładu, iż należy wywołać komendę mvn install to albo zrobią to z poziomu konsoli, albo np. Cygwina. O konieczności dopisania lokalizacji plików wykonywalnych Mavena do zmiennych systemowych chyba nie muszę wspominać.

Na początek powiedzmy, że chcemy poprawić naszą wersję JUnita. Trochę nie bardzo wygląda wersja 3.8.1, kiedy kilka tygodni temu wyszła wersja o 1 oczko “wyższa”. Edytujemy zatem plik POM.xml i zmieniamy numerek wersji na 4.8.1. Teraz wystarczy dać PPM na zakładce Test Libraries i wybrać opcję Download missing dependencies. Mamy nowego JUnita.

Zajmiemy się teraz Springiem. Postanowiłem używać wersji 2.5.6, gdyż najnowsza (trzecia) została wydana raptem w lutym bodajże, dlatego też nie jest dla mnie na tyle “wiarygodna” by pisać w niej edukacyjną aplikację (w sensie pierwszej styczności z frameworkiem). Do tego dorzucimy rzecz jasna Spring MVC. Takie zależności dopisujemy do odpowiedniego miejsca w POM.xml.

 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring</artifactId>
    <version>2.5.6</version>
    <type>jar</type>
    <scope>compile</scope>
 </dependency>

 <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>2.5.6</version>
    <type>jar</type>
    <scope>compile</scope>
 </dependency>

Próba zbudowania projektu w tej chwili po prostu się nie powiedzie. Dlatego choćby, że nasze biblioteki nie zostały bynajmniej ściągnięte. Prawy przycisk myszy na zakładce Libraries i bodajże wybieramy Download source (nie jestem w stanie powtórzyć sytuacji, kiedy nie mam źródeł na kompie, nawet przy nowym projekcie). Jednakże zasadniczo przy dodawaniu zależności należy obserwować widok naszego projektu, gdyż NetBeans wszystko startuje od razu. Grzebiąc dalej trzeba by dodać Hibernate i tutaj zrobimy inaczej. Prawy przycisk myszy na zakładce libraries i wybieramy AddDependency. Pola na górze przeznaczone dla id artefaktu i grupy są podpięte pod autocompleter – zatem spokojnie można wpisać tam org.hi i na liście powinniśmy zostać już tylko z Hibernate. Ostatecznie po dodaniu wpis w pliku konfiguracyjnym wygląda tak:

  <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate</artifactId>
          <version>3.2.6.ga</version>
      </dependency>

Jeśli potencjalnie chcemy używać adnotacji do kontrolowania Hibernate, wówczas trzeba dodać jeszcze taką oto zależność:

 <dependency>
    	<groupId>org.hibernate</groupId>
    	<artifactId>hibernate-annotations</artifactId>
    	<version>3.4.0.GA</version>
    </dependency>

Poprzez dodanie tych dwóch zależności do listy używanych bibliotek zostanie przy okazji dołączony szereg innych. Teraz dla odmiany z konsoli uruchomimy Mavena by pociągnął wszystkie świeże zależności. Polecenie jest proste:

mvn compile

Niestety okazało się, że nie udało się dociągnąć zależności JTA – zrobimy to ręcznie – wchodząc na podaną przez Mavena stronę i ściągając plik JAR na nasz komputer. Potem w konsoli:

mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B -Dpackaging=jar -Dfile=sciezka\do\pliku\jar\wraz\z\nim\samym

No i udało się – plik zainstalowany. Jednakże samo Hibernate to także plik konfiguracyjny. No i tutaj trzeba utworzyć ten plik, a także wskazać go aplikacji. W tym celu w katalogu projektu (konkretnie ścieżka to src/main/resources) tworzymy katalog hibernate i tam wrzucimy nasz plik hibernate.cfg.xml:

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

    <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
    <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
    <property name="hibernate.connection.url">jdbc:postgresql://88.198.31.169/chlebik</property>
    <property name="hibernate.connection.username">moj_tajny_login</property>
    <property name="hibernate.connection.password">moje_tajne_haslo</property>


  </session-factory>
</hibernate-configuration>

I teraz w pliku POM.xml w elemencie build dodajemy taki wpis:

 <resources>
      <resource>
        <directory>src/main/resources/hibernate</directory>
      </resource>
 </resources>

Na sam koniec zaś musimy ściągnąć nasz connector do PostgreSQL. I znów kolejna zależność.

   <dependency>
       <groupId>postgresql</groupId>
       <artifactId>postgresql</artifactId>
       <version>8.3-603.jdbc4</version>
   </dependency>

Ufff, już teraz wiem co to znaczy konfiguracja XMLem. Pozostaje mieć nadzieję, że to wszystko jakoś działa, lub też będzie działać. Nie chciałbym wychodzić za bardzo do przodu i implementować tutaj DAO by sprawdzić czy w ogóle to połączenie działa (mam cichą nadzieję, że tak). Na razie zatem temat zostawiam – kiedy dojdziemy do implementowania logiki biznesowej aplikacji wówczas z całą pewnością zmienię treść wpisu gdyby cosik nie działało jak powinno.

Na sam koniec jeszcze dodatek do konfiguracji Mavena. Otóż podczas budowania projektów dostawałem wciąż komunikat o tym, iż kodowanie projektu to CP-1250 i w związku z tym aplikacja nie będzie przenośna (też nowość). Próby zmiany tego stanu rzeczy w właściwościach projektu nie dawały efektu, dlatego też trzeba było znów odwiedzić plik POM.xml. W sekcji build dorzucamy takie coś:

 <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.4.2</version>
        <configuration>
          <encoding>UTF-8</encoding>
        </configuration>
 </plugin>

I w ten oto sposób po zbudowaniu projektu (no i rzecz jasna ściągnięciu plugina) nasz output radośnie będzie generowany w UTF-8. Jak to w cywilizowanych krajach się dzieje 🙂 To tyle na dziś – w następnym wpisie spróbujemy coś zrobić z widokiem i postawić jakieś bardziej rozbudowane “Hello World”.

Oficjalny nowy projekt – SCJPTester

W ostatnich bojach z Mavenem nie powiedziałem słowa o tym, do czego będzie służyła aplikacja, którą zamierzam tworzyć. Pewnikiem niektórzy domyślili się po nazwie, która przewijała się w screenach z widoku projektu, ale też i na niewiele się to zdało, gdyż ostatecznie nazwę zmieniłem. Panie i Panowie – przed Wami SCJPTester!

Spora część ruchu na blogu jest generowana poprzez zawartość powiązaną z certyfikatem SCJP. Zatem naturalnym rozwinięciem mojego contentu byłoby stworzenie aplikacji, która dałaby możliwość symulacji prawdziwego egzaminu. I taką właśnie funkcjonalność będzie posiadał SCJPTester – napisany z pomocą Mavena, Springa, Springa MVC, a także jakiegoś systemu szablonów integrującego się ze Springiem (nie wybrałem jeszcze żadnego), prace trwają. Zastanawiam się czy nie uderzyć z obsługą frontendu od strony AJAXa i interfejsu w GWT. Kozioł próbował przekonać mnie do Vaadina, że niby lepszy niż GWT, ale moim przekleństwem jest to, iż cały czas “zaliczam” technologie, które są najbardziej popularne i do nich niestety należy GWT, zaś Vaadin nie. Ale to jeszcze pogrzebię, przygoda z Mavenem jeszcze się nie skończyła 🙂