Primera página con ADF
Domingo, Febrero 1st, 2009Vamos a realizar una pagina con dos inputText y hacer una pantalla de logueo. Si se hace correcta ir a una segunda página y si no es válida sacar un mensaje por el FacesContext.
Vamos a realizar una pagina con dos inputText y hacer una pantalla de logueo. Si se hace correcta ir a una segunda página y si no es válida sacar un mensaje por el FacesContext.
Este tutorial esta pensado para usuarios que tengan cierto conocimiento sobre el funcionamiento del framework ADF. Pues en este se usan terminos que no han sido explicados previamente y pueden resultar complejos para usuarios novatos.
El componente processTrain es un componente ADF del tipo menú. Consiste en crear varias páginas JSF que están enlazadas entre sí. Este componente actualmente está en discusión entre los creadores de ADF, pues su lógica se realiza en el fichero de configuración faces-config.
La creación de popups varía según la implementación de JSF que utilicemos para cada proyecto. Cada implementación nos da la opción de crear popups modales o no modales. Hoy vamos a hablar sobre los popups en ADF, los cuales son modales.
Existe un objeto en ADF de tipo botón llamado Reset pero para este caso no nos serviría pues tendríamos que asociar uno por cada formulario que tengamos. La solución a nuestro problema sería crear un metodo que refresque el objeto ViewRoot. Se haría del siguiente modo:
public void recargarPagina(FacesContext contexto) {
String currentView = contexto.getViewRoot().getViewId();
ViewHandler vh = contexto.getApplication().
getViewHandler();
UIViewRoot x = vh.createView(contexto, currentView);
x.setViewId(currentView);
contexto.setViewRoot(x);
}
Si nos fijamos, este metodo recoge la vista actual de la página (viewId) y lo que hace básicamente es crearla de nuevo y crear un nuevo viewRoot. Una vez que hemos creado el nuevo viewRoot se lo asociamos al contexto y el entenderá que tiene que refrescar la página completamente.
Lo primero que necesitamos es configurar en el fichero web.xml ciertos parametros necesarios para gestionar la subida del fichero, vamos a darle valor a las propiedades que se van a encargar de gestionar donde se almacenarán los ficheros temporales, y cual va a ser el tamaño máximo permitido para los ficheros y para el buffer de memoria:
<context-param>
<!– Memoria maxima para cada peticion (en bytes) –>
<param-name>
oracle.adf.view.faces.UPLOAD_MAX_MEMORY
</param-name>
<param-value>992000000</param-value>
</context-param>
<context-param>
<!– Tamano maximo en disco por peticion (en bytes) –>
<param-name>
oracle.adf.view.faces.UPLOAD_MAX_DISK_SPACE
</param-name>
<param-value>992000000</param-value>
</context-param>
<context-param>
<!– Directorio de los ficheros temporales –>
<param-name>
oracle.adf.view.faces.UPLOAD_TEMP_DIR
</param-name>
<param-value>/tmp/ADFUploads/</param-value>
</context-param>
Una vez configurado el fichero web.xml, podríamos comenzar a generar nuestra página. Para poder realizar la subida de ficheros, el componente que vamos a necesitar es <af:inputFile>. Nuestra página además llevará un botón que llevará asociado el evento ActionEvent para procesar la subida de ficheros cuando se pulse el mismo.
<af:messages />
<af:inputFile label="Seleccione el archivo"
value="#{backing_registro.file}" />
<af:commandButton text="Enviar"
actionListener="#{backing_registro.procesarUpload}" />
Un dato a tener muy en cuenta, ya que a veces se nos puede olvidar, es que a la etiqueta que define el form, ya sea <h:form> o <afh:form>, debe llevar seteada una propiedad para indicarle que lo que se va a gestionar es una subida de ficheros. Veamos que valor hay que dar dependiendo del tipo de form que hayamos establecido:
<af:form usesUpload="true">
<h:form enctype="multipart/form-data">
Solo nos quedaría realizar el código del backing bean, como indicamos antes, el metodo llevará como parametro un ActionEvent para capturar el evento lanzado por el actionListener. En el método lo que vamos a realizar es una comprobación previa que el fichero no nos llega nulo, y si el fichero llega correctamente mostraremos un mensaje por pantalla:
private UploadedFile file;
public void procesarUpload(ActionEvent evento) {
UploadedFile file = getFile();
if (file != null)
{
FacesContext context =
FacesContext.getCurrentInstance();
FacesMessage message = new FacesMessage(
"Subida del fichero " + file.getFilename() +
" satisfactoria (" + file.getLength() +
" bytes)");
context.addMessage(
evento.getComponent().
getClientId(context),message);
// Aqui procesariamos el fichero
// para guardarlo donde queramos
}
}
public UploadedFile getFile() {
return file;
}
public void setFile(UploadedFile file) {
this.file = file;
}
Aún no habríamos guardado el fichero en nuestro servidor, ya es cuestión del programador realizarlo de una manera u otra, y para ello ya no es necesario ningún framework, con las librerías de Java debería bastar. De todos modos, si alguien tuviera dudas de como realizarlo, hacédnoslo saber y ampliaríamos el tutorial.
Si hemos realizado todo correctamente, la página nos quedaría del siguiente modo:
oracle.adf.view.faces.component.core.data.CoreTable
El componente Table se usa para mostrar datos de manera ordenada. Este componente permite la selección de datos única y multiple, ordenación de campos por las columnas, así como más funcionalidades que iremos viendo a lo largo del manual.
Los valores que acepta este componente son CollectionModel, aunque nosotros podemos darle como valor un List o un SortableModel y él mismo se encargará de convertirlo en el tipo CollectionModel.
Para renderizar correctamente este componente, debemos asociarle unos hijos, que serán de tipo Column. Cada Column representará una columna de la tabla.
Podemos ver como deberíamos anotar una tabla en el fichero JSF en el siguiente ejemplo:
<af:table …>
<af:column …/>
<af:column …/>
</af:table>
A cada columna, podemos darle como valores de los hijos, cualquier componente que queramos que sea mostrado. Normalmente este componente será un OutputText que mostrará la información necesaria en cada momento:
<af:table …>
<af:column …>
<af:outputText …/>
</af:column>
</af:table>
Las tablas tienen asociados una serie de facet en los cuales podemos colocar distintos componentes para darle un aspecto y funcionalidades distintos a las tablas según lo que añadamos. Vamos a ver uno a uno cuales son estos facets:
Un ejemplo completo de tabla sería el siguiente:
<af:table emptyText="No items were found" banding="row"
bandingInterval="1" binding="#{backing_untitled1.table1}"
id="table1" rows="3" var="row"
value="#{backing_untitled1.listaManuales}">
<af:column sortable="false" headerText="Titulo"
binding="#{backing_untitled1.column1}" id="column1">
<af:outputText value="#{row.titulo}"
binding="#{backing_untitled1.outputText1}"
id="outputText1"/>
</af:column>
<af:column sortable="false" headerText="Autor"
binding="#{backing_untitled1.column2}" id="column2">
<af:outputText value="#{row.autor}"
binding="#{backing_untitled1.outputText2}"
id="outputText2"/>
</af:column>
<af:column sortable="false" headerText="Formato"
binding="#{backing_untitled1.column3}" id="column3">
<af:outputText value="#{row.formato}"
binding="#{backing_untitled1.outputText3}"
id="outputText3"/>
</af:column>
<f:facet name="detailStamp">
<af:commandButton text="commandButton 1"
binding="#{backing_untitled1.commandButton1}"
id="commandButton1" blocking="true"/>
</f:facet>
<f:facet name="selection">
<af:tableSelectMany text="Select items and …"
binding="#{backing_untitled1.tableSelectMany1}"
id="tableSelectMany1" required="false"/>
</f:facet>
<f:facet name="actions">
<af:commandButton text="commandButton 2"
binding="#{backing_untitled1.commandButton2}"
id="commandButton2"/>
</f:facet>
<f:facet name="header">
<af:outputText value="Cabecera"
binding="#{backing_untitled1.outputText4}"
id="outputText4"/>
</f:facet>
<f:facet name="footer">
<af:outputText value="Pie de tabla"
binding="#{backing_untitled1.outputText5}"
id="outputText5"/>
</f:facet>
</af:table>
Vamos a conocer ahora más propiedades que tienen asociadas los componentes Table:
<af:outputText value="#{row.formato}" />
Como hemos comentado antes, las tablas aceptan varios tipos de valores, los cuales se encargará de convertir a CollectionModel, para nuestro ejemplo vamos a crear una lista de objetos del tipo List y se la asociaremos a la tabla para que sean mostrados por pantalla:
public List<Manuales> getListaManuales(){
List<Manuales> listaManuales = new ArrayList<Manuales>();
Manuales manual = new Manuales();
manual.setTitulo("Tablas");
manual.setFormato("HTML");
manual.setAutor("nuevascreaciones");
listaManuales.add(manual);
manual = new Manuales();
manual.setTitulo("JSF");
manual.setFormato("Word");
manual.setAutor("nuevascreaciones");
listaManuales.add(manual);
manual = new Manuales();
manual.setTitulo("ADF");
manual.setFormato("PDF");
manual.setAutor("nuevascreaciones");
listaManuales.add(manual);
return listaManuales;
}
Este resultado es el que le asociamos a la propiedad value de la tabla:
<af:table emptyText="No items were found" banding="row"
bandingInterval="1" binding="#{backing_untitled1.table1}"
id="table1" rows="3" var="row"
value="#{backing_untitled1.listaManuales}">
Ahora sólo bastaría crear 3 columnas en nuestra tabla, que se encarguen de mostrarnos los valores de la lista. Como vimos antes, primero debemos setear un valor a la propiedad var y desde los outputText que están asociados como hijos en los column acceder a las propiedades de la lista:
<af:column sortable="false" headerText="Formato"
binding="#{backing_untitled1.column3}" id="column3">
<af:outputText value="#{row.formato}"
binding="#{backing_untitled1.outputText3}"
id="outputText3"/>
</af:column>
Si ejecutásemos ahora nuestra página, nos debería de aparecer algo parecido a lo siguiente:

Los componentes Table llevan también asociadas unas propiedades para capturar los eventos referentes a las filas de la table. Estos son el SelectionListener, Disclosure Listener, etc. Con ellos, podemos acceder a las filas y realizar su tratamiento de manera individual. Esto se realiza de igual manera que con cualquier otro componente. Debemos asociar al Listener el evento que tenemos en el BackingBean que reciba como parámetro el correspondiente Event.
Existen métodos del componente para acceder al elemento seleccionado, como es el getSelectedRowData() que nos devuelve la fila marcada. Éste y otros métodos serán estudiados con más detalles en futuros manuales.