ProgramBash – Hibernate wkracza do gry

Jak pisałem w poprzednim wpisie na podpięcie bazy danych miał przyjść czas. No i ten czas właśnie nadszedł. W dzisiejszym wpisie zajmiemy się podpięciem do naszej aplikacji ORMa Hibernate i spróbujemy go zmusić do pracy z PostgreSQL. A kiedy już zmusimy to i może coś ładnego da się z tego wykrzesać. Zaczynamy.

Pierwszą rzecz, a mianowicie zaimportowane biblioteki do obsługi Hibernate mamy już za sobą. Podczas tworzenia projektu zaznaczyłem opcję mówiącą o imporcie tej jakże przydatnej biblioteki. Domyślnie ustawiłem dialekt na MySQL, jednakże po pobieżnym researchu okazało się, że u mnie na hostingu da się bez problemu zainstalować Postgresa w związku z tym zaczniemy od zmiany pliku konfiguracyjnego – wszak i lokalnie będę pracował z tym systemem bazodanowym.

Obslugiwany dialekt Hibernate znajdziemy spokojnie w źródłach tejże biblioteki, jednakże sterownik dla Postgresa już niekoniecznie. Zatem wypada ściągnąć najnowszą wersję sterownika i dodać do bibliotek w naszym projekcie (PPM na Libraries -> Add i wskazujemy plik ). Ja wrzuciłem swój do katalogu \WEB-INF\lib wraz z kilkoma innymi bibliotekami.
Edytujemy zatem 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://localhost/bash:5432</property>
<property name="hibernate.connection.username">chlebik</property>
<property name="hibernate.connection.password">chlebik</property>

     <mapping resource="/hibernate/mapping/News.hbm.xml"/>

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

Jak widać obok standardowych zapisów mówiących o dialekcie i takich tam dodałem już z góry oddzielny zapis o pliku odwzorowania. Pakiet, który będzie zawierał pliki odwzorowań dla Hibernate (jest to najzwyklejszy pakiet utworzony w katalogu ze wszystkimi innymi pakietami) będzie nazywał się com.wordpress.chlebik.mappings. Na pierwszy ogień zaimplementujmy coś prostego – choćby listę newsów pojawiających się zaraz po wejściu do serwisu. Plik News.hbm.cfg prezentuje się następująco:

<hibernate-mapping package="hibernate.mappings">
 <class name="com.wordpress.chlebik.News" table="news">
 <id name="id" type="long" column="id">
 <generator />
 </id>
<property name="adddate" column="adddate" type="integer" />
<property name="header" column="header" type="string" />
<property name="content" column="content" type="string" />
 <class>
</hibernate-mapping>

Jak widać nie jest on specjalnie skomplikowany. Relacji nie ma, raptem 4 pola, wszystko w miarę proste i oczywiste. Jest to odwzorowanie zwykłego POJO, którego zresztą trzeba stworzyć.

package com.wordpress.chlebik;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Klasa, ktora ma za zadanie byc beanem wystepujacym jako news na portalu
 *
 * @author Michal Piotrowski
 */
@Entity
@Table(name="news")
public class News {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String header;
    private String content;
    private Integer adddate;

    public News() {
    }

    public News( String header, String content, Integer adddate ) {
        this.header = header;
        this.content = content;
        this.adddate = adddate;
    }

    // Gettery
    public String getHeader()
    {
        return header;
    }

    public String getContent()
    {
        return content;
    }

    //  To jest konieczne by moc formatowac date za pomoca znacznikow JSF
    public Date getAdddate()
    {
        Date dateDateObject = new Date();
        long dateInMilis = ((long)adddate)*1000;
        dateDateObject.setTime(dateInMilis);
        return dateDateObject;
    }

    protected Long getId()
    {
        return id;
    }

     // Settery - bardziej dla poprawnosci niz potrzeby
    public void setHeader( String header )
    {
        this.header = header;
    }

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

    public void setAdddate( Integer adddate )
    {
        this.adddate = adddate;
    }

    protected void setId( Long id )
    {
        this.id = id;
    }
}

Mamy odwzorowanie, mamy POJO, co teraz? Normalnie wypadałoby zrobić dwie rzeczy – zapewnić sobie jeszcze jedną klasę, która zajęła by się tylko dostępem do danych. Czyli np. wyciąganiem obiektów, ich zapisywaniem i takimi tam. W przypadku zwykłych newsów, które na razie będą dodawane bezpośrednio przez bazę (tworzenie panelu administracyjnego dla mojej skromnej edukacyjnej aplikacji uważam za pozbawione sensu), nie ma absolutnie potrzeby rozgraniczanie logiki biznesowej na kolejne warstwy. Przykład jest póki co banalny, myślę że nie popełnię większego naduzycia jeśli po prostu wrzucę metodę wyciągającą ostatnie newsy w komponencie zarządzanym i na tym poprzestaniemy.

Teraz sprawa druga – dostęp do bazy danych. Jak piszą autorzy mojej książki o Hibernate obiekt, który zawiaduje połączeniami do bazy danych i całym tym jarmarkiem to SessionFactory. Jest to jednakże obiekt “ciężki” (heavyweight object), dlatego najlepiej mieć go raptem jeden na całą aplikację. Co zatem trzeba zrobić? Ano jak piszą mądrzy ludzie najlepiej zaimplementować klasę, która będzie trzymała takowy “ciężki” obiekt w formie zmiennej statycznej i w ten sposób po uruchomieniu aplikacji będziemy mogli wyciągać tylko obiekty sesji z istniejącej już fabryki.

Robimy to następująco. Wybieramy sobie pakiet, w którym chcemy takowy obiekt umieścić i prawy przycisk myszy -> New -> Other -> Hibernate -> Hibernate Util. Dzięki temu mamy od razu stworzoną klasę, która wszystko pięknie nam obsłuży. U mnie wygenerowany plik wygląda tak:


package com.wordpress.chlebik;


import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

/**
 * Hibernate Utility class with a convenient method to get Session Factory object.
 *
 * @author chlebik
 */
public class ProgramBashUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml) 
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Log the exception. 
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

Uff. Mamy chyba wszystko. Pozostaje nam podpiąć pod główną stronę pięknego managed-beana i jesteśmy prawie w domu. Wpierw XML (plik faces-config.xml), potem kod Javy:

<managed-bean>
  <managed-bean-name>NewsBean</managed-bean-name>
  <managed-bean-class>com.wordpress.chlebik.NewsBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
 </managed-bean>

No i teraz kod Javy. Nasze ziarenko będzie posiadało tylko jedną metodę – getNews, co pozwoli wylistować wszystkie newsy z bazy. Listing zatem przedstawia się dość prosto:

package com.wordpress.chlebik;

import java.io.Serializable;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;


public class NewsBean implements Serializable {
       
    public NewsBean() {        
    }

   
    public List<News> getNews()
    {
        SessionFactory sessionFactory = com.wordpress.chlebik.ProgramBashUtil.getSessionFactory();
        Session session = sessionFactory.openSession();

        List<News> newsy = session.createQuery("from News order by adddate DESC").list();
        return newsy;
    }
}

Ano i tyle. Od tej pory wystarczy w plikach JSP odwołać się do zapisu #{newsBean.news} i mamy piękną listę newsów. Ja wrzuciłem listowanie newsów na stronę główną w taki oto sposób:

<rich:dataList var="news" value="#{newsBean.news}" rowClasses="newsElement">

  <div>
      <div class="newsHeader"><h:outputText value="#{news.header}"/></div>
      <div class="newsDate">
         <h:outputText value="#{news.adddate}">
             <f:convertDateTime type="date" dateStyle="full" />
        </h:outputText>
      </div>
      <div class="newsContent"><h:outputText value="#{news.content}" /></div>
      
  </div>

</rich:dataList>

Rzecz jasna klasy CSSa również ładnie podpiąłem i stąd ładny widok. Nieprawda?

glownaHibernateProgramBash

Advertisements

Leave a Reply

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

WordPress.com Logo

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

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s