In part 1 we connected a web application to a database using an EJB for reading access, deployed on a Glassfish Server. In part 2 we do some modifications to create a true CRUD application by adding add, delete and update.
Pre-Requirements:
- Netbeans 6.7 or later
- Installed ZK plugin (link)
- Glassfish V3 or later
- Netbeans Project from Part 1 (link)
Tutorial:
- EJB modifications
are not required because for the basic CRUD functions we will use the provide abstract facade.package ejb; import java.util.List; import javax.persistence.EntityManager; public abstract class AbstractFacade<T> { private Class<T> entityClass; public AbstractFacade(Class<T> entityClass) { this.entityClass = entityClass; } protected abstract EntityManager getEntityManager(); public void create(T entity) { getEntityManager().persist(entity); } public void edit(T entity) { getEntityManager().merge(entity); } public void remove(T entity) { getEntityManager().remove(getEntityManager().merge(entity)); } public T find(Object id) { return getEntityManager().find(entityClass, id); } public List<T> findAll() { javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery(); cq.select(cq.from(entityClass)); return getEntityManager().createQuery(cq).getResultList(); } public List<T> findRange(int[] range) { javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery(); cq.select(cq.from(entityClass)); javax.persistence.Query q = getEntityManager().createQuery(cq); q.setMaxResults(range[1] - range[0]); q.setFirstResult(range[0]); return q.getResultList(); } public int count() { javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery(); javax.persistence.criteria.Root<T> rt = cq.from(entityClass); cq.select(getEntityManager().getCriteriaBuilder().count(rt)); javax.persistence.Query q = getEntityManager().createQuery(cq); return ((Long) q.getSingleResult()).intValue(); } } - Modification of the zul file
We add a button for delete and a grid with the 3 table columns, plus update and create buttons.<?xml version="1.0" encoding="UTF-8"?> <zk xmlns="http://www.zkoss.org/2005/zul"> <?init?> <window id="list" apply="controller.indexController" title="Customer List"> <listbox id="lst" width="100%" > <listhead sizable="true"> <listheader id="col1" label="Company"/> <listheader id="col2" label="First Name" /> <listheader id="col3" label="Last Name" /> </listhead> </listbox> <button id="btnDelete" label="Delete record"/> <separator bar="true"/> <grid width="40%"> <columns> <column label=""/> <column label=""/> </columns> <rows> <row> <label value="Company:" /> <textbox id="txtCompany" value=""/> </row> <row> <label value="First:" /> <textbox id="txtFirst" value=""/> </row> <row> <label value="Last:" /> <textbox id="txtLast" value=""/> </row> </rows> </grid> <button id="btnUpdate" label="Update record"/> <button id="btnAdd" label="Add record"/> </window> </zk>
- Modification to the controller class
We need to add variables for the additional components, create a separate instance of the model to update the listbox without re-reading the data from the DB when changes are applied.package controller; import ejb.customerZK; import ejb.customerFacade; import java.util.ArrayList; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.util.GenericForwardComposer; import org.zkoss.zul.Button; import org.zkoss.zul.ListModelList; import org.zkoss.zul.Listbox; import org.zkoss.zul.Listcell; import org.zkoss.zul.Listitem; import org.zkoss.zul.ListitemRenderer; import org.zkoss.zul.Textbox; public class indexController extends GenericForwardComposer { Context context; customerFacade facade; List<customerZK> customer = null; ListModelList model; private Listbox lst; private Textbox txtLast; private Textbox txtFirst; private Textbox txtCompany; @Override public void doAfterCompose(Component comp) throws Exception { super.doAfterCompose(comp); context = new InitialContext(); try { facade = (customerFacade) context.lookup("java:global/ZK_EJB_WEB/customerFacade"); // Read all records and store it in a arraylist customer = new ArrayList(); customer.addAll(facade.findAll()); // Set listmodel for the ZK list component model = new ListModelList(customer); lst.setModel(model); // Custom renderer ListitemRenderer listitem = new ListitemRenderer() { @Override public void render(Listitem item, Object data) throws Exception { item.setValue(data); item.appendChild(new Listcell(((customerZK) data).getCompanyName())); item.appendChild(new Listcell(((customerZK) data).getFirstName())); item.appendChild(new Listcell(((customerZK) data).getLastName())); } }; lst.setItemRenderer(listitem); } catch (Exception e) { System.out.println(e.getMessage()); } } public void onSelect$lst(Event evt) throws InterruptedException { // read values from selected record txtLast.setValue(((customerZK) lst.getSelectedItem().getValue()).getLastName()); txtFirst.setValue(((customerZK) lst.getSelectedItem().getValue()).getFirstName()); txtCompany.setValue(((customerZK) lst.getSelectedItem().getValue()).getCompanyName()); } public void onClick$btnDelete(Event evt) throws InterruptedException { System.out.println("Deleting ID: " + ((customerZK) lst.getSelectedItem().getValue()).getId()); // persist facade.remove((customerZK) lst.getSelectedItem().getValue()); // update listmodel model.remove((customerZK) lst.getSelectedItem().getValue()); } public void onClick$btnUpdate(Event evt) throws InterruptedException { customerZK modCustomer = new customerZK(); // read values from textbox modCustomer.setId(((customerZK) lst.getSelectedItem().getValue()).getId()); modCustomer.setCompanyName(txtCompany.getValue()); modCustomer.setFirstName(txtFirst.getValue()); modCustomer.setLastName(txtLast.getValue()); // persist facade.edit(modCustomer); // update listmodel model.set(model.indexOf((customerZK) lst.getSelectedItem().getValue()) , modCustomer); } public void onClick$btnAdd(Event evt) throws InterruptedException { customerZK modCustomer = new customerZK(); modCustomer.setCompanyName(txtCompany.getValue()); modCustomer.setFirstName(txtFirst.getValue()); modCustomer.setLastName(txtLast.getValue()); // persist facade.create(modCustomer); // update listmodel model.add(modCustomer); } } - Run the application
Remarks:
- There are smarter (?) ways to bind the textbox to an entity, but for the sake of simplicity I used this hands-on approach.
- Complete Netbeans projects: http://sourceforge.net/projects/coffeeshop/files (ZK_EJB_WEB_0.2.zip and ZK_EJB_0.1.zip)

Hi dude,
why do you prefer to lookup the facade instead of injecting it? Like:
@EJB customerFacade facade;
about your first final remarks, a smarter way could be to use the zk Binder and the @ annotations in the zul?
Wonderfull.
It gave me the light to choose btw Spring and EJB3 vs. ZK5
Thanks
Cossa