Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Implementazione di un carrello e-commerce mediante EJB 3.0

Implementazione passo-asso di un semplice carrello e-commerce tramite EJB 3.0 (stateful), con esempi scaricabili.
Implementazione passo-asso di un semplice carrello e-commerce tramite EJB 3.0 (stateful), con esempi scaricabili.
Link copiato negli appunti

Attraverso questo articolo vedremo come realizzare il carrello di un sito di e-commerce facendo uso degli EJB 3.0. In particolare faremo uso di Session Bean di tipo Stateful, per mantenere lo stato del carrello (la lista dei prodotti scelti dall’utente) fra una richiesta e l’altra.

Sebbene il progetto che svilupperemo sia abbastanza semplice da realizzare, è comunque buona norma quella di separare in moduli l’intera applicazione.
In particolare realizzeremo una Enterprise Application composta dai seguenti sottoprogetti:

  • web-carrello: contenente servlet e jsp di visualizzazione
  • ejb-carrello: contenente l’EJB Stateful che conserva lo stato del carrello
  • ejb-carrelloClient: contenente la definizione dell’interfaccia dell’EJB Stateful
  • utils-carrello: contenente le classi di ausilio

A tali progetti farà riferimento il progetto principale: carrello, contenente il file application.xml di configurazione dei vari moduli.

Il risultato finale sarà un file ear (Enterprise Archive), che includerà al suo interno un file war (Web Archive) e delle librerie di ausilio (jar).
Prima di analizzare il modo in cui questi moduli sono inclusi e organizzati all’interno del file ear, esaminiamoli singolarmente, partendo dal progetto che descrive le classi di dominio (ovvero gli oggetti che verranno utilizzati dentro il carrello).

Il progetto utils-carrello

Il progetto utils-carrello, contiene la definizione della classe Oggetto.java, che rappresenta gli oggetti che verranno inseriti all’interno nel carrello.

Per ogni oggetto vengono memorizzati un id (identificativo univoco del prodotto) ed un nome ma nulla vieta, in implementazioni più complesse, di memorizzare informazioni aggiuntive (quali un url della foto che rappresenta l’oggetto, una descrizione etc...)

In ogni caso il progetto verrà tradotto in un file .jar incluso nella cartella lib dell’ear generato.

package web.util;
public class Oggetto {
	
	private int id;
	private String nome;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
}

I progetti ejb-carrelloClient ed ejb-carrello

La definizione dell'EJB Stateful che verrà utilizzato per memorizzare lo stato del carrello consta di due differenti progetti: il primo ejb-carrelloClient contiene la definizione dell'interfaccia, il secondo ejb-carrello invece contiene l'implementazione di tale interfaccia.

Dal momento che l'EJB verrà utilizzato all'interno dell'Application Server, l'interfaccia verrà annotata con @Local:

package web.ejb;

import java.util.ArrayList;
import javax.ejb.Local;
import web.util.Oggetto;

@Local
public interface CarrelloLocal {
	public void aggiungi(Oggetto oggetto);
	public void rimuovi(int indice);
	public ArrayList<Oggetto> getOggettiCarrello();
}

Come vediamo essa contiene la definizione di tre metodi:

  • aggiungi (Oggetto oggetto): aggiunge un oggetto al carrello
  • rimuovi (int indice): rimuove l’oggetto di cui viene passato l’indice dal carrello
  • getOggettiCarrello: restituisce la lista di oggetti contenuti nel carrello

Il progetto ejb-carrelo contiene quindi la classe (Carrello.java) che implementa l’interfaccia.
Come è possibile notare, tale classe è annotata con @Stateful e contiene l'implementazione dei tre metodi definiti nell'interfaccia oltre ad un costruttore che inizializza la variabile oggetti_carrello che rappresenta il contenuto del carrello stesso.

In particolare il metodo aggiungi effettua l'aggiunta dell'Oggetto passato come argomento alla variabile oggetti_carrello, il metodo rimuovi effettua la rimozione dell'oggetto di cui viene passato l'indice dal carrello, e il metodo getOggettiCarrello restituisce la variabile oggetti_carrello stessa.

package web.ejb;

import java.util.ArrayList;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import web.util.Oggetto;

@Stateful
public class Carrello implements CarrelloLocal {
	
	ArrayList<Oggetto> oggetti_carrello;
	
	public Carrello() {
	 		oggetti_carrello = new ArrayList<Oggetto>();
	}
	    
	public void aggiungi(Oggetto oggetto) {
	 		oggetti_carrello.add(oggetto);
	}
	public void rimuovi(int indice) {
	 		oggetti_carrello.remove(indice);
	}   
	public ArrayList<Oggetto> getOggettiCarrello() {
	 		return oggetti_carrello;
	}
}

Il progetto web-carrello

Il progetto web-carrello infine contiene l’implementazione di quello che è il livello View dell'applicazione di e-commerce che, nel nostro caso si compone di:

  • una jsp che rappresenta l'elenco dei prodotti disponibili e lo stato del carrello
  • una servlet che inoltra all'EJB Stateful le richieste di aggiunta e rimozione dei prodotti dal carrello

Se esaminiamo la Servlet, vediamo che questa tramite l'annotazione @EJB inietta nella variabile carrello l'EJB Stateful che abbiamo implementato.

Quindi l'implementazione del metodo doPost (che risponde alle richieste client di tipo POST) lavora in questo modo:

  • se il parametro "azione" (passato come parametro della richiesta) ha valore "aggiungi" viene creato un nuovo Oggetto con id e nome passati sempre come parametri della richiesta e viene invocato il metodo aggiungi dell'EJB passando come parametro l'oggetto creato.
  • se il parametro "azione" (passato sempre come parametro della richiesta) ha invece valore "rimuovi" viene invocato il metodo rimuovi dell’EJB passando come parametro l'indice dell'elemento del carrello da rimuovere.
  • in ogni caso alla fine viene messo nella variabile di sessione carrello, il contenuto del carrello ottenuto invocando il metodo getOggettiCarrello dell'EJB iniettato e quindi viene effettuato un redirect verso /web-carrello (al quale come vedremo successivamente risponde una jsp)
package web.servlet;
import ...

public class CarrelloServlet extends HttpServlet {
	
	@EJB
	CarrelloLocal carrello;
	...
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		if (request.getParameter("azione").equals("aggiungi")) {
			Oggetto oggetto = new Oggetto();
			oggetto.setId(Integer.parseInt(request.getParameter("id")));
			oggetto.setNome(request.getParameter("nome"));
			carrello.aggiungi(oggetto);
		}
		else if (request.getParameter("azione").equals("rimuovi")) {
			carrello.rimuovi(Integer.parseInt(request.getParameter("indice")));
		}
		request.getSession().setAttribute("carrello", carrello.getOggettiCarrello());
		response.sendRedirect("/web-carrello");
	}
}

Per quanto riguarda la index.jsp, le parti fondamentali di questa sono essenzialmente due: la prima è costituita da tre form (uno per ogni oggetto che è possibile inserire nel carrello) ciascuno dei quali ha al suo interno un'immagine rappresentativa dell'oggetto, 3 campi hidden ("azione" con valore "aggiungi", "id" con valore progressivo e "nome" del prodotto) e un submit per l'invio al server:

<div>
		<div style="font-family:Verdana; text-align:center; background-color: #ddd; border: 1px #ddd solid; width: 330px">
		Prodotti
		</div>
		<div style="border: 1px #ddd solid; width:330px">
			<form method="post" action="./CarrelloServlet" style="margin-top: 5px; margin-bottom:5px; position: relative;">
				<img src="./images/0.jpg" style="width:50px"/>
				<input type="hidden" name="azione" value="aggiungi" />
				<input type="hidden" name="id" value="0" />
				<input type="hidden" name="nome" value="Oggetto 0" />
				<input type="submit" value="Aggiungi Oggetto 0"  style="position: absolute; top:10px; left:50px; border: 1px #ddd solid; height:30px; width:270px; " />
			</form>
			<form method="post" action="./CarrelloServlet" style="margin-top: 5px; margin-bottom:5px; position: relative;">
				<img src="./images/1.jpg" style="width:50px"/>
				<input type="hidden" name="azione" value="aggiungi" />
				<input type="hidden" name="id" value="1" />
				<input type="hidden" name="nome" value="Oggetto 1" />
				<input type="submit" value="Aggiungi Oggetto 1"  style="position: absolute; top:10px; left:50px; border: 1px #ddd solid; height:30px; width:270px; "  />
			</form>
			<form method="post" action="./CarrelloServlet" style="margin-top: 5px; margin-bottom:5px; position: relative;">
				<img src="./images/2.jpg" style="width:50px"/>
				<input type="hidden" name="azione" value="aggiungi" />
				<input type="hidden" name="id" value="2" />
				<input type="hidden" name="nome" value="Oggetto 2" />
				<input type="submit" value="Aggiungi Oggetto 2" style="position: absolute; top:10px; left:50px; border: 1px #ddd solid; height:30px; width:270px; " />
			</form>
		</div>
	</div>

La seconda parte della jsp invece non fa altro che visualizzare tutti i prodotti contenuti nel carrello (recuperando l'ArrayList<Oggetto> dalla variabile di sessione "carrello"):

per ogni prodotto viene creato un form contenente l’immagine rappresentativa dell’oggetto, due campi hidden (“azione” con valore “rimuovi” e “indice” con valore progressivo) e un submit per inviare la richiesta di rimozione del prodotto dal carrello.

	<div>
		<div style="font-family:Verdana; text-align:center; background-color: #ddd; border: 1px #ddd solid; width: 330px">
		Carrello
		</div>
		<div style="border: 1px #ddd solid; width:330px">
		<%	
			ArrayList<Oggetto> contenuto_carrello = (ArrayList<Oggetto>)(session.getAttribute("carrello"));
			if (contenuto_carrello!=null) {
				int indice = 0;
				for (Oggetto oggetto: contenuto_carrello) {
		%>
		<form method="post" action="./CarrelloServlet" style="margin-top: 5px; margin-bottom:5px; position: relative;">
			<img src="./images/<% out.print(oggetto.getId()); %>.jpg" style="width:50px"/>
			<input type="hidden" name="azione" value="rimuovi" />
			<input type="hidden" name="indice" value="<% out.print(indice); %>" />
			<input type="submit" value="Rimuovi <% out.print(oggetto.getNome()); %>"   style="position: absolute; top:10px; left:50px; border: 1px #ddd solid; height:30px; width:270px; "  />
		</form>
		<%
					indice++;
				}
			}
		%>
		</div>
	</div>

Sia le richieste di aggiunta che quelle di rimozione di prodotti sono indirizzate verso l'url /CarrelloServlet (valore del campo action dei form) sul quale è mappata la servlet precedentemente definita, come è possibile vedere dal file web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app ... version="2.5">
<display-name>web-carrello</display-name>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
  	<servlet>
 		<description></description>
 		<display-name>CarrelloServlet</display-name>
 		<servlet-name>CarrelloServlet</servlet-name>
 		<servlet-class>web.servlet.CarrelloServlet</servlet-class>
	</servlet>
	<servlet-mapping>
 		<servlet-name>CarrelloServlet</servlet-name>
 		<url-pattern>/CarrelloServlet</url-pattern>
	</servlet-mapping>
</web-app>

Il progetto carrello

Il progetto carrello come già detto non fa altro che assemblare tutti gli altri progetti in un unico ear: il modo in cui tali progetti sono assemblati è definito all'interno del file application.xml il quale contiene la definizione di due moduli:

  • il primo contenente la definizione dell'ejb (ejb-carrello.jar)
  • il secondo contenente la definizione del modulo web-carrello.war contenente servlet e jsp

<?xml version="1.0" encoding="UTF-8"?>
<application ... id="Application_ID" version="5">
<display-name>carrello</display-name>
	<module>
	 	<ejb>ejb-carrello.jar</ejb>
	</module>
	<module>
 		<web>
 			<web-uri>web-carrello.war</web-uri>
 			<context-root>web-carrello</context-root>
 		</web>
	</module>
</application>

Nella cartella lib dell’ear generato da eclipse troviamo invece il jar contenente la definizione della classe di ausilio Oggetto.java.

Con Eclipse è possibile generare automaticamente il file application.xml indicando al momento della creazione dell’Enterprise Application Project i progetti dai quali questo dipende e spuntando la casella "Generate application.xml deployment descriptor":

Figura 1. progetto ear del carrello
(clic per ingrandire)


progetto ear

Generazione del file EAR e deploy del progetto in JBoss AS 5

Una volta avviato l'application server (nel nostro caso JBoss AS 5.0) e generato mediante IDE il file ear, sarà sufficiente fare il deploy di tale file copiandolo nella cartella deploy del server.
JBoss risponderà all'operazione di deploy nel seguente modo:

22:23:36,827 INFO  [JBossASKernel] Created KernelDeployment for: ejb-carrello.jar
22:23:36,827 INFO  [JBossASKernel] installing bean: jboss.j2ee:ear=carrello.ear,jar=ejb-carrello.jar,name=Carrello,service=EJB3
22:23:36,827 INFO  [JBossASKernel]   with dependencies:
22:23:36,827 INFO  [JBossASKernel]   and demands:
22:23:36,827 INFO  [JBossASKernel] 	jboss.ejb:service=EJBTimerService
22:23:36,828 INFO  [JBossASKernel]   and supplies:
22:23:36,828 INFO  [JBossASKernel] 	jndi:carrello/Carrello/remote
22:23:36,828 INFO  [JBossASKernel] 	jndi:carrello/Carrello/local-web.ejb.CarrelloLocal
22:23:36,828 INFO  [JBossASKernel] 	Class:web.ejb.CarrelloLocal
22:23:36,828 INFO  [JBossASKernel] 	jndi:carrello/Carrello/local
22:23:36,828 INFO  [JBossASKernel] Added bean(jboss.j2ee:ear=carrello.ear,jar=ejb-carrello.jar,name=Carrello,service=EJB3) to KernelDeployment of: ejb-carrello.jar
22:23:36,829 INFO  [EJB3EndpointDeployer] Deploy AbstractBeanMetaData@1fcc4bdf{name=jboss.j2ee:ear=carrello.ear,jar=ejb-carrello.jar,name=Carrello,service=EJB3_endpoint bean=org.jboss.ejb3.endpoint.deployers.impl.EndpointImpl properties=[container] constructor=null autowireCandidate=true}
22:23:36,851 INFO  [SessionSpecContainer] Starting jboss.j2ee:ear=carrello.ear,jar=ejb-carrello.jar,name=Carrello,service=EJB3
22:23:36,851 INFO  [EJBContainer] STARTED EJB: web.ejb.Carrello ejbName: Carrello
22:23:36,858 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:

	carrello/Carrello/local - EJB3.x Default Local Business Interface
	carrello/Carrello/local-web.ejb.CarrelloLocal - EJB3.x Local Business Interface
	
22:23:36,919 INFO  [TomcatDeployment] deploy, ctxPath=/web-carrello

comunicandoci che l'applicazione è stata deployata con successo ed è raggiungibile all’indirizzo /web-carrello.
Quindi una volta digitato http://<indirizzo_AS>:<porta>/web-carrello/ ci troveremo di fronte ad una pagina con 3 oggetti che è possibile aggiungere al carrello inizialmente vuoto. Ad ogni click sul prodotto da aggiungere, il carrello si riempirà e i prodotti inseriti potranno potenzialmente essere rimossi:

Figura 2. rimozione ed aggiunta elementi dal carrello e-commerce
(clic per ingrandire)


rimozione ed aggiunta elementi dal carrello di e-commerce

L'EJB Stateful manterrà infine fra una richiesta e l'altra del browser lo stato dei prodotti inseriti nel carrello, come volevamo. (è possibile scaricare un file compresso contenente tutti i progetti realizzati in ambiente Eclipse)

Ti consigliamo anche