Category Archives: PostgreSQL

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:

Advertisements

Instalujemy PostgreSQL na Debianie Lenny

Odgrażałem się chyba z 10 razy, że w końcu zainstaluję PostgreSQL, aby podpiąć pod ten system bazodanowy swoje aplikacje. Lata płyną 🙂 zaś PostgreSQL ani widu, ani słychu. Przy okazji tworzeniu nowego projektu i zabaw z Mavenem przyszedł czas i na bazę.

Mój VPS posiada zainstalowanego MySQLa, który służy nie tylko do obsługi moich aplikacji, ale też trzymania wiki, czy Kulturalnego Chlebika. W tym wpisie opiszę jak przebiega instalacja oraz konfiguracja PostgreSQL na serwerze z Debianem Lenny i jak to poskładać do kupy, aby dobrze działało. Wpierw rzecz jasna trzeba odpowiedzieć sobie na pytanie jaką wersję RDBMSa instalujemy. W sumie najbardziej “nową” wersją jest ta oznaczona numerkiem 8.4. Jednakże moja polityka dotycząca nowych wersji jest powszechnie znana, a co więcej, w tym przypadku jest wspierana tym, iż w repozytoriach Debiana znalazłem gotowy pakiet z wersją 8.3. Po części system zadecydował za mnie. Uruchamiamy zatem apta:

sudo apt-get install postgresql-8.3

Apt pomieli swoje i na końcu całego listingu zobaczyłem takie oto dobre rzeczy:

Creating new cluster (configuration: /etc/postgresql/8.3/main, data: /var/lib/postgresql/8.3/main)…
Moving configuration file /var/lib/postgresql/8.3/main/postgresql.conf to /etc/postgresql/8.3/main…
Moving configuration file /var/lib/postgresql/8.3/main/pg_hba.conf to /etc/postgresql/8.3/main…
Moving configuration file /var/lib/postgresql/8.3/main/pg_ident.conf to /etc/postgresql/8.3/main…
Configuring postgresql.conf to use port 5432…
Starting PostgreSQL 8.3 database server: main.

Informacje o utworzeniu nowego klastra plus pojawienie się plików konfiguracyjnych są bardzo dobre – w necie znalazłem informacje, że zdarzały się przypadki ‘niepełnej’ instalacji z paczek, co skutkowało koniecznością dziwnych zabaw z samą bazą i jej skryptami konfiguracyjnymi lub uruchomieniowymi. W moim przypadku jak widać wszystko poszło OK i serwer PostgreSQL został uruchomiony. Wypada przyjrzeć się choć trochę konfiguracji – otwieramy plik postgresql.conf, który znajdziemy w katalogu wskazanym przy instalacji (u mnie jest to /etc/postgresql/8.3/main ). Jest on dość duży i rozbudowany, ale ten wpis nie jest o tuningowaniu PostgreSQL dlatego na razie odpuścimy sobie większość rzeczy poza wartościami zmiennych timezone oraz datastyle. Zgodnie z zaleceniami powinny one wyglądać tak:

datestyle = 'European, German'
timezone = Poland

Choć to w sumie duperel. Istotne jest to, aby móc łączyć się z bazą z dowolnego miejsca. W pliku konfiguracyjnym odnajdujemy zmienną listen_addresses i jeśli jest inaczej to ustawiamy jej wartość na ‘*’ (czyli na wszystkie możliwe interfejsy). Zamykamy plik. PostgreSQL domyślnie tworzy użytkownika o nazwie postgres, ale lepiej zostawić go w spokoju, za to do łączenia się z bazą lepiej stworzyć oddzielnego użytkownika, albo użyć jednego z istniejących – głównie dla bezpieczeństwa (ograniczenie dostępu lub różne prawa). Edycji poddajemy plik ph_hba.conf, który znajduje się tam gdzie główny plik konfiguracyjny. Dopisujemy tam następującą linijkę:

host all chlebik 0.0.0.0 0.0.0.0 password

Co oznacza tyle, że można połączyć się z serwerem bazy danych spoza serwera macierzystego używając do zalogowania użytkownika o nazwie chlebik. Dla łatwości również stworzymy nową bazę danych dla tych połączeń:

su
su postgres
createuser -a -d -P -e -W chlebik
createdb -e -E UTF-8 -O chlebik chlebik

Restartujemy serwer. Teraz wypadałoby sprawdzić czy nasze zabiegi przyniosły jakikolwiek efekt:

su
su postgres
psql template1
\du

I powinniśmy zobaczyć chlebika jako jednego z użytkowników bazy. Skoro tak to pewnie dałoby się zalogować jako chlebik i przy okazji zobaczyć co tam słychać w naszej bazie (pamiętajmy, że utworzyliśmy właśnie nową dla tego użytkownika ).

psql -U chlebik -h localhost chlebik

Logujemy się jako user chlebik do bazy danych o nazwie również ‘chlebik’ znajdującej się na lokalnej maszynie. Zostaniemy poproszeni o hasło. Jeśli wszystko jest OK to zostaniemy zalogowani do konsoli psql-a, gdzie możemy dla przykładu wydać takie polecenie:

\dt

Co powinno doprowadzić do pojawienia się komunikatu No relations found. Trudno by cokolwiek znaleziono – w końcu baza danych jest czysta jak pierwszy śnieg. Jednakże proces logowania przebiegł pomyślnie i wypada się z tego cieszyć. Jednakże to jeszcze nie koniec – połączenie z serwera jest dobre – na pewno nasze aplikacje na nim wdrożone uruchomią się bez problemów. Jednakże ustawialiśmy możliwość łączenia się z bazą spoza serwera. Teraz przetestujemy tę możliwość – ja wybralem do tego program PgAdmin, który mam na dysku, gdyż lokalnie na maszynie developerskiej posiadam zainstalowanego PostgreSQL. Wpisujemy dane i oto mamy:

Cytat dnia

Ostatnio poczytuję sobie dokumentację PostgreSQL. Rzecz to olbrzymi ebook mający ponad 2000 stron – dzieło dość ciężkie. Ale dla śmiechu – jeden z cytatów mnie rozbroił:

There is no century number 0, you go from -1 century to 1 century. If you disagree with this, please write your complaint to: Pope, Cathedral Saint-Peter of Roma, Vatican.