La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Java Server Faces.

Presentaciones similares


Presentación del tema: "Java Server Faces."— Transcripción de la presentación:

1 Java Server Faces

2 JSF Framework Java que permite construir páginas como interfaces de usuario Distintos tipos de componentes. Estados y eventos/funcionalidad (JavaScript). Asociación entre datos de la interfaz y datos de la aplicación web (Java Beans, etc). Especificación de la navegación del usuario. Colección de etiquetas Facelets/JSP asociadas.

3 Facelets y JSP Facelets y JSP son dos tecnologías diferentes. JSF permite la utilización de ambas, incluso conjuntamente Facelets es más reciente, es específica para JSF y ofrece más posibilidades al desarrollador La especificación actual de JSF, 2.0, recomienda la utilización de Facelets

4 Hello World (con Facelets)
Componente de presentación: Hello.xhtml Atributos de la etiqueta html para la inclusión de librerías en lugar de directivas de página Etiquetas especiales h:head y h:body Cláusulas especiales en web.xml: context-param (desarrollo, producción, …) servlet (FacesServlet, load-on-startup) Servlet-mapping (por defecto, /faces/*) welcome-file (faces/Hello.xhtml)

5 Ejemplo de Hello.xhtml <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " <html xmlns= xmlns:f= xmlns:h= xmlns:ui= <h:head> <title>Facelet Title</title> </h:head> <h:body> <h1> Hello from Facelets </h1> </h:body> </html>

6 Ejemplo de web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns=" xmlns:xsi=" xsi:schemaLocation=" <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param>

7 Ejemplo de web.xml, II <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</s-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>faces/Hello.xhtml</welcome-file> </welcome-file-list> </web-app>

8 Etiquetas y componentes
Hay tres tipos de etiquetas JSF, incluidos en tres bibliotecas: Etiquetas de carácter transversal (biblioteca core), comunes a JSP y Facelets. Etiquetas de componentes gráficas (biblioteca HTML), comunes a JSP y Facelets. Etiquetas específicas de Facelets (biblioteca facelets) Además, las aplicaciones JSF pueden utilizar otras etiquetas de la biblioteca estándar de JSP (c:if, c:foEach, etc.)

9 Facelets vs JSP Facelets permite definir plantillas de páginas web que contienen partes pendientes de concretar También permite definir componentes de documentos, que se pueden incluir en las partes incompletas de las plantillas Las componentes pueden depender de parámetros (colores, tamaño, etc.) que se determinan al incluirlas en plantillas

10 JSF: Algunas características
Especificación en las etiquetas de caminos (paths) relativos y absolutos para el servidor de acceso a recursos (imágenes, etc). Traducción automática al cliente. Asociación directa en las etiquetas a datos de la aplicación (Java Beans, etc): Datos necesarios para la visualización de la página. Datos proporcionados por el usuario (formularios). Otros datos que permiten parametrizar el código del servidor que genera la interfaz.

11 JSF: Algunas características, II
JSF utiliza la arquitectura MVC de forma sistemática El servlet controlador, FacesServlet, es fijo y lo proporciona JSF La especificación concreta de la navegación por la aplicación en cada caso se realiza mediante un fichero de configuración XML que da lugar a una estructura de datos (un autómata)

12 JSF: Algunas características, III
El modelo está formado por los Beans que guardan los datos generados por la aplicación. Cada solicitud incorpora datos nuevos, que pueden ser parámetros de control o informa-ción a incorporar al modelo del servidor Utiliza exclusivamente peticiones POST, que van siempre al servlet principal. No permiten motores de búsqueda ni guardar URLs favoritas.

13 Hello dinámico Aplicación que: Pide al usuario su nombre.
Tras pulsar un botón, se saluda al usuario por su nombre. Permite la vuelta a la página inicial pulsando en otro botón. Sin necesidad de volver a identificarse, vuelve a la segunda página pulsando el botón y le vuelve a saludar correctamente.

14 Hello dinámico, II Páginas web: Identificación y saludo
Página de identificación: Etiqueta estática que pide la identificación Formulario con dos componentes: Campo de texto para introducir la identificación Botón para pasar a la segunda página Página de información: Texto dinámico de saludo Formulario con botón para volver a la página inicial

15 Hello dinámico: identifica.xhtml
<h:body> <h:form> <h:outputLabel for=“nombre” value="Introduzca su nombre:"/> <h:inputText value=“#{nombre}” id=“nombre”> <h:commandButton value=“OK” action=“hello”/> </h:form> </h:body>

16 Hello dinámico: hello.xhtml
<h:body> <h1> Hello ${nombre} </h1> <h:commandButton value="OK" action="index"/> </h:body> Recomendación: Implementarlo y ver los códigos de las páginas generadas

17 Ciclo de vida de aplicaciones JSF: Ejecución
Las componentes web dan lugar a un objeto Java que las modeliza (se puede ver como una estructura análoga al DOM, que tiene un nodo por cada etiqueta de Facelets) Las componentes se reutilizan total o parcialmente de una vez para otra

18 Ciclo de vida de aplicaciones JSF: Ejecución, II
Tras (re)construir la vista de la aplicación, se aplican los valores de los parámetros de la solicitud. A continuación se realizan conversiones y validaciones de valores. Tras ello se actualizan los beans asociados de acuerdo con la información contenida en las componentes Por último se ejecutan los métodos apropiados.

19 Ciclo de vida de aplicaciones JSF: Tratamiento
Una vez ejecutada la vista, se realiza su tratamiento (render) para generar el código HTML correspondiente. El tratamiento lo efectúa un objeto, denominado renderer, cuya funcionalidad puede adaptarse para distintas aplicaciones. Java EE proporciona un renderer por defecto que es apropiado para la mayoría de las aplicaciones web

20 Ciclo de vida de aplicaciones JSF
1 (Re)construir árbol 5 Eventos Aplicación 123 3 Validación 2 Pasar parámetros 4 Incorporar información 6 HTML

21

22 Ciclo de vida de aplicaciones JSF, II
Durante cada fase en el ciclo de vida se producen eventos, ante los cuales la aplicación puede reaccionar mediante listeners

23 Beans gestionados en aplicaciones JSF
Según hemos visto en el apartado de CDI, en las aplicaciones web (por lo tanto, en particular, en las aplicaciones JSF) se pueden asociar beans a contextos El contexto de los beans utilizados en JSF se especifica mediante las anotaciones que hemos visto en el apartado de CDI.

24 Beans gestionados en aplicaciones JSF, II
Para que los beans gestionados de una aplicación JSF se adapten al ciclo de vida de la página han de tener además de las anotaciones previstas por CDI la La configuración de los beans gestionados en JSF se puede hacer en el ficherode configuración faces-config.xml, que es obligatorio pero puede estar vacío.

25 Especificación de la navegación entre páginas JSF
La página de destino tras pulsar un botón en una página JSF puede no ser fija. Además de la posibilidad de utilizar un método que la calcule, también se puede utilizar un autómata (máquina de estados). El autómata se puede definir mediante reglas de navegación incluidas en el fichero de configuración faces-config.xml.

26 Uso de expresiones UEL Los atributos de las componentes y otros objetos generados por JFS se evalúan en el momento que les corresponde del ciclo de vida. Por ejemplo, los valores que se obtienen de la aplicación, como los contenidos de las etiquetas, se evalúan en la fase de incorporación de datos de la aplicación, tras procesar los parámetros de la solicitud.

27 Uso de expresiones UEL, II
Para controlar la evaluación de los atributos, sus valores son normalmente expresiones UEL de evaluación retardada, #{…}. Normalmente son expresiones que corresponden a l-values, es decir que su valor es una referen-cia asignable. Por ejemplo, no pueden ser el resultado de una operación o una comparación ni números, pero pueden ser atributos de objetos. También pueden ser colecciones o enumeraciones.

28 Ejercicio opcional [JSF1] Aplicación JSF que muestra una lista de nombres de personas extraída de una base de datos que contiene información adicional sobre ellas y permite seleccionar personas de la lista y, tras pulsar en un botón, muestra en otra página la información de todas las personas seleccionadas.

29 Diferencias en la ejecución entre SJP y Facelets
El código JSP da lugar a un servlet que se compila la primera vez que se accede a la página y (re)construye la vista cada vez El código Facelets se compila y el servlet FacesContext lo llama cuando tiene que (re)construir la página

30 Componentes gráficas: Texto fijo
<h:outputText value=“${price}” lang=“en_US” />

31 Componentes gráficas: Campo de texto
<h:inputText required=“true” maxLength=“30” value=#{book.price}> </h:inputText>

32 Componentes gráficas: Imagen
<h:graphicImage height=“20” length=“100” value=“/images/book.gif” />

33 Componentes gráficas: Menús de selección
<h:selectOneMenu id="selectOneCar“ value="#{carBean.currentCar}"> <f:selectItems value="#{carBean.carList}" /> </h:selectOneMenu> (También: h:selectManyMenu)

34 Componentes gráficas: Recuadros de selección múltiple
<h:selectManyCheckbox id="cars“ value="#{carsBean.car}"> <f:selectItems value="#{carBean.carList}"/> </h:selectManyCheckbox>

35 Componentes gráficas: Recuadros seleccionables
<h:selectBooleanCheckbox title=" Updates“ value="#{jsfex.wantsUpdates}" > </h:selectBooleanCheckbox> <h:outputText value="Would you like updates?"/>

36 Otras componentes de selección
h:selectManyListbox h:selectOneListbox h:selectOneRadio

37 Componentes gráficas: Paneles
Tabla con números 1 2 3 Pie de tabla

38 Componentes gráficas: Paneles, II
<h:panelGrid columns=“2“ <f:facet name="header"> <h:outputText value="Tabla con números"/> </f:facet> <h:outputText value="1" /> <h:outputText value="2" /> <h:outputText value="3" /> <f:facet name="footer"> <h:outputText value=“Pie de tabla" /> </h:panelGrid>

39 Componentes gráficas: Tablas
<h:dataTable id="books“ value="#{BookStore.items}“ var=“book"> <h:column> <f:facet name="header"> <h:outputText value="#{msg.storeNameLabel}"/> </f:facet> <h:outputText value="#{book.name}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value=“#{msg.storeTypeLabel}”/> </f:facet> <h:outputText value="#{book.subject}"/> </h:column> </h:dataTable>

40 Componentes gráficas: Botón y enlace con acción
<h:commandButton action=“pg2” value=“OK” /> <h:commandLink action=“${pg2}” value=“UAM”

41 Componentes gráficas: Botón y enlace con acción, II
Se pueden utilizar varios botones y enlaces en un mismo formulario (JSF genera el código necesario para su funcionamiento, utilizando campos ocultos en el formulario). El atributo action, además de una cadena de caracteres, puede ser un método público de cualquier objeto sin argumentos, que devuelva una cadena.

42 Componentes gráficas: Mensajes de errores del usuario
Incluye todos los mensajes de error para el usuario: <h:messages style=“color: red” /> Incluye mensajes de error de una componente: <h:message style="color: red“ for="useraddress" /> <h:inputText id="useraddress“ value="#{jsfexample.address}“ required="true"/>

43 Depuración JSF (con facelets) no crea un servlet por cada página
Las páginas no se pueden depurar línea a línea (cada línea de código se transforma en instrucciones distribuidas en varios lugares del código Java) Los errores producidos en el contenedor se pueden utilizar para depurar igual que en las demás aplicaciones web

44 Depuración, II El fichero web.xml incluye información acerca de la forma de ejecución. En la forma de desarrollo la aplicación muestra en el navegador información detallada acerca de los errores de compilación Se puede obtener información acerca del árbol de componentes web introduciendo en una componente la etiqueta ui:debug. La información se muestra con Ctrl-Shft-D

45 Depuración, III Hay herramientas que permiten seguir el ciclo de vida de la aplicación jsftutorials.net/faces-config/phaseTracker.html Phase Tracker muestra la información correspondiente a cada cambio de fase en el ciclo de vida Phase Tracker utiliza un listener de eventos de la evolución del ciclo de vida

46 Funcionalidad de etiquetas transversales
Acciones para la manipulación de eventos Conversión de datos Validación de datos Internacionalización

47 Modelo de conversión de datos
La estructura de datos utilizada en la presentación no es la misma que se utiliza en la representación de datos por el servidor. Ejemplo: Una fecha se puede mostrar mediante tres cadenas de caracteres. JSF proporciona conversores estándar. Se pueden definir más conversores.

48 Ejemplos de conversores de datos
<h:outputText value=“${price}” lang=“en_US” converter=<f:convertNumber type=“currency” maxFractionDigits=“2” /> /> <h:outputText value="#{article.date}"> <f:convertDateTime dateStyle="full"/> </h:outputText>

49 Modelo de validación JSF permite definir restricciones sobre los valores de determinados datos introducidos por los usuarios. JSF proporciona validadores estándar. Se pueden definir más validadores.

50 Ejemplos de validadores
<h:inputText required=“true” maxLength=“3” value=#{article.price}> <f:validateLongRange minimum=“#{article.minPrice}” maximum=“#{article.maxPrice}” /> </h:inputText>

51 Modelo de eventos Las acciones del usuario generan eventos, que son objetos de una clase JSF. Los eventos de acción, como los botones y los enlaces, dan lugar a una petición al servidor y pueden activar acciones en él. Los eventos de cambio de valor, como la selección de items en una lista y la activación de un check box, además de poder generar la evaluación de métodos JS en el cliente, pueden activar acciones específicas en el servidor, como el acceso a una base de datos.

52 Modelo de eventos: Ejemplo
<h:commandButton action=“#{bean.method}” value=“OK”/> class Bean { … String method() { … } } Los objetos registrados para recibir eventos reciben el valor que devuelve method()

53 Recordatorio: Ciclo de vida
5 Eventos Aplicación 1 Crear 123 abc 3 Validar y eventos c.v. 2 Pasar 4 Incorporar 6 HTML

54 Modelo de eventos: Priorización
Las acciones desencadenadas en el servidor por los eventos de acción se ejecutan inmediatamente antes de generar la respuesta. Las acciones desencadenadas en el servidor por los eventos de cambio de valor se ejecutan en la fase de validación.

55 Modelo de eventos: Priorización, II
A veces se desea que las acciones asociadas a eventos de acción modifiquen datos necesarios en fases previas, como la incorporación de datos de la aplicación (por ejemplo, si un dato generado por el usuario se utiliza en la presentación inmediata). A veces se desea priorizar la ejecución de las acciones asociadas a eventos de cambio de valor (por ejemplo, si modifican datos necesarios en otra acción del mismo tipo).

56 Modelo de eventos: Priorización, III
Si una componente gráfica tiene su atributo immediate con valor true, las acciones desencadenadas en el servidor por los eventos de acción y cambio de valor se ejecutan al final de la fase de aplicación de parámetros de la petición, resolviendo los problemas anteriores.

57 Modelo de navegación JSF permite especificar la navegación entre páginas mediante reglas que indican qué eventos permiten pasar de una página a otra. El evento null dirige de nuevo a la última página. La especificación de la navegación en aplicaciones basadas en JSF se hace mediante el fichero de configuración faces-config.xml en lugar de utilizar un servlet.

58 Modelo de navegación: Formato de las reglas
<navigation-rule> <from-view-id>/init.jsp</from-view-id> <navigation-case> <from-outcome>event</from-outcome> <to-view-id>/end.jsp</to-view-id> </navigation-case> </navigation-rule>

59 Inclusión de mensajes (parte del texto de la página)
Fichero src/articles/ArticleMsgs.properties: ServerError=Request not completed ClientError=Form not filled

60 Inclusión de mensajes: Carga selectiva
Fichero Articles.jsp: <f:loadBundle basename=“articles.ArticleMsgs“ var=“artmsg“/> <h:outputText value=“#{artmsg.ServerError}”/>

61 Inclusión de mensajes: Carga global
Fichero faces-config.xml: <resource-bundle> <base-name> articles.ArticleMsgs </base-name> <var>artmsg</var> </resource-bundle> Fichero Articles.jsp: <h:outputText value=“#{artmsg.ServerError}”/>

62 Parametrización de mensajes
Fichero de propiedades: Selección=El socio {0} ha sido seleccionado Fichero Socios.jsp: <f:loadBundle basename=“…“ var=“sls“/> <h:outputFormat value=“#{sls.Seleccion}”> <f:param value=“#{socios.seleccion}”/> </h:outputFormat> Permite cambiar el orden de las palabras en distintos idiomas.

63 Componentes gráficas: Adaptación de mensajes de errores del usuario
<h:inputText id=“cap” label=“Capitulo” value=“#{LibroBean.capNum}” converterMessage = “#{ErrMsg.capE}”>

64 Internacionalización
Forma idiomática (locale): Especifica un idioma, país y variante del idioma Ejemplo: Inglés de Estados Unidos Español de España, variante andaluza Francés Se especifica mediante una cadena de la forma XXX_YYY_ZZZ Ejemplo: en_US Normalmente, el país se pone con mayúsculas

65 Internacionalización, II
Ficheros de propiedades: ArticleMessages.properties ArticleMessages_en_UK.properties ArticleMessages_en_US.properties ArticleMessages_es_ES.properties ArticleMessages_es_MX.properties Alternativa: ArticleMessages_en.properties ArticleMessages_es.properties

66 Internacionalización, III
Cada navegador en cada PC tiene una preferencia idiomática establecida. Cada aplicación web puede tener una preferencia idiomática propia. En general, las componentes gráficas pueden establecer un locale específico.

67 Internacionalización, IV
Preferencia idiomática de una aplicación JSF: Fichero faces-config.xml <application><locale-config> <default-locale>es_ES</default_locale> <supported-locale>es_MX </ supported-locale> <supported-locale>en_UK </locale-config></application>

68 Internacionalización, V
Internacionalización de aplicaciones web generales: Exige programación en Java Utilizar la clase PropertyResourceBundle, construyendo instancias a partir de un locale y los ficheros de propiedades. Construir los mensajes que aparecen en las páginas a partir de los propertyResourceBundles consruidos.

69 Facelets: Plantillas Una plantilla es un documento de Facelets que tiene partes pendientes de rellenar. Las partes pendientes de rellenar pueden tener un contenido por defecto, que se sustituye por otro contenido cuando se instancia la plantilla. Por ejemplo, la tabla de la transparencia siguiente puede ser una plantilla.

70 Visualización de plantilla sin instanciar
UAM Escuela Politécnica de Madrid Aquí va su Menú Aquí va su texto, que puede ser tan largo y aburrido como Vd. quiera, pero eso sí, lo tiene que escribir desde el principio hasta el final, porque si no aparecerá esto.

71 Codificación de la plantilla (fichero plantilla.xhtml)
<h:body> <table width=“100%” border=“1”> <tr> <td> UAM </td> <td> Escuela Politénica Superior> </td> </tr> <tr> <td> <ui:insert name=“21”> Aquí <br> su <br> menú <br> … </ui:insert> </td> <td> <ui:insert name=“22”> Aquí su texto, que puede ser tan largo y aburrido como … </ui:insert> </td> </tr> </table> </h:body>

72 Instanciación de la plantilla (fichero instanciaciacion.xhtml)
<h:body> <ui:composition template=“plantilla.xhtml”> <ui:define name=“21”> Servlets <br> JSP <br> JSF </ui:define> <ui:define name=“22”> Bienvenido a la web de CLS. Aquí … </ui:define> </ui:composition> </h:body>

73 Consideraciones acerca de la instanciación
El contenido que se incluye en los huecos de una plantilla puede ser arbitrario. Por ejemplo, se pueden incluir formularios, tablas o elementos HTML de JSF de cualquier tipo y en cantidad arbitraria. También se pueden incluir componentes compuestas reutilizables, como un formulario que pide un texto al usuario y lo guarda en un lugar de memoria.

74 Componentes compuestas: Ejemplo
Cantidad: Euros OK Las etiquetas “Cantidad:”, “Euros” y “OK” se pueden cambiar cada vez que se utiliza la componente. También se pueden cambiar el nombre de la variable donde se guarda el valor introducido por el usuario y la URL destino.

75 Utilización de la componente compuesta
Cantidad: Euros OK Preetiqueta Contenido Postetiqueta BotonOK <rm:introtext preetiqueta=“Cantidad:” contenido=“#{cantidadBean}” postetiqueta=“Euros” botonok=“OK” action=“index”/>

76 Definición de la componente compuesta
Idea: Se considera a la componente como una función de cinco argumentos: la preetiqueta, la cantidad, la postetiqueta, el botónOK y la action. Según hemos visto, en la utilización de la componente los valores de los argumentos se especifican indicando correlativamente sus nombres y valores, en lugar de escribir sus valores concatenados separados por comas.

77 Definición de la componente compuesta, II
La definición de la componente es parte de un fichero xhtml, que incluye una cabecera (la especificación de los argumentos) y un cuerpo (la especificación de la componente en sí). Los argumentos se especifican dentro de una cláusula con etiqueta composite:interface, y cada uno lleva la etiqueta composite:attribute.

78 Definición de la componente compuesta, III
La componente parametrizada (cuerpo de la definición) se especifica en la forma que le corresponde mediante cláusulas de Facelets dentro de una cláusula con etiqueta <composite:implementation>, incluyendo en los lugares donde tienen que aparecer los argumentos la fórmula UEL #{cc.attrs.nombreparam}, donde nombreparam es el nombre del parámetro que tiene que aparecer.

79 Ejemplo de definición de componente compuesta
<composite:interface> <composite:attribute name=“preetiqueta”/> <composite:attribute name=“contenido”/> <composite:attribute name=“postetiqueta”/> <composite:attribute name=“botonOK”/> <composite:attribute name=“action”/> </composite:interface> …

80 Ejemplo de definición de componente compuesta, II
… <composite:implementation> <h:form> <h:outputLabel value=“#{cc.attrs.preetiqueta}”/> <h:outputText value=“#{cc.attrs.contenido}”/>

81 Ejemplo de definición de componente compuesta, III
… <h:outputLabel value=“#{cc.attrs.postetiqueta}”/> <h:commandButton value=“#{cc.attrs. botonOK}” action=“#{cc.attrs.action}”/> </h:form>

82 Definición de la componente compuesta, IV
El fichero xhtml con la definición de una componente se incluye en un directorio que corresponde a una biblioteca de recursos. El directorio es un subdirectorio de la forma /resources/nombreBiblioteca.

83 Utilización de la componente compuesta, II
El fichero que utiliza la componente tiene que incluir la biblioteca igual que lo hace con las bibliotecas estándar de Facelets: <html xmlns= xmlns:f=“ xmlns:h=“ xmlns:ui=“ xmlns:rm=“ Donde … es el nombre del subdirectorio.

84 Componentes compuestas y patrones de documentos
Los atributos de las componentes compuestas son cadenas de caracteres, al igual que los de cualquier etiqueta en XML, y en particular los de componentes gráficas de Facelets. Las componentes compuestas no son documentos completos, sino que se incluyen en huecos de plantillas.

85 Componentes compuestas y patrones de documentos, II
Las plantillas de documentos JSF son documentos que se pueden ver como funciones de los huecos que contienen. Desde este punto de vista, sus parámetros o argumentos son componentes, bien sean predefinidas en la biblioteca HTML de Facelets o definidas por usuarios como componentes compuestas.

86 Ejercicio opcional [JSF2] Diseñar una plantilla, una componente compuesta y dos páginas de Facelets que hagan lo siguiente: La plantilla muestra en la parte superior un formulario con un campo de texto y un botón “Show”, que hace que el texto introducido por el usuario se guarde en un atributo de sesión fijo; la parte inferior por defecto contiene el texto “Por determinar”.

87 Ejercicio opcional, II [JSF2] …
La primera página utiliza la plantilla para mostrar en la parte inferior la imagen de un directorio que corresponde al texto introducido por el usuario en la parte superior. La componente compuesta muestra el contenido de una tabla, cuyo nombre es su único parámetro, de una base de datos fija.

88 Ejercicio opcional, III
[JSF2] … La segunda página utiliza la plantilla y la componente compuesta para mostrar en la parte inferior la tabla cuyo nombre introduce el usuario en la parte superior (En general, la plantilla se puede utilizar para visualizar instanciaciones de componentes compuestas arbitrarias con un solo atributo)


Descargar ppt "Java Server Faces."

Presentaciones similares


Anuncios Google