- Introducción
- Capa Negocio.EJB
- CapaWEB. JSF
Introducción
Objetivo
El objetivo de esta entrada es mostrar el uso del componente h:selectOneMenu obteniendo los datos de forma dinámica, para ello utilizaremos f:selectItems al definir los items de éste. Además los items mostrados en el componente h:selectOneMenu serán objetos, por lo que será necesario definir un f:converter para convertir el id, de tipo String, en un objeto.
Diseño de datos
Como he comentado anteriormente, el objetivo de esta entrada no es mostrar el uso de entidades y la forma en la que estas se enlazan, sino mostrar el uso de h:selectOneMenu a la hora de trabajar con listas de datos dinámicos. Para poder realizar el ejemplo he definido dos entidades muy sencillas: Clientes y Categorías.
Categorias.java
@Entity
public class Categorias implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id")
private Long id;
@Column(name="referencia")
private String referencia;
@Column(name="descripcion")
private String descripcion;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getReferencia() {
return referencia;
}
public void setReferencia(String referencia) {
this.referencia = referencia;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + Objects.hashCode(this.referencia);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Categorias other = (Categorias) obj;
if (!Objects.equals(this.referencia, other.referencia)) {
return false;
}
return true;
}
}
Clientes.java
@Entity
public class Clientes implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id")
private Long id;
@Column(name="cuenta")
private String cuenta;
@Column(name="nombre")
private String nombre;
@ManyToOne
@JoinColumn(name="categoria")
private Categorias categoria;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCuenta() {
return cuenta;
}
public void setCuenta(String cuenta) {
this.cuenta = cuenta;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Categorias getCategoria() {
return categoria;
}
public void setCategoria(Categorias categoria) {
this.categoria = categoria;
}
@Override
public int hashCode() {
int hash = 3;
hash = 71 * hash + Objects.hashCode(this.cuenta);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Clientes other = (Clientes) obj;
if (!Objects.equals(this.cuenta, other.cuenta)) {
return false;
}
return true;
}
}
En otro entrada describiré de forma más detalla la forma de definir las entidades. En esta entrada quería destacar únicamente la anotación @ManyToOne que nos permite definir claves ajenas. Fijese que el tipo de datos de esta "clave-ajena" es de la clase de la entidad relacionada.
Capa Negocio.EJB
En este punto voy a mostrar de una manera muy superficial, la forma en la que accedemos a los datos. En este ejemplo he definido la unidad de persistencia PersistencePruebas con el proveedor de persistencia EclipseLink. En esta unidad de persistencia he incluido las dos entidades definidas en el punto anterior. Para acceder a los datos he implementado un Session Bean (Stateless) con su correspondiente interfaz local.
CategoriasEjb.java
@Stateless
public class CategoriasEjb implements CategoriasEjbLocal {
@PersistenceContext(unitName = "PersistencePruebas")
private EntityManager entityManager;
@Override
public List obtenerTodas()
{
Query que = entityManager.createQuery("select c from Categorias c order by c.nombre");
return que.getResultList();
}
@Override
public Categorias obtenerById(Long id)
{
return entityManager.find(Categorias.class, id);
}
}
CategoriasEjbLocal.java
@Local
public interface CategoriasEjbLocal {
public List obtenerTodas();
public Categorias obtenerById(Long id);
}
He definido dos métodos: obtenerTodas() y obtenerById. El primero realiza una consulta obteniendo todos los registros de la tabla categorias ordenados por nombre. Este método lo utilizaré a la hora de obtener los datos para generar la lista que asociaremos en f:selectItems
El segundo, dado un id nos devuelve la categoría cuyo identificador es éste. El metodo obtenerById lo usaré en el converter que asociaremos en h:selectOneMenu
CapaWEB. JSF
ManagedBean
Tal y como indica en este tutorial, un ManagedBean es un java bean gestionado por el Framenwork JSF. En otras palabras, son objetos que va a gestionar el Framework JSF en los que daremos soporte a las páginas xhtml, que describiré a continuación, desarrollando los getter y setter y la lógica de negocio.
Pare este ejemplo he desarrollado dos managedBean: clientesManaged.java, en los que están desarrollados los getter y setter de clientes, y categoriasManaged.java, donde está desarrollada la lógica de busqueda de registros de la entidad Categorias.
clientesManaged.java
public class clientesManaged {
private Clientes cliente;
public Clientes getCliente() {
return cliente;
}
public void setCliente(Clientes cliente) {
this.cliente = cliente;
}
public clientesManaged() {
cliente = new Clientes();
}
}
categoriasManaged.java
public class categoriasManaged {
@EJB
private CategoriasEjbLocal categoriasEjb;
public categoriasManaged() {
}
public List obtenerListado()
{
List vresultado= new ArrayList();
List listado= this.categoriasEjb.obtenerTodas();
for (Categorias cat:listado)
{
SelectItem item = new SelectItem();
item.setLabel(cat.getReferencia());
item.setDescription(cat.getDescripcion());
item.setValue(cat);
vresultado.add(item);
}
return vresultado;
}
}
Converter
Desarrollando clases que implementen la interfaz javax.faces.convert.Converter podremos "traducir" objetos en String y String en objetos. En este ejemplo se úsa a la hora de asociar un valor al h:selectOneMenu. No hay que olvidar que lo que va a ser generado al final es un formulario HTML, por lo que los parametros tienen que ser de tipo cadena.
categoriasConverter.java
public class CategoriasConverter implements Converter {
CategoriasEjbLocal categoriasEjb = lookupCategoriasEjbLocal();
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Long id = Long.valueOf(value);
Categorias cat = this.categoriasEjb.obtenerById(id);
return cat;
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
Categorias cat = (Categorias) value;
return cat.getId().toString();
}
private CategoriasEjbLocal lookupCategoriasEjbLocal() {
try {
Context c = new InitialContext();
return (CategoriasEjbLocal) c.lookup("java:comp/env/CategoriasEjb");
} catch (NamingException ne) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
throw new RuntimeException(ne);
}
}
}
Como vemos se tienen que implementar dos metodos: getAsObject y getAsString. En el primero dado un String tenemos que obtener el objeto que es representado por ese valor. Para ello llamamos al metodo obtenerById definido en CategoriasEjbLocal.java. Aquí hay que tener en cuenta que la referencia al EJB hay que definirla en el fichero web.xml, tal y como se muestra a continuación.
web.xmlCategoriasEjb Session com.pruebas.selectonemenu.ejb.CategoriasEjbLocal CategoriasEjb
faces-config.xml
En el fichero faces-config.xml se definen las clases que van a ser gestionadas por el Framework JSF, tanto los ManagedBean, los converter y las reglas de navegación. A la hora de definir un ManagedBean tenemos que indicar el alcance de estos objetos. Es decir, si son de sesión, de aplicación o de petición.
faces-config.xmlclientesManaged com.pruebas.selectonemenu.managed.clientesManaged session categoriasManaged com.pruebas.selectonemenu.managed.categoriasManaged request /index.xhtml ok /mostrar.xhtml categoriaConverter com.pruebas.selectonemenu.converters.CategoriasConverter
XHTML
Una vez definido el modelo, desarrollada la capa de negocio y desarrolladas las clases que van a dar soporte a las vista, sólo queda definir como queremos mostrar la información en pantalla. Para ello damos de alta una página jsf. En ella definiremos un h:form compuesto por dos componentes, h:selectOneMenu donde asociaremos el f:selectItems para obtener los dato, y un h:commandButton para hacer el submit del formulario.
index.xhtml
Facelet Title
Aquí vemos como asociamos al value del h:selectOneMenu un objeto de tipo Categoria y esto se puede realizar gracias al converter categoriaConverter. Para mostrar los datos dentro de la lista desplegable asociamos a h:selectOneMenu un atributo del tipo f:selectItems en el que indicamos en la propiedad value el método donde podremos obtener la lista de SelectItem.