In un articolo precedente ho mostrato come effettuare una configurazione minima di Hibernate in un applicazone web Struts MVC. Vediamo ora come implementare le funzionalità CRUD di base (Create Read Update Delete) riprendendo l’esempio di progetto dell’articolo precedente in cui il livello di business è rappresentato da un ipotetico cliente.
Di seguito riporto i principali oggeti Struts-MVC utilizzati:
– ActionForm: mantiene lo stato in sessione dell’applicazone web e rappresentata il contenitore dei dati inseriti dall’utente in un form lato client
– DispatchAction: delega e raggruppa tutte le azioni legate al CRUD del cliente a un unico oggetto CustomerAction
– ActionForward, ActionMapping: definizione dei path ai quali la servlet di Struts inoltra il flusso elaborativo; integrazione con il livello di View rappresentato dalle pagine Velocity del cliente.
Creiamo prima l’oggetto ActionForm per il cliente
– CustomerForm
package com.demo.form; import org.apache.struts.action.ActionForm; public class CustomerForm extends ActionForm { private static final long serialVersionUID = 3L; private Long id; private String name; private String lastname; private String address; private String city; public CustomerForm() { // TODO Auto-generated constructor stub } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } }
Definiamo il form bean nel file struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <!-- ================================================ Form Bean Definitions --> <form-beans> <form-bean name="customerForm" type="com.demo.form.CustomerForm" /> </form-beans> <!-- =========================================== Action Mapping Definitions --> <!-- A Velocity test --> <action-mappings> <action path="/testVelocity" forward="/velocityPage.vm" /> </action-mappings> </struts-config>
Passiamo ora al livello Controller dell’MVC. Creiamo l’oggetto CustomerAction che estende DispatchAction di Struts. La classe contiene tutti i metodi per le funzionalità di CRUD.
– CustomerAction
package com.demo.action; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.actions.DispatchAction; import com.demo.domain.Customer; import com.demo.form.CustomerForm; import com.demo.hibernate.DAOFactory; import com.demo.persistence.CustomerDAO; public class CustomerAction extends DispatchAction { private Log log = LogFactory.getLog(this.getClass()); private DAOFactory factory = DAOFactory.instance(DAOFactory.HIBERNATE); /** * * Retrieve a list of Customer * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward multiRetrieve(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception{ try { DAOFactory factory = DAOFactory.instance(DAOFactory.HIBERNATE); CustomerDAO CustomerDao = factory.getCustomerDAO(); List<?> customers = CustomerDao.findAll(); request.setAttribute("customerList", customers); } catch (Exception e) { log.error("customers not found", e); } return mapping.findForward("showMulti"); } /** * Retrieve a single Customer * * @param mapping * @param form * @param request * @param response * @return */ public ActionForward singleRetrieve ( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){ try { CustomerDAO cdao = factory.getCustomerDAO(); Customer customer = new Customer(); if (request.getParameter("id") != null) { customer = cdao.findById(new Long(request.getParameter("id")),true); } BeanUtils.copyProperties(form, customer); request.setAttribute("customer", customer); } catch (Exception e) { e.printStackTrace(); log.error(e); } return mapping.findForward("showSingle"); } /** * * Create or update a Customer * * @param mapping * @param form * @param request * @param response * @return */ public ActionForward createOrUpdate (ActionMapping mapping, ActionForm form,HttpServletRequest request, HttpServletResponse response) { try { CustomerDAO cdao = factory.getCustomerDAO(); Customer customer = new Customer(); CustomerForm customerForm = (CustomerForm) form; BeanUtils.copyProperties(customer, customerForm); cdao.makePersistent(customer); request.setAttribute("id", customer.getId()); } catch (Exception e) { e.printStackTrace(); log.error(e); } return mapping.findForward("successCreateOrUpdate"); } /** * * Delete a Customer * * @param mapping * @param form * @param request * @param response * @return */ public ActionForward delete ( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){ try { CustomerDAO cdao = factory.getCustomerDAO(); Customer customer = cdao.findById(new Long(request.getParameter("id")),true); cdao.makeTransient(customer); } catch (Exception e) { e.printStackTrace(); log.error(e); } return mapping.findForward("successDelete"); } }
Definiamo le action nel file di mapping struts-config.xml. Da notare l’utilizzo della definizione parameter=”action” usata per specificare l’azione ActionForward nella request http (i.e. http://localhost:8080/demo/customers.do?action=multiRetrieve)
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <!-- ================================================ Form Bean Definitions --> <form-beans> <form-bean name="customerForm" type="com.demo.form.CustomerForm" /> </form-beans> <!-- =========================================== Action Mapping Definitions --> <!-- A Velocity test --> <action-mappings> <action path="/testVelocity" forward="/velocityPage.vm" /> <!-- Customer Actions --> <action parameter="action" path="/customers" type="com.demo.action.CustomerAction" scope="request" name="customerForm"> <forward name="showMulti" path="/pages/customers.vm" /> <forward name="showSingle" path="/pages/customer.vm" /> <forward name="successCreateOrUpdate" redirect="true" path="/customers.do?action=multiRetrieve" /> <forward name="successDelete" redirect="true" path="/customers.do?action=multiRetrieve" /> </action> </action-mappings> </struts-config>
Passiamo infine al livello View dell’MVC. Utilizziamo il template engine di Velocity e creiamo una pagina per visualizzare l’elenco dei clienti e una pagina per visualizzarne il dettaglio. Quest’ultima pagina verrà utilizzata anche per le operazioni di aggiornamento o creazione di un nuovo cliente.
– WebContent/pages/customers.vm
<html> <haed> <title></title> </haed> <body> <h5 class="titoloElenco"> CUSTOMER LIST</h5> <div align="center"> <table class="tabellaElenco"> <tr align="right"> <td colspan="6"> <a href="./customers.do?action=singleRetrieve">+ Create New</a> </td> </tr> </table> <table class="tabellaElenco"> <thead > <tr > <th >Name</th> <th >Lastname</th> <th >Address</th> <th >City</th> <th> </th> <th> </th> </tr> </thead> #foreach($Customers in $customerList) <tr> <td #alternateColorRows()>$!Customers.name</td> <td #alternateColorRows()>$!Customers.lastname</td> <td #alternateColorRows()>$!Customers.address</td> <td #alternateColorRows()>$!Customers.city</td> <td #alternateColorRows()><a href="./customers.do?action=singleRetrieve&id=$Customers.id">Update</a></td> <td #alternateColorRows()><a href="./customers.do?action=delete&id=$Customers.id">Delete</a></td> </tr> #end <tr align="left"> <td colspan="6"> </td> </tr> </table> </div> </body> </html>
– WebContent/pages/customer.vm
<body> <div class="ritorna"><a href="./customers.do?action=multiRetrieve">Back to Customer List</a> </div> <h5 class="titoloElenco"> Customer Create or Update </h5><br><br> <div align="center"> <table class="tabellaElenco"> <form id="customerForm" name="customerForm" action="./customers.do?action=createOrUpdate" method="post"> <input type="hidden" id="id" name="id" value="$!customerForm.id"> <!--<tr><td>$!customerForm.id </td></tr>--> <tr><td style="background:#EFF1FF;" ><h5>Name</h5></td> <td><input type="text" name="name" value="$!customerForm.name" ></td> <td style="background:#EFF1FF;"><h5>Lastname</h5></td> <td><input type="text" name="lastname" value="$!customerForm.lastname"></td> </tr><tr><td> </td><td> </td></tr> <tr><td style="background:#EFF1FF;"><h5>Address</h5></td> <td><input name="address" value="$!customerForm.address"></td> <td style="background:#EFF1FF;"><h5>City</h5></td> <td><input type="text" name="city" value="$!customerForm.city" ></td> </tr> <tr align="right"> <td colspan="6"><input type="submit" name="Save" value="Save"/></td> </tr> </form> </table> </div> </body>
Ecco come si presenta il layout di progetto