jsf - Creating master-detail pages for entities, how to link them and which bean scope to choose -
i have started learning jsf, sadly tutorials out there present log in or register section.
can point me more in depth examples? 1 thing i'm interested in page presenting list of products. i'm on page home , press on page products can see latest products added. , every time visit page, product list created latest entries in database. how can handle this?
one way solve create session scoped managed bean in place different entities updated through other managed beans. found kind of approach in tutorials, seems quite difficult , clumsy.
which best approach solve thing this? correct usage of session scope in two-page master-detail user interface?
what correct usage of session scope
use session scoped data only, nothing else. example, logged-in user, settings, chosen language, etcetera.
see also:
and every time visit page, product list created latest entries in database. how can handle this?
typically use request or view scope it. loading of list should happen in @postconstruct
method. if page doesn't contain <h:form>
, request scope fine. view scoped bean behave request scoped when there's no <h:form>
anyway.
all "view product" , "edit product" links/buttons retrieve information (i.e. idempotent) whould plain <h:link>
/ <h:button>
wherein pass entity identifier request parameter <f:param>
.
all "delete product" , "save product" links/buttons manipulate information (i.e. non-idempotent) should perform post <h:commandlink>
/<h:commandbutton>
(you don't want them bookmarkable/searchbot-indexable!). in turn requires <h:form>
. in order preserve data validations , ajax requests (so don't need reload/preinitialize entity on every request), bean should preferably view scoped.
note should have separate bean each view , note beans doesn't need reference each other.
so, given "product" entity:
@entity public class product { @id private long id; private string name; private string description; // ... }
and "product service" ejb:
@stateless public class productservice { @persistencecontext private entitymanager em; public product find(long id) { return em.find(product.class, id); } public list<product> list() { return em.createquery("select p product p", product.class).getresultlist(); } public void create(product product) { em.persist(product); } public void update(product product) { em.merge(product); } public void delete(product product) { em.remove(em.contains(product) ? product : em.merge(product)); } // ... }
you can have "view products" on /products.xhtml
:
<h:datatable value="#{viewproducts.products}" var="product"> <h:column>#{product.id}</h:column> <h:column>#{product.name}</h:column> <h:column>#{product.description}</h:column> <h:column> <h:link value="edit" outcome="/products/edit"> <f:param name="id" value="#{product.id}" /> </h:link> </h:column> </h:datatable>
@named @requestscoped public class viewproducts { private list<product> products; // +getter @ejb private productservice productservice; @postconstruct public void init() { products = productservice.list(); } // ... }
and can have "edit product" on /products/edit.xhtml
:
<f:metadata> <f:viewparam name="id" value="#{editproduct.product}" converter="#{productconverter}" convertermessage="unknown product, please use link within system." required="true" requiredmessage="bad request, please use link within system." /> </f:metadata> <h:messages /> <h:form rendered="#{not empty editproduct.product}> <h:inputtext value="#{editproduct.product.name}" /> <h:inputtextarea value="#{editproduct.product.description}" /> ... <h:commandbutton value="save" action="#{editproduct.save}" /> </h:form>
@named @viewscoped public class editproduct { private product product; // +getter +setter @ejb private productservice productservice; public string save() { productservice.save(product); return "/products?faces-redirect=true"; } // ... }
and converter <f:viewparam>
of "edit product":
@named @requestscoped public class productconverter implements converter { @ejb private productservice productservice; @override public object getasobject(facescontext context, uicomponent component, string value) { if (value == null || value.isempty()) { return null; } try { long id = long.valueof(value); return productservice.find(id); } catch (numberformatexception e) { throw new converterexception("the value not valid product id: " + value, e); } } @override public string getasstring(facescontext context, uicomponent component, object value) { if (value == null) { return ""; } if (value instanceof product) { long id = ((product) value).getid(); return (id != null) ? string.valueof(id) : null; } else { throw new converterexception("the value not valid product instance: " + value); } } }
Comments
Post a Comment