Академический Документы
Профессиональный Документы
Культура Документы
Desarrollo de
componentes web
con tecnologías
Servlet y JSP
Profesional en
Plataforma
JAVA
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Contenido
Introducción y Objetivos ........................................................................................................ 1
Unidad 1. Introducción a las Tecnologías de las Aplicaciones WEB ............................................... 2
Definir la tecnología servlet .................................................................................................................................... 3
Definir la tecnología JavaServer Pages ................................................................................................................... 4
JSTL ......................................................................................................................................................................... 5
Definir la tecnología EJB ......................................................................................................................................... 5
Definir la tecnología Struts ..................................................................................................................................... 6
Definir la tecnología JavaServer Faces .................................................................................................................... 7
Definir la tecnología Java Message Service ............................................................................................................ 8
Definir la tecnología JDBC....................................................................................................................................... 9
Laboratorio: Creación de proyecto Web. ............................................................................................................... 9
Unidad 2. Desarrollo de un Componente Vista ......................................................................... 12
Métodos más importantes de la clase HttpServlet. .............................................................................................. 13
Métodos de la clase ServletRequest ..................................................................................................................... 14
Métodos de la clase ServletResponse .................................................................................................................. 15
Buffering............................................................................................................................................................... 15
Método Service .................................................................................................................................................... 15
Cabeceras ............................................................................................................................................................. 16
Elementos del path de la petición ........................................................................................................................ 16
Desarrollar un servlet HTTP sencillo ..................................................................................................................... 17
Configuración de un servlet .................................................................................................................................. 18
Laboratorio: Solicitud de un Servlet. .................................................................................................................... 19
Unidad 3. Desarrollo de un componente controlador ................................................................ 21
Desarrollar un Servlet con getParameterValues ................................................................................................... 26
Laboratorio: Recogida de parámetros .................................................................................................................. 28
Unidad 4. Desarrollo de Formularios Dinámicos ....................................................................... 30
Introducción ciclo de vida de un Servlet ............................................................................................................... 30
Parámetros de inicialización de un Servlet ........................................................................................................... 31
Controladores de error ......................................................................................................................................... 33
Seguridad ............................................................................................................................................................. 34
Laboratorio: Ciclo de vida de un servlet ............................................................................................................... 37
Unidad 5 . Uso compartido de recursos de la aplicación con el contexto servlet ........................... 41
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Describir la finalidad y las funciones del contexto servlet. ................................................................................... 41
Interface ServletContext....................................................................................................................................... 44
Eventos ServletContext ........................................................................................................................................ 47
Interface ServletContextListener .......................................................................................................................... 47
Unidad 6 . Diseño de la Capa de Negocio ................................................................................ 48
Arquitectura Aplicaciones J2EE ............................................................................................................................ 50
Las etapas del análisis y del diseño orientado a objetos ...................................................................................... 50
Modelo Tres Capas ............................................................................................................................................... 52
Modelo Cuatro capas ........................................................................................................................................... 54
Diseño de componentes ....................................................................................................................................... 54
Unidad 7. Desarrollo de Aplicaciones Eeb con Struts ................................................................ 56
Marco de trabajo MVC ......................................................................................................................................... 57
Desarrollar una clase action de Struts .................................................................................................................. 58
Fichero de Configuración de los Mapeos de Action ............................................................................................. 60
Laboratorio: Creación de propiedades en el archivo ApplicationResource. ......................................................... 65
Unidad 8. Desarrollo de Aplicaciones Web con Administración de Sesiones ................................. 67
Desarrollar servlets utilizando la administración de sesiones .............................................................................. 69
Describir la implementación de cookies de la administración de sesiones. ......................................................... 72
Ejemplo de uso de cookies ................................................................................................................................... 72
Laboratorio: Creación y uso de Cookies. .............................................................................................................. 75
Unidad 9. Uso de Filtros en Aplicaciones Web .......................................................................... 78
Programando los filtros ........................................................................................................................................ 79
Configurar un filtro en el archivo web.xml ........................................................................................................... 82
Unidad 10. Integración de Aplicaciones Web con Bases de Datos ............................................... 85
Tipos de drivers .................................................................................................................................................... 85
Diseñar una aplicación web para integrarla con un DBMS ................................................................................... 86
Conexión .............................................................................................................................................................. 86
Creando sentencias SQL ....................................................................................................................................... 87
API de Java Naming and Directory Interface (JNDI) .............................................................................................. 96
Los servicios de Nombre y Directorio ................................................................................................................... 97
Interacción con los servicios de Nombre y Directorio .......................................................................................... 97
Proveedores de servicios JNDI .............................................................................................................................. 98
Laboratorio: Paginación de registros. ................................................................................................................... 98
Unidad 11. Desarrollo de páginas JSP ................................................................................... 104
Introducción a la tecnología de páginas JSP ....................................................................................................... 104
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Elementos de Script JSP ...................................................................................................................................... 105
Directiva JSP page ............................................................................................................................................. 107
Acciones ............................................................................................................................................................. 108
Laboratorio: Directivas JSP ................................................................................................................................. 115
Unidad 12. Desarrollo de páginas JSP con etiquetas personalizadas .......................................... 121
Diseñar una aplicación web con etiquetas personalizadas ................................................................................. 121
Etiquetas con contenido en el cuerpo ................................................................................................................ 126
Utilizar etiquetas JSTL en una página JSP ........................................................................................................... 127
Base de Datos ..................................................................................................................................................... 132
Laboratorio: Contador de visitas con Custom Tags. ........................................................................................... 141
Contador.tld ....................................................................................................................................................... 141
Web.xml ............................................................................................................................................................. 141
Contador.java ..................................................................................................................................................... 142
indice.jsp ............................................................................................................................................................ 143
Unidad 13. Desarrollo de Aplicaciones Web con la Clase ActionForm de Struts............................ 144
Crear una clase ActionForm ............................................................................................................................... 145
Laboratorio: Internacionalizar una aplicación .................................................................................................... 150
Unidad 14. Construcción de Componentes de Presentación Web Reutilizables ............................ 152
Crear diseños utilizando la infraestructura Struts Tiles ...................................................................................... 155
Ejemplo de uso de plantillas ............................................................................................................................... 157
Laboratorio: Librería de etiquetas Logic. ............................................................................................................ 160
IndexLibros.jsp ................................................................................................................................................... 160
Libros.java .......................................................................................................................................................... 161
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Introducción y Objetivos
1
Introducción y Objetivos
Durante el desarrollo de este módulo el estudiante entenderá los conceptos básicos de las
aplicaciones en capas para lograr crear una aplicación. También se darán los conocimientos que le
permitan desplegar y ejecutar una aplicación en un servidor JAVA EE.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 1. Introducción a las Tecnologías de
las Aplicaciones WEB
Objetivos
Entender los conceptos básicos de las aplicaciones en capas.
Entender los conceptos básicos de la Plataforma Java EE.
Crear una aplicación Java EE multicapa.
Desplegar y ejecutar la aplicación en un servidor Java EE.
Saber dónde buscar más información acerca de la plataforma Java EE.
Introducción
La plataforma Java, Enterprise Edition 5 (Java EE 5), es una plataforma de programación para
desarrollar y ejecutar software de aplicaciones en Lenguaje de programación Java con arquitectura
de N capas distribuidas y que se apoya ampliamente en componentes de software modulares
ejecutándose sobre un servidor de aplicaciones.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
JavaServer Faces
Java Message Service (JMS).
Java Transaction API (JTA).
JavaMail API y JavaBeans Activation Framework (JAF).
Tecnologías XML (JAXP, JAX-RPC, JAX-WS, JAXB, SAAJ, JAXR)
JDBC API
Java Naming and Directory Interface (JNDI)
Java Authentication and Authorization Service (JAAS)
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
tener ningún temor a que los usuarios puedan introducir Servlet en el servidor, ya que se
encuentran protegidos frente a código malicioso.
Al estar escritos en Java, tienen todas las ventajas de este lenguaje (pueden hacer uso de cualquier
paquete de Java). Como es un lenguaje altamente escalable surgirán paquetes de una forma muy
rápida (por ejemplo, ya existen paquetes para la gestión de documentos XML).
Los Servlets son portables entre plataformas (siguen la premisa de Java "escribir una vez, ejecutar
en cualquier lugar"). Netscape, Apache e IIS, los tres servidores Web más populares, soportan los
Servlets.
En esta imagen podemos apreciar el esqueleto básico de una aplicación Servlet:
Las sentencias import indican al compilador de Java la inclusión de todas las clases públicas e
interfaces de los paquetes java.io y javax.servlet en la compilación.
La clase extiende (extends), es heredera de la clase HttpServlet. Esta clase proporciona la interfaz
para que el servidor le pase las peticiones al servlet y el mecanismo para controlar el ciclo de vida del
servlet.
En esta imagen podemos apreciar las directivas que utilizaremos en aplicaciones JSP:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Una página JSP cuando se ejecuta el servidor de base de datos genera un servlet. El ejemplo
anterior generará un servlet como el de la imagen siguiente:
El motor de las páginas JSP está basado en los servlets de Java -programas en Java destinados a
ejecutarse en el servidor-, aunque el número de desarrolladores que pueden afrontar la
programación de JSP es mucho mayor, dado que resulta mucho más sencillo aprender que los
servlets.
En JSP creamos páginas de manera parecida a como se crean en ASP o PHP -otras dos tecnologías
de servidor-. Generamos archivos con extensión .jsp que incluyen, dentro de la estructura de
etiquetas HTML, las sentencias Java a ejecutar en el servidor. Antes de que sean funcionales los
archivos, el motor JSP lleva a cabo una fase de traducción de esa página en un servlet,
implementado en un archivo class (Byte codes de Java). Esta fase de traducción se lleva a cabo
habitualmente cuando se recibe la primera solicitud de la página .jsp, aunque existe la opción de
precompilar en código para evitar ese tiempo de espera la primera vez que un cliente solicita la
página.
JSTL
JSTL es una biblioteca que implementa funciones de uso frecuente en aplicaciones JSP. En concreto,
JSTL proporciona
Cinco bibliotecas de etiquetas JSP:
Funciones comunes de iteración sobre datos, operaciones condicionales, e importación de
otras páginas.
Internacionalización y formateo de texto.
Funciones de manipulación de cadenas.
Procesamiento de XML.
Acceso a bases de datos.
Un lenguaje de expresión para referenciar objetos y sus propiedades sin necesidad de código
Java.
Validadores de bibliotecas de etiquetas (Tag Library Validators, TLVs).
JSTL requiere un contenedor de JSP 2.0.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Un ejemplom práctico sería el siguiente:
Customer.java: es en este ejemplo el "remote interface" que define los métodos de negocio
que puede invocar el cliente. En este caso podéis comprobar que existen sólo un método
getInformation, que permite obtener la información asociada a un usuario de la tienda de
venta de Logos. Este método se implementa en la clase del bean.
CustomerHome.java: es en este ejemplo el "home interface" que define los métodos que le
permiten al cliente crear, buscar y eliminar el bean. En este caso podéis comprobar que esta
interfaz proporciona un método que permite crear el bean a partir de los datos asociados a
un usuario, devolviendo un objeto que implementa la interfaz remota definida en
Customer.java, de esta forma se crea un nuevo usuario en nuestro sistema que se
almacenará de manera persistente en la base de datos. En esta interfaz también existe un
método que permite buscar una instancia del bean a partir de la clave primaria, que en este
caso es el nombre del usuario.
CustomerBean.java: es en este ejemplo el código del "enterprise bean" que implementa los
métodos de negocio definidos en el interfaz remoto Customer, además de todos los métodos
definidos en la interfaz EntityBean.
CustomerTO.java: es una clase auxiliar que representa la información asociada a un usuario,
es una clase serializable ya que el método de negocio definido en la interfaz remota devuelve
un objeto de este tipo.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Definir la tecnología JavaServer Faces
JavaServer Faces (JSF) es una tecnología y framework para aplicaciones Java basadas en web que
simplifica el desarrollo de interfaces de usuario en aplicaciones Java EE. JSF usa JavaServer Pages
(JSP) como la tecnología que permite hacer el despliegue de las páginas, pero también se puede
acomodar a otras tecnologías como XUL.
JSF incluye:
Un conjunto de APIs para representar componentes de una interfaz de usuario y administrar su
estado, manejar eventos, validar entrada, definir un esquema de navegación de las páginas y dar
soporte para internacionalización y accesibilidad.
Un conjunto por defecto de componentes para la interfaz de usuario.
Dos bibliotecas de etiquetas personalizadas para JavaServer Pages que permiten expresar una
interfaz JavaServer Faces dentro de una página JSP.
- Un modelo de eventos en el lado del servidor.
- Administración de estados.
- Beans administrados.
El objetivo de la tecnología JavaServer Faces es desarrollar aplicaciones web de forma parecida a
como se construyen aplicaciones locales con Java Swing, AWT (Abstract Window Toolkit), SWT
(Standard Widget Toolkit) o cualquier otra API similar.
Tradicionalmente, las aplicaciones web se han codificado mediante páginas JSP (JavaServer Pages)
que recibían peticiones a través de formularios y construían como respuesta páginas HTML (Hiper
Text Markup Language) mediante ejecución directa o indirecta -a través
de bibliotecas de etiquetas- de código Java, lo que permitía, por ejemplo, acceder a bases de datos
para obtener los resultados a mostrar amén de realizar operaciones marginales como insertar o
modificar registros en tablas relacionales, actualizar un carrito de la compra, etc.
JavaServer Faces pretende facilitar la construcción de estas aplicaciones proporcionando un entorno
de trabajo (framework) vía web que gestiona las acciones producidas por el usuario en su página
HTML y las traduce a eventos que son enviados al servidor con el objetivo de
regenerar la página original y reflejar los cambios pertinentes provocados por dichas acciones.
En definitivas cuentas, se trata de hacer aplicaciones Java en las que el cliente no es una ventana de
la clase JFrame o similar, sino una página HTML.
Como el lector puede imaginar, cualquier evento realizado sobre una página JSF incurre en una
carga sobre la red, ya que el evento debe enviarse a través de ésta al servidor, y la respuesta de
éste debe devolverse al cliente; por ello, el diseño de aplicaciones JavaServer Faces
debe hacerse con cuidado cuando se pretenda poner las aplicaciones a disposición del mundo entero
a través de internet. Aquellas aplicaciones que vayan a ser utilizadas en una intranet podrán
aprovecharse de un mayor ancho de banda y producirán una respuesta mucho más rápida.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Una de las ventajas de que JSF sea una especificación estándar es que pueden encontrarse
implementaciones de distintos fabricantes. Esto permite no vincularse exclusivamente con un
proveedor concreto, y poder seleccionar el que más interese en cada caso según el número de
componentes que suministra, el rendimiento de éstos, soporte
proporcionado, precio, política de evolución, etc.
JSF trata la vista (la interfaz de usuario) de una forma algo diferente a lo que estamos
acostumbrados en aplicaciones web, ya que este tratamiento es mucho más cercano al estilo de
Java Swing, Visual Basic o Delphi, donde la programación de la interfaz se hace a través de
componentes y está basada en eventos (pulsación de un botón, cambio en el valor de un campo,
etc.).
JSF es muy flexible. Por ejemplo nos permite crear nuestros propios componentes, y/o crear
nuestros propios renderizadores para pintar los componentes en la forma que más nos convenga.
Una de las grandes ventajas de la tecnología JavaServer Faces es que ofrece una clara separación
entre el comportamiento y la presentación. Las aplicaciones web construidas con tecnología JSP
conseguían parcialmente esta separación. Sin embargo, una aplicación JSP no puede mapear
peticiones HTTP al manejo de eventos específicos de los componentes o manejar elementos UI como
objetos con estado en el servidor. La tecnología JavaServer Faces permite construir aplicaciones web
que introducen realmente una separación entre el comportamiento y la presentación, separación
sólo ofrecida tradicionalmente por arquitecturas UI del lado del cliente.
Separar la lógica de negocio de la presentación también permite que cada miembro del equipo de
desarrollo de la aplicación web se centre en su parte asignada del proceso diseño, y proporciona un
modelo sencillo de programación para enlazar todas las piezas. Por ejemplo,
personas sin experiencia en programación pueden construir páginas JSF usando las etiquetas de
componentes UI que esta tecnología ofrece, y luego enlazarlas con código de la aplicación sin
escribir ningún script ni nada.
Otro objetivo importante de la tecnología JavaServer Faces es mejorar los conceptos familiares de
componente-UI y capa-web sin limitarnos a una tecnología de script particular o un lenguaje de
marcas. Aunque la tecnología JavaServer Faces incluye una librería de etiquetas JSP personalizadas
para representar componentes en una página JSP, las APIs de JavaServer Faces se han creado
directamente sobre el API JavaServlet. Esto nos permite, teóricamente, hacer algunas cosas
avanzadas: usar otra tecnología de presentación junto a JSP, crear nuestros propios componentes
personalizados directamente desde las clases de componentes, y generar salida para diferentes
dispositivos cliente, entre otras.
En definitivas cuentas, la tecnología JavaServer Faces proporciona una rica arquitectura para
manejar el estado de los componentes, procesar los datos, validar la entrada del usuario, y manejar
eventos.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
el receptor no esta disponible para aceptar el mensaje o atenderlo, de cualquier forma se le
envía el mensaje y este se encola en una pila del tipo FIFO para luego ser recibido según
haya entrado.
Modelo Publicador/Suscriptor (Publish/Subscribe): Este modelo cuenta con varios clientes,
unos que publican temas(tópicos) o eventos, y los que ven estos tópicos, a diferencia del
modelo punto a punto este modelo tiende a tener más de un consumidor.
Ambos modelos pueden ser síncronos mediante el método receive y asíncronos por medio de un
MessageListener.
Objetivo
Enunciado:
Abrir NetBeans y crear un proyecto web siguiendo los siguientes pasos:
1. Seleccionar la opción archivo y nuevo proyecto.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
2. En categorías elegimos Java Web, y en proyectos web application.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
5. Por último, no seleccionaremos ningún Framework y pulsamos en finalizar.
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 2. Desarrollo de un Componente
Vista
Objetivos
Entender el papel que juega el componente vista en un desarrollo web.
Trabajar con la configuración de un servlet.
Introducción HttpServlet
Es una clase que implementa la interfaz Servlet incorporando además métodos específicos para
servidores Web.
Un uso típico de HttpServlet es el procesamiento de formularios html.
El método service() de la clase HttpServlet lanza diferentes métodos dependiendo de las diferentes
peticiones que se pueden recibir y que ya explicamos al analizar el protocolo HTTP. Este método es
capaz de reconocer las peticiones estándar del protocolo HTTP 1.1 y no es conveniente
sobreescribirlo en las subclases, a no ser que se desee una implemetación más específica de él.
Los tipos de petición que reconoce y el método al que llama se encuentran en la siguiente tabla:
Tipo de petición Método al que se llama.
GET doGet(HttpServletRequest, HttpServletResponse)
POST doPost(HttpServletRequest, HttpServletResponse)
HEAD Devuelve lo mismo que GET pero sin el cuerpo.
PUT doPut(HttpServletRequest, HttpServletResponse)
DELETE doDelete(HttpServletRequest,
HttpServletResponse)
OPTION No está permitido sobrecargarlo.
TRACE No está permitido sobrecargarlo.
Cualquier otro tipo desconocido Devuelve el mensaje de error "BAD REQUEST".
Las implementaciones de estos métodos por defecto devuelven el error "BAD REQUEST", por tanto,
si queremos obtener cierta funcionalidad de ellos debemos sobreescribirlos en nuestro Servlet.
La interface Servlet declara los métodos del ciclo de vida de un servlet, que son:
void init(ServletConfig config): es llamado, una sola vez, por el contenedor del servidor J2EE
compatible donde se hospeda el servlet y se emplea para inicializarlo. Se ejecutará cuando se realice
la primera petición. Este método y el resto del ciclo de vida se tratarán con más detalle en el
siguiente apartado.
void destroy(): es llamado por el contenedor antes de que el servlet se descargue de memoria y
deje de prestar servicio.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
void service(ServletRequest request, ServletResponse reponse): es invocado por el contenedor para
procesar las peticiones, una vez que el servlet se ha inicializado. Sus argumentos son instancias de
las interfaces javax.servlet.ServletRequest y javax.servlet.ServletResponse que modelan,
respectivamente, la petición del cliente y la respuesta del servlet. En un servlet http, este método
suele sustituirse por los métodos de javax.servlet.http.HttpServlet.
void doPost(HttpServletRequest request, HttpServletResponse response) para gestionar peticiones
post.
El método POST solo esta accesible desde los formularios. Se envían los parámetros de forma
implícita junto a la página, es decir, al pasar los parámetros, nosotros no vemos reflejado en ningún
sitio qué parámetros son y cual es su valor.
El método GET envía los parámetros de forma explicita junto a la página, mostrando en la barra de
navegación los parámetros y sus valores. Son esas largas cadenas que aparecen en algunas páginas
en nuestra barra de navegación.
doGet(HttpServletRequest req, Recibe una petición HTTP tipo GET del método
HttpServletResponse resp) protegido service y gestiona la petición.
doPost(HttpServletRequest req, Recibe una petición HTTP tipo POST del método
HttpServletResponse resp) protegido service y gestiona la petición.
doPut(HttpServletRequest req, Recibe una petición HTTP tipo PUT del método
HttpServletResponse resp) protegido service y gestiona la petición.
doTrace(HttpServletRequest req, Recibe una petición HTTP tipo TRACE del método
HttpServletResponse resp) protegido service y gestiona la petición.
Todo los métodos reciben dos parámetros que son HttpServletRequest(Objeto que representa a la petición y
cuyos métodos nos van a permitir analizarla.) y HttpServletResponse (Objeto que nos va a permitir emitir la
respuesta).
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Métodos de la clase ServletRequest
Método Descripción
getAttribute(java.lang.String name) Devuelve el valor del atributo especificado como
un objeto.
getAttributeNames() Devuelve un objeto Enumeration que contiene los
nombres de todos los atributos de la petición que
están disponibles.
getCharacterEncoding() Devuelve el nombre del estilo de codificación de
caracteres usados en esta petición.
getContentLength() Devuelve la longitud, en bytes, del contenido de
la petición o -1 si la longitud no se conoce.
getContentType() Devuelve el tipo MIME del contenido de la petición,
o null si el tipo no es conocido.
getInputStream() Devuelve datos binrarios desde el cuerpo de la
petición como un ServletInputStream, el cual te
da la capacidad de leer toda una línea a la vez.
getParameter(java.lang.String name) Devuelve el valor del parámetro de la petición
especificado como un String o null si el parámetro
no existe.
getParameterNames() Devuelve un objeto Enumeration de objetos String
que contiene el nombre de los parámetros de la
petición.
getParameterValues(java.lang.String nam Devuelve un array de objetos String que contienen
e) todos los valores de los parámetros que tiene la
petición, o null si lo sparámetros no existen.
getProtocol() Devuelve el nombre y versión del protocolo usado
en la petición con el formato:
protocol/majorVersion.minorVersion, por ejemplo,
HTTP/1.1.
getReader() Devuelve el cuerpo de la petición como un
BufferedReader.
getRemoteAddr() Devuelve la dirección IP del cliente que envía la
petición.
getRemoteHost() Devuelve el nombre completo (de la máquina) del
cliente que envía la petición.
getScheme() Devuelve el nombre del esquema usado en la
realización de la petición, por ejemplo, http, https,
or ftp.
getServerName() Devuelve el nombre del host dónde reside es
servidor que recibió la petición.
getServerPort() Devuelve el número el puerto en el cual se recibió
la petición.
setAttribute(java.lang.String key, Almacena un atributo en el contexto de esta
java.lang.Object o) petición.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Métodos de la clase ServletResponse
Método Descripción
getCharacterEncoding() Devuelve el nombre del conjunto de caracteres de
codificación usado para el envío de tipos MIME en el
cuerpo de la respuesta.
getOutputStream() Devuelve un ServletOutputStream adecuado para
escribir datos binarios en la respuesta.
getWriter() Devuelve un objeto PrintWriter que puede ser usado
para enviar caracteres de texto al cliente.
setContentLength(int len) Pone la longitud del contenido que el servidor
devuelve al cliente.
setContentType(java.lang.String type) Pone el tipo de contenido de la respuesta que el
servidor envía al cliente.
Buffering
Un contenedor servlet está permitido, aunque no es necesario, para que la salida del buffer vaya al
cliente por motivos de eficiencia. Los servidores típicos crean un buffer por defecto, pero permiten a
los servlets especificar sus parámetros. Los siguientes métodos de la interfaz ServletResponse
permiten al servlet acceder y establecer la información del buffer:
getBufferSize: devuelve el tamaño del buffer que está siendo usado.
setBufferSize: establece el tamaño del buffer.
isCommitted: devuelve true si el cliente devuelve los bytes de respuesta.
reset: limpia toda la información antes de que la respuesta sea enviada, incluyendo las cabeceras y
los códigos de estado.
resetBuffer: limpia toda la información del buffer, sin incluir las cabeceras y los códigos de estado.
flushBuffer: obliga que el buffer se escriba en el cliente.
Estos métodos son proporcionados por la interfaz ServletResponse para permitir operaciones de
buffer que mejoran el rendimiento del servlet usando un ServletOutputStream o un Writer.
Si la respuesta es enviada y se invoca el reset o el resetBuffer, se lanzará una excepción del tipo
IllegalStateException.
Cuando el buffer está lleno, el contenedor debe volcar inmediatamente el contenido al cliente. Si es
la primera información que se manda al cliente, la respuesta se considera que está enviada
(committed).
Método Service
El método Service es el método principal, llamado cuando el servlet recibe una solicitud de servicio.
Define un paquete de lógica de procesamiento proporcionado por el servlet. En la declaración se
puede notar que el denominado método service toma dos parámetros (Objetos): uno llamado
request del tipo HttpServletRequest y otro por nombre response del tipo HttpServletResponse,
ambos representan el objeto de entrada y salida del Servlet respectivamente.
Lo anterior significa que dentro de estos Objetos reside la información con que será atendida la
solicitud así como la información que será enviada de respuesta, por decirlo de otra manera, son
estos dos objetos con los que juega todo Servlet, y por ende un JSP también.
Ejemplo de Servlet con método Service:
import javax.servlet.*;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
import javax.servlet.http.*;
public class ServletConService extends HttpServlet
{
public void service(HttpServletRequest request,
HttpServletResponse response)
throws IOException
{
response.setContentType("text/html");
Cabeceras
Un servlet puede acceder a las cabeceras de una petición HTTP a través de los siguientes métodos
de la interfaz HttpServletRequest:
getHeader: devuelve el nombre de la cabecera. Aunque puede haber múltiples cabeceras con
el mismo nombre, este método sólo devuelve el nombre de la primera cabecera de la
petición.
getHeaders: permite acceder a todos los valores asociados a un nombre de cabecera,
devolviendo una Enumeration de String’s.
getHeaderNames
Las cabeceras pueden contener representaciones de enteros (int) o fechas (Date)
almacenadas como String. Para acceder a esta información, la interfaz HttpServletRequest
proporciona métodos para acceder a la información en uno de estos formatos:
getIntHeader: si no puede transformar el valor de la cabecera a entero, lanzará la excepción
NumberFormatException.
getDateHeader: si no puede transformar el String a fecha, lanzará IllegalArgumentException.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
un dirección “/”. Los siguientes métodos existen en la interface HttpServletRequest para acceder a
esta información.
getContextPath
getServletPath
getPathInfo
Es importante hacer notar que, excepto para la codificicación URL, las diferencias entre el URI de
petición y las partes del path hacen que siempre se cumpla la siguiente ecuación:
requestURI = contextPath + servletPath + pathInfo
<head>
<title>PAGINA 1</title>
</head>
<body>
<form name="form1" action= "Servlet1" method="post">
<input type="submit" value="enviar">
</form>
</body>
</html>
Al ejecutar la página html y pulsar sobre el botón de submit solicitaremos el Servlet1.
Crear un servlet con el código siguiente:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class Servlet1 extends HttpServlet{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Respuesta Servlet</title>");
out.println("</head>");
out.println("<body bgcolor='white'>");
out.println("<center><h3>Bienvenido</h3></center>");
out.println("</body>");
out.println("</html>");
}
}
En el servlet hemos sobreescrito el método doPost para responser al cliente con el objeto response
una página HTML con un mensaje de bienvenida.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Configuración de un servlet
El fichero web.xml define las asignaciones entre las rutas de URL y los servlets que controlan las
solicitudes con estas rutas. El servidor web utiliza esta configuración para identificar el servlet que
controla una solicitud concreta y ejecuta el método de clase que corresponde al método de solicitud
(por ejemplo, el método doGet() para solicitudes GET HTTP).
Para asignar una URL a un servlet, declara el servlet con el elemento , a continuación,
define una asignación desde una ruta de URL hasta una declaración de servlet con el elemento
El elemento declara el servlet, incluido un nombre utilizado para hacer referencia al servlet
por parte de otros elementos del archivo, la clase que se va a utilizar para el servlet y los
parámetros de inicialización. Puedes declarar varios servlets con la misma clase y diferentes
parámetros de inicialización. El nombre de cada servlet debe ser único en todo el descriptor de
implementación.
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>paquete1.servlet1</servlet-class>
<init-param>
<param-name>nombre</param-name>
<param-value>pepe</param-value>
</init-param>
<init-param>
<param-name>apellido</param-name>
<param-value>pogre</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>Servlet2</servlet-name>
<servlet-class>paquete2.servlet2</servlet-class>
<init-param>
<param-name>nombre</param-name>
<param-value>pepe</param-value>
</init-param>
<init-param>
<param-name>apellido</param-name>
<param-value>pogre</param-value>
</init-param>
</servlet>
El elemento especifica un patrón URL y el nombre de un servlet declarado que se
va a utilizar para las solicitudes cuya URL corresponde al patrón. El patrón URL puede utilizar un
asterisco (*) al principio o al final del patrón para indicar cero o más caracteres. (El estándar no
admite comodines en mitad de una cadena y no permite varios comodines en un patrón). El patrón
corresponde a la ruta completa de la URL, empezando con e incluyendo la barra inclinada (/),
seguida del nombre de dominio.
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/s1/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet2</servlet-name>
<url-pattern>/s2/*</url-pattern>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</servlet-mapping>
Ver Video: Primer ejemplo de Servlet, en la Unidad 2,
en el Módulo 5, en la plataforma elearning
import java.io.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;
//------------------------------------------
public void doGet (HttpServletRequest peticion, HttpServletResponse respuesta) throws
IOException, ServletException{
Gestionar(peticion, respuesta);
}
//------------------------------------------
public void doPost (HttpServletRequest peticion, HttpServletResponse respuesta) throws
IOException, ServletException{
Gestionar(peticion, respuesta);
}
//------------------------------------------
public void Gestionar (HttpServletRequest peticion, HttpServletResponse respuesta) throws
IOException, ServletException{
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
archivo = new File ("C:\\EJFundamentos\\Visitas.txt");
DecimalFormat formato = new DecimalFormat("00000");
//para dar formato decimal
if(!archivo.exists()){
escribir= new DataOutputStream (new
FileOutputStream("C:\\EJFundamentos\\Visitas.txt"));
try{
escribir.writeInt(0);
escribir.close();
}catch (IOException e){}
}else{
leer = new DataInputStream (new FileInputStream (archivo));
try{
contador= leer.readInt();
leer.close();
}catch (IOException e){}
}
escribir = new DataOutputStream (new
FileOutputStream("C:\\EJFundamentos\\Visitas.txt"));
try{
escribir.writeInt(++contador);
escribir.close();
}catch (IOException e){}
flujo.println("<HTML>");
flujo.println("<HEAD>");
flujo.println("<TITLE>RESPUESTA</TITLE>");
flujo.println("</HEAD>");
flujo.println("<BODY TEXT=#FFFFFF BGCOLOR=#000080 LINK = #FFFFFF ALINKCYAN
VLINKORANGE><CENTER>");
flujo.println("<FONT FACE=ARIAL");
String s_cont= formato.format(contador);
flujo.println("<br><h2>Estado del contador de visitas:<br><br>");
flujo.println("<table border=2 align=center width=5% height=1% cellsapcing=2
border=1 cellpadding=3>");
flujo.println("<tr align=center><td><h2>"+ s_cont+"</h2></td></tr></table>");
flujo.println("</font></center></body>");
flujo.println("</html>");
flujo.close();
}
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 3. Desarrollo de un componente
controlador
Objetivos
Desarrollar un Servlet con los métodos más interesantes.
Trabajar con el componente controlador en las peticiones de un servlet.
Introducción
Envio de datos del formulario HTML en la petición HTTP
La etiqueta FORM encierra al resto de etiquetas que pueden componer el formulario. Dispone de los
siguientes atributos:
method= especifica la forma en la que los datos del formulario son enviados. Sus valores son post y
get.
Cuando el método es get, los datos son enviados al servidor como una petición HTTP GET, añadidos
a la url especificada mediante el atributo action; por ejemplo: http://Servlet1?nombre=pepe
Los datos así remitidos tienen un doble límite. Como se envían dentro de una url, deben utilizarse
únicamente caracteres ASCII, y su longitud está limitada a la longitud de la url que el servidor
pueda manejar. La regla general es la de no utilizar el método get si esperamos recibir caracteres no
ASCII o datos de más de 100 caracteres.
Con el método post, los datos son enviados como una petición HTTP POST, en el cuerpo de la
petición. El método usual es post.
action indica el destino de los datos. Aquí es donde debe especificarse una cuenta de correo o un
programa procesador CGI.
enctype=, se usa cuando se ha especificado method=post, para determinar el sistema de
encriptación. Por defecto, si no se incluye este atributo se enviará el formulario con el tipo MIME. Si
se desea no incluir encriptación ninguna, deberá indicarse "text/plain".
Otros atributos de son accept= que permite especificar los caracteres admisibles, y target=
que permite indicar el frame donde se presentan los resultados, si los hay.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<html>
<head>
<title>PAGINA 1</title>
</head>
<body>
<form name="form1" action= "Servlet1" method="post">
Nombre:<input type="text" name="txtNombre">
<br><input type="submit" value="enviar">
</form>
</body>
</html>
Enviaremos la información del nombre de usuario con el método Post.
El Servet1 recogerá la información que le envían a través del método getParameter(nombre) del
objeto request.
Código Servlet:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Respuesta Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("Hola: "+request.getParameter("txtNombre"));
out.println("</body>");
out.println("</html>");
}
}
El fichero web.xml quedará configurado de la siguiente manera:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" _
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_2_5.xsd">
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/Servlet1</url-pattern>
</servlet-mapping>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>pagina1.html</welcome-file>
</welcome-file-list>
</web-app>
Parámetros del protocolo http
Los parámetros de petición son cadenas enviadas por el cliente al contenedor de servlets como parte
de su petición. Los parámetros están almacenados como pares de nombre-valor. Algún nombre
concreto, puede almacenar múltiples valores. Los siguientes métodos de la interfaz ServletRequest
están disponibles para acceder a los parámetros:
getParameter
getParameterNames
getParameterValues: devuelve una matriz de String que contiene todos los valores asociados al
nombre del parámetro.
getParameterMap: devuelve un java.util.Map del parámetro de la petición, que contiene nombres y
valores como un Map.
Atributos
Los atributos son objetos asociados a una petición. Los atributos se utilizan por el contenedor de
servlets para expresar información que de otra manera, no podría ser expresada por la API, o puede
servir para que un servlet le pase la información a otro (a través del RequestDispatcher). Para
trabajar con atributos se utilizan los siguientes métodos de la interfaz ServletRequest:
getAttribute
getAttributeNames
setAttribute
El nombre de un atributo sólo puede estar asociado a un valor.
Envio por GET
En el siguiente ejemplo insertaremos un hipervínculo en la página html. Al pulsar el hipervínculo
llamaremos al Servlet y le pasaremos un parámetro llamado nombre con el valor pepe.
<html>
<head>
<title>PAGINA 1</title>
</head>
<body>
<a href="Servlet1?nombre=pepe"> Pulse para llamar al Servlet1</a>
</body>
</html>
Como no hemos indicado el method por defecto es Get.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Código Servlet:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Respuesta Servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("Hola: "+request.getParameter("nombre"));
out.println("</body>");
out.println("</html>");
}
}
El fichero web.xml quedará configurado de la siguiente manera:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" _
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_2_5.xsd">
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/Servlet1</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>pagina1.html</welcome-file>
</welcome-file-list>
</web-app>
Atributos SSL
Si una petición ha sido transmitida sobre un protocolo seguro, por ejemplo HTTPS, la interfaz
ServletRequest proporciona el método isTrue. Si sí se ha utilizado este protocolo, devolverá trae.
Internacionalización
Los clientes pueden opcionalmente indicar al servidor web cuál es el lenguaje que prefieren utilizar.
Esta información es transmitida por el cliente usando la cabecera Accept-Language, además de otros
mecanismos explicados en la especificación 1.1 de HTTP. Los siguientes métodos son
proporcionados por la interfaz ServletRequest para determinar el lugar preferido por el cliente.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
getLocale
getLocales: devuelve una Enumeration de objetos Locales indicando, en orden decreciente
(empezando con el lugar preferido), los lugares que aceptará el cliente.
Codificación de la información de la petición
Actualmente, muchos navegadores no envían una codificación de caracteres cualificada con la
cabecera Content-Type, dejando claro la determinación de la codificación de caracteres para leer las
peticiones http. La codificación por defecto de una petición es la “ISO-8859-1”. Para indicar al
desarrollador que ha ocurrido un error enviando al cliente una codificación de caracteres, el
contenedor devuelve null cuando se invoca el método getCharacterEncoding.
Si el cliente no tiene establecido ninguna codificación de caracteres y la información de la petición
está codificada, puede ocurrir un error. Para remediarlo, se ha añadido un nuevo método a la
interfaz ServletRequest. Se trata del setCharacterEncoding(String enc), que se usa para establecer
la codificación de caracteres.
Class ServletOutputStream
java.lang.Object
|
+--java.io.OutputStream
|
+--javax.servlet.ServletOutputStream
public abstract class ServletOutputStream
extends java.io.OutputStream
Representa un flujo de salida (escritura) a través del cual se genera y se envía la respuesta desde el
servlet al cliente.
Constructor
protected ServletOutputStream()
Se utiliza únicamente en caso de que se cree una clase anónima interna a esta.
Excepciones
ServletException es un error de ejecución del programa que se genera cuando se produce un
error interno del servlet.
UnavailableException se genera cuando el servlet no está a disposición del cliente porque se
esté modificando, el servidor este apagado...
Al servidor le llegan muchas peticiones, estando representadas cada una de ellas por un objeto de la
interfaz ServletRequest dice que usuario, contraseña...
Después se crea un objeto Dispatcher (es el objeto que recibe todas las peticiones) redirige la
petición al servlet o al recurso que se ha pedido
Dentro del servidor el sitio web se compone de recursos todos los servlets que se están
ejecutando a la vez dentro del servidor tienen un objeto común que es la interfaz ServletContext
pasa información de un servlet a otro en ejecución.
Cada uno de los servlets individualmente tiene asociado un objeto de la interfaz ServletConfig
Con todo esto se genera la respuesta y se manda. Cada una de las respuestas constituye un objeto
de la interfaz ServletResponse. (Siempre son paginas html)
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Desarrollar un Servlet con getParameterValues
Cuando una página Html envía información con etiquetas que tienen el mismo nombre, tendremos
que recurrir a recuperar la información con el método getParameterValues.
En el siguiente ejemplo creamos tres checkbox con el mismo nombre, “so”.
<html>
<head>
<title>Formulario</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script language="javascript">
function ok(){
if (formulario.nombre.value.length==0)
{
alert("INTRODUZCA NOMBRE!");
}
else if(formulario.apellido_1.value.length==0){
alert("INTRODUZCA Primer Apellido!");
}
else if(formulario.apellido_2.value.length==0){
alert("INTRODUZCA el segundo Apellido!");
}
else if(formulario.domicilio.value.length==0){
alert("INTRODUZCA el Domicilio!");
}
else{
formulario.submit();
}}
</script>
</head>
<body>
<form name="formulario" action="Servlet1 " method="POST">
<center> <H1><B>FICHA DEL CLIENTE</B></H1>
NOMBRE<input type="text" name="nombre" value="" />
PRIMER APELLIDO<input type="text" name="apellido_1" value="" />
SEGUNDO APELLIDO<input type="text" name="apellido_2" value="" /><br>
DOMICILIO<input type="text" name="domicilio" value="" /><br>
CIUDAD<select name="cuidad"><br>
<option>León</option>
<option>Madrid</option>
<option>Sevilla</option>
</select>
<br>
VARÓN<input type="radio" name="sexo" value="varon" />
MUJER<input type="radio" name="sexo" value="mujer" /><br>
<H2>SISTEMA OPERATIVO</H2>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Windows 7<input type="checkbox" name="so" value="W7" />
<br>WINDOWS VISTA<input type="checkbox" name="so" value="vista" />
<br>MAC OS<input type="checkbox" name="so" value="mac" /><br>
<H2>COMENTARIOS</H2><textarea name="comentarios" rows="10" cols="70">
</textarea><br>
<input type="button" value="REGISTRAR" onclick="ok()" />
</center>
</form>
</body>
</html>
El servlet tendrá que recoger los checkbox seleccionados con el método getParameterValues, que
devolverá un array con los elementos que se seleccionaron.
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet1 extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse res) _
throws IOException, ServletException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
if (req.getParameter("so")!=null){
String[] op = req.getParameterValues("so");
String sb= new String();
for (int i = 0; i < op.length; i++) {
sb=sb.concat(op[i]+" ,");
}
//elimino el ultimo
int lon=sb.length();
sb=sb.substring(0, (lon-2));
out.println("<html>");
out.println("<head>");
out.println("<title>Ejemplo 2</title>");
out.println("</head>");
out.println("<body>");
out.println("<center>Sistemas operativos seleccionados:"+sb+"</center>");
out.println("</body>");
out.println("</html>");
}
}
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Laboratorio: Recogida de parámetros
Capturar Elementos Seleccionados:Checkbox
Objetivos:
Enunciado:
Realizar una página JSP que envie información sobre si misma al pulsar sobre un botón.
Cuando enviemos información, mostraremos en una etiqueta DIV los elementos
seleccionados.
Para completar la práctica, debemos dejar marcados los elementos que el usuario haya
seleccionen nuestra página.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%}%>
<%}
}%>
<tr><td><input type="submit" name="btnenviar" value="Enviar Datos"></td></tr>
</form>
</table>
<%
if (datos!=null)
{
for (int i=0;i<datos.length;i++)
{%>
<div style="background-color:fuchsia">
Elementos seleccionados:<%=datos[i]%>
</div>
<%}
}
%>
</body></html>
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 4. Desarrollo de Formularios
Dinámicos
Objetivos
Comprender el ciclo de vida de un serlet
Localizar el mecanismo de control de errores en formularios Servlet
Todos los servlet tienen el mismo ciclo de vida, analizaremos cada uno de ellos:
Inicializar un Servlet
Cuando un servidor carga un servlet, ejecuta el método init del servlet. La inicialización se completa
antes de manejar peticiones de clientes y antes de que el servlet sea destruido.
Aunque muchos servlets se ejecutan en servidores multi-thread, los servlets no tienen problemas de
concurrencia durante su inicialización. El servidor llama sólo una vez al método init al crear la
instancia del servlet, y no lo llamará de nuevo a menos que vuelva a recargar el servlet. El servidor
no puede recargar un servlet sin primero haber destruido el servlet llamando al método destroy.
Interactuar con Clientes
Después de la inicialización, el servlet puede manejar peticiones de clientes. Estas respuestas son
manejadas por la misma instancia del servlet por lo que hay que tener cuidado con acceso a
variables compartidas por posibles problemas de sincronización entre requerimientos concurrentes.
Destruir un Servlet
Los servlets se ejecutan hasta que el servidor los destruye, por cierre el servidor o bien a petición
del administrador del sistema. Cuando un servidor destruye un servlet, ejecuta el método destroy
del propio servlet. Este método sólo se ejecuta una vez y puede ser llamado cuando aún queden
respuestas en proceso por lo que hay que tener la atención de esperarlas. El servidor no ejecutará
de nuevo el servlet, hasta haberlo cargado e inicializado de nuevo.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ciclo de vida de Servlet Suspendido
El ciclo de vida de una petición se extiende de modo que la gestión de una única petición puede
englobar múltiples envíos a la cadena de filtros y al método service del servlet. Esto permite que la
gestión de una petición y la generación de una respuesta se retrasen hasta que los recursos estén
disponibles u ocurran o acaben eventos asíncronos.
El ciclo de vida de una petición empieza cuando una pareja petición/respuesta sea despachada por
primera vez. Normalmente, se completa el ciclo de vía de una petición cuando retorna el despacho y
se confirma, se lanza y se finaliza la respuesta. Sin embargo, la extensión permite que una petición
sea suspendida, tal que cuando el dispatch vuelve al contenedor, el ciclo de vida de la petición no
sea completado.
El contenedor mantiene la petición suspendida hasta que o se reanuda o expira por sobrepasar el
tiempo de espera. Entonces la petición se devuelve siendo despachada a la cadena de filtros normal
y al método service del servlet. Este ciclo se puede repetir más de una vez y la suspensión
transforma el mecanismo existente de despacho en un callback asíncrono. Para permitir que este
mecanismo funcione con los frameworks y códigos existentes, se puede usar en cualquier momento
durante el ciclo de vida de la petición y no se deshabilita por la suspensión de la petición.
Eventos del ciclo de vida de un servlet
Objeto Evento Interfase Listener y clase Event
Contexto Inicialización y javax.servlet.ServletContextListener y ServletContextEvent
Web destrucción
Atributo agregado, javax.servlet.ServletContextAttributeListener y
eliminado o remplazado ServletContextAttributeEvent
Session Creación, invalidación, javax.servlet.http.HttpSessionListener,
activación, desactivación javax.servlet.http.HttpSessionActivationListener, y
y tiempo afuera HttpSessionEvent
Atributo agregado, javax.servlet.http.HttpSessionAttributeListener y
eliminado o HttpSessionBindingEvent
reemplazado
Request Un componente Web ha javax.servlet.ServletRequestListener y ServletRequestEvent
comenzado a procesar
una petición a servlet
Atributo agregado, javax.servlet.ServletRequestAttributeListener y
eliminado o remplazado ServletRequestAttributeEvent
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Siempre suelen ser cosas relativas a la configuración del servlet.
Lo primero que tenemos que hacer es definir en el descriptor de despliegue (/WEB-INF/web.xml) del
servlet:
<servlet>
<description>Ejemplo ...bla bla bla.</description>
<display-name>P1</display-name>
<servlet-name>P1</servlet-name>
<servlet-class>Servlet1</servlet-class>
</servlet>
El servlet se define mediante la etiqueta . Dentro de esta tenemos dos etiquetas
importantes. será el nombre de referencia del servlet y será la clase
java que implementa dicho servlet.
Los parámetros del servlet también se definen dentro de la etiqueta Para ello utilizaremos
la etiqueta . Anidada a este tenemos dos etiquetas: que será el nombre del
parámetro y que será el valor que le demos al parámetro de inicio.
En nuestro ejemplo vamos a definir dos parámetros. El primero será NivelLog que almacenará el tipo
de log con el que grabaremos y NumeroPeticiones que nos pasará un indicador de limitación.
<servlet>
<init-param>
<description>Nivel de log a aplicar</description>
<param-name>NivelLog</param-name>
<param-value>DEBUG</param-value>
</init-param>
<init-param>
<description>Número de peticiones para atender</description>
<param-name>NumeroPeticiones</param-name>
<param-value>8</param-value>
</init-param>
</servlet>
Una vez que hemos definido esto en el descriptor de despliegue, tendremos que acceder a los
valores desde el servlet.
Lo más normal es acceder a esta información en el método init(). Si es que la información aplica a
todas las peticiones del servlet.
Para recuperar los parámetros tenemos que acceder a el método .getInitParameter(String
parámetro) que permite acceder al valor del parámetro pasado como argumento a dicho método.
Ejemplo de inicialización de parámetros en un proyecto con NetBeans:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Controladores de error
El descriptor de implementación nos permite personalizar lo que el servidor envía al usuario cuando
se produce un error. El servidor puede mostrar una ubicación de página alternativa cuando se trata
de enviar un código de estado HTTP concreto o cuando un servlet genera una excepción Java
concreta.
El elemento error-page contiene tanto un elemento error-code con un valor de código de error HTTP
(como por ejemplo 1500) o un elemento con el nombre de clase de la excepción
prevista (como por ejemplo java.io.IOException). También contiene un elemento que
contiene a su vez la ruta de URL del recurso que se va a mostrar cuando se produzca el error.
<error-page>
<error-code>1500</error-code>
<location>/paginasdeerror/ServletError1.jsp</location>
</error-page>
Ejemplo de gestión de errores de un proyecto completo:
<error-page>
<error-code>500</error-code>
<location>/errorNolocalizado.htm</location>
</error-page>
<error-page>
<exception-type>java.sql.SQLException</exception-type>
<location>/ServidorNoDisponible.htm</location>
</error-page>
Las primeras dos declaraciones indican una página de redirección mediante el elemento ,
esta redirección sería llevada a cabo cada vez que el "Servlet" encontrara un error HTTP 404 (Página
no Encontrada) y/o HTTP 500 (Error Interno).
La tercera declaración indica una redirección en base a un error por Clase, en este caso se está
indicando que en caso de surgir un error de tipo java.sql.SQLException se redireccione al usuario a
la página base_nodisponible.htm.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Seguridad
Una aplicación web contiene recursos que pueden ser accedidos por muchos usuarios. Esos recursos
no están protegidos en una red abierta como es Internet. Esto no es permisible para muchas
aplicaciones, que deben tener seguridad.
Aunque la garantía de calidad y los detalles de implementación pueden variar, los contenedores de
servlets tienen mecanismos e infraestructura para congregar esos requerimientos que comparten las
siguientes características:
Autenticación: permite saber si un determinado usuario tiene o no acceso a determinados recursos.
Control para el acceso a los recursos: las interacciones con los recursos están limitadas para
determinados grupos de usuarios o programas para poder así implementar integridad,
confidencialidad, o restricciones de disponibilidad.
Integridad de datos (Data Integrity): asegura que la información no ha sido modificada por un
tercero en la transmisión de los datos.
Confidencialidad o privacidad de datos (Confidentiality or Data Privacy): se asegura que los datos no
podrán ser vistos por personas que no estén autorizadas.
Seguridad declarativa
La seguridad declarativa hace referencia a la estructura de seguridad de una aplicación, en la que
están inmersos los roles, los controles de acceso, los requerimientos de autenticación, pero de una
manera externa a la aplicación. El descriptor de aplicación es el primer vehículo para la seguridad
declarativa en las aplicaciones web. Esto asegura que en tiempo de ejecución, el contenedor de
servlets usa la política de seguridad que se ha establecido para asegurar la autenticación y la
autorización.
El modelo de seguridad se aplica al contenido estático de la aplicación web y a los servlets dentro de
la aplicación que demanda el cliente. El modelo de seguridad no se aplica cuando un servlet usa el
RequestDispatcher para invocar un recurso estático o un servlet, es decir, cuando se usa el método
forward o include.
Seguridad programada
La seguridad programada se usa cuando la seguridad declarativa no es suficiente para el modelo de
seguridad de la aplicación. Este tipo de seguridad consiste en los siguientes métodos
(proporcionados por la interfaz HttpServletRequest):
getRemoteUser: devuelve una cadena con el nombre del usuario que ha hecho la petición y que se
va a autenticar.
isUserInRole: true si el usuario que ha hecho la petición pertenece al grupo o rol que se pasa en el
argumento. False en el caso contrario. El rol se debe crear en el descriptor de aplicación. Para ello se
añade un elemento como el siguiente:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
getUserPrincipal: devuelve un objeto de la clase java.security.
Principal que representa las restricciones principales de seguridad establecidas en la aplicación.
Cuando no hay ninguna restricción devuelve null.
Papeles
Como ya se ha visto, el proceso de comprobación de un usuario dentro de una aplicación se conoce
como autenticación. Por el contrario, al usuario que accede o intenta acceder se le llama agente.
Los agentes se pueden agrupar en grupos por funcionalidad que se denominan roles.
Los agentes y roles permitidos en un servidor web están siempre en un fichero de configuración. En
el Tomcat están en la carpeta conf y el fichero es Tomcat-users.xml
Ejemplo:
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="admin"/>
<role rolename="manager"/>
<role rolename="role1"/>
<role rolename="tomcat"/>
<user username="admin" password="" roles="admin,manager"/>
<user username="role1" password="tomcat" roles="role1"/>
<user username="tomcat" password="tomcat" roles="tomcat"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
</tomcat-users>
Con la etiqueta role se definen los roles y con users los usuarios individualmente. Roles es para
formar grupos de roles, separados por comas:
<roles="admin,manager"/> es igual a:
<role rolename="admin"/>
<role rolename="manager"/>
Para añadir otro usuario utilizamos la etiqueta user, indicando nombre y contraseña y si tiene roles.
Autenticación
Consiste en comprobar la seguridad de dos formas:
Mediante código
Dejando que se encargue el contenedor servlet. Ésta a su vez se divide en 4 tipos:
Básica
Basada en formularios
Con resúmenes
SSL (Con certificados de cliente)
Están ordenadas de la menos segura (básica) a la más segura (SSL)
Cuando se trabaja con la seguridad en servlet el subtipo (cualquiera de estas 4) se indica en el
descriptor de distribución
<login-config> se hace a través de este elemento que es subelemento de web-app.
Se utiliza para definir el tipo de autenticación declara en el sitio
<description>: es una breve descripción del modo de seguridad
<auth-method>: obligatorio de una única aparición. Indica el tipo de autenticación
<realm-name>: obligatorio de una única aparición. Se utiliza para establecer
un nombre utilizado por aplicaciones externas
</login-config>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Autenticación básica
Cuando se intenta acceder a un recurso protegido de la aplicación solicitar usuario y contraseña a
través de un cuadro de dialogo de sistema (no lo creamos nosotros sino que sale automáticamente).
En el caso de que el agente este autenticado en la aplicación se le muestra el recurso solicitado, en
caso contrario se le dan tres intentos para conexión trascurridos los cuales se le redirecciona a una
página de error.
Se indica en el elemento <auth-method> del login-config con la palabra BASIC ( <auth-method> BASIC).
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
El form_login_page contiene la página que se va a mostrar una vez autenticado el usuario.
El form_error_page contiene la página que se va a mostrar si se produce un error.
Estas dos páginas tenemos que crearlas nosotros.
Restricciones de seguridad
Las restricciones de seguridad son una manera declarativa de definir el nivel de protección o
seguridad de contenido web.
Una restricción de seguridad asocia la autorización (o restricción de datos) de un usuario con
operaciones HTTP dentro de la aplicación web. La restricción consta de los siguientes elementos:
Colección de recursos web.
Restricción de autorización.
La restricción de datos del usuario.
Las operaciones HTTP y los recursos web se identifican por una o más colección de recursos. Éstas
se dividen en los siguientes elementos:
Patrón URL.
Métodos HTTP.
Una restricción de seguridad establece un requisito de autenticación para permitir a la petición
acceder a determinados recursos. Un usuario debe pertenecer al menos, a uno de los roles que
están definidos en el descriptor de aplicación. Si no es así, no se permite su acceso bajo ningún
aspecto. Una restricción de seguridad se compone de los siguientes elementos:
Nombre de rol: Una restricción de datos de usuario establece como requisito, que todas las
peticiones que lleguen, lo hagan sobre una conexión protegida. La magnitud de esta protección,
viene dada por el valor de la garantía de transporte. Un transporte se dice que tiene garantía
INTEGRAL cuando sólo se asegura el transporte. La garantía CONFIDENTIAL se usa para asegurar la
confidencialidad de los datos. Por el contrario, la garantía “NONE” indica que el contenedor debe
aceptar cualquier tipo de petición, incluso las que no están protegidas.
Garantía del transporte: Si no se aplica una restricción de autenticación a una petición, el
contenedor debe aceptarla sin requerir la identificación del usuario. Si a la petición no se le aplica
una restricción de datos, el contenedor debe aceptarla siempre que reciba una conexión, aunque
esta esté sin protección.
Políticas por defecto.
Por defecto, la autenticación no es necesaria para acceder a los recursos. Sólo se hará cuando se
especifique en el descriptor de aplicación.
Las características de la conexión admitida, debe satisfacer al menos, las restricciones que fueron
establecidas. Si no es así, el contenedor la rechazará y la redireccionará a un puerto HTTPS.
Si el usuario no está autenticado, la petición será rechazada enviando el código de error 401
(SC_UNAUTHORIZED).
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Enunciado:
Sobreescribir los métodos init, destroy, post, get y service en un servlet.
1. Abrir un proyecto web y agregar un fichero Servlet.
2. Sobreescribir los métodos como se indica en el siguiente código para entender el ciclo de vida
de un servlet.
import java.sql.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
if(peticion.getMethod().equals("GET")){
doGet(peticion,respuesta);
}else if(peticion.getMethod().equals("POST")){
doPost(peticion,respuesta);
}
}
try{
out.println("<html>");
out.println("<head>");
out.println("<title> </TITLE>");
out.println("</HEAD>");
out.println("<BODY> Métodos del ciclo de vida");
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
out.println("</body>");
out.println("</html>");
out.close();
//------------------------------------------
public void doGet (HttpServletRequest peticion, HttpServletResponse respuesta) _
throws IOException, ServletException{
Gestionar(peticion, respuesta);
}
//------------------------------------------
public void doPost (HttpServletRequest peticion, HttpServletResponse respuesta) _
throws IOException, ServletException{
Gestionar(peticion, respuesta);
}
//------------------------------------------
public void Gestionar (HttpServletRequest peticion, HttpServletResponse respuesta) _
throws IOException, ServletException{
archivo = new File ("C:\\EJFundamentos\\Visitas.txt");
DecimalFormat formato = new DecimalFormat("00000");
//para dar formato decimal
if(!archivo.exists()){
escribir= new DataOutputStream _
(new FileOutputStream("C:\\EJFundamentos\\Visitas.txt"));
try{
escribir.writeInt(0);
escribir.close();
}catch (IOException e){}
}else{
leer = new DataInputStream (new FileInputStream (archivo));
try{
contador= leer.readInt();
leer.close();
}catch (IOException e){}
}
escribir = new DataOutputStream _
(new FileOutputStream("C:\\EJFundamentos\\Visitas.txt"));
try{
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
escribir.writeInt(++contador);
escribir.close();
}catch (IOException e){}
flujo.println("<HTML>");
flujo.println("<HEAD>");
flujo.println("<TITLE>RESPUESTA</TITLE>");
flujo.println("</HEAD>");
flujo.println("<BODY TEXT=#FFFFFF BGCOLOR=#000080 _
LINK = #FFFFFF ALINKCYAN VLINKORANGE><CENTER>");
flujo.println("<FONT FACE=ARIAL");
String s_cont= formato.format(contador);
flujo.println("<br><h2>Estado del contador de visitas:<br><br>");
flujo.println("<table border=2 align=center width=5% height=1% _
cellsapcing=2 border=1 cellpadding=3>");
flujo.println("<tr align=center><td><h2>"+ s_cont+"</h2></td></tr></table>");
flujo.println("</font></center></body>");
flujo.println("</html>");
flujo.close();
}
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 5 . Uso compartido de recursos de la
aplicación con el contexto servlet
Introducción
El contexto en donde los componentes Web se ejecutan es un objeto que implementa la interfase ServletContext.
Se puede recuperar el contexto Web utilizando el método getServletContext. El contexto Web proporciona
métodos para acceder a:
Parámetros de inicialización
Recursos asociados con el contexto Web
Atributos como objetos
Habilidades de registro
Un contexto está asociado a un objeto ServletContext, que está contenido en un objeto
ServletConfig. Es utilizado para compartir datos entre todos los servlets y jsps de una aplicación.
Proporciona al programador:
Un contenedor virtual para almacenar objetos a los que pueden acceder todos los servlets y jsps de
una misma aplicación web. En este sentido, se emplea para pasar datos de un servlet a otro. Es
importante resaltar que hay un contexto por cada aplicación web.
Interfaces que permiten comunicarse con el entorno de ejecución de la aplicación web, es decir, con
el contenedor web, por ejemplo, para obtener el tipo MIME de un fichero, para escribir en un fichero
log del servidor, para obtener un objeto RequestDispatcher usado para delegar en otros recursos el
procesamiento de la petición, para conocer la ruta asociada al directorio raíz de una aplicación web,
etc. Consultar la API.
el contexto de una aplicación web se obtiene mediante el método ServletContext
getServletContext() de la interface ServletConfig o mediante getServletContext () de GenericServlet.
Se obtiene un contexto vacío, todavía no contiene elementos.
Los atributos se agregan al contexto de una aplicación web mediante el método de la interface
javax.servlet.ServletContext void setAttribute(String clave, Object valor). Se asigna una clave y un
valor asociado a la misma. La clave debe ser una String y el valor un Object.
Objetivos
Describir la finalidad del contexto servlet
Trabajar con el contexto de un servlet.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Método Descripción
Java.net.URL getResource(String Devuelve un objeto de la clase java.net.URL
path) para el recurso mapeado por la ruta
proporcionada. La ruta debería empezar con
/ si no es una ruta absoluta (relativa al
documento root). Por ejemplo, si pasas una
ruta de un archivo JSP, te devolverá los
datos no procesados, en este caso, el código
JSP, cuando se lea el contenido.
java.io.InputStream Este método es un shortcut si quieres
getResourceAsStream(String path) obtener un InputStream de un recurso. Es
equivalente a
getResource(path).openStream().
Inicialización de parámetros
Los siguientes métodos de la interfaz ServletContext permiten el acceso a los parámetros de
inicialización del servlet asociados con la aplicación web especificada en el descriptor de aplicación:
getInitParameter.
getInitParameterNames.
Atributos
Un servlet puede añadir atributos al objeto de la interfaz ServletContext. Cuando se hace esto, el
atributo estará disponible para el resto de servlets que se encuentren en la misma aplicación web.
Los siguientes métodos de la interfaz ServletContext permiten este cometido:
setAttribute
getAttribute
getAttributeNames
removeAttribute
Se ha de tener en cuenta, que los atributos son locales a cada máquina virtual, por lo que si se
necesita compartir información en un entorno distribuido, la información debería almacenarse en
una sesión, en una base de datos o en un Enterprise JavaBean.
Recursos
Podemos ver la interfaz ServletContext como una ventana para la visualización del entorno de un
servlet. Un servlet puede utilizar esta interfaz para conseguir información, tal como parámetros de
inicialización para las aplicaciones web de la versión del contenedor. Esta interfaz también
proporciona métodos de utilidad para recuperar el tipo MIME de un archivo, recursos compartidos,
para logeo, y demás. Toda aplicación web tiene un único ServletContext, y es accesible en todos los
recursos activos de la aplicación. También es usado por los Sevlets para compartir datos entre ellos.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Es importante tener conocimientos sólidos de esta interfaz puesto que el examen contiene
numerosas preguntas acerca de ella.
En esta sección, estudiaremos los métodos getResource() y getResourceAsStream(). Estos métodos
son usados por los servlets para acceder a cualquier recurso sin importar dónde reside actualmente
dicho recurso. La siguiente tabla proporciona una breve descripción de estos métodos, para más
información consultar la API:
Método Descripción
java.net.URL getResource(String Devuelve un objeto de la clase java.net.URL
path) para el recurso mapeado por la ruta
proporcionada. La ruta debería empezar con
/ si no es una ruta absoluta (relativa al
documento root). Por ejemplo, si pasas una
ruta de un archivo JSP, te devolverá los
datos no procesados, en este caso, el código
JSP, cuando se lea el contenido.
java.io.InputStream Este método es un shortcut si quieres
getResourceAsStream(String path) obtener un InputStream de un recurso. Es
equivalente a
getResource(path).openStream().
Recarga
Para que la aplicación se comporte como espera el desarrollador, se debe asegurar que todos los
servlets y clases que se vayan a usar en ella, estén cargados en el ámbito de un solo cargador de
clase. Como ayuda al desarrollo, el contenedor notifica si una sesión se añade o se termina.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Interface ServletContext
public abstract interface ServletContext
Representa el contexto de ejecución del servlet dentro del servidor web. Permite comunicar y pasar
información entre diferentes servlets que corren en el mismo servidor, comunicarse con el propio
servidor web y generar ficheros con mensajes introducidos desde el servlet.
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Set;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
public void log(Exception exception, String msg);
Métodos
java.lang.Object getAttribute(java.lang.String name)
Devuelve un object que corresponde al valor del atributo cuyo nombre se
pasa como argumento. Si el atributo no existe devuelve null.
java.util.Enumeration getAttributeNames()
Devuelve un objeto enumeration donde cada elemento es un String que
corresponde al nombre del atributo del Servlet. En caso de que no haya
ninguno devolvería una enumeración vacía
ServletContext getContext(java.lang.String uripath)
Devuelve un objecto de la interfaz.
int getMajorVersion()
Devuelve un entero que corresponde a la ultima versión de la API referente
al servlet que esta soportada en el servidor web.
java.lang.String getMimeType(java.lang.String file)
Devuelve un String que indica el tipo mime del fichero que se pasa como
argumento. Si no se puede determinar devuelve null. (tipo mime la
codificación interna que lleva un fichero para que a la hora de cargarse en
una aplicación se interprete de una forma u otra)
int getMinorVersión()
Devuelve un int que corresponde a la versión mas baja del api del servlet
que soporta el servidor web
java.lang.String getRealPath(java.lang.String path)
Devuelve un String que indica la ruta completa donde se encuentra el
recurso que se pasa como cadena en el argumento.
RequestDispatcher getRequestDispatcher(java.lang.String urlpath)
Devuelve un objeto de la interfaz RequestDispatcher que corresponde al
recurso que se pasa como cadena en el argumento. Con este objeto se
puede redireccionar e incluir otros recursos que utilizasen el recurso pasado
en el argumento de la función (se utiliza para saber cuando se llama a un
servlet desde otro)
java.net.URL getResource(java.lang.String path)
Este método devuelve una URL que corresponde al recurso cuyo path se
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
pasa como cadena en el argumento o null en el caso de que no exista.
A partir de tener la URL tenemos el método openConnection para abrir una
conexión desde el recurso.
java.io.InputStream getResourceAsStream(java.lang.String path)
La diferencia con el anterior es que este método devuelve un objeto
InputStream que corresponde o esta asociado al recurso cuyo path se pasa
como cadena en el argumento. Si no existe el recurso devuelve null. En
caso contrario, si devuelve el objeto inputStream puedes utilizar el flujo de
lectura para leer desde el servlet el contenido del recurso
java.lang.String getServerInfo()
Devuelve un String que indica el servidor web y la versión en la cual esta
corriendo el servlet
void log(java.lang.String msg)
Escribe en un fichero asociado al servlet la cadena que se pasa como
argumento
void log(java.lang.String message, java.lang.Throwable throwable)
El primer argumento es lo mismo que en el anterior método y el segundo
argumento es un objeto de la clase thowable o derivada suya que se ha de
generar al escribir dicho mensaje en el fichero.
Se utiliza siempre que se utilice propagación o captura de excepciones (try
catch finally)
Por defecto cualquier tipo de recurso que se cree desde un servlet se crea
desde la raiz
void removeAttribute(java.lang.String name)
Para eliminar del contexto del servlet el recurso cuyo nombre se pasa como
argumento
void setAttribute(java.lang.String name, java.lang.Object object)
Para establecer dentro del contexto del servlet un atributo cuyo nombre se
pasa como cadena en el primer argumento y cuyo valor se pasa como
object en el segundo argumento
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Enumeration attributes = servletContext.getAttributeNames();
while (attributes.hasMoreElements()) {
String attribute = (String) attributes.nextElement();
System.out.println("Attribute name : " + attribute);
System.out.println("Attribute value : " +
servletContext.getAttribute(attribute));
}
System.out.println("Major version : " + servletContext.getMajorVersion());
System.out.println("Minor version : " + servletContext.getMinorVersion());
System.out.println("Server info : " + servletContext.getServerInfo());
}
Eventos ServletContext
En la siguiente imagen podemos apreciar todos los eventos que se producen en el ciclo de vida de
un Servlet.
Interface ServletContextListener
Un objeto de esta interface recibe los eventos de creación y destrucción del contexto servlet. El
contenedor crea el contexto del servlet como paso previo a servir cualquier contenido de la
aplicación.
La clase que implemente esta interface debe estar definida en el archivo web.xml, a través del
elemento
Métodos
void contextDestroyed(ServletContextEvent sce)
Notifica que el contexto del servlet está a punto de ser cerrado.
void contextInitialized(ServletContextEvent sce)
Notifica que el uso del recurso web está listo para ser solicitado.
Actividades
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
Introducción
La programación por capas es un estilo de programación en la que el objetivo primordial es la
separación de la lógica de negocios de la lógica de diseño, un ejemplo básico de esto es separar la
capa de datos de la capa de presentación al usuario. Es la alternativa más radiacal al modelo
centralizado que consiste en un conjunto de terminales brutas que se conectan a un Mainframe
todas la operaciones se realizan en ésta, mientras que las terminales solo se emplean como
interface.
Entre los motivos por los cuales se recurre a la arquitectura multicapas se cuentan los siguientes:
• Aislamiento de la lógica de aplicaciones en componentes independientes susceptibles de
reutilizarse después en otros sistemas; distribución de las capas en varios nodos físicos de
cómputo y en varios procesos. Esto puede mejorar el desempeño, la coordinación y el
compartir la información en un sistema de cliente-servidor.
• Asignación de los diseñadores para que construyan determinadas capas; por ejemplo, un
equipo que trabaje exclusivamente en la capa de presentación. Y así se brinda soporte a los
conocimientos especializados en las habilidades de desarrollo y también a la capacidad de
realizar actividades simultáneas en equipo.
En toda arquitectura de capa los elementos agrupados en una misma capa pueden comunicarse
entre sí; pero existen variantes en cuanto a las comunicaciones permitidas entre elementos de
capas diferentes:
Arquitectura top-down de capas: Los elementos de una capa i+1 pueden enviar solicitudes de
servicio a elementos de la capa inferior i. Típicamente se produce una cascada de solicitudes, es
decir para satisfacer una solicitud a una capa i+2, ésta requiere enviar varias solicitudes a la capa
i+1; cada una de estas solicitudes a la capa i+1 genera a su vez un conjunto de solicitudes a la capa
i y así sucesivamente. Una arquitectura top-down es laxa (o no estricta) si los elementos de una
capa i+1 pueden enviar solicitudes de servicio directamente a un elemento de cualquiera de las i
capas inferiores.
Arquitectura bottom-up de capas: Cada elemento de una capa i puede notificar a elementos de
la capa superior i+1 de que ha ocurrido algún evento de interés (ej. manejadores de dispositivos).
La capa i+1 puede juntar varios eventos antes de notificar a su vez an elemento de la capa i+2. Una
arquitectura bottom-up tambien puede ser no estricta si el elemento de la capa i puede notificar a
cualquier elemento de cualquier capa superior a la capa i.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Al implementar una arquitectura top-down de capas, se deben tomar en cuenta los siguientes
factores:
¿Cuál es el criterio de abstracción para agrupar servicios/clases en una capa?
Mencionar el criterio Presentación-Dominio de Aplicación-Repositorio de Sistemas de Información.
Determinar el número de capas En términos simplistas, a más capas más flexibilidad pero menor
desempeño.
Típicamente las capas más internas ofrecen menos servicios. Esto ayuda la reutilización de capas.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
• Arquitectura de cuatro capas.
Estas etapas suelen seguirse por la mayoría de los métodos de diseño OO existentes.
De hecho, para los sistemas orientados a objetos se suelen definir según el siguiente formato en
pirámide.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
La capa del subsistema. Contiene una representación de cada uno de los subsistemas que le
permiten al software conseguir los requisitos definidos por el cliente e implementar la
infraestructura técnica que los soporta.
La capa de clases y Objetos. Contiene las jerarquías de clase que permiten crear el sistema
usando generalizaciones y especializaciones mejor definidas. Esta capa también contiene
representaciones de diseño para cada objeto.
La capa de mensajes. Contiene los detalles que le permiten a cada objeto comunicarse con sus
colaboradores. Esta capa establece las interfaces externas e internas para el sistema.
Al igual que el diseño de software convencional, el DOO aplica diseño de datos (cuando se
representan atributos), diseño de interfaces (cuando se presenta el intercambio de mensajes) y
diseño procedimental (en el diseño de operaciones), no obstante el diseño arquitectónico es
diferente. La arquitectura de diseño OO se centra más en las colaboraciones entre los objetos que
con el flujo de control de datos. De esta manera las capas de la pirámide se renombran para reflejar
de forma más exacta la naturaleza del DOO. La siguiente figura muestra ahora la correspondencia
entre el AOO con las correspondientes capas de la pirámide de diseño OO.
Algunos criterios nos permiten juzgar la capacidad que posee un método de diseño en poder lograr
ciertos elementos importantes tales como la modularidad:
Composición. Grado con el cual un método de diseño asegura que los componentes de un
programa (módulos), una vez diseñados y construidos, pueden reusarse para crear otros sistemas.
Estos criterios y principios de diseño pueden aplicarse a cualquier método de diseño, incluyendo el
antiguo diseño estructurado. No obstante, el método de diseño orientado a objetos logra cada uno
de los principios de manera más eficiente que otros enfoques y el resultado final es una arquitectura
modular que permite cumplir con todos los principios de modularidad de una manera más eficiente.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Modelo Tres Capas
En una arquitectura de tres niveles, los términos "capas" y "niveles" no significan lo mismo ni son
similares. El término "capa" hace referencia a la forma como una solución es segmentada desde el
punto de vista lógico:
Presentación/ Lógica de Negocio/ Datos.
En cambio, el término "nivel", corresponde a la forma en que las capas lógicas se encuentran
distribuidas de forma física. Por ejemplo:
Una solución de tres capas (presentación, lógica, datos) que residen en un solo ordenador
(Presentación+lógica+datos). Se dice, que la arquitectura de la solución es de tres capas y un nivel.
Una solución de tres capas (presentación, lógica, datos) que residen en dos ordenadores
(presentación+lógica, lógica+datos). Se dice que la arquitectura de la solución es de tres capas y
dos niveles.
Una solución de tres capas (presentación, lógica, datos) que residen en tres ordenadores
(presentación, lógica, datos). La arquitectura que la define es: solución de tres capas y tres niveles.
Es el sucesor de la arquitectura de dos capas, ésta implementa una ó n capas adicionales las cuales
se encargan de encapsular las reglas del negocio asociadas con el sistema y las separa de la
presentación y del código de la D.B.
El modelo de 3 capas es una forma lógica de agrupar los componentes que creamos. Está basado en
el concepto de que todos los niveles de la aplicación, son una colección de componentes que se
proporcionan servicios entre sí o a otros niveles adyacentes. La única comunicación que no está
permitida es la de Frond-End con Back-End.
Los servicios se forman de componentes: El modelo de 3 capas está destinado a ayudarnos a
construir componentes físicos a partir de los niveles lógicos. Así que podemos empezar tomando
decisiones sobre qué parte lógica de la aplicación vamos a encapsular en cada uno de nuestros
componentes de igual modo que encapsulamos los componentes en varios niveles.
Un nivel está conformado por varios componentes, por tanto puede suplir varios servicios.
Niveles del modelo:
Nivel de Usuario: es la que ve el usuario, presenta el sistema al usuario, le comunica la
información y captura la información del usuario dando un mínimo de proceso (realiza un filtrado
previo para comprobar que no hay errores de formato). Esta capa se comunica únicamente con la
capa de negocio. Los componentes del nivel de usuario, proporcionan la interfaz visual que los
clientes utilizarán para ver la información y los datos. En este nivel, los componentes son
responsables de solicitar y recibir servicios de otros componentes del mismo nivel o del nivel de
servicios de negocio.Es muy importante destacar que, a pesar de que las funciones del negocio
residen en otro nivel, para el usuario es transparente la forma de operar.
Nivel de Negocios: es donde residen los programas que se ejecutan, recibiendo las peticiones del
usuario y enviando las respuestas tras el proceso. Se denomina capa de negocio (e incluso de lógica
del negocio) pues es aquí donde se establecen todas las reglas que deben cumplirse. Esta capa se
comunica con la capa de presentación, para recibir las solicitudes y presentar los resultados, y con la
capa de datos, para solicitar al gestor de base de datos para almacenar o recuperar datos de él.
Como los servicios de usuario no pueden contactar directamente con el nivel de servicios de datos,
es responsabilidad de los servicios de negocio hacer de puente entre estos. Los objetos de negocio
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
proporcionan servicios que completan las tareas de negocio tales como verificar los datos enviados
por el cliente. Antes de llevar a cabo una transacción en la D.B. Los componentes de los servicios de
negocio también nos sirven para evitar que el usuario tenga acceso directo a la base de datos, lo
cual proporciona mayor seguridad en la integridad de ésta.
Nivel de Datos: es donde residen los datos. Está formada por uno o más gestor de bases de datos
que realiza todo el almacenamiento de datos, reciben solicitudes de almacenamiento o recuperación
de información desde la capa de negocio. El nivel de datos se encarga de las típicas tareas que
realizamos con los datos: Inserción, modificación, consulta y borrado. La clave del nivel de datos es
que los papeles de negocio no son implementados aquí. Aunque un componente de servicio de
datos es responsable de la gestión de las peticiones realizadas por un objeto de negocio. Un nivel de
servicios de datos apropiadamente implementado, debería permitir cambiar su localización sin
afectar a los servicios proporcionados por los componentes de negocio.
Ventajas:
Los componentes de la aplicación pueden ser desarrollados en cualquier lenguaje.
Los componentes son independientes.
Los componentes pueden estar distribuidos en múltiples servidores.
La D.B. es solo vista desde la capa intermedia y no desde todos los clientes.
Los drivers del D.B. No tienen que estar en los clientes.
Mejora la administración de los recursos cuando existe mucha concurrencia.
Permite reutilización real del software y construir aplicaciones escalables.
La ventaja principal de este estilo, es que el desarrollo se puede llevar a cabo en varios niveles y en
caso de algún cambio sólo se ataca al nivel requerido sin tener que revisar entre código mezclado.
Un buen ejemplo de este método de programación seria: Modelo de interconexión de sistemas
abiertos
Además permite distribuir el trabajo de creación de una aplicación por niveles, de este modo, cada
grupo de trabajo está totalmente abstraído del resto de niveles, simplemente es necesario conocer
la API que existe entre niveles.
En el diseño de sistemas informáticos actual se suele usar las arquitecturas multinivel o
Programación por capas. En dichas arquitecturas a cada nivel se le confía una misión simple, lo que
permite el diseño de arquitecturas escalables (que pueden ampliarse con facilidad en caso de que las
necesidades aumenten).
El diseño más en boga actualmente es el diseño en tres niveles (o en tres capas).
Todas estas capas pueden residir en un único ordenador (no sería lo normal), si bien lo más usual es
que haya una multitud de ordenadores donde reside la capa de presentación (son los clientes de la
arquitectura cliente/servidor). Las capas de negocio y de datos pueden residir en el mismo
ordenador, y si el crecimiento de las necesidades lo aconseja se pueden separar en dos o mas
ordenadores. Así, si el tamaño o complejidad de la base de datos aumenta, se puede separar en
varios ordenadores los cuales recibirán las peticiones del ordenador en que resida la capa de
negocio.
Si por el contrario fuese la complejidad en la capa de negocio lo que obligase a la separación, esta
capa de negocio podría residir en uno o mas ordenadores que realizarían solicitudes a una única
base de datos. En sistemas muy complejos se llega a tener una serie de ordenadores sobre los
cuales corre la capa de datos, y otra serie de ordenadores sobre los cuales corre la base de datos.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Por estas razones, existe una fuerte y bien avanzada tendencia a adoptar una arquitectura de tres
capas.
Diseño de componentes
Para que una solución sea considerada un patrón debe poseer ciertos componentes fundamentales:
• Nombre del patrón. Permite describir en pocas palabras un problema de diseño junto con sus
soluciones y consecuencias.
• Problema (o fuerzas no balanceadas). Indica cuándo aplicar el patrón. En algunas
oportunidades el problema incluye una serie de condiciones que deben darse para aplicar el
patrón. Muestra la verdadera esencia del problema. Este enunciado se completa con un
conjunto de fuerzas, término que se utiliza para indicar cualquier aspecto del problema que
deba ser considerado a la hora de resolverlo, entre ellos:
- Requerimientos a cumplir por la solución.
- Restricciones a considerar.
- Propiedades deseables que la solución debe tener.
Son las fuerzas las que ayudan a entender el problema dado que lo exponen desde distintos puntos
de vista.
• Solución. No describe una solución o implementación en concreto, sino que un patrón es más
bien como una plantilla que puede aplicarse en diversas situaciones diferentes. El patrón
brinda una descripción abstracta de un problema de diseño y cómo lo resuelve una
determinada disposición de objetos. Que la solución sea aplicable a diversas situaciones
denota el carácter “recurrente” de los patrones.
• Consecuencias. Resultados en términos de ventajas e inconvenientes.
Actividades
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 7. Desarrollo de Aplicaciones Eeb con
Struts
Objetivos
Introducirse en el patrón MVC.
Creación de proyectos basados en el patrón MVC con Struts.
Desarrollar ejemplos con el Framework de Struts.
Introducción
Struts se basa en en el patrón de diseño MVC, en el patrón MVC el flujo de la aplicación está dirigido
por un Controlador central. El Controlador delega solicitudes HTTP a un manejador. Los
manejadores están unidos a un Modelo, y cada manejador actúa como un adaptador entre la
solicitud y el Modelo. En los desarrollos web el Modelo representará la lógica de negocio de la
aplicación. Luego el control normalmente es devuelto a través del Controlador hacia la Vista
apropiada. El reenvío puede determinarse consultando los conjuntos de mapeos, normalmente
cargados desde una base de datos o un fichero de configuración. Esto proporciona un acoplamiento
cercano entre la Vista y el Modelo, que puede hacer las aplicaciones significativamente más fáciles
de crear y de mantener.
Struts es un framework que implementa el patrón de arquitectura MVC en Java
Un framework es la extensión de un lenguaje mediante una o más jerarquías de clases que
implementan una funcionalidad y que pueden ser extendidas. El framework puede involucrar
TagLibraries.
El patrón de arquitectura MVC (Model-View-Controller) es un patrón que define la organización
independiente del Model (Objetos de Negocio), la View (interfaz con el usuario u otro sistema) y el
Controller.
Las aplicaciones Struts tiene tres componentes principales: un servlet controlador, que está
proporcionado por el propio Struts, páginas JSP (la "vista"), y la lógica de negocio de la aplicación (o
el "modelo"). Veamos como esto funciona todo junto.
El servlet controlador de Struts une solicitudes HTTP con otros objetos desarrollados por el
programador. Una vez inizializado, el controlador analiza un fichero de configuración de recursos, La
configuración de recursos define (entre otras cosas) los
org.apache.struts.action.ActionMapping para una aplicación. El controlador usa estos
mapeos para convertir las solicitudes HTTP en acciones de aplicación.
En el ActionMapping debemos inlcuir un path solicitado, el tipo objeto (subclase de Action) para
actuar sobre la solicitud, y otras propiedades según se necesite.
El objeto Action puede manejar la solicitud y responder al cliente, o indicar a que control debería
ser reenviado.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Marco de trabajo MVC
Componentes del modelo
Corresponden a la lógica del negocio con el cual se comunica la aplicación web. Usualmente el
modelo comprende accesos a Bases de Datos o sistemas que funcionan independientemente de la
aplicación web.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Desarrollar una clase action de Struts
La clase Action define dos métodos que podrían ser ejecutados dependiendo de nuestro entorno
servlet:
public ActionForward perform(ActionMapping mapping,
ActionForm form,
ServletRequest request,
ServletResponse response)
throws IOException, ServletException;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
en la lógica de nuestro método perform(), y guardalas en el fichero de log de la aplicación (junto con
el seguimiento de pila correspondiente) llamando a:
servlet.log("Error message text", exception);
Como regla general, asignar recursos y mantenerlos a través de las solicitudes del mismo usuario
(en la misma sesión de usuario) puede causar problemas de escalabilidad. Deberíamos pensar en
liberar esos recursos (como las conexions a una base de datos) antes de reenviar el control al
componente de la Vista apropiado -- incluso si un método del bean que hemos llamado lanza una
excepción.
Además, queremos protegernos contra clases Action que son demasiado largas. La forma más fácil
de hacer que esto suceda es embeber la lógica funcional en la propia clase Action, en vez codificarla
en beans de lógica de negocio independientes. Además de hacer la propia clase Action dura de
entender y de mantener, esta aproximación también hace díficil re-utilizar el código de la lógica de
negocio, porque está embebido dentro de un componente (la clase Action) que está concebido para
ser ejecutado en un entorno de aplicación Web.
Una Action puede dividirse en varios métodos locales, mientras que todas las propiedades
necesarias sean pasadas en las firmas de métodos. La JVM maneja dichas propiedades usando la
pila, y por eso son seguras ante los threads.
La aplicación de ejemplo incluida con Struts no cumple este principio, porque la propia lógica de
negocio está embebida dentro de las clases Action. Esto debería considerarse un bug en el diseño de
la aplicación de ejemplo, en vez de una característica intrínseca de la arquitectura , o una
aproximación a emular.
ActionMapping
Para poder operar satisfactoriamente, el servlet controlador Struts necesita conocer varias cosas
sobre como se debería mapear toda URI solicitada a una clase Action apropiada. El conocimiento
requerido ha sido encapsulado en un interface Java, llamado ActionMapping, estas son las
propiedades más importantes:
type - nombre totalmente cualificado de la clase Java que implementa la clase Action usada
por este mapeo.
name - El nombre del bean de formulario definido en el fichero de configuración que usará
este action.
path - El path de la URI solicitada que corresponden con la selección de este mapeo.
unknown - Seleccionado a true si este action debería ser configurado como por defecto para
esta aplicación, para manejar todas las solicitudes no manejadas por otros action. Sólo un
Action puede estar definido como por defecto dentro de una sóla aplicación.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
validate - Seleccionado a true si se debería llamar al método validate() de la action asociada
con este mapeo.
forward - El path de la URI solicitada a la que se pasa el control cuando se ha invocado su
mapeo. Esto es una alternativa a declarar una propiedad type.
Esta sección contiene nuestras definiciones de beans. Usamos un elemento por cada
bean de formulario, que tiene los siguientes atributos importantes:
name: Un identificador único para este bean, que será usado para referenciarlo en los
correspondientes mapeos de acciones. Normalmente, es también el nombre del atributo de solicitud
o sesión bajo el que se almacena este bean de formulario.
type: El nombre totalmente cualificado de la clase Java de nuestro bean de formulario.
Esta sección contiene nuestras definiciones de acciones. Usamos un elemento por cada una
de nuestras acciones que queramos definir. Cada elemento action requiere que se definan los
siguientes atributos:
path: El path a la clase action en relación al contexto de la aplicación.
type: El nombre totalmente cualificado de la clase Java de nuestra clase Action.
name: El nombre de nuestro elemento para usar con esta action.
El fichero struts-config.xml de la aplicación de ejemplo incluye las siguientes entradas de mapeo
para la función "log on", que se usará para ilustrar los requerimientos. Podemos apreciar que las
entradas para otras acciones se han dejado fuera:
<struts-config>
<form-beans>
<form-bean
name="FormularioLogin"
type="org.apache.struts.example.FormularioLogin" />
</form-beans>
<global-forwards
type="org.apache.struts.action.ActionForward" />
<forward name="login" path="/login.jsp"
redirect="false" />
</global-forwards>
<action-mappings>
<action
path="/logon"
type="org.apache.struts.example.ActionLogin"
name="FormularioLogin"
scope="request"
input="/login.jsp"
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
unknown="false"
validate="true" />
</action-mappings>
</struts-config>
Primero se define el bean formulario, Un bean básico de la clase
"org.apache.struts.example.FormularioLogin" es mapeado al nombre lógico "FormularioLogin". Este
nombre se usa como un nombre de atributo de sesión o solicitud para el bean de formulario.
La sección "global-forwards" se usa para crear mapeos de nombres lógicos para páginas JSP usadas
comunmente. Cada uno de estos reenvíos está disponible a través de una llamada a nuestro
ejemplar de mapeo de action, por ejemplo actionMappingInstace.findForward("envio").
Como podemos ver, este mapeo corresponde con el path /logon (realmente, porque la aplicación de
ejemplo usa mapeo de extensión, la URI que especificamos en una página JSP terminaría en
/logon.do). Cuando se recibe una solicitud que corresponde con el path, se crea un ejemplar de
ActionLogin (sólo la primera vez). El Servlet controlador buscará un bean de ámbito de sesión bajo
la clave FormularioLogin, creando y guardando un bean de la clase especificada si es necesario.
Opcionales pero muy útiles son los elementos localizados en "forward". En la aplicación de ejemplo,
muchas acciones incluyen un reenvio local "success" y/o "failure" como parte de un mapeo de
Action.
<action path="/editSubscription"
type="org.apache.struts.example.Actionrecogida"
name="RecogidaForm"
scope="request"
validate="false">
<forward name="failure" path="/Menu.jsp"/>
<forward name="success" path="/Recogida.jsp"/>
</action>
Usando estas dos propiedades extras, las clases Action de la aplicación de ejemplo son casi
totalmente independientes de los nombres reales de las páginas JSP que son usadas por los
diseñadores, Las páginas, pueden renombrarse (por ejemplo) durante un rediseño, con un mínimo
impacto en las propias clases Action. Si los nombres de las páginas JSP "next" estuvieran codificados
dentro de las clases Action, todas estas clases tendrían que ser modificadas. Por supuesto, podemos
definir cualquier propiedad de reenvío local que tenga sentido para nuestra aplicación.
Una sección más de buen uso es la sección que especifica las fuentes de datos que
puede usar nuestra aplicación. Aquí podemos ver cómo especificar una fuente de datos para nuestra
aplicación dentro de struts-config.xml:
<struts-config>
<data-sources>
<data-source
autoCommit="false"
description="Ejemplo de conexión"
driverClass="org.postgresql.Driver"
maxCount="4"
minCount="2"
password="passwordeconexion"
url="jdbc:postgresql://localhost/BDEjemplos"
user="nombreusuario"/>
</data-sources>
</struts-config>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En este ejercicio desarrollaremos un ejemplo web donde utilicemos la clase action y el método
Action Forward.
Cargaremos en la página Visitas.jsp en un combo la información devuelta de un HashTable.
Al seleccionar un elemento el Combo y rellenar las observaciones realizaremos un submit que nos
enviará a resultadocorrecto.jsp.
Visitas.jsp
Resultadocorrecto.jsp
VISTA: Visitas.jsp
<html>
<head>
<title></title>
</head>
<body>
<center>
<h2></h2>
<hr width='60%'>
<html:form action='/InsertaVisistas'>
<table border="0">
<tr>
<td>Pais</td><td>
<html:select property="pais" >
<html:options collection="tablapaises" property="key" labelProperty="value" />
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</html:select>
</td>
</tr>
<tr>
<td>
Observaciones</td><td> <html:textarea property="observaciones" cols="50" rows="3" />
</td><td></td>
</tr>
<tr><td> <html:submit value="Enviar"/></td> </tr>
</table>
</html:form>
<br/>
</center>
</body>
</html>
VISTA: resultadocorrecto.jsp
<%@page contentType="text/html"%>
<html>
<head><title>JSP Page</title></head>
<body>
</body>
</html>
CONTROLADOR: InsertaVisitasAction
package webstruts;
import org.apache.struts.action.*;
import javax.servlet.http.*;
import java.util.*;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
// redirigimos a la presentación
retValue = actionMapping.findForward("correcto");
}
catch(Exception e) // en caso de problemas retornar a la página origen
{
// recuperamos acceso al JSP de origen
retValue = actionMapping.getInputForward();
/*
* Los métodos destroy e init son obligatorios al implementar el interfaz PlugIn
*/
public void destroy() {
}
// aqui hay que poner el código que nos proporcione los datos de la base de datos
vPaises.put("1","España");
vPaises.put("2","Francia");
vPaises.put("3","Inglaterra");
vPaises.put("4","Italia");
<form-beans>
<form-bean
name="VisitasForm"
type="org.apache.struts.action.DynaActionForm">
<form-property name="pais" type="java.lang.Integer"/>
<form-property name="observaciones" type="java.lang.String"/>
</form-bean>
</form-beans>
<global-exceptions>
</global-exceptions>
<global-forwards>
<forward name="correcto" path="/resultadocorrecto.jsp"/>
</global-forwards>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<action-mappings>
<action path="/InsertaVisistas"
type="webstruts.InsertaVisitasAction"
name="VisitasForm"
scope="request"
validate="true"
input="/Visitas.jsp"/>
</action-mappings>
<controller processorClass="org.apache.struts.tiles.TilesRequestProcessor"/>
<message-resources parameter="com/myapp/struts/ApplicationResource"/>
<plug-in className="org.apache.struts.tiles.TilesPlugin" >
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
</struts-config>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
TiendaStruts.jsp
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<html>
<body bgcolor="Blue">
<form>
<div style="left: 210px; top: 10px; font-size: 24px;
font-weight: bold; position: absolute">
<bean:message key="literal.bienvenida" />
</div>
<div style="left: 250px; top: 40px; font-size: 12px; position: absolute">
*<bean:message key="literal.mensajeEnvios" />
</div>
<form>
</body>
</html>
Applicationresource.properties
literal.bienvenida=Bienvenido a la tienda oficial
literal.mensajeEnvios=Selecciona si tu envío es dentro de España o Internacional
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 8. Desarrollo de Aplicaciones Web
con Administración de Sesiones
Objetivos
Realizar desarrollos web Accediendo a una sesión y Asociando objetos con una sesión.
Comprender la importancia de las Cookies en el desarrollo de una aplicación web.
Introducción
En muchos desarrollos las aplicaciones necesitan que una serie de solicitudes de un cliente sean
asociadas con otro. Por ejemplo, una aplicación de compra de productos guarda el estado de un
carrito de compras de un usuario a través de las solicitudes. Las aplicaciones basadas en Web son
responsables por mantener este estado, llamado sesión, ya que HTTP no tiene estado. Para soportar
las aplicaciones que necesitan mantener el estado, la tecnología Servlet de Java proporciona una API
para manejo de sesiones y permite varios mecanismos para implementar sesiones.
El API de los servlets nos da un modelo para guardar información sobre una sesión. Una sesión
consiste en todas las peticiones (request) hechas durante una invocación desde un navegador. En
otras palabras, una sesión comienza cuando se abre el navegador y termina cuando este se cierra.
El primer problema con el que nos encontramos es identificar a cada cliente que se conecta. Esto se
soluciona asignando un identificador a cada cliente cada vez que este hace una petición a través de
http. Se podría pensar como identificador en la dirección IP de cada navegador, pero esto no es
posible porque puede haber varios clientes usando el mismo navegador, y por tanto, con la misma
dirección IP. Lo que usaremos son las llamadas cookies o una técnica conocida como la reescritura
del URL.
La clase HttpSession:
Métodos de esta clase:
getCreationTime(): Devuelve el tiempo en que la sesión fue creada.
getId(): Devuelve el identificador de la sesión.
getLastAccessedTime(): Devuelve la última vez que el cliente hizo una petición para esta
sesión.
getMaxInactiveInterval(): Devuelve la máxima cantidad de tiempo en el que la sesión se
mantiene en el motor del servlet.
getValue(String): Devuelve el valor del objeto asociado al campo que se le pasa por
parámetro.
getValueNames(): Devuelve un array de los datos de la sesión.
invalidate(): invalida la sesión y la borra del contexto de la sesión.
isNew(): Devuelve true si el contexto ha sido creado por el Server pero no ha sido usado por
el cliente.
putValue(String, Object): Pone el dato objeto en el campo de nombre String.
removeValue(String): Borra el campo del array de datos de la sesión.
setMaxInactiveInterval(int): pone un tiempo límite que una sesión puede estar inactiva antes
de que el motor de servlets la elimine.
Hay tres aspectos del manejo de datos que deben de estar muy claros: el intercambio de sesiones,
la relocalización de sesiones y la persistencia de las sesiones.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Intercambio de sesiones (session swapping): Todos los servidores de servelts tienen una cantidad
limitada de recursos para la información de la sesión. En un esfuerzo por mantener el consumo de
estos recursos bajo control, la mayoría de los servidores de servlet tendrán un número máximo de
sesiones concurrentes en un mismo tiempo. Del mismo modo, tendremos un tiempo máximo de
espera, de forma que cuando una sesión permanece inactiva durante demasiado tiempo dentro de
un servidor, esa sesión será sustituída por otra. Esto sólo se podrá hacer si todos los objetos (datos)
de la sesión son serializables (implementan la interfaz java.io.Serializable). Si la sesión no es
serializable deberemos tenerla en memoria hasta que salga por sí sola.
Relocalización de las sesiones (session relocation): No hay ningún convenio que diga que un servlet
requerido sea servido por la misma JVM (Java Virtual Machine) o ni siquiera por el mismo servidor
físico. Un servidor debe de enviar el servlet lo más rápido posible. Por eso, para trabajar con datos
almacenados dentro de una sesión, el objeto sesión debe de ser relocalizable. De nuevo, esto
conlleva que los datos (objetos) almacenados en la sesión deben de ser serializables. Si los datos de
la sesión son serializables será fácil moverlos de una JVM a otra.
Persistencia de las sesiones (session persistence): Los servidores WEB deben de estar activados 24
horas al día, 7 días a la semana. Sin embargo, de vez en cuando es necesario tumbar los servidores
para su mantenimiento. De nuevo, la serialización nos va a salvar el día. El servidor de servlets
serializará todas las sesiones y las volcará en un disco auxiliar. Cuando la limpieza del servidor esté
completada, se recuperarán las sesiones sin que el usuario note el cambio.
El protocolo HTTP no permite almacenar estados. Para que una aplicación web sea efectiva, es
necesario que las peticiones de un cliente particular, sean asociadas con otras. Existen muchas
estrategias para el seguimiento de sesiones, han evolucionado con el tiempo, pero son difíciles o
problemáticas si se usan directamente. Esta especificación define una la interfaz HttpSession para
este cometido.
Mecanismos
Cookies. Podemos usar cookies HTTP para almacenar información sobre una sesión de compra, y
cada conexión subsecuente puede buscar la sesión actual y luego extraer la información sobre esa
sesión desde una localización en la máquina del servidor. Esta es una excelente alternativa, y es la
aproximación más ampliamente utilizada. Sin embargo, aunque los servlets tienen un Interface de
alto nivel para usar cookies, existen unos tediosos detalles que necesitan ser controlados:
- Extraer el cookie que almacena el identificador de sesión desde los otros cookies (puede
haber muchos, después de todo),
- Seleccionar un tiempo de expiración apropiado para el cookie (las sesiones interrumpidas
durante 24 horas probablemente deberían ser reseteadas), y
- Asociar la información en el servidor con el identificador de sesión (podría haber demasiada
información que se almacena en el cookie, pero los datos sensibles como los números de las
tarjetas de crédito nunca deben ir en cookies).
Reescribir la URL. Podemos añadir alguna información extra al final de cada URL que identifique la
sesión, y el servidor puede asociar ese identificador de sesión con los datos que ha almacenado
sobre la sesión. Esta también es una excelente solución, e incluso tiene la ventaja que funciona con
navegadores que no soportan cookies o cuando el usuario las ha desactivado. Sin embargo, tiene
casi los mismos problemas que los cookies, a saber, que los programas del lado del servidor tienen
mucho proceso que hacer, pero tedioso. Además tenemos que ser muy cuidadosos con que cada
URL que le devolvamos al usuario tiene añadida la información extra. Y si el usuario deja la sesión y
vuelve mediante un bookmark o un enlace, la información de sesión puede perderse.
Campos de formulario ocultos. Los formularios HTML tienen una entrada que se parece a esto:
Esto significa que, cuando el formulario se envíe, el nombre y el valor especificado se incluirán en
los datos GET o POST. Esto puede usarse para almacenar información sobre la sesión. Sin embargo,
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
tiene la mayor desventaja en que sólo funciona si cada página se genera dinámicamente, ya que el
punto negro es que cada sesión tiene un único identificador.
Los servlets proporcionan una solución técnica. Al API HttpSession. Este es un interface de alto nivel
construido sobre las cookies y la reescritura de URL. De hecho, muchos servidores, usan cookies si
el navegador las soporta, pero automáticamente se convierten a reescritura de URL cuando las
cookies no son soportadas o están desactivadas. Pero el autor de servlets no necesita molestarse
con muchos detalles, no tiene que manipular explícitamente las cookies o la información añadida a
la URL, y se les da automáticamente un lugar conveniente para almacenar los datos asociados con
cada sesión.
Creación de una sesión
Una sesión se considera nueva sólo cuando es prospectiva o no ha sido establecida. Debido a que
HTTP es un protocolo basado en petición-respuesta, una sesión no se considera nueva hasta que el
cliente se “une” a ella. Esto ocurre cuando la información de seguimiento de la sesión, es devuelta al
servidor, indicando que la sesión ha sido establecida. Mientras que esto no suceda, no se puede
asumir que la siguiente petición del cliente sea reconocida como parte de una sesión.
Ámbito de sesión
El objeto HttpSession tiene ámbito de aplicación (o servlet context). El mecanismo subyacente,
como por ejemplo la cookie que se utiliza para establecer una sesión, puede ser la misma o
diferente para distintos contextos, pero los objetos referenciados (incluyendo sus atributos), nunca
deben ser compartidos por el contenedor de servlets entre diferentes contextos.
Asociar atributos a una sesión
Un servlet puede añadir un atributo a una HttpSession mediante el nombre. Cualquier objeto
añadido a la sesión, estará disponible para otro servlet que tenga el mismo ServletContext y maneje
una petición identificada al principio como parte de la misma sesión.
Algunos objetos pueden requerir notificación cuando ellos son añadidos o removidos desde una
sesión. Esta información puede ser obtenida si el objeto implementa la interfaz
HttpSessionBindingListener. Esta interfaz define los siguientes métodos:
- valueBound: se debe llamar antes de que el objeto esté disponible a través del método
getAttribute de la interfaz HttpSession
- valueUnbound: se debe llamar después de que el objeto no esté disponible a través del
método getAttribute de la internas HttpSession.
Últimos accesos
El método getLastAccessedTime de la interfaz HttpSession permite a un servlet determinar el último
acceso a la sesión, antes de la actual petición. Se considera que ha habido un acceso a la sesión,
cuando el contenedor de servlets maneja primero la petición que es parte de la sesión.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Otra posibilidad que nos permite un proyecto servlet es modificar el tiempo de espera en el archivo
de configuración XML, en el web.xml.
Podemos invalidar una sesión en tiempo de ejecución utilizando el método invalidate del objeto
session.
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
getAttributesNames():Retorna una Enumeration con los nombres de todos los atributos establecidos
en la sesión del usuario.
1. Abriremos un proyecto web con NetBeans o el IDE que estemos utilizando y crearemos dos
ficheros servlet.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
3. Insertar en el segundo fichero servlet el siguiente código:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class Servlet2 extends HttpServlet {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
HttpSession sesion = request.getSession(false);
//false por ser acceso de lectura
String NombreCliente = (String)sesion.getAttribute( "nombre" );
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet Servlet2</title>");
out.println("</head>");
out.println("<body>");
out.println("HOLA:"+NombreCliente);
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
}
Creamos un objeto HttpSession(HttpSession sesion = request.getSession(false);) y recuperamos el
valor de la variable session con el método getAttribute(sesion.getAttribute("nombre”);)
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
PÁGINA HTML
<html>
<head>
<title>RESPUESTA</title>
</head>
</table>
</form>
</center>
</body>
</html>
2. Solicitaremos un Servlet que se encargará de guardar en una Cookie el valor de los datos
introducidos en las cajas de texto.
Si es la primera vez que solicita el Sevlet, mostraremos un mensaje dando las gracias por
registrarse en nuestro sitio, si por el contrario ya se han creado las Cookies, mostraremos un
mensaje de bienvenida al sitio.
SERVLET
Si no ha creado la Cookie:
Si ha creado la Cookie:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
galletas = peticion.getCookies();
if (galletas!=null){
for(int i=0; i<galletas.length; i++){
if(galletas[i].getName().equals(usuario) &&
galletas[i].getValue().equals(contra)){
nuevo=false;
break;
}
}
}
ServletOutputStream flujo = respuesta.getOutputStream ();
respuesta.setContentType("text/html");
Cookie galleta = new Cookie (usuario, contra);
galleta.setMaxAge(30);
respuesta.addCookie(galleta);
flujo.println("<html>");
flujo.println("<head><title>RESPUESTA</TITLE></HEAD>");
flujo.println("<BODY TEXT=#FFFFFF BGCOLOR=#000080><CENTER><H1>");
if (nuevo){
flujo.println("GRACIA POR REGISTRARSE CON NOSOTROS");
}else{
flujo.println("BIENVENIDO A TU SITIO FAVORITO");
}
flujo.println("</H1></CENTER></BODY></HTML>");
flujo.close();
}
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Laboratorio: Creación y uso de Cookies.
Objetivos
Coprender el funcionamiento y tratamiento de la Cookies en Java.
Enunciado
- Crear una página en la que podamos crear cookies para capturar las aficiones de un usuario.
- Si es la primera vez que el usuario entra en nuestra página le redireccionaremos hacia la
página de creación de Cookies para que nos describa sus gustos.
- Una vez que el usuario haya rellenado los datos, crearemos las Cookies correspondientes y el
usuario podrá entrar en nuestra página tantas veces como desee, escribiendo los valores que
el usuario haya seleccionado.
SOLUCIÓN
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.*;
import javax.servlet.http.*;
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
"<tr><td>Rojo: <input type=radio name=color value=rojo><br>" +
"Azul: <input type=radio name=color value=azul></td></tr></table><br>" +
"<input type=submit value=Enviar>" +
"</form></center></body></html>";
try {
cooks = request.getCookies();
if (cooks==null){
out.println(pedirDatos);
Cookie cook = new Cookie("alta", "s");
cook.setMaxAge(60);
response.addCookie(cook);
}
else{
String usuario = "";
String aficion = "";
String color = "";
int visitas = 0;
String fecha ="";
boolean nuevo = true;
for(int i=0; i<cooks.length; i++){
if(cooks[i].getName().equals("nombre")){
usuario = cooks[i].getValue();
nuevo = false;
}
if(cooks[i].getName().equals("aficion")){
aficion = cooks[i].getValue();
}
if(cooks[i].getName().equals("colorFav")){
color = cooks[i].getValue();
}
if(cooks[i].getName().equals("visitas")){
visitas = Integer.parseInt(cooks[i].getValue()) + 1;
}
if(cooks[i].getName().equals("fecha")){
fecha = cooks[i].getValue();
}
}
if(nuevo){
usuario = request.getParameter("usuario");
aficion = request.getParameter("aficiones");
color = request.getParameter("color");
visitas = 1;
}
Cookie cook = new Cookie("nombre",usuario);
cook.setMaxAge(30);
response.addCookie(cook);
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
response.addCookie(cook);
out.println("<html>");
out.println("<head>");
out.println("<title>Hola otra vez</title>");
out.println("</head>");
out.println("<body><center>");
String colSal;
if (color.equals("rojo")) colSal = "#FF0000";
else colSal = "#0000FF";
out.println("<table border=1 bgcolor=" + colSal +">");
out.println("<tr><td><b>Bienvenido</b></td></tr");
out.println("<tr><td>Esta es su visita: "+ visitas +"</td></tr");
out.println("<tr><td>Última visita: "+ fecha +"</td></tr");
if (aficion.equals("lectura"))
out.println("<tr><td><img src=http://localhost:8084/ServletsVariados/russell.jpg" +
"></td></tr");
else
out.println("<tr><td><img src='http://localhost:8084/ServletsVariados/tycho.jpg'" +
"></td></tr");
out.println("</table>");
out.println("</center></body>");
out.println("</html>");
}
}
catch(Exception e){
} finally {
out.close();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 9. Uso de Filtros en Aplicaciones Web
Objetivos
Programar el filtro
Programar las solicitudes y respuestas a medida
Especificando la cadena de filtros para cada recurso Web
Introducción
Un filtro es una clase que tiene como tarea trabajar con una solicitud como lo hace un servlet, pero
debe permitir la gestión de la solicitud para seguir con otros filtros o servlets. Un filtro puede realizar
una tarea auxiliar como, por ejemplo el inicio de sesión, la realización de comprobaciones de
autenticación especializadas o la anotación de la solicitud o de los objetos de respuesta antes de
ejecutar el servlet.
Los filtros son objetos Java que pueden añadir funcionalidad a los servlets (u otros artefactos web)
interceptando las peticiones y las respuestas.
Es una implementación del patrón de diseño Decorador.
Permiten gestionar el control de acceso, registros (logs), transformar contenido, mantener una
caché de páginas dinámicas, etc.
Pueden encadenarse y formar una cadena de filtros.
Se configuran en web.xml
Los filtros son objetos que permiten modificar un encabezado y contexto en una solicitud o
respuesta.
Los filtros no son capaces de crear una respuesta por si mismos, lo que le diferencia es que puede
ser utilizada en cualquier tipo de recurso web.
Las principales tareas que un filtro puede realizar son las siguientes:
Modificar los encabezados y los datos de la solicitud.
Modificar los encabezados y datos de la respuesta. Puede hacer para proveer una versión a
medida de la respuesta.
Consultar la solicitud y actuar de acuerdo a esta.
Bloquear la solicitud y respuesta de seguir ejecutando.
Interactuar con recursos externos.
Encapsular tareas comunes en unidades reutilizables.
Realizar labores de autentificación y bloqueo de peticiones.
Realizar estadísticas de impactos al Sitio Web.
Formatear los datos enviados al usuario
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
los datos enviados como respuesta al usuario pueden ser transformados al pasar por un Filtro de
salida. En este caso los Filtros pueden comprimir la información, manipular imágenes para
sobreponer en ellas un texto o logo representativo de nuesto sitio Web
La versión 2.3 de la especifiación de los Servlets introduce los Filtros como un medio flexible de
interactuar con peticiones y respuestas HTTP antes y después de que el Contenedor Web llame a los
recursos Web. Estos recursos Web pueden ser tanto estáticos como dinámicos:
recursos Web estáticos:
páginas HTML e imágenes
recursos Web dinámicos:
Servlets y páginas JSP
Los Filtros son una especie de Servlets que interceptan dinámicamente peticiones y respuestas y
pueden manipular la información contenida en ellas.
Son clases Java que pueden interceptar y manipular las peticiones de un Navegador antes de que el
Contenedor Web las pueda ejecutar.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En el siguiente ejemplo se indica una sencilla implementación de filtro que registra un mensaje y
transmite el control a la cadena, que puede incluir otros filtros o un servlet, tal como describe el
descriptor de implementación:
Package ejemplo;
import java.io.IOException;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
filterConfig.doFilter(request, response);
}
<filter>
<filter-name>logSpecial</filter-name>
<filter-class>ejemplo.FiltroLog</filter-class>
<init-param>
<param-name>logType</param-name>
<param-value>special</param-value>
</init-param>
</filter>
El elemento contiene un elemento que se corresponde con el nombre de
un filtro declarado y también un elemento
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<filter-mapping>
<filter-name>logSpecial</filter-name>
<url-pattern>*.special</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>logSpecial</filter-name>
<servlet-name>comingsoon</servlet-name>
</filter-mapping>
javax.servlet.FilterConfig
El contenedor de servlets provee una implementación para esta interface. Al igual que ServletConfig,
la instancia se pasa a través del método init(FilterConfig). Esta interface provee métodos para
acceder a los parámetros de inicialización de un filtro, y algunos otros datos:
Método Significado
getFilterName() Devuelve el nombre del filtro,
especificado en web.xml
getInitParameter(String name) Devuelve el valor del parámetro, null si
no existe
getInitParameterNames() Devuelve un Enumeration con los
nombres de los parámetros. Null si no
tiene parámetros de iniciacización.
getServletContext() Devuelve una referencia al contexto de
Servlet asociado a la aplicación.
javax.servlet.FilterChain
El contenedor de servlets provee una implementación para esta interface y pasa una instancia de la
misma al método doFilter() del filtro. Posee solo un método:
void doFilter (ServletRequest, ServletResponse): Pasa la petición al próximo componente en la
cadena, otro filtro o el recurso original.
Ejecución de filtros
Como la especificación de Servlets 2.4 permite invocar servlets de las siguientes maneras:
Como un resultado del método RequestDispatcher.forward():
El método forward de la interfaz RequestDispatcher puede ser llamado por el servlet llamante sólo
cuando la salida no ha sido enviada al cliente. Si la información existe en el buffer de respuesta y no
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
ha sido enviada, el contenido deberá limpiarse antes de que el método service del servlet de destino
sea llamado. Si la respuesta ha sido enviada, una excepción del tipo IllegalStateException será
lanzada.
Como un resultado del método RequestDispatcher.include():
El método include de la interfaz RequestDispatcher puede ser llamado en cualquier momento. El
servlet de destino del método include tiene acceso a todos los aspectos de la petición, pero el uso
del objeto response (respuesta) es más limitado: sólo puede escribir información al
ServletOutputStream o al objeto Writer de la respuesta y enviar la respuesta escribiendo el
contenido pegado al final del buffer, o llamando explícitamente al método flushBuffer de la interfaz
ServletResponse. Él no puede establecer las cabeceras o llamar a algún método que afecte a las
cabeceras de la respuesta. Cualquier intento será ignorado.
En páginas de error.
El elemento es obligatorio.
Se debe usar un elemento no se pueden usar ambos dentro de un mismo
elemento
Se pueden usar de 0 a 4 subelementos dentro de un elemento
Por defecto (si no se especifica ningún subelemento los filtros solo se aplican para
peticiones entrantes a la aplicación. Es decir, solo el valor REQUEST es aplicado por defecto.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<!ELEMENT filter-mapping (filter-name, (url-pattern | servlet-name)) >
<filter>: Cada elemento de este tipo, introduce un nuevo filtro en la aplicación web. Este elemento _
puede contener varios elementos más. Algunos opcionales como: <icon>, <display-name> y <init-
param>.
Otros obligatorios como:
<filter-name>: Define el nombre del filtro dentro del archivo de configuración.
<filter-class>: Define la clase utilizada para instanciar el filtro.
<filter-mapping>: Al igual que <servlet-mapping>, este elemento asocia un filtro con
un conjunto de URLs. Contiene los elementos:
<filter-name>: Identifica el filtro a asociar.
<url-pattern>: Se utiliza para aplicar el filtro a las peticiones que concuerden con el patrón URL.
<servlet-name>: Se utiliza para aplicar el filtro a todas las peticiones que se realicen al servlet asociado.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" _
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_2_5.xsd">
<filter>
<filter-name>ImpuestosRegistro</filter-name>
<filter-class>filtros.ImpuestosRegistro</filter-class>
<init-param>
<param-name>impuestos</param-name>
<param-value>15</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>ImpuestosRegistro</filter-name>
<url-pattern>/javabeans/subasta.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>ImpuestosRegistro</filter-name>
<url-pattern>/javabeans/subasta_cambio.jsp</url-pattern>
</filter-mapping>
</web-app>
es el elemento raíz empleado para definir un filtro, dentro de este elemento se anidan :
empleado para definir un nombre descriptivo del filtro y que indica la clase
que contiene el filtro (Dicha clase también sería colocada dentro del directorio classes, o bien ,
dentro de un archivo JAR colocado en el directorio lib, como indica la estructura de WAR's).
Además de estos últimos elementos, también pueden ser agregados los elementos para
indicar elementos de configuración iniciales del filtro; en caso de ser proporcionados dichos valores,
cada uno debe incluir un par de elementos : para especificar el nombre
y valor del parámetro respectivamente.
Una vez definido un filtro, se indica un mapeo para aplicar las reglas de determinado filtro a un URL,
através de los elementos se indica que el filtro llamado ImpuestosRegistro sea
aplicado a las solicitudes de las paginas /javabeans/subasta.jsp y /java/subasta_cambio.jsp.
En el diseño del filtro descrito en la sección anterior se hacia alusión a una cadena de filtros, esta
cadena o grupo quedaría conformada por el número de mapeos que correspodan a determinada
ruta, esto es, si existen dos o tres elementos que cumplan con la ruta, la cadena
quedaría conformada por estos filtros, de igual manera si existiera unicamente un
que coincida con la requisición la cadena equivaldría a un solo filtro.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Los filtros pueden tener los siguientes tipos de distribución:
REQUEST: Solo cuando la solicitud viene directamente del cliente
FORWARD: Solo cuando la solicitud ha sido reenviada a un componente (vea Transfiriendo el
control a otro componente Web)
INCLUDE: Solo cuando la solicitud es procesada por un componente que ha sido incluido (vea
Incluyendo Otros recursos en la respuesta)
ERROR: Solo cuando la solicitud ha sido procesada mediante el mecanismo de páginas de
error (vea Manejando errores en servlets)
Puede dirigir que los filtros sean aplicados a cualquier combinación de las situaciones anteriores
seleccionando varios tipos de distribución. Si no se especifican tipos la opción por defecto es
REQUEST.
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 10. Integración de Aplicaciones Web
con Bases de Datos
Objetivos
Integración de aplicaciones web con la api de JDBC
Realizar desarrollos web que interactuen con Base de datos
Introducirnos en JNDI
Introducción
JDBC (Java DataBase Connectivity) es un API de Java que permite al programador el acceso a Bases
de Datos usando el lenguaje estándar SQL.
Las tres acciones principales que nos proporcionará JDBC son:
Establecer la conexión con la base de datos.
Enviar sentencias SQL a esa base de datos.
Procesar los resultados obtenidos de la base de datos.
Java soporta dos modelos de acceso a bases de datos:
Modelo Descripción
Modelo de dos capas La aplicación Java o el applet se conectan directamente a la base de
datos.
Por tanto, el driver JDBC específico para conectarse con la base de
datos debe residir en el sistema local (dónde se encuentra la
aplicación o el applet). La base de datos puede estar en cualquier
otra máquina y se accede a ella mediante la red.
Esta es la configuración típica Cliente/Servidor. El programa cliente
envía instrucciones SQL a la base de datos, ésta los procesa y envía
los resultados de vuelta a la aplicación.
Modelo de tres capas Las instrucciones son enviadas a una capa intermedia entre Cliente y
Servidor, que es la que se encarga de enviar las sentencias SQL a la
base de datos y recoger los resultados.
Los driver JDBC no tienen porque residir en la máquina local.
Esta es la configuración típica en Internet, a través de las páginas
ASP, los servlets y demás tecnologías.
Tipos de drivers
Para conectarse a bases de datos individuales, JDBC necesita un driver específico para cada una de
ellas.
Hay cuatro tipos de drivers:
Tipo de Driver Descripción
Puente JDBC-ODBC Este es el driver que se incluye en la plataforma Java2.
Proporciona acceso a base de datos a través de uno o más drivers
ODBC, aprovechando todo lo que ya existe.
El rendimiento se resiente al tener que realizarse la conversión de
las transacciones de JDBC a ODBC.
Java / Binario Este driver realiza la comunicación directa con la libreria que
proporciona el fabricante de la base de datos.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Actualmente, sólo IBM y Oracle proporcionan este tipo de drivers
para acceso a sus base de datos.
WebLogic ofrece dirvers de este tipo para acceder a las base de
datos más populares: SQL Server, Sybase.
100% JAVA/ Protocolo Realizado totalmente en Java, convierte directamente las peticiones
Nativo JDBC del cliente en peticiones de red contra el servidor. Esta
conversión se realiza en el cliente.
100% JAVA/ Protocolo El driver convierte las llamadas JDBC directamente a llamadas
independiente nativas hacia el sistema DBMS de que se trate.
Esta conversión se realiza en el servidor, el cliente puede usar un
driver JDBC genérico.
El paso 1 será cargar el driver que suminstra Oracle para poder conectarnos a su motor de base de
datos.
// Cargamos driver ORACLE
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
Conexión
Una vez cargado el driver, podemos realizar la conexión.
Esta conexión se realiza mediante el método getConnection() de la clase DriverManager.
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@Servidor:1521:NombreBD","usuario", "password");
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Métodos de la clase
connection
void clearWarnings()
Borra todos los warnings comunicados por este objeto
Connection
void close()
Cierra la conexión liberando todos los recursos que estuviese
utilizando.
Statement createStatement()
Crea una sentencia (representada por el objeto Statement)
que permitirá enviar comandos SQL a la base de datos.
SQLWarning getWarnings()
Devuelve el primer warning provocado por llamadas sobre
este objeto Connection.
boolean isClosed()
Comprueba si la conexión está cerrada.
boolean isReadOnly()
Comprueba si la conexión está en modo de sólo lectura.
void setReadOnly(boolean readOnly)
Pone esta conexión en modo sólo lectura.
Métodos de la clase
Statement
void cancel()
Cancela este objeto Statement si el DBMS y el driver
soportan el abortar sentencias SQL.
void clearWarnings()
Borra todos los warnings comunicados por este objeto
Statement.
void close()
Cierra este objeto Statement y libera todos los recursos que
estaba usando.
boolean execute(String sql)
Ejecuta una sentencia SQL que puede retornar múltiples
resultados.
ResultSet executeQuery(String sql)
Ejecuta una sentencia SQL que devuelve un único ResultSet.
Por ejemplo, un SELECT.
int executeUpdate(String sql)
Ejecuta una sentencia SQL de tipo SQL INSERT, UPDATE o
DELETE.
Connection getConnection()
JDBC 2.0 Devuelve el objeto Connection que produjo este
objeto Statement.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
int getMaxFieldSize()
Devuelve el número máximo de bytes permitidos en el valor
de cualquier columna.
int getMaxRows()
Devuelve el número máximo de registros que puede
contener un ResultSet.
boolean getMoreResults()
Se mueve al siguiente registro del objeto Statement.
int getQueryTimeout()
Devuelve el número de milisegundos que esperará el driver a
que una sentencia SQL se ejecute.
ResultSet getResultSet()
Devuelve el resultado actual como un objeto ResultSet.
SQLWarning getWarnings()
Devuelve el primer warning comunicado en la llamadas sobre
este objeto Statement.
void setCursorName(String name)
Define el nombre del cursor que será usado por los métodos
execute de los objetos Statement siguientes.
void setMaxFieldSize(int max)
Pone el número máximo de bytes para una columna.
void setMaxRows(int max)
Pone el número máximo de registros que un ResultSet puede
contener.
void setQueryTimeout(int seconds)
Pone el número de segundos que esperará el driver a que
una sentencia se ejecute.
Recuperando registros
Para recuperar información de la base de datos se recurre al método executeQuery(), el cual
devuelve un objeto de tipo ResultSet
ResultSet resultado=sentencia.executeQuery("SELECT * FROM tabla");
while(resultado.next()){
String titulo=resultado.getString("TITULO");
String autor=resultado.getString("AUTOR");
int precio=resultado.getInt("Precio");
Date publicacion=resultado.getDate("PUBLICACION");
System.out.println(....imprimir campos...");
}
Como se puede ver en los métodos de abajo, cada getxxx tiene dos posibilidades: dar el nombre de
la columna como un String o dar un índice que hace referencia al campo en concreto (el índice
comienza en 1 y se refiere al ResultSet que obtenemos de la consulta y no a la base de datos
completa).
Los métodos que podemos usar sobre el objeto ResultSet son:
Métodos de ResultSet
boolean absolute(int row)
JDBC 2.0 Permite situarnos en un registro en concreto.
void afterLast()
JDBC 2.0 Permite situarnos después del último registro.
void beforeFirst()
JDBC 2.0 Permite situarnos antes del primer registro.
void close()
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Cierra el objeto ResultSet y se liberan los recursos que
estaba usando.
void deleteRow()
JDBC 2.0 Borra el registro del ResultSet en el que nos
encontramos actualmente.Deletes the current row from the result
set and the underlying database.
boolean first()
JDBC 2.0 Nos colocamos en el primer registro.
BigDecimal getBigDecimal(int columnIndex)
JDBC 2.0 Obtiene el valor de una columna del registro
actual como un java.math.BigDecimal con precisión completa.
BigDecimal getBigDecimal(String columnName)
JDBC 2.0 Obtiene el valor de una columna del registro
actual como un java.math.BigDecimal con precisión completa.
InputStream getBinaryStream(int columnIndex)
Obtiene el valor de una columna como un stream de bytes.
InputStream getBinaryStream(String columnName)
Obtiene el valor de una columna como un stream de bytes.
boolean getBoolean(int columnIndex)
Obtiene el valor de una columna como un boolean.
boolean getBoolean(String columnName)
Obtiene el valor de una columna como un boolean.
byte getByte(int columnIndex)
Obtiene el valor de una columna como un byte.
byte getByte(String columnName)
Obtiene el valor de una columna como un byte.
byte[] getBytes(int columnIndex)
Obtiene el valor de una columna como un array de bytes.
byte[] getBytes(String columnName)
Obtiene el valor de una columna como un array de bytes.
Reader getCharacterStream(int columnIndex)
JDBC 2.0 Obtiene el valor de una columna como un
Reader.
Reader getCharacterStream(String columnName)
JDBC 2.0 Obtiene el valor de una columna como un
Reader.
String getCursorName()
Obtiene el nombre del cursor SQL usado por este
ResultSet.
Date getDate(int columnIndex)
Obtiene el valor de una columna como un objeto
java.sql.Date.
Date getDate(int columnIndex, Calendar cal)
JDBC 2.0 Obtiene el valor de una columna como un objeto
java.sql.Date.
Date getDate(String columnName)
Obtiene el valor de una columna como un objeto
java.sql.Date.
Date getDate(String columnName, Calendar cal)
Obtiene el valor de una columna como un objeto
java.sql.Date.
double getDouble(int columnIndex)
Obtiene el valor de una columna como un double.
double getDouble(String columnName)
Obtiene el valor de una columna como un double.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
float getFloat(int columnIndex)
Obtiene el valor de una columna como un float.
float getFloat(String columnName)
Obtiene el valor de una columna como un float.
int getInt(int columnIndex)
Obtiene el valor de una columna como un int.
int getInt(String columnName)
Obtiene el valor de una columna como un int.
long getLong(int columnIndex)
Obtiene el valor de una columna como un long.
long getLong(String columnName)
Obtiene el valor de una columna como un long.
Object getObject(int columnIndex)
Obtiene el valor de una columna como un object.
Object getObject(String columnName)
Obtiene el valor de una columna como un object.
short getShort(int columnIndex)
Obtiene el valor de una columna como un short.
short getShort(String columnName)
Obtiene el valor de una columna como un short.
Statement getStatement()
JDBC 2.0 Devuelve el objeto Statement que produjo este
objeto ResultSet.
String getString(int columnIndex)
Obtiene el valor de una columna como un String.
String getString(String columnName)
Obtiene el valor de una columna como un String.
Time getTime(int columnIndex)
Obtiene el valor de una columna como un objeto
java.sql.Time.
Time getTime(int columnIndex, Calendar cal)
Obtiene el valor de una columna como un java.sql.Time.
Time getTime(String columnName)
Obtiene el valor de una columna como un java.sql.Time.
Time getTime(String columnName, Calendar cal)
Obtiene el valor de una columna como un java.sql.Time.
int getType()
JDBC 2.0 Devuelve el tipo de este ResultSet.
SQLWarning getWarnings()
Retorna el primer warning comunicado en llamadas a este
ResultSet.
void insertRow()
JDBC 2.0 Inserta los contenidos del registro en el objeto
ResultSet y en la base de datos.
boolean isAfterLast()
JDBC 2.0 Detecta si el cursor está después del último
registro.
boolean isBeforeFirst()
JDBC 2.0 Detecta si el cursor está antes del primer
registro.
boolean isFirst()
JDBC 2.0 Detecta si el cursor está en el primer registro.
boolean isLast()
JDBC 2.0 Detecta si el cursor está en el último registro.
boolean last()
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
JDBC 2.0 No sitúa en el último registro.
boolean next()
Mueve el cursor al siguiente registro.
boolean previous()
JDBC 2.0 Mueve el cursor al registro anterior.
void refreshRow()
JDBC 2.0 Refresca la fila actual con su valor más reciente
en la base de datos.
boolean relative(int rows)
JDBC 2.0 Nos movemos el número de registros indicando
desde la posición actual.
boolean rowDeleted()
JDBC 2.0 Indica si un registro ha sido borrado. Contrasta
nuestro ResultSet con la base de datos.
boolean rowInserted()
JDBC 2.0 Indica si el registro actual ha sufrido alguna
inserción.
boolean rowUpdated()
JDBC 2.0 Indica si el registro actual ha sido actualizado.
void updateBigDecimal(int columnIndex, BigDecimal x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor BigDecimal indicado.
void updateBigDecimal(String columnName, BigDecimal x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor BigDecimal indicado.
void updateBoolean(int columnIndex, boolean x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor boolean indicado.
void updateBoolean(String columnName, boolean x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor boolean indicado.
void updateByte(int columnIndex, byte x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor byte indicado.
void updateByte(String columnName, byte x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor byte indicado.
void updateBytes(int columnIndex, byte[] x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el array de bytes indicado.
void updateBytes(String columnName, byte[] x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el array de bytes indicado.
void updateDate(int columnIndex, Date x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor Date indicado.
void updateDate(String columnName, Date x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor Date indicado.
void updateDouble(int columnIndex, double x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor double indicado.
void updateDouble(String columnName, double x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor double indicado.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
void updateFloat(int columnIndex, float x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor float indicado.
void updateFloat(String columnName, float x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor float indicado.
void updateInt(int columnIndex, int x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor int indicado.
void updateInt(String columnName, int x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor int indicado.
void updateLong(int columnIndex, long x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor long indicado.
void updateLong(String columnName, long x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor long indicado.
void updateNull(int columnIndex)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor null indicado.
void updateNull(String columnName)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor null indicado.
void updateObject(int columnIndex, Object x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor Object indicado.
void updateObject(String columnName, Object x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor Object indicado.
void updateRow()
JDBC 2.0 Actualiza la base de datos con los nuevos
contenidos del registro actual.
void updateShort(int columnIndex, short x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor short indicado.
void updateShort(String columnName, short x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor short indicado.
void updateString(int columnIndex, String x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor String indicado.
void updateString(String columnName, String x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor String indicado.
void updateTime(int columnIndex, Time x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor Time indicado.
void updateTime(String columnName, Time x)
JDBC 2.0 Actualiza la columna indicada del registro actual
con el valor Time indicado.
boolean wasNull()
Comunica si la última columna leída tiene un valor SQL
nulo.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Para obtener información relativa a cada campo basta con utilizar el método getMetaData() sobre el
objeto ResultSet y obtenemos un objeto ResultSetMetaData sobre el que se pueden usar los
siguientes métodos:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Métodos de
ResultSetMetaData
int getColumnCount()
Devuelve el número de columnas de este ResultSet.
int getColumnDisplaySize(int column)
Indica el ancho máximo de la columna especificada en
caracteres.
String getColumnName(int column)
Devuelve el nombre de la columna especificada.
int getColumnType(int column)
Devuelve el tipo SQL de la columna especificada.
String getColumnTypeName(int column)
Devuelve el tipo de dato de la columna según la base de
datos.
int getPrecision(int column)
Obtiene la precisión usada en la columna. Tiene sentido en
datos decimales.
int getScale(int column)
Obtiene el número de dígitos usados a la derecha del
punto decimal.
String getTableName(int column)
Gets a column's table name.
boolean isAutoIncrement(int column)
Indica si la columna especificada es automáticamente
numerada, esto es de sólo lectura.
boolean isCaseSensitive(int column)
Indica si la columna indicada es sensible a mayúsculas y
minúsculas.
boolean isCurrency(int column)
Indica se la columna indicada es un valor de moneda.
int isNullable(int column)
Indica si la columna indicada permite valores null.
boolean isReadOnly(int column)
Indica si la columna indicada es de sólo lectura.
boolean isSearchable(int column)
Indica si la columna puede ser usada en un claúsula
where.
boolean isSigned(int column)
Indica si los valores de la columna especificada son
número con signo.
boolean isWritable(int column)
Indica si se puede escribir en la columna especificada.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
INSERT INTO DISTRIBUIDORAS VALUES('MGM','mgm.jpg','http://www.mgm.com/');
INSERT INTO DISTRIBUIDORAS VALUES('Miramax','miramax.jpg','http://www.miramax.com/');
INSERT INTO DISTRIBUIDORAS VALUES('New Line Cinema','newlinecinema.jpg','http://www.newline.com/');
INSERT INTO DISTRIBUIDORAS VALUES('Tri-Pictures','tripictures.gif','http://www.tripictures.com/');
INSERT INTO DISTRIBUIDORAS VALUES('UIP - Paramount,Universal y
Dreamworks','paramount.jpg','http://www.uip.es/');
INSERT INTO DISTRIBUIDORAS VALUES('Walt Disney','waltdisney.jpg','http://www.disney.com/');
INSERT INTO DISTRIBUIDORAS VALUES('Warner Bross','warner.gif','http://www.warnerbros.com/');
commit;
La página Distribuidoras.jsp debe cargar los datos de los tres campos de la tabla distribuidoras:
Mostrar en una etiqueta img la imagen de la distribuidora.
Cargar en un hipervínculo el nombre de la distribuidora.
Al pulsar sobre la distribuidora debemos redirigir al usuario al sitio web de la distribuidora.
Código JSP
<%@page language = "java" import="java.sql.*" %>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%-- Aqui la lista creada en un bucle--%>
<%
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
Statement sentencia=conexion.createStatement();
rs=sentencia.executeQuery("SELECT internet,distribuidora,imagen from
distribuidoras");
while(rs.next()){
String direccion=rs.getString(1);
String nombre=rs.getString(2);
String imagen=rs.getString(3);
if(par%2!=0){
out.println("<tr>");
}
String enlazar= "<a href="+direccion +" TARGET=_blank
class=mediano>";
out.println("<TD><table border=0 cellpadding=4 width=180;><tr>");
out.println("<tD width=30>"+enlazar+"<img
src=IMAGENES\\DISTRIBUIDORAS\\"+imagen+" alt=_
\""+nombre+"\" border=0 width=60 height=42></a></td>");
out.println("<td
align=left>"+enlazar+nombre+"</a></td></tr></table></TD>");
if(par%2==0){
out.println("</tr>");
}
par++;
}
if(par%2==0){
out.println("</tr>");
}
%>
</table>
</body>
</html>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
servicio de directorio sean integradas en el framework. Las implementaciones pueden hacer uso de
un servidor, un fichero, o una base de datos; la elección depende del vendedor.
JNDI proporciona una API común a una variedad de servicios de directorios. Este API está incluida
como parte estándar de Java, del mismo modo que JDBC proporciona una API estándar para las
Bases de Datos Relacionales.
Esta imagen nos muestra cómo JNDI unifica el acceso a servicios de directorio de redes
heterogéneos:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Proveedores de servicios JNDI
En grandes Centros de Cálculo se suele disponer de un Ordenador que realiza las labores de
proveedor de servicios JNDI.
De esta forma todo el mundo que quiera acceder a una BDS particular solamente tiene que
comunicarse con el proveedor de servicios JNDI e indicarle el nombre de directorio de la BDS en
cuestión.
La ventaja de utilizar esta forma de acceder a una BDS es que ésta puede cambiar su localización,
es decir su direección IP, e incluso también puede cambiar el nombre de la BDS pero todos estos
cambios son tranparentes al usuario que quiere conectar con dicha BDS.
Un proveedor de servicios JNDI es en definitiva un conjunto de Clases Java. Una de estas Clases
tiene que implementar la Interfaz DirectoryContext que a su vez hereda de la Interfaz Context.
El proveedor de servicios JNDI necesita que el usuario que requiere un servicio se autentifique a
través de un nombre de usuario y una contraseña.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Creación de la table emp e inserción de registros:
CREATE TABLE EMP
(EMP_NO NUMBER(4,0)
CONSTRAINT EMP_PRIMARY_KEY PRIMARY KEY,
APELLIDO VARCHAR2(10)
NOT NULL,
OFICIO VARCHAR2(10)
CONSTRAINT EMP_CHK_OFICIO CHECK(OFICIO
IN('ANALISTA','DIRECTOR','EMPLEADO','PRESIDENTE','VENDEDOR')),
DIR NUMBER(4,0)
CONSTRAINT EMP_SELF_KEY REFERENCES EMP(EMP_NO),
FECHA_ALT DATE
DEFAULT SYSDATE,
SALARIO NUMBER(10,0)
CONSTRAINT EMP_CHK_SALARIO CHECK(SALARIO BETWEEN 100000 AND 999999),
COMISION NUMBER(10,0),
DEPT_NO NUMBER(2,0)
NOT NULL,
CONSTRAINT EMP_FOREIGN_KEY FOREIGN KEY(DEPT_NO) REFERENCES
DEPT(DEPT_NO)
);
<%
if (request.getParameter("registros") != null)
vReg = Integer.parseInt(request.getParameter("registros"));
else
vReg = 5;
if (request.getParameter("posicion") != null)
vPosicion = Integer.parseInt(request.getParameter("posicion"));
else
vPosicion = 1;
%>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<script language="javascript">
function paginar(pNumReg)
{
var vDestino = "paginacion.jsp?registros=" + pNumReg + "&posicion=1";
window.location = vDestino;
}
</script>
<style>
BODY {
text-align: center;
background-color: #EEEEEE;
}
TD, SELECT, OPTION {
background-color: #CCDDFF;
font-size: 12px;
color: #660099;
border: 1px solid #9999CC;
font-family: tahoma;
}
TH {
font-size: 14px;
font-family: arial;
text-align: center;
}
A, A.link, A.visited {
text-decoration: none;
font-size: 12px;
color: #6699CC;
}
A:hover {
color: #660099;
}
.CENTRO {
background-color: #660099;
font-weight: bold;
color: #FFFFFF;
}
</style>
</HEAD>
<BODY>
<table style="border: 1px solid #99CCFF; background-color: #DDDDDD; width: 500px;">
<tr>
<td colspan="3" style="text-align: right; color: #000000; background-color: #FFCC99;">
registros por pantalla _
<select name="fNumRegistros" style="width: 50px;" onchange="paginar(this.value);">
<%
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
_
for (int i=5; i<=20; i+=5)
_
{
_
if (i == vReg)
_
{
_
%>
_
<option value="<%= i %>" selected> <%= i %> </option>
_
<%
_
}
_
else
_
{
_
%>
_
<option value="<%= i %>"> <%= i %> </option>
_
<%
_
}
_
}
%>
_
</select>
</td>
</tr>
<tr><td colspan="3" style="background-color: #DDDDDD; border: 0px;"> </td></tr>
<tr>
<th colspan="3"> Listado de empleados </th>
</tr>
<tr>
<td class="CENTRO" style="width: 50px;"> Num. </td>
<td class="CENTRO" style="width: 225px;"> Apellido </td>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<td class="CENTRO" style="width: 225px;"> Puesto </td>
</tr>
<%
Connection vConexion;
Statement vSentencia;
ResultSet vRegistros;
String vConsulta;
int vNumReg = 0;
try
{
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
}
catch(Exception e){ System.out.println("Error en la carga del driver..."); }
try
{
vSentencia =
vConexion.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, _
ResultSet.CONCUR_UPDATABLE);
vConsulta = "SELECT emp_no, apellido, oficio FROM emp ORDER BY
apellido;";
vRegistros = vSentencia.executeQuery(vConsulta);
vRegistros.last();
vNumReg = vRegistros.getRow();
vRegistros.absolute(vPosicion);
%>
<tr>
<th colspan="3" style="text-align: right;">
<%
for (int p=0, j=1; p <= vNumReg-1; p += vReg, j++)
{
%>
<a
href="paginacion.jsp?registros=<%=vReg%>&posicion=<%=p+1%>">_
<%=j%></a>
<%
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
%>
</th>
</tr>
<%
vConexion.close();
}
catch(SQLException e) { System.out.println(e.toString()); }
catch(Exception e) { System.out.println(e.toString()); }
%>
</table>
</BODY>
</HTML>
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 11. Desarrollo de páginas JSP
Objetivos
Entender la tecnología JSP y sus tipos de construcciones.
Desarrollar aplicaciones con los elementos de script de JSP.
Utilizar las acciones JSP que usan construcciones en sintaxis XML para controlar el
comportamiento de la máquina servlet
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Elementos de Script JSP
Los elementos de script de JSP te permite insertar código Java en el servlet que será generado a
partir de la página JSP. Hay tres formas:
Las expresiones de la forma
<%= expression %>
serán evaluadas e insertadas en la salida.
Los Scriptlets de la forma
<% code %>
serán insertadas en el método service del servlet.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%= Java Expression %>
La expresión es evaluada, convertida a String e insertada en la página. La evaluación es realizada en
tiempo de ejecución (cuando la página es solicitada), y por eso tiene acceso completo a la
información de la petición.
Existen un número de variables predefinidas que se pueden usar (no podrán ser definidas como
variables nuestras dentro de la página JSP):
JSP Scriptlets
Si queremos hacer algo más complejo que insertar una simple expresión, Los scriptlets JSP te
permiten insertar cualquier tipo de código java dentro del método servlet que será construido para
generar la página. Tienen el siguiente formato:
<% Java Code %>
Los Scriptlets tienen también acceso a las variables definidas automáticamente por el sistema.
<%
String consultadatos = request.getQueryString();
out.println("Datos obtenidos: " + consultadatos);
%>
El siguiente fragmento JSP que contiene mezcla de texto HTMl y scriptlets:
<% if (Math.random() < 1.1) { %>
Hola
<% } else { %>
Adios
<% } %>
Si queremos usar "%>" dentro del scriptlet, debes usar "%\>" .
Por último, recordar que el equivalente XML de <% Code %> es:
<jsp:scriptlet>
Code
</jsp:scriptlet>
Declaraciones JSP
Una declaración JSP te permite definir métodos o campos que serán insertados en el cuerpo
principal de la clase servlet (fuera del método service que procesa la petición). Tiene el siguiente
formato:
<%! Java Code %>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ya que las declaraciones no generan ninguna salida por sí solas, ellos normalmente se usan en
conjunción con expresiones o scriptlets JSP.
Directivas JSP
Una directiva JSP afecta a la estructura completa de la clase del servlet que se crea a partir de la
página JSP. Normalmente tiene el siguiente formato:
<%@ directive attribute="value" %>
Sin embargo, puedes también combinar multiples atributos en una única directiva, de la siguiente
manera:
<%@ directive attribute1="value1"
attribute2="value2"
...
attributeN="valueN" %>
Hay dos tipos principales de directivas:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Directiva JSP include
Esta directiva te permite incluir ficheros en el momento en el que la página JSP está siendo
convertida en servlet. El formato es el siguiente:
<%@ include file="relative url" %>
La URL especificada es considerada normalmente de forma relativa a la página JSP desde la que se
hace la referencia, pero se puede indicar al servidor que la interprete de forma relativa desde el
directorio raiz de dicho servidor comenzando la URL con "/" (forward slash).
Los contenidos del fichero incluido son interpretados como texto JSP normal y, por tanto, puede
incluirse:
- HTML estático.
- Elementos de script, directivas y acciones.
<%@page contentType="text/html"%>
<html>
<head><title>JSP Page</title></head>
<body>
<%@ include file="ejemplo.html" %>
</ body>
</ html>
Acciones
Las acciones JSP usan construcciones en sintaxis XML para controlar el comportamiento de la
máquina servlet.
jsp:include
Esta acción te permite insertar ficheros en la página que está siendo generada. La sintaxis es:
<jsp:include page="relative URL" flush="true" />
A diferencia de la directiva include, la cual inserta el fichero en el momento en el que la página JSP
es convertida a un servlet, esta acción inserta el fichero en el momento en el que la página es
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
solicitada. Esto pierde un poco de eficiencia y no permite que la página contenga código JSP general
(no se pueden manipular las cabecereas HTTP, por ejemplo), pero gana significativamente en
flexibilidad.
<%@page contentType="text/html"%>
<html>
<head><title>JSP Page</title></head>
<body>
<OL>
<LI><jsp:include page="Item1.html" flush="true"/>
<LI><jsp:include page="Item2.html" flush="true"/>
</OL>
</BODY>
</HTML>
jsp:useBean
Esta acción te permite cargar un JavaBean para ser usado en una página JSP. Esta es una capacidad
muy útil porque permite explotar la reusabilidad de las clases de Java sin sacrificar las ventajas de
JSP añade sobre los servlets. La sintaxis más simple para especificar el bean que será usado es:
<jsp:useBean id="name" class="package.class" />
Esto significa:
" instancia un objeto de la clase especificada en el atributo class, y enlazalo a una variable con el
nombre especificado en el atributo id".
Una vez que tenemos una instancia de un bean, podemos modificar sus propiedades mediante la
acción jsp:setProperty, o usando un scriptlet que llame a un método del objeto referenciado por el
nombre de la variable especificado en el atributo id.
Podemos leer alguna de sus propiedades mediante la acción jsp:getProperty o usando algún método
que nos devuelva el valor de la propiedad.
En el siguiente ejemplo creamos un JavaBeans con un método llamado hora que devuelve la hora
formateada:
Bean (Bean1.class)
package BeansPropios;
import java.util.*;
import java.text.*;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%@page contentType="text/html"%>
<html>
<head>
<title>HORA DEL SISTEMA CON JAVABEAN</TITLE>
</HEAD>
jsp:setProperty.
Haremos uso de la acción jsp:setProperty para dar valores a las propiedades de los beans que han
sido referenciados anteriormente. Se puede hacer en dos contextos. En el primero, puedes usar
jsp:setProperty fuera de jsp:useBean:
<jsp:useBean id="nombreBean" ... />
...
<jsp:setProperty name="nombreBean" property="nombre ... />
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En el siguiente ejemplo desarrollar una aplicación web que nos permita generar números aleatorios
entre un valor inicial y uno final.
Incorporar el algoritmo en un Java Beans donde almacenemos el valor inicial, el final y la cantidad
de números en tres propiedades del Java Beans.
Bean
package BeansPropios;
public BJSPPARAMETROS() {
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
}
if (!existe)
{
aleatorios[i] = candidato;
}
} while (existe);
}
return aleatorios;
}
}
Página html
<html>
<head>
<title>NUMEROS ALEATORIOS</TITLE>
</head>
<BODY bgcolor=#aab42a text=navy>
<form action="pagina.jsp" method=post>
<center>
GENERAR<INPUT TYPE=TEXT NAME=cantidad SIZE=5> NUMEROS ALEATORIOS ENTRE
<INPUT TYPE=TEXT NAME=inferior size=5> Y <INPUT TYPE=TEXT NAME=superior size=5>
<br><br>
<input type=submit value="GENERAR">
</center>
</FORM>
</BODY>
</html>
En la página jsp asignaremos los valores de las cajas de texto a las propiedades cantidad,inferior y
superior.
pagina.jsp
<%@page contentType = "text/html" %>
<html>
<head><title>Numero aleatorio sin repetición</title></head>
<body bgcolor = #AAB42A text = navy>
<jsp:useBean id="objeto" scope="session" class="BeansPropios.BJSPPARAMETROS" />
<jsp:setProperty name="objeto" property="cantidad" param = "cantidad"/>
<jsp:setProperty name="objeto" property="inferior" param = "inferior"/>
<jsp:setProperty name="objeto" property="superior" param = "superior"/>
<font size ="6">Números generados</FONT>
<BLOCKQUOTE>
<ol type = "disc">
<%
int [] resultado = objeto.Devolver();
for (int i=0; i<resultado.length; i++)
{%>
<li><%=resultado[i]%></li>
<%}%>
</ol>
<% } else { %>
<h3> no hay suficientes numeros en el intervalo solicitado </h3>
<% } %>
</body>
</html>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Como las cajas de texto y las propiedades cantidad, inferior y superior tienen el mismo nombre
podemos asignar el valor automáticamente colocando un “*”.
<%@page contentType = "text/html" %>
<html>
<head><title>Numero aleatorio sin repetición</title></head>
<body bgcolor = #AAB42A text = navy>
<jsp:useBean id="objeto" scope="session" class="BeansPropios.BJSPPARAMETROS" />
<jsp:setProperty name="objeto" property="*" />
<font size ="6">Números generados</FONT>
<BLOCKQUOTE>
<ol type = "disc">
<%
int [] resultado = objeto.Devolver();
for (int i=0; i<resultado.length; i++)
{%>
<li><%=resultado[i]%></li>
<%}%>
</ol>
<% } else { %>
<h3> no hay suficientes numeros en el intervalo solicitado </h3>
<% } %>
</body>
</html>
Si el valor que pasamos a las propiedades proviene de una variable declarada en un script de jsp,
usaremos el atributo value:
<%@page contentType = "text/html" %>
<html>
<head><title>Numero aleatorio sin repetición</title></head>
<body bgcolor = #AAB42A text = navy>
<%
int supe = Integer.parseInt(request.getParameter("superior"));
int infe = Integer.parseInt(request.getParameter("inferior"));
int canti = Integer.parseInt(request.getParameter("cantidad"));
if (supe - infe >= canti-1){
%>
<jsp:useBean id="objeto" scope="session" class="BeansPropios.BJSPPARAMETROS" />
<jsp:setProperty name="objeto" property="cantidad" value = "<%=canti%>"/>
<jsp:setProperty name="objeto" property="inferior" value = "<%=infe%>"/>
<jsp:setProperty name="objeto" property="superior" value = "<%=supe%>"/>
<font size ="6">Números generados</FONT>
<BLOCKQUOTE>
<ol type = "disc">
<%
int [] resultado = objeto.Devolver();
for (int i=0; i<resultado.length; i++)
{%>
<li><%=resultado[i]%></li>
<%}%>
</ol>
<% } else { %>
<h3> no hay suficientes numeros en el intervalo solicitado </h3>
<% } %>
</body>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</html>
jsp:getProperty
Este elemento devuelve el valor de una propiedad del Bean, lo convierte a un String y lo inserta en
la salida. Los dos atributos requeridos son name, el nombre del Bean previamente referenciado
mediante jsp:useBean, y property. el nombre de la propiedad cuyo valor deseamos obtener. Este
ejemplo aclara un poco más la inserción del parámetro en la página:
<jsp:useBean id="Bean1" ... />
Nombre:
<jsp:getProperty name="Bean1" property="nombre" />
Edad:
<jsp:getProperty name="Bean1" property="edad" />
jsp:forward
Esta acción te permite redirigir la petición a otra página. Tiene un único atributo, page, el cual
contiene una URL relativa. Esta puede ser un valor fijo o ser obtenido en el momento de la petición.
<jsp:forward page="/pagina1.jsp" />
En el siguiente ejemplo enviamos a la página autorizado.html o noautorizado.html dependiendo de
si el usuario tiene o no acceso al portal web.
<html>
<head><title>JSP Page</title></head>
<body>
<jsp:forward page="autorizado.html"/>
<%}%>
</body>
</html>
jsp:plugin
La acción proporciona fácil apoyo para incluir applets de Java en páginas generadas por
JSP. Es utilizado para generar etiquetas específicas para cada navegador: embed para explorer u
object para netscape) que resultan de la descarga de software Plug-in de Java si fuera preciso.
permite olvidarnos de las diferencias de navegador o de la maquina virtual incorporada a
nuestro navegador.
Componentes de la etiqueta <jsp:plugin>:
<jsp:params>: Permite pasar parámetros al applet.
<jsp:fallback>: Si el plug-in no puede ser lanzado, lo que se incluya en esta etiqueta será lo que
visualicemos
en el navegador del cliente.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%@page contentType="text/html"%>
<HTML>
<head><title>CARGA DE APPLET</TITLE>
</head>
</jsp:plugin>
</body>
</HTML>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
IN('ANALISTA','DIRECTOR','EMPLEADO','PRESIDENTE','VENDEDOR')),
DIR NUMBER(4,0)
CONSTRAINT EMP_SELF_KEY REFERENCES EMP(EMP_NO),
FECHA_ALT DATE
DEFAULT SYSDATE,
SALARIO NUMBER(10,0)
CONSTRAINT EMP_CHK_SALARIO CHECK(SALARIO BETWEEN 100000 AND 999999),
COMISION NUMBER(10,0),
DEPT_NO NUMBER(2,0)
NOT NULL,
CONSTRAINT EMP_FOREIGN_KEY FOREIGN KEY(DEPT_NO) REFERENCES
DEPT(DEPT_NO)
);
<%
if (request.getParameter("registros") != null)
vReg = Integer.parseInt(request.getParameter("registros"));
else
vReg = 5;
if (request.getParameter("posicion") != null)
vPosicion = Integer.parseInt(request.getParameter("posicion"));
else
vPosicion = 1;
%>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
function paginar(pNumReg)
{
var vDestino = "paginacion.jsp?registros=" + pNumReg + "&posicion=1";
window.location = vDestino;
}
</script>
<style>
BODY {
text-align: center;
background-color: #EEEEEE;
}
TD, SELECT, OPTION {
background-color: #CCDDFF;
font-size: 12px;
color: #660099;
border: 1px solid #9999CC;
font-family: tahoma;
}
TH {
font-size: 14px;
font-family: arial;
text-align: center;
}
A, A.link, A.visited {
text-decoration: none;
font-size: 12px;
color: #6699CC;
}
A:hover {
color: #660099;
}
.CENTRO {
background-color: #660099;
font-weight: bold;
color: #FFFFFF;
}
</style>
</HEAD>
<BODY>
<table style="border: 1px solid #99CCFF; background-color: #DDDDDD; width: 500px;">
<tr>
<td colspan="3" style="text-align: right; color: #000000; background-color: #FFCC99;">_
_
for (int i=5; i<=20; i+=5)
_
{
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
if (i == vReg)
_
{
_
%>
_
<option value="<%= i %>" selected> <%= i %> </option>
_
<%
_
}
_
else
_
{
_
%>
_
<option value="<%= i %>">_
<%= i %> </option>
_
<%
_
}
_
}
%>
_
</select>
</td>
</tr>
<tr><td colspan="3" style="background-color: #DDDDDD; border: 0px;"> </td></tr>
<tr>
<th colspan="3"> Listado de empleados </th>
</tr>
<tr>
<td class="CENTRO" style="width: 50px;"> Num. </td>
<td class="CENTRO" style="width: 225px;"> Apellido </td>
<td class="CENTRO" style="width: 225px;"> Puesto </td>
</tr>
<%
Connection vConexion;
Statement vSentencia;
ResultSet vRegistros;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
String vConsulta;
int vNumReg = 0;
try
{
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
}
catch(Exception e){ System.out.println("Error en la carga del driver..."); }
try
{
vConexion = DriverManager.getConnection
("jdbc:oracle:thin:@Servidor:1521:BdEmpleados","system", "a1b2");
vSentencia =
vConexion.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, _
ResultSet.CONCUR_UPDATABLE);
vConsulta = "SELECT emp_no, apellido, oficio FROM emp ORDER BY
apellido;";
vRegistros = vSentencia.executeQuery(vConsulta);
vRegistros.last();
vNumReg = vRegistros.getRow();
vRegistros.absolute(vPosicion);
%>
<tr>
<th colspan="3" style="text-align: right;">
<%
for (int p=0, j=1; p <= vNumReg-1; p += vReg, j++)
{
%>
<a
href="paginacion.jsp?registros=<%=vReg%>&posicion=<%=p+1%>">_
<%=j%></a>
<%
}
%>
</th>
</tr>
<%
vConexion.close();
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
catch(SQLException e) { System.out.println(e.toString()); }
catch(Exception e) { System.out.println(e.toString()); }
%>
</table>
</BODY>
</HTML>
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 12. Desarrollo de páginas JSP con
etiquetas personalizadas
Objetivos
Desarrollar aplicaciones encapsulando la funcionalidad dinámica de objetos.
Definir e implementar cada uno de los archivos que intervienen en un desarrollo con Custom
Tags.
Introducción
Los Custom Tags (etiquetas personalizadas) son un mecanismo para encapsular funcionalidad
dinámica en objetos accedidos a través de extensiones del lenguaje JSP.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
implementemos la lógica de negocio de las etiquetas, y por último un fichero XML(web.xml) que
indique la localización del archivo tld.
En el siguiente ejemplo realizaremos una etiqueta básica que muestre información en pantalla:
mensaje.tld
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.2</jspversion>
<shortname>Autor</shortname>
<tag>
<name>primera</name>
<tagclass>etiquetas.Etiqueta1</tagclass>
<bodycontent>empty</bodycontent>
</tag>
</taglib>
Etiqueta1.java
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
package etiquetas;
import java.io.IOException;
import java.util.Date;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.TagSupport;
return SKIP_BODY;
}
try {
pageContext.getOut().write("Primer ejemplo de Custom Tags");
} catch (IOException ex) {
throw new JspTagException(
"Error");
}
return EVAL_PAGE;
}
Método doStartTag():
Será invocado cuando la máquina JSP encuentre el inicio de una etiqueta implementado por esta
clase.
Valores de retorno:
EVAL_BODY_INCLUDE: Destinado a evaluar el contenido del cuerpo de la etiqueta y cualquier sub-
etiqueta.
SKIP_BODY: Los contenidos de la etiqueta serán ignorados.
Método doEndTag():
Será invocado cuando la máquina JSP encuentre el final de una etiqueta implementado por esta
clase.
Valores de retorno:
EVAL_PAGE: Hará que la máquina JSP evalúe el resto de la página jsp.
SKIP_PAGE: Hará que la máquina JSP no evalúe el resto de la página jsp
web.xml
<web-app>
<welcome-file-list>
<welcome-file>indice.jsp</welcome-file>
</welcome-file-list>
<taglib>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<taglib-uri>eti</taglib-uri>
<taglib-location>/WEB-INF/etiquetas/mensaje.tld</taglib-location>
</taglib>
</web-app>
indice.jsp
<%@ taglib uri="eti" prefix="MiEtiqueta" %>
<html>
<head>
<title>Primer TAG</title>
</head>
<body>
<MiEtiqueta:primera/>
</body>
</html>
mensaje.tld
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.2</jspversion>
<shortname>Autor</shortname>
<tag>
<name>primera</name>
<tagclass>etiquetas.Etiqueta1</tagclass>
<bodycontent>empty</bodycontent>
<attribute>
<name>nombre</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
Etiqueta1.java
package etiquetas;
import java.io.IOException;
import java.util.Date;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.TagSupport;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
public class Etiqueta1 extends TagSupport {
return SKIP_BODY;
}
<web-app>
<welcome-file-list>
<welcome-file>indice.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>eti</taglib-uri>
<taglib-location>/WEB-INF/etiquetas/mensaje.tld</taglib-location>
</taglib>
</web-app>
indice.jsp
<%@ taglib uri="eti" prefix="MiEtiqueta" %>
<html>
<head>
<title>Primer TAG</title>
</head>
<body>
<MiEtiqueta:primera nombre="pepe"/>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</body>
</html>
Mostrará en pantalla el mensaje:
import java.io.IOException;
import java.util.Date;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.TagSupport;
return EVAL_BODY_INCLUDE;
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
} catch (IOException ex) {
throw new JspTagException(
"Error");
}
return EVAL_PAGE;
}
web.xml
<web-app>
<welcome-file-list>
<welcome-file>indice.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>eti</taglib-uri>
<taglib-location>/WEB-INF/etiquetas/mensaje.tld</taglib-location>
</taglib>
</web-app>
indice.jsp
<%@ taglib uri="eti" prefix="MiEtiqueta" %>
<html>
<head>
<title>Primer TAG</title>
</head>
<body>
<MiEtiqueta:primera>
Nombre del cliente:
<%String nombre="Pepe ";%>
<%String Apellido="Ramos";%>
<%=nombre%><%=Apellido%><br/>
</MiEtiqueta:primera>
</body>
</html>
Resultado:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Etiquetas para iteración sobre datos, operaciones condicionales, e importación de datos de otras
páginas
c:out
Muestra el resultado de una expresión. Su funcionalidad es equivalente a la de
Ejemplo:
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<c:out value="Hola mundo"/><br/>
<c:out value="${variableInexistente}" default="La expresión fallo"/><br/>
<c:out value="${variableInexistente}">
Por defecto el atributo default va en el cuerpo
</c:out>
c:set
Atributo Descripción Requerido Por
defecto
value Información a grabar. no cuerpo
target Nombre de la variable cuya propiedad será modificada no ninguno
property Propiedad a modificar no ninguna
var Nombre de la variable en la que guardar. no ninguno
scope Ámbito de la variable en la que grabar la información (page, no page
request, session, o application)
Ejemplos:
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%-- graba la variable cuatro=4 en el ámbito page --%>
<c:set var="cuatro" value="${2 + 2}"/>
<%-- equivalente al anterior pero con ámbito session --%>
<c:set var="cuatro" scope="session">
4
</c:set>
<%-- equivalente al anterior --%>
<c:set var="cuatro" scope="session">
<c:out value="4"/>
</c:set>
c:remove
Atributo Descripción Requerido Por defecto
var Nombre de la variable a quitar. sí --
scope Ámbito de la variable a quitar. no todos los ámbitos
c:if
Atributo Descripción Requerido Por
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
defecto
test Condición a evaluar. Solo procesa el cuerpo si es true. sí --
var Nombre del atributo con el que grabar el resultado booleano de no ninguno
la condición.
scope Ámbito en el que exponer el atributo anterior. no page
En el cuerpo es posible colocar otras etiquetas, incluyendo otras Es útil guardar el resultado
de evaluar la condición para evitar repetir los cálculos.
Ejecuta el cuerpo de la primera etiqueta when cuya condición evalúe a true, o el cuerpo de la
etiqueta otherwise (si existe).
Ejemplos:
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<c:set var="hour" value="${18}"/>
<c:choose>
<c:when test="${hour>=7 && hour<=12}"> morning </c:when>
<c:when test="${hour>12 && hour<=17}"> afternoon </c:when>
<c:when test="${hour>17 && hour<22}"> evening </c:when>
<c:otherwise>night</c:otherwise>
</c:choose>
c:forEach
Permite iterar sobre los elementos siguientes:
Arrays de objetos o tipos primitivos.
Instancias de java.util.Collection, java.util.Map, java.util.Iterator, java.util.Enumeration.
Cadenas delimitadas por comas.
Es posible anidar varias etiquetas c:forEach.
Atributo Descripción Requerido Por
defecto
items Colección sobre la que iterar. no ninguno
begin Elemento con el que empezar (0=primero). no 0
end Elemento con el que terminar (0=primero). no último
step Procesa solo cada step elementos. no 1 (todos)
var Nombre del atributo con el que exponer el elemento actual. no ninguno
varStatus Nombre de la variable con la que exponer el estado de la no ninguno
iteración.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
count número Número de iteración (empezando en 1).
first boolean Indica si estamos en la primera iteración.
last boolean Indica si estamos en la última iteración.
step número El valor del atributo step.
c:import
c:import proporciona toda la funcionalidad de jsp:include y añade otras:
Permite incluir páginas de otros servidores.
Permite guardar el texto leído en una variable.
Atributo Descripción Requerido Por defecto
url URL para importar la página. Es válido sí --
cualquier protocolo soportado por
java.net.URL. Es decir, al menos HTTP,
HTTPS, FTP, file, y JAR.
context Barra (/) seguido del nombre de la no contexto actual
aplicación local
var Nombre del atributo con el que exponer no muestra en página
el texto importado.
scope Ámbito del atributo anterior. no page
charEncoding Juego de caracteres con el que importar no ISO-8859-1
los datos.
varReader Nombre de una variable con la que no ninguno
exponer el java.io.Reader con que se lee
la URL.
c:param
c:import puede tener hijos c:param, que se usan para pasar parametros a la URL a recuperar.
Los atributos de c:param son
c:redirect
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ejecuta un forward. Es decir, se para la ejecución de la página actual (no se ejecuta nada de lo que
este por debajo de esta instrucción) y el navegador es enviado a otra URL.
Sus atributos son
Atributo Descripción Requerido Por defecto
url URL a la que redirigir. sí --
context Barra (/) seguido del nombre de una no contexto actual
aplicación local.
Ejemplo:
c:catch
Normalmente los errores en una página JSP interrumpen la ejecución de la página y se envían al
contenedor, que a su vez muestra un mensaje de error. La etiqueta c:catch permite capturar y
tratar los errores.
La alternativa a c:catch es usar páginas de error con JSP convencional.
Atributo Descripción Requerido Por defecto
var Variable para exponer información no ninguno
sobre el error.
IGUAL QUE CON JSP, al estar controlado el error en la página actual no se va a error.jsp.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%-- nunca llega aquí --%>
...
<c:if test="${not empty error}">
Introduzca números.<br/>
Detalles del error: <c:out value="${error}"/>
</c:if>
error.jsp
<%@ page isErrorPage="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
</html>
<head>Incidencia en el sistema</head>
<body>
El error fue..<br/>
<c:out value="${pageContext.exception.message}"/>
</body>
</html>
Base de Datos
<%@ taglib prefix="sql" uri="http://java.sun.com/jstl/sql_rt"%>
sql:DataSource
Atributo Descripción Requerido Por defecto
dataSource Base de datos a usar. no ningúno
driver Nombre de la clase JDBC a no ningúno
usar como driver.
url URL de la base de datos. no ningúno
user Nombre del usuario de la base no ningúno
de datos.
password Password del usuario de la no ningúno
base de datos.
var Nombre de la variable que no ningúno
representa la base de datos.
scope Ámbito de la variable anterior. no page
Ejemplos:
MYSQL
<sql:setDataSource driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"
user="alicia" password="secreto"/>
ORACLE
<sql:setDataSource driver="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@maquina:puerto:instancia"
…………………
PUENTE JDBC-ODBC
<sql:setDataSource driver="sun.jdbc.odbc.JdbcOdbcDriver"
url="jdbc:odbc:nombreDsn;UID=uid;PWD=password"
................
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<sql:setDataSource driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"
user="alicia"
password="secreto"
var="development1"/>
<sql:setDataSource dataSource="${development1}"
scope="request" />
sql:query
Cualquier consulta de selección (no de acción) sobre la base de datos usaremos sql:query,
previamente tendremos creado un sql:setDataSource.
Esta etiqueta no muestra datos, solo los graba en la variable indicada por var.
Atributo Descripción Requerido Por
defecto
sql Consulta SQL a ejecutar. no si ponemos el SQL en el cuerpo
cuerpo de la etiqueta
dataSource Proveedor de conexiones. no
startRow Primeras filas a ignorar (ej: 10=ignora no 0
las diez primeras filas). (primero)
maxRows Máximo número de filas. no
var Variable con la que exponer el sí ningúno
resultado.
scope Ámbito de la anterior variable. no page
El atributo maxRows indica el número por defecto de filas a recuperar. Podemos asignar un valor a
este atributo para cambiar el límite de filas, o asignar -1 si no queremos límite.
Las propiedades disponibles son:
columnNames: Lista de nombres de columnas. Podemos acceder a ella con paréntesis cuadrados o
iterando sobre ella.
limitedByMaxRows: Booleano que indica si el resultado contenía más de las filas indicadas por
maxRows.
rows: Acceso a filas usando por nombre.
rowsByIndex: Acceso a filas por índice.
rowCount: Número de filas.
Ejemplos:
<sql:query var="empleados">
SELECT * FROM emp
</sql:query>
Forma equivalente a la anterior:
<sql:query var="empleados" sql="SELECT * FROM USERS"/>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Suponiendo que el SQL este en una variable:
<sql:query var="empleados" sql="${sql}"/>
EJEMPLO, VISUALIZAR APELLIDO Y SALARIO DE TODOS LOS EMPLEADOS:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jstl/sql_rt"%>
<sql:setDataSource driver="sun.jdbc.odbc.JdbcOdbcDriver"url="jdbc:odbc:java_jstl;UID=sa"/>
<sql:update var="n">
DELETE FROM empleados
WHERE apellido = ‘pepe’
</sql:update>
Hemos borrado <c:out value="${n}"/> filas.
sql:param
Utilizado para las consultas preparedStatement, pasar parámetros (?) a consultas preparadas para
ello.
La etiqueta sql:param sustituirá los caracteres ? de las sentencias SQL. Los caracteres ? únicamente
pueden usarse para sustituir un valor (string o número).
No válido para fechas.
Atributo Descripción Requerido Por defecto
value valor del parámetro no cuerpo
<sql:setDataSource driver="sun.jdbc.odbc.JdbcOdbcDriver"url="jdbc:odbc:java_jstl;UID=sa"/>
<sql:update var="ni">
INSERT INTO departamentos VALUES(?,?,?)
<sql:param value="${p_deptno}"/>
<sql:param value="${p_loc}"/>
<sql:param value="${p_dnombre}"/>
</sql:update>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
value fecha a sustituir en sí --
el carácter ?
type time, date, o no timestamp
timestamp
Ejemplo:
<sql:query>
SELECT * FROM emp
WHERE fecha_alt < ?
<sql:dateParam value="${p_fecha}"/>
</sql:query>
sql:transaction
Se usa para lanzar actualizaciones y consultas bajo una transacción. Para ello las sentencias
sql:update y sql:query se colocan como cuerpo de esta etiqueta. Todas las sentencias en una
transacción tienen éxito o fallan como unidad, es decir si alguno de ellos falla se realiza un rollback
de todos, y la base de datos queda como antes de comenzar la transacción.
Ejemplo intentar duplicar registros:
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jstl/sql_rt"%>
<sql:setDataSource driver="sun.jdbc.odbc.JdbcOdbcDriver" url="jdbc:odbc:java_jstl;UID=sa"
var="ORIGEN_EMPLEADOS"/>
<sql:transaction dataSource="${ORIGEN_EMPLEADOS}">
<sql:update>
insert into dept values(11,'Valencia','Astronauta')
</sql:update>
<sql:update>
insert into dept values(11,'Valencia','Astronauta')
</sql:update>
</sql:transaction>
ERROR: No se insertará ninguno de los dos registros, se deshacen las dos consultas.
Formateo
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>
fmt:formatNumber
Funciona como c:out pero permitiendo más control sobre el formato.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
maxIntegerDi Máximo número de dígitos a no ningúno
gits mostrar.
minIntegerDig Mínimo número de dígitos a no ningúno
its mostrar.
maxFractionDi Máximo número de dígitos no ningúno
gits fraccionarios a mostrar.
minFractionDi Mínimo número de dígitos no ningúno
gits fraccionarios a mostrar.
pattern Patrón con el formateo del número. no ningúno
Sigue la convención de
java.util.DecimalFormat.
var Variable en la que grabar el no ningúno
resultado.
scope Ámbito de la anterior variable. no page
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
fmt:formatDate
No acepta valores en el cuerpo. Requiere un atributo value con una variable que represente una
fecha (conviene usar fmt:parseDate). Un modo rápido de crear una variable con una fecha es
instanciar java.util.Date como bean:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
h Hora (1-12). 9
hh Hora (1-12) con dos dígitos. 09
m Minuto. 4
mm Minuto con dos dígitos. 04
s Segundo. 6
ss Segundo con dos dígitos. 06
S Milisegundo. 249
a AM / PM PM
zz Nombre corto de zona horaria. EST
zzzz Zona horaria. Eastern Standard Time
Z Descripción de zona horaria. -0500
'cadena' Cadena a incluir. 'cadena'
Ejemplos de patrones:
Patrón Resultado
yyyy.MM.dd G 'at' HH:mm:ss z 2004.09.05 AD at 18:06:56 CEST
EEE, MMM d, ''yy Sun, Sep 5, '04
h:mm a 6:06 PM
hh 'o''clock' a, zzzz 06 o'clock PM, Central European Summer Time
K:mm a, z 6:06 PM, CEST
yyyyy.MMMMM.dd GGG hh:mm aaa 02004.September.05 AD 06:06 PM
EEE, d MMM yyyy HH:mm:ss Z Sun, 5 Sep 2004 18:06:56 +0200
yyMMddHHmmssZ 040905180656+0200
fmt:parseNumber
Interpreta cadenas como números. Es necesario para pasar valores numéricos a algunas etiquetas
como sql:param, fmt:formatNumber, y otras.
Atributo Descripción Requerido Por defecto
value Cadena a interpretar como no cuerpo
número.
type Como interpretarlo. no number (puede ser number, currency, o
percent)
integerOnly Si descartar decimales. no false
pattern Patrón de formato. no ningúno. Ver SimpleDateFormat.
parseLocale Locale a usar. no
var Variable en la que grabar el no ningúno
resultado.
scope Ámbito de la variable anterior. no page
fmt:parseDate
Interpreta cadenas como fechas.
dateStyle Estilo preferido para la fecha. no default (puede ser default, short,
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Atributo Descripción Requerido Por defecto
medium, long)
fmt:setTimeZone
Permite cambiar la zona horaria:
fmt:timeZone
Permite cambiar temporalmente la zona horaria. Se usa colocando en el cuerpo de la etiqueta, las
instrucciones que queremos que se ejecuten en la nueva zona horaria.
Ningúno.
Identificador de la zona http://www.timeanddate.com
value sí
horaria. /library/abbreviations/timezon
es/
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Laboratorio: Contador de visitas con Custom Tags.
Objetivo
Creación de una etiqueta personalizada.
Enunciado
Realizar una aplicación JSP que incluya un contador de visitas realizado con Customs Tags.
Contador.tld
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.2</jspversion>
<shortname>Benito Floro</shortname>
<tag>
<name>primera</name>
<tagclass>etiquetas.Contador</tagclass>
<bodycontent>empty</bodycontent>
</tag>
</taglib>
Web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app>
<welcome-file-list>
<welcome-file>indice.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>contador</taglib-uri>
<taglib-location>/WEB-INF/etiquetas/contador.tld</taglib-location>
</taglib>
</web-app>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Contador.java
package etiquetas;
import java.io.*;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.http.HttpServletRequest;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
escritor.close();
}
catch( Exception e ) {
throw new JspException( e.getMessage() );
}
}
indice.jsp
<HTML>
<HEAD>
<TITLE>Etiqueta contador</TITLE>
</HEAD>
<BODY bgcolor="navy" text="white">
<%@ taglib uri="contador" prefix="prueba" %>
<H1>La página ha sido visitada <prueba:primera /> veces.</H1>
</BODY>
</HTML>
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 13. Desarrollo de Aplicaciones Web
con la Clase ActionForm de Struts
Objetivos
Trabajar con la clase ActionForm de Struts
Desarrollar aplicaciones Struts con una clase que herede de Action Form.
Introducción
El marco de trabajo Struts generalmente asume que hemos definido un bean ActionForm por cada
formulario de entrada necesario en nuestra aplicación. Los beans ActionForm algunas veces son sólo
llamados "beans formuLario". Si declaramos dichos beans en nuestro fichero de configuración
ActionMapping , el servlet controlador Struts realiza automáticamente los siguientes servicios por
nosotros, antes de llamar al método Action apropiado:
Chequea en la sesión de usuario si hay un ejemplar de un bean de la clase apropiada, bajo la clave
apropiada.
Si no está disponible dicho bean en el ámbio de la sesión, se crea uno nuevo automáticamente y se
añade a la sesión de usuario.
Por cada parámetro de la solicitud cuyo nombre corresponda con el nombre de una propiedad del
bean, se llamará al correspondiente método set(). Esto opera de una forma similar a la acción JSP
estándard cuando usamos el comodín asterisco para seleccionar todas las propiedades.
El bean ActionForm actualizado será pasado al método perform() de la clase Action cuando es
llamado, haciendo que esos valores estén disponibles inmediatamente.
Cuando codifiquemos nuestros beans ActionForm, debemos tener en mente los siguientes principios:
La propia clase ActionForm no requiere que se implemente ningún método específico. Se usa para
identificar el rol que esos beans particulares juegan en la arquitectura general. Normalmente, un
bean ActionForm sólo tendrá metodos setxxx() y getxxx(), sin lógica de negocio.
El objeto ActionForm también ofrece un mecanismo de validación estándard. Si sobreescribimos un
método "stub", y proporcionamos mensajes de error en el recurso de aplicación estándard, Struts
validará automáticamente la entrada del formualrio (usando nuestro método). Ver Validación del
Formulario para más detalles. Por supuesto, también podemos ignorar la validación de ActionForm y
proporcionar nuestro propio objeto Action.
Definir una propiedad (asociada con métodos getXxx() y setXxx()) para cada campo que esté
presente en el formulario. El nombre del campo y el nombre de la propiedad deben corresponder de
acuerdo a las convenciones usuales de los JavaBeans. Por ejemplo, un campo de entrada llamado
username hará que se llame al método setUsername().
Debemos pensar en nuestros beans ActionForm como firewall ente HTTP y el objeto Action. Usamos
el método validate para asegurarnos de que están presentes todas las propiedades requeridas, y
que contienen valores razonables. Un ActionForm que falla en la validación incluso ni será
presentado para el manejo del Action.
También podríamos situar un ejemplar bean en nuestro formulario, y usar referencias a propieades
anidadas. Por ejemplo, podríamos tener un bean "customer" en nuestro Action Form, y luego
referirnos a la propiedad "customer.name" en nuestra vista JSP. Esto correspondería con los
métodos customer.getName() y customer.setName(string Name) de nuestro bean customer.
Si anidamos ejemplares de beans existentes en nuestro formulario, debemos pensar en las
propiedades que exponemos. Cualquier propiedad pública en un ActionForm que acepta un simple
valor String puede seleccionarse con un string de consulta. Podría ser muy útil situar dichos beans
dentro de una fina "envoltura" que exponga sólo las propiedades requeridas. Esta envoltura también
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
puede proporcionar un filtro para asegurarnos en tiempo de ejecución de que las propiedades no se
seleccionan con valores inapropiados.
Deberías haber observado que un "formulario", en el sentido discutido aquí, no corresponde
necesariamente con una sóla página JSP en el interface de usuario. Es común en muchas
aplicaciones tener un "formulario" (desde la perspectiva del usuario) que se extienda sobre múltiples
páginas. Piensa por ejemplo, en un interface de usuario al estilo de los wizard que se utilizan
comunmente cuando instalamos nuevas aplicaciones. Struts nos aconseja definir un sólo ActionForm
que contenga las propiedades de todos los campos, sin importar que página de campo se está
mostrando actualmente. De igual forma, las distintas páginas del mismo formulario deberían ser
reenvidas a la misma clase Action. Si seguimos estas sugerencias, los diseñadores de páginas
podrán reordenar los campos entre varias páginas, frecuentemente sin requerir que cambiemos la
lógica de procesamiento.
Clase ActionForm creada con NetBeans
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En el fichero struts-config.xml el asistente de NetBeans ha añadido el elemento
<form-bean>
<struts-config>
<form-beans>
<form-bean name="TiendaActionForm" type="pqActionForms.TiendaActionForm"/>
</form-beans>
Modificamos el fichero TiendaActionForm para incuir las propiedades nombre y apellido, además de
controlar que el campo nombre y apellido no se queden en blanco.
package pqActionForms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
public TiendaActionForm() {
super();
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
ActionErrors errors = new ActionErrors();
if (getNombre() == null || getNombre().length() < 1) {
errors.add("nombre", new ActionMessage("error.nombre.requerido"));
}
if (getApellido() == null || getApellido().length() < 1) {
errors.add("apellido", new ActionMessage("error.apellido.requerido"));
}
return errors;
}
}
ApplicationResource.propierties
error.nombre.requerido=Nombre obligatorio
error.apellido.requerido=Apellido obligatorio
Creación de un proyecto mvc con struts
TiendaForm.jsp
En esta página insertaremos etiquetas de la librería de Struts Html para rellenar un formulario y
controlar que los datos que se introduzcan sean válidos.
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<title>JSP Page</title>
</head>
<body>
<html:form action="Tienda">
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
errors.header=
errors.prefix=<span style="font-size: 10px; color: red" >
errors.suffix=</span>
errors.footer=
TiendaActionForm
Modificamos el fichero TiendaActionForm para incuir las propiedades nombre y apellido, además de
controlar que el campo nombre y apellido no se queden en blanco.
package pqActionForms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
public TiendaActionForm() {
super();
}
TiendaAction
Esta clase sería la encargada de recoger los datros del formulario e insertarlos en la base de datos:
public ActionForward execute(ActionMapping mapping, ActionForm form,
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
HttpServletRequest request, HttpServletResponse response)
throws Exception {
return mapping.findForward(SUCCESS);
ESPAÑOL:
INGLÉS:
SeleccionarIdioma.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"
import="org.apache.struts.Globals, java.util.Locale"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<title>JSP Page</title>
</head>
<body bgcolor="#FF2400">
<%
Locale locale = null;
ApplicationResource.properties
literal.cambiarIdioma.español=Español
literal.cambiarIdioma.ingles=Ingles
literal.registroUsuario=Registro de usuario
ApplicationResource_en.properties
literal.cambiarIdioma.español=Spanish
literal.cambiarIdioma.ingles=English
literal.registroUsuario=User registry
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 14. Construcción de Componentes de
Presentación Web Reutilizables
Objetivos
Uso de la capa de presentación en desarrollos Struts
Desarrollar aplicaciones utilizando Struts Tiles.
Introducción
La librerías de Stuts que podemos utilizar en la presentación se describen a continuación:
struts-tiles:
Contiene etiquetas que definen un mecanismo de plantillas.
struts-bean:
Contiene etiquetas útiles para acceder a los beans y sus propiedades, así como para definir nuevos
beans que son accesibles para el resto de la página mediante variables de scripting y atributos de
ámbito de página.
struts-html:
Contiene etiquetas para crear formularios de entrada struts, así como otras etiquetas generalmente
útiles en la creación de interfaces de usuario basados en HTML.
struts-logic:
Contiene etiquetas que son útiles para manejar la generación condicional de salida de texto, hacer
bucles sobre colecciones de objetos para generación repetitiva de salida de texto y control del flujo
de la aplicación.
Apreciamos en la imagen como en un proyecto Struts se agregan las TLD de las librerías de
etiquetas de Struts.
La librería struts-bean contiene etiquetas útiles para acceder a los beans y sus propiedades, así
como para definir nuevos beans (basados en esos accesores) que son accesibles para el resto de la
página mediante variables de scripting y atributos de ámbito de página. También se proporcionan
mecanismos convenientes para crear nuevos beans basados en el valor de una cookie, de las
cabeceras y de los parámetros.
La librería struts-html contiene etiquetas para crear formularios de entrada struts, así como otras
etiquetas generalmente útiles en la creación de interfaces de usuario basados en HTML.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
La librería struts-logic contiene etiquetas que son útiles para manejar la generación condicional
de salida de texto, hacer bucles sobre colecciones de objetos para generación repetitiva de salida de
texto y control del flujo de la aplicación.
La librería struts-template contiene etiquetas que definen un mecanismo de plantillas.
Abajo podemos ver cómo se definirían todas las librerías de etiquetas para usarlas en nuestra
aplicación, en realidad, sólo deberíamos especificar las librerías que vayamos a utilizar:
<taglib>
<taglib-uri>
/WEB-INF/struts-bean.tld
</taglib-uri>
<taglib-location>
/WEB-INF/struts-bean.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
/WEB-INF/struts-html.tld
</taglib-uri>
<taglib-location>
/WEB-INF/struts-html.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
/WEB-INF/struts-logic.tld
</taglib-uri>
<taglib-location>
/WEB-INF/struts-logic.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
/WEB-INF/struts-template.tld
</taglib-uri>
<taglib-location>
/WEB-INF/struts-template.tld
</taglib-location>
</taglib>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Campos de entrada de texto text
textareas
En cada caso, una etiqueta de campo debe estár anidada dentro de una etiqueta form, por eso los
campos saben qué bean utilizar para inicializar los valores mostrados.
[bean] parameter recupera el valor del parámetro solicitado, y define el resultado como un atributo
de ámbito de página del tipo String o String[].
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</HTML>
Utilizar Tiles
Cuando construimos un Web, podemos considerar que éste está formado por una o varias plantillas
en la que únicamente cada página cambia una porción (normalmente central) del contenido
mostrado respecto a las restantes. La plantilla normalmente contiene un menú, publicidad,
cabeceras, pies, etc.
Tiles permite separar el diseño del contenido, insertando el contenido de forma dinámica.
Las principales características de Tiles se describen a continuación:
Existe la posibilidad del uso de las mencionadas plantillas.
Construcción y carga de páginas dinámicas.
Internacionalización.
Definición de plantillas.
Principales etiquetas Tiles
Nombre Descripción
add Añade un elemento a la lista
definition Crea una definición de componente Title
get Obtiene el contenido del ámbito de
petición que situó allí una etiqueta put.
getAsString Muestra el valor del atributo de
title/componente/plantilla especificado
para el JSPWriter actual.
importAttribute Importa un atributo de title en el
contexto especificado.
initComponentDefinitions Inicializa un factory de definiciones title
Insert Inserta un componente title
put Sitúa un atributo en un contexto
putList Declara una lista que se pasará como un
atributo
useAttribute Utiliza un valor de atributo dentro de
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
una página
Etiqueta Insert
La etiqueta insert es responsable de insertar contenido en una página. En un title de diseño, la
etiqueta insert prescribe dónde irá el contenido utilizando valores de atributo.
Tabla de atributos de la etiqueta insert
Nombre Descripción
atrribute El nombre de un atributo en el contexto
title/componente actual.
beanName El nombre del bean utilizado como un
valor. El bean se recupera del contexto
especificado.
beanProperty El nombre de la propiedad del bean.
beanScope El ámbito del contexto dónde se puede
utilizar el bean.
component Un string que representa el URI de un
title.
controllerURL El URL del controlador llamado
inmediatamente antes de que se inserte
la página.
controlerClass El tipo de clase del controlador
definition El nombre de la definición a insertar.
Las definiciones se definen en un
archivo centralizado.
flush Bolean. True si el flujo de salida de la
página actual se borra antes de la
inserción del title.
ignore True y el name no existe, regresa sins
escribir nada.
name El nombre de una entidad a insertar.
page String que representa el URI de un title
o plantilla.
role Si el usuario está en el rol especificado,
la etiqueta se tiene en cuenta; de lo
contrario, la etiqueta se salta y el
contenido no se escribe.
template String que representa el URI de un title
o plantilla. Mismo comportamiento que
page y component.
Etiqueta put
La etiqueta put se utiliza para pasar atributos a un componente title. Esta etiqueta se puede utilizar
solamente dentro de las etiquetas insert o definitions.
Tabla de atributos de la etiqueta put
Nombre Descripción
beanName El nombre del bean utilizado para
recuperar el valor.
beanProperty El nombre de propiedad en el bean.
beanScope El ámbito del contexto dónde se puede
utilizar el bean.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ejemplo de uso de plantillas
Plantilla.jsp
En este archivo definimos como debe quedar la plantilla de nuestro sitio web.
Definimos con la etiqueta getAsString donde colocaremos el título de la página:
<tiles:getAsString name="titulo" />
Definimos con la etiqueta insert donde colocaremos el cuerpo:
<tiles:insert attribute="cuerpo"/>
<%@page contentType="text/html"%>
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>
<html>
<head><title><tiles:getAsString name="titulo" /></title></head>
<body>
<div align="center">
<center>
<table border="1" cellpadding="2" style="border-collapse:
collapse; border-width: 0" bordercolor="#111111" id="AutoNumber1" width="800">
<tr>
<td width="773" style="border-style: none; border-width: medium" colspan="3">
LOGOS EMPRESA
</td>
</tr>
<tr>
<td width="140" style="border-style: none; border-width: medium">
</td>
<td width="508" style="border-style: none; border-width: medium">
Mensajes
</td>
<td width="117" style="border-style: none; border-width: medium">
login
</td>
</tr>
<tr>
<td width="140" style="border-style: none; border-width: medium">
menu
</td>
<td width="508" style="border-style: none; border-width: medium">
<tiles:insert attribute="cuerpo"/>
</td>
<td width="117" style="border-style: none; border-width: medium">
otros
</td>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</tr>
</table>
</center>
</div>
</body></html>
Index.jsp
Será la página principal de nuestro sitio web, se encargará de utilizar la plantilla previamente
creada.
Introduciremos un valor en las etiquetas titulo e insert.
Titulo: Mostraremos el mensaje de nuestra página principal.
Cuerpo: Indicaremos que el contenido de la página principal se inserte en la etiqueta definida con el
nombre cuerpo.
<%@page contentType="text/html"%>
<html>
<head><title><tiles:getAsString name="titulo" /></title></head>
<body>
<div align="center">
<center>
<table border="1" cellpadding="2" style="border-collapse:
collapse; border-width: 0" bordercolor="#111111" id="AutoNumber1" width="800">
<tr>
<td width="773" style="border-style: none; border-width: medium" colspan="3">
<a href="http://www.infoservicios.es/">
<img src="imagenes/logoinfostruts.jpg" border="0" width="571" height="77">
</a><a href="http://www.infoempleo.com">
<img src="imagenes/LOGOARRIBA2.GIF" border="0" width="179" height="77">
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</a></td>
</tr>
<tr>
<td width="140" style="border-style: none; border-width: medium">
</td>
<td width="508" style="border-style: none; border-width: medium">
Mensajes
</td>
<td width="117" style="border-style: none; border-width: medium">
login
</td>
</tr>
<tr>
<td width="140" style="border-style: none; border-width: medium">
menu
</td>
<td width="508" style="border-style: none; border-width: medium">
<tiles:insert attribute="cuerpo"/>
</td>
<td width="117" style="border-style: none; border-width: medium">
otros
</td>
</tr>
</table>
</center>
</div>
<br><br><br><b>
<tiles:getAsString name="copyright" /></b>
</body>
</html>
Página que especifica la plantilla a utilizar (IndexTiles2.jsp)
<%@page contentType="text/html"%>
<%@taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-tiles" prefix="tiles" %>
<bean:define id="copyright" value="copyright 2010 Viva JAVA s.l.,Todos los derechos reservados"
type="String" toScope="request" />
</tiles:insert>
Página que rellenará el cuerpo (tiles/hometiles.jsp)
<table border="1" cellpadding="2" style="border-collapse: collapse"
bordercolor="#111111" width="100%" id="AutoNumber2">
<tr>
<td width="100%"><i><b><font size="6" color="#0000FF">Home</font></b></i><p>
Aquí va a ir el cuerpo de la nueva home
</td>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</tr>
</table>
IndexLibros.jsp
<%@ page import="Libros.*" %>
<ol>
<h2>LISTADO DE LIBROS MÁS VENDIDOS:</h2>
<logic:iterate id="misLibros" collection="<%= libros %>">
</logic:iterate>
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
</ol>
</body>
</html>
Libros.java
package Libros;
import java.util.Vector;
public Libro()
{
}
Actividades
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.