giovedì 22 gennaio 2015

WebApp con Spring Hibernate e Primefaces

Vai all'indice

L'obiettivo di questo post è la realizzazione di un'architettura enterprise e multidatasource costruita integrando i framework Spring, Hibernate e Primefaces. La web application proposta in questo esempio gestisce i dati contenuti nel database Apache Derby già utilizzato in precedenza di cui riporto di seguito la struttura.



Per fare questo riprenderò i concetti visti nei post Introduzione a Spring con esempio pratico e Inserire, cancellare modificare righe su Datatable Primefaces. Nel primo esempio vi ho mostrato come mappare il modello dati e costruire le classi per la gestione delle informazioni provenienti dal database grazie all'utilizzo di Spring e Hibernate, mentre nel secondo abbiamo visto la gestione grafica dell'interfaccia utente con Primefaces.

La costruzione della WebApp


Per prima cosa creo una nuova WebApp mantenendo l'interfaccia già vista nell' esempio precedente, pertanto, dopo avere definito un nuovo progetto Maven, importo la pagina index.xhtml, i bean associati, i file web.xml e faces-context.xml di configurazione.

Dall'esempio Introduzione a Spring con esempio pratico importo i pacchetti contenenti le entità e le classi DAO. Inoltre inserisco il file applicationContext.xml di Spring nel percorso WebContent > WEB-INF.

A questo punto, dopo l'importazione dei moduli di nostro interesse dai due progetti, è necessario integrare la parte di gestione dati con l'interfaccia grafica, riporto di seguito le modifiche salienti ai singoli moduli.
Come prima cosa aggiungo nel web.xml i listener di Spring.

  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
      /WEB-INF/applicationContext.xml
      </param-value>
  </context-param>
  <listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
   </listener>
   <listener>
  <listener-class>
   org.springframework.web.context.request.RequestContextListener
  </listener-class>
   </listener>

La classe ContextLoaderListener è un ServletContextListener, che viene chiamato all’avvio del Tomcat, per inizializzare e caricare il context di Spring nell'applicazione, mentre RequestContextListener serve a Spring per dichiarare lo scope associato al bean.
Grazie al parametro contextConfigLocation è possibile indicare il percorso del file di configurazione del contesto di Spring.

   <application>
     <el-resolver>
      org.springframework.web.jsf.el.SpringBeanFacesELResolver
     </el-resolver>
   </application>

Sia JSF che Spring gestiscono un proprio IoC Container, per cui è necessario trovare un modo per farli comunicare, ed è Spring che se ne occupa. Inserendo nel faces-context.xml di JSF la definizione della classe el-resolver che delega a Spring tutte le espressioni EL che JSF non riesce a risolvere, tra cui gli stessi bean definiti nel container di Spring.

  <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.16</version>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>1.5.6</version>
  </dependency>
  <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
     <version>1.5.6</version>
  </dependency>


Nel pom.xml inserisco tutte le dipendenze di Spring, Hibernate e Primefaces già viste nei due esempi sopra citati. Inoltre ho aggiunto la dipendenza c3p0 per la gestione del pool di connessione e le dipendenze slf4j e log4j per inserire nel progetto la gestione di un sistema di logging.

@ManagedBean(name = "utenti")
@RequestScoped
public class utentiBean implements Serializable {

    private static final long serialVersionUID = 1L;
    public int userid;
    public String nome;
    public String cognome;
    public String ruolo;
    private Date data;
    public String via;
    public String citta;
    public String telefono;
    public List<Utente> users;
utenteBean utente;
    
    @ManagedProperty(value="#{utenteDao}")
    UtenteDao utenteDao;
    
    // Definizione Getter e Setter

    private static final ArrayList<utenteBean> utentiList = new ArrayList<utenteBean>();

    public ArrayList<utenteBean> getUtentiList() {
        return utentiList;
    }
    
    @PostConstruct
    public void init() {
   users = utenteDao.getAll();
   inizializza();
   initdata();
}

    public String addAction() {
   
     // Istanzio e salvo gli oggetti utente e dettaglioutente
     Dettaglioutente dettUte = new Dettaglioutente(this.data, this.via, this.citta, this.telefono);
     Utente ute = new Utente(this.nome, this.cognome, this.ruolo);
     utenteDao.saveDetUte(ute, dettUte);
   
     inizializza();

     nome = "";
     cognome = "";
     ruolo = "";
     via = "";
     citta = "";
     telefono = "";
     initdata();
     return null;
    }
    
    public void onEdit(RowEditEvent event) { 
        Dettaglioutente dettUte = new Dettaglioutente(((utenteBean) event.getObject()).getUserid(), ((utenteBean) event.getObject()).getData(), ((utenteBean) event.getObject()).getVia(), ((utenteBean) event.getObject()).getCitta(), ((utenteBean) event.getObject()).getTelefono());
        Utente ute = new Utente(((utenteBean) event.getObject()).getUserid(), ((utenteBean) event.getObject()).getNome(), ((utenteBean) event.getObject()).getCognome(), ((utenteBean) event.getObject()).getRuolo());  
        // Aggiorno l'utente
        utenteDao.aggUte(ute, dettUte);
        inizializza();
        FacesMessage msg = new FacesMessage("Record modificato",((utenteBean) event.getObject()).getNome());  
        FacesContext.getCurrentInstance().addMessage(null, msg);  
    }  
       
    public void onCancel(RowEditEvent event) {  
        FacesMessage msg = new FacesMessage("Modifiche annullate");   
        FacesContext.getCurrentInstance().addMessage(null, msg); 
    } 
    
public void delete(utenteBean std){ 
// Elimina l'utente
        utenteDao.deleteUtente(std.getUserid());
        inizializza();
FacesMessage msg = new FacesMessage("Record cancellato");   
        FacesContext.getCurrentInstance().addMessage(null, msg);
}

public void inizializza(){
        utentiList.clear();
   List<Utente> users = utenteDao.getAll();
for (Utente user : users) {
Dettaglioutente dettuser = utenteDao.getDettaglioutente(user.getuserId());
utenteBean utentetmp = new utenteBean(user.getuserId(), user.getNome(), user.getCognome(), user.getRuolo(), dettuser.getDataNascita(), dettuser.getVia(), dettuser.getCitta(), dettuser.getTelefono());
       utentiList.add(utentetmp);
}
}

public void initdata(){
    String dateStr = "1970-01-01T00:00:00.000+01:00";
    SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); 
    try  {
    data = sdf.parse(dateStr.replaceAll(":(?=..$)", "")); 
    } catch (ParseException e) { 
        System.out.println("Anomalia parser data " + sdf); 
    }
}



UtentiBean è la classe di gestione della pagina index.xhtml ed è il modulo chiave su cui agire per collegare la parte di presentazione con la gestione dei dati.
L'annotazione @managedbean è usata per configurare l’iniezione di dipendenza in Spring ed è associata alla classe UtenteDao che contiene i metodi di interfaccia per l'accesso alle tabelle utente.
@PostContruct è l'annotazione applicata al metodo init() per indicare che deve essere chiamato dopo che tutte le dependency injection sono state completate. Nel nostro caso specifico è utilizzata per caricare i campi del Datatable coi dati estratti dal database.
Le chiamate ai metodi della gestione dei dati vengono attivate tramite gli eventi di inserimento, cancellazione e modifica dei dati presenti nel Datatable di Primefaces.
A questo punto la stesura del codice è terminata ed è possibile testare l'applicazione.



L'interfaccia grafica gestisce i dati relativi agli utenti ed è formata da un'unica pagina web divisa in due schede. La scheda inferiore contiene il modulo di inserimento nuovo utente, mentre la scheda superiore contiene un oggetto Datatable che permette la visualizzazione, l'aggiornamento e la cancellazione dei dati inseriti. Poichè a livello di Database i dati relativi agli utenti sono divisi in 2 tabelle (utente e dettaglioutente tra cui esiste una relazione uno a uno) ma l'oggetto datatable è unico, per comodità ho mappato i dati nel POJO UtenteBean prima di caricarli nel Datatable.

Nei prossimi post vedremo come implementare e completare il progetto appena iniziato.

Anche questo esempio è scaricabile da GitHub.

Hai apprezzato questo post? Conferma le mie competenze o scrivi una segnalazione sul mio profilo Linkedin!

Nessun commento:

Posta un commento