4. Contexto global de la aplicación web
Vamos a estudiar los elementos que podemos utilizar para establecer una comunicación entre los distintos componentes de una aplicación web, tanto entre distintos servlets como entre servlets y otros elementos de la aplicación.
4.1. Contexto de los servlets
Comenzaremos estudiando el contexto de los servlets (Servlet Context).
Este objeto de contexto es propio de cada aplicación web, es
decir, tendremos un objeto ServletContext
por aplicación
web, por lo que nos servirá para comunicar los servlets de dicha
aplicación.
public void init(ServletConfig config)
En la inicialización del servlet (método init
), se
nos proporcionará un objeto ServletConfig
como parámetro.
Mediante este objeto podemos:
-
Obtener el nombre del servlet, que figurará en el descriptor de despliegue de la aplicación web (
web.xml
en Tomcat).String nombre = config.getServletName();
-
Obtener los valores de los parámetros de inicialización del servlet, que se hayan establecido en el descriptor de despliegue. Tanto los nombres como los valores de los parámetros son cadenas de texto (
String
).String valor_param = config.getInitParameter(nombre_param); Enumeration nombres_params = config.getInitParameterNames();
-
Acceder al objeto de contexto de la aplicación a la que pertenece el servlet.
ServletContext context = config.getServletContext();
Esta última función es la más importante, ya que nos permite acceder al objeto de contexto global de la aplicación, con el que podremos realizar una serie de operaciones que veremos a continuación.

Tanto el objeto ServletConfig
como ServletContext
pueden ser obtenidos directamente desde dentro de nuestro servlet llamando
a los métodos getServletConfig
y getServletContext
respectivamente, definidos en GenericServlet
,
y por lo tanto disponibles en cualquier servlet.
4.1.1. Atributos de contexto
Dentro del objeto de contexto de nuestra aplicación podremos establecer
una serie de atributos, que serán globales dentro de ella. Estos
atributos son un conjunto de pares <nombre, valor> que
podemos establecer y consultar desde los distintos servlets de nuestra
aplicación web. El nombre del atributo será una cadena
de texto (String
), mientras que el valor podrá ser cualquier
objeto java (Object
).
Para consultar el valor de un atributo utilizaremos:
Object valor = context.getAttribute(nombre);
Daremos valor a un atributo con:
context.setAttribute(nombre, valor);
Podemos también eliminar un atributo:
context.removeAttribute(nombre);
Lo cual dejará el atributo a null
, igual que si nunca le
hubiesemos asignado un valor. Por último, con
Enumeration enum = context.getAttributeNames();
Obtenemos la lista de nombres de atributos definidos en el contexto.
Hay que hacer notar en este punto, que el objeto de contexto a parte de ser propio de cada aplicación web, es propio de cada máquina virtual Java. Cuando trabajemos en un contexto distribuido, cada máquina ejecutará una VM distinta, por lo que tendrán también objetos de contexto diferentes. Esto hará que si los servlets de una aplicación se alojan en máquinas distintas, tendrán contextos distintos y este objeto ya no nos servirá para comunicarnos entre ellos. Veremos más adelante formas alternativas de comunicación para estos casos.
4.1.2. Parámetros de inicialización
El objeto ServletConfig
nos proporcionaba acceso a los parámetros
de inicialización del servlet en el que nos encontramos. Con
ServletContext
, tendremos acceso a los parámetros de inicialización
globales de nuestra aplicación web. Los métodos para obtener
dichos parámetros son análogos a los que usabamos en ServletConfig
:
String valor_param = context.getInitParameter(nombre_param);
Enumeration nombres_params = context.getInitParameterNames();
4.1.3. Acceso a recursos estáticos
Este objeto nos permite además acceder a recursos estáticos alojados en nuestro sitio web. Utilizaremos los métodos:
URL url = context.getResource(nombre_recurso);
InputStream in = context.getResourceAsStream(nombre_recurso);
El nombre del recurso que proporcionamos será una cadena que comience
por "/"
, lo cual indica el directorio raiz dentro del contexto
de nuestra aplicación, por lo tanto serán direcciones relativas
a la ruta de nuestra aplicación web.
El primer método nos devuelve la URL de dicho recurso, mientras que el segundo nos devuelve directamente un flujo de entrada para leer dicho recurso.
Hay que señalar que esto nos permitirá leer cualquier recurso
de nuestra aplicación como estático. Es decir, si proporcionamos
como recurso "/index.jsp"
, lo que hará será leer
el código fuente del JSP, no se obtendrá la salida procesada
que genera dicho JSP.
Podemos también obtener una lista de recursos de nuestra aplicación web, con:
Set recursos = context.getResourcePaths(String ruta);
Nos devolverá el conjunto de todos los recursos que haya en la ruta indicada (relativa al contexto de la aplicación), o en cualquier subdirectorio de ella.
4.1.4. Redirecciones
Si lo que queremos es acceder a recursos dinámicos, el método
anterior no nos sirve. Para ello utilizaremos estas redirecciones. Utilizaremos
el objeto RequestDispatcher
que nos proporciona ServletContext
.
Hemos de distinguir estas redirecciones de la que se producen cuando ejecutamos
response.sendRedirect();
Con sendRedirect
lo que estamos haciendo es devolver al cliente
una respuesta de redirección. Es decir, será el cliente,
quien tras recibir esta respuesta solicite la página a la que
debe redirigirse.
Con RequestDispatcher
es el servidor internamente quien solicita
el recurso al que nos redirigimos, y devuelve la salida generada por
éste al cliente, pero todo ello de forma transparente al cliente.
En cliente no sabrá en ningún momento que se ha producido
una redirección.
Para obtener un objeto RequestDispatcher
podemos usar los siguientes
métodos de ServletContext
:
RequestDispatcher rd = context.getRequestDispatcher(ruta);
RequestDispatcher rd = context.getNamedDispatcher(ruta);
Como ruta proporcionaremos la ruta relativa al contexto de nuestra aplicación,
comenzando por el carácter "/"
, del recurso al que nos
queramos redirigir. También podemos obtener este objeto proporcionando
una ruta relativa respecto al recurso actual, utilizando para ello el
método getRequestDispatcher
del objeto ServletRequest
,
en lugar de ServletContext
:
RequestDispatcher rd = request.getRequestDispatcher(ruta);
Podemos utilizar el RequestDispatcher
de dos formas distintas:
llamando a su método include
o a forward
.
rd.include(request, response);
El método include
incluirá el contenido generado
por el recurso al que redireccionamos en la respuesta, permitiendo que
se escriba este contenido en el objeto ServletResponse
a continuación
de lo que se haya escrito ya por parte de nuestro servlet. Se podrá
llamar a este método en cualquier momento. Lo que no podrá
hacer el recurso al que redireccionamos es cambiar las cabeceras de
la respuesta, ya que lo único que estamos haciendo es incluir
contenido en ella. Cualquier intento de cambiar cabeceras en la llamada
a include será ignorado.
Si hemos realizado la redirección utilizando un método getRequestDispatcher
(no mediante getNamedDispatcher
), en la petición del servlet
al que redireccionamos podremos acceder a los siguientes atributos:
javax.servlet.include.request_uri
javax.servlet.include.context_path
javax.servlet.include.servlet_path
javax.servlet.include.path_info
javax.servlet.include.query_string
Con los que podrá consultar la ruta desde donde fué invocado.
rd.forward(request, response);
El método forward
sólo podrá ser invocado
cuando todavía no se ha escrito nada en la respuesta del servlet.
Esto es así porque esta llamada devolverá únicamente
la salida del objeto al que nos redirigimos. Si esto no fuese así,
se produciría una excepción IllegalStateException
.
Una vez el método forward
haya devuelto el control, la
salida ya habrá sido escrita completamente en la respuesta.
Si el recurso al que redireccionamos utiliza direcciones relativas, estás
direcciones se considerarán relativas al servlet que ha hecho
la redirección, por lo que si se encuentran en rutas distintas
se producirá un error. Tenemos que hacer que las direcciones sean
relativas a la raiz del servidor para que funcione correctamente (direcciones
que comiencen por "/"
).
4.1.5. Otros métodos
La clase ServletContext
nos proporciona otros métodos de
utilidad, que podremos consultar accediendo a su documentación
JavaDoc.
Un método de interés es log
, que nos permite escribir
texto en el fichero de log del servlet:
context.log(mensaje);
Esto será util para tener un registro de eventos que ocurren en nuestra web, o bien para depurar errores.
4.1.6. Listeners de contexto
Existen objetos que permanecen a la escucha de los distintos eventos que pueden
ocurrir en el objeto de contexto de servlets, ServletContext
.
Un primer listener, es el ServletContextListener
, que nos permitirá
dar respuesta a los eventos de creación y destrucción del contexto
del servlet. El código para este listener será como sigue a continuación:
import javax.servlet.*;
@WebListener
public class MiContextListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent sce) {
// Destruccion del contexto
}
public void contextInitialized(ServletContextEvent sce) {
// Inicialización del contexto
}
}
Esto nos será de gran utilidad si necesitamos inicializar ciertas estructuras de datos que van a utilizar varios servlets. De esta forma el contexto se habrá inicializado antes de que los servlets puedan ejecutarse.
Si lo que queremos es saber cuando se ha añadido, eliminado, o modificado
alguno de los atributos del contexto global, podemos utilizar un listener
ServletContextAttributeListener
. Los métodos que deberemos
definir en este caso son los siguientes:
import javax.servlet.*;
@WebListener
public class MiContextAttributeListener
implements ServletContextAttributeListener {
public void attributeAdded(ServletContextAttributeEvent scae) {
// Se ha añadido un nuevo atributo
}
public void attributeRemoved(ServletContextAttributeEvent scae) {
// Se ha eliminado un atributo
}
public void attributeReplaced(ServletContextAttributeEvent scae) {
// Un atributo ha cambiado de valor
}
}
Hemos visto que podemos declarar listeners mediante la anotación
@WebListener
. Con esto el servidor de aplicaciones reconocerá estas clases
como listeners del contenedor web y los registrará de forma automática sin necesidad de hacerlo
nosotros. Los listeners que podremos declarar de esta forma son:
-
ServletContextListener
-
ServletContextAttributeListener
-
ServletRequestListener
-
ServletRequestAttributeListener
-
HttpSessionListener
-
HttpSessionAttributeListener
Sin embargo, esta anotación sólo está disponible a partir de la API de Servlets 3.0. En versiones anteriores
para hacer que estos objetos se registren como listeners y permanezcan
a la escucha, deberemos registrarlos como tales en el descriptor de despliegue
de la aplicación (web.xml
.). Para ello deberemos añadir un elemento <listener>
para cada objeto listener que queramos registrar:
<listener>
<listener-class>MiContextListener</listener-class>
</listener>
<listener>
<listener-class>MiContextAttributeListener</listener-class>
</listener>
Esta declaración no es necesaria si estamos utilizando la anotación @WebListener
en
Servlet 3.0.
4.1.7. Declaración dinámica de servlets
En Servlet 3.0 también tenemos la opción de configurar nuestros servlets de forma programática durante la inicialización del contexto, e incluso declarar servlets que no habían sido declarados previamente:
@WebListener
public class MiListener implements ServletContextListener {
public void contextInitialized (ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
// Declara un nuevo servlet y lo configura
ServletRegistration servletNuevo = sc.addServlet("miServlet",
"es.ua.jtech.servlet.MiServlet");
servletNuevo.addMapping("/UrlServlet");
// Obtiene un servlet ya declarado para configurarlo
ServletRegistration sr = sc.addServlet("otroServlet");
sr.addMapping("/UrlOtroServlet");
sr.setInitParameter("param1", "valor1");
}
}
Por lo tanto, en Servlet 3.0 podemos declarar los servlets de tres formas distintas:
-
En el descriptor de despliegue
web.xml
. -
Mediante anotaciones en la propia clase del servlet.
-
De forma programática en la inicialización del contexto.
4.2. Inyección de dependencias
Los objetos de una aplicación normalmente necesitan otros objetos para realizar su tarea. Por ejemplo, un servlet puede necesitar una fuente de datos de la que obtener la información a mostrar al cliente web. Tradicionalmente, este servlet deberá obtener el objeto del que depende, por ejemplo buscando la fuente de datos en JNDI. El patrón de inyección de dependencias (DI) consiste en invertir este comportamiento: no será el servlet quién busque la fuende de datos, sino que la fuente de datos le será inyectada al servlet de forma externa. Las ventajas de este patrón son el bajo acoplamiento existente entre el servlet y los objetos de los que depende, y la facilidad para cambiar la implementación de la dependencia sin tener que modificar el código del servlet. Por ejemplo, esto facilitará las pruebas, ya que podremos sustituir la fuente de datos original por un mock sin tener que hacer ningún cambio en el código del servlet.
En Java SE 6 se integra la inyección de dependencias mediante la especificación Contexts and Dependency Injection (CDI, JSR-299). La implementación de referencia de CDI se denomina Weld (http://seamframework.org/Weld).
4.2.1. Configuración de Weld
Weld ya se encuentra integrado en la API de Java EE 7, por lo que no es necesario añadir esta librería como dependencia de forma explícita, a no ser que estuviésemos utilizando un contenedor web que no soporte la especificación completa de Java EE.
Para poder utilizar objetos CDI deberemos añadir un fichero beans.xml
al directorio
WEB-INF
de nuestra aplicación web. Dicho fichero puede estar vacío, pero al menos debe existir. Si no
queremos dejarlo vacío, podemos utilizar la siguiente plantilla inicial:
<?xml version="1.0" encoding="UTF-8"?>
<beans 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/beans_1_0.xsd">
</beans>
Podemos crear este fichero desde IntelliJ pulsando con el botón derecho sobre el directorio WEB-INF y seleccionando New > XML Configuration File > CDI beans.xml.
|

4.2.2. Managed beans
Podemos inyectar distintos tipos de objetos, como fuentes de datos, contextos de persistencia JPA, o casi cualquier objeto Java plano (POJOs). Nos referiremos a los objetos que inyectamos como managed beans.
Casi cualquier clase Java puede ser un managed bean, sin ser necesario anotarla de ninguna forma. Para que una clase pueda comportarse como managed bean debe cumplir lo siguiente:
-
No puede ser una clase interna, a no ser que sea de tipo
static
. -
Tiene un constructor sin parámetros.
-
No tiene constructor sin parámetros, pero tiene un constructor anotado con
@Inject
.
Por ejemplo, el siguiente POJO podría ser inyectado como managed bean:
public class HolaMundo {
public String saluda(String nombre) {
return "Hola " + nombre;
}
}
4.2.3. Inyección de objetos
Para inyectar un bean utilizamos la etiqueta @Inject
. Vamos a ver el caso en el que se inyecta
en un servlet, aunque podría inyectarse en cualquier otra clase (incluso dentro de otro managed bean):
@WebServlet(urlPatterns = "/miServlet")
public class MiServlet extends HttpServlet {
@Inject
private HolaMundo holaMundo;
}
El tiempo de vida del objeto inyectado dependerá del ámbito en el que se defina.
4.2.4. Ámbito de los beans
Los managed beans pueden existir en distintos ámbitos. Según el ámbito especificado mantendrá su estado durante un tiempo diferente:
Ámbito | Descripción |
---|---|
|
Se mantiene durante el tiempo que dure la petición ( |
|
Se mantiene durante el tiempo que dure la sesión ( |
|
Se mantiene durante toda la vida de la aplicación web (contexto). Será accesible por todas las peticiones de todas las sesiones. |
|
Es el valor por defecto. Se mantiene con vida mientras exista el objeto en el que se ha inyectado. |
Por ejemplo, podemos etiquetar el bean anterior para que sólo se mantenga con vida durante el tiempo que dure la petición de la siguiente forma:
@RequestScoped
public class HolaMundo {
public String saluda(String nombre) {
return "Hola " + nombre;
}
}
Para que un managed bean anotado con @SessionScoped funcione correctamente
deberemos hacer que sea Serializable . De no ser así, obtendremos el mensaje de error
Managed bean declaring a passivating scope must be passivation capable.
|
4.2.5. Clasificadores
Podemos crear varias versiones de un bean, y distinguirlas mediante lo que se conoce como clasificadores (qualifiers
).
Podemos definir clasificadores de la siguiente forma:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Dia {}
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Tarde {}
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Noche {}
Podríamos crear distintas versiones del bean HolaMundo
, y etiquetar cada una de ellas con
un clasificador distinto:
@Dia
public class HolaMundoDia extends HolaMundo {
public String saluda(String nombre) {
return "Buenos días " + nombre;
}
}
@Tarde
public class HolaMundoTarde extends HolaMundo {
public String saluda(String nombre) {
return "Buenas tardes " + nombre;
}
}
@Noche
public class HolaMundoNoche extends HolaMundo {
public String saluda(String nombre) {
return "Buenas noches " + nombre;
}
}
Si un bean no lleva clasificador, se entiende que por defecto tiene el clasificador @Default
.
También podemos etiquetar alguna de las versiones de forma explícita con este clasificador por defecto.
Cuando inyectamos el bean, podemos indicar qué versión queremos inyectar mediante el clasificador:
@WebServlet(urlPatterns = "/miServlet")
public class ItemServlet extends HttpServlet {
@Inject @Tarde
private HolaMundo holaMundo;
}
Si no indicamos clasificador, se buscará la versión @Default
, de la misma forma que si hiciésemos:
@WebServlet(urlPatterns = "/miServlet")
public class ItemServlet extends HttpServlet {
@Inject @Default
private HolaMundo holaMundo;
}
4.2.6. Productores
Podemos definir métodos que produzcan objetos para ser inyectados. De esta forma podemos definir la forma de obtener los objetos a inyectar. Hasta ahora, al inyectar un objeto lo que se hacía era construir una nueva instancia del objeto utilizando alguno de sus constructores, e inyectar dicha instancia. Utilizando un método productor podremos construir los objetos de otras formas.
Por ejemplo, nos puede ser útil para definir una fuente de datos:
public @interface FuenteDatos {}
public class ProductorConexiones {
@Produces @FuenteDatos
public Connection getConnection() throws Exception {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/miBD");
return ds.getConnection();
}
}
Podemos inyectar las conexiones producidas por la anterior fuente de datos:
@Inject @FuenteDatos Connection conexion;
De esta forma inyectamos objetos Connection
generados por una fuente de datos, que no son
instanciados utilizando un constructor, sino una factoría, y que por lo tanto no podían ser inyectados
como se ha visto anteriormente.
4.2.7. Definición de alternativas
Podemos definir distintas implementaciones alternativas para los beans a inyectar, de forma que en tiempo de despliegue podamos cambiar la implementación que se va a utilizar. Esto es especialmente útil para la implementación de pruebas. Por ejemplo, si tenemos el siguiente bean:
public class FuenteDatos implements IFuenteDatos
Podemos definir una implementación alternativa que contenga un mock
para realizar pruebas:
@Alternative
public class MockFuenteDatos implements IFuenteDatos
Por defecto siempre se utilizará la implementación original, a no ser que en el fichero beans.xml
indiquemos el nombre de la implementación alternativa:
<beans 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/beans_1_0.xsd">
<alternatives>
<class>es.ua.jtech.MockFuenteDatos</class>
</alternatives>
</beans>
En este caso, para usar el mock deberemos incluir el fichero beans.xml
que así lo indique.
También podemos crear la clase alternativa como una especialización:
@Specializes
public class MockFuenteDatos extends FuenteDatos
En este caso la especialización siempre sustituirá a la original. De esta forma, si incluimos la especialización en el carpeta de fuente de prueba (test), cuando incluyamos dichas clases en la aplicación siempre se usará el mock, mientras que en el caso de compilar únicamente las clases de la carpeta main para poner la aplicación en producción, se utilizará la implementación original. Esta es una forma sencilla de sustituir clases por mock en nuestras pruebas.
4.3. Ejercicios
4.3.1. Ejemplo de contexto (0 puntos)
Vamos a probar la aplicación cweb-contexto
incluida en los ejercicios de la sesión.
a) Desplegar la aplicación web en Tomcat, y acceder a la dirección:
http://localhost:8080/cweb-contexto
Veremos la aplicación web ya en marcha.
b) La aplicación web nos permite visualizar los atributos de contexto definidos y sus valores, y añadir nuevos atributos. A parte de los atributos que nosotros añadimos manualmente, ¿hay más atributos de contexto definidos?
c) Podemos añadir nuevos atributos de contexto. Daremos un nombre del atributo, y un texto que contendrá como valor. Además como valor también se introducirá el identificador de sesión del navegador que haya creado dicho atributo. Abrir distintos navegadores y añadir atributos de contexto desde cada uno. Comprobar que en cada navegador vemos tanto los atributos creados en su sesión, como lo atributos creados creados en las sesiones de otros navegadores (el identificador de sesión será distinto).
d) Si nos fijamos en el paquete org.expertojava.cweb.contexto.listener
, veremos
que se ha añadido un listener sobre los atributos del contexto. Este
listener imprime mensajes en el log indicando cuando se añade,
elimina o reemplaza un atributo de contexto. Comprobar en el fichero de logs
correspondiente que se han registrado los cambios en los atributos que hayamos hecho.
4.3.2. Chat con servlets (0.7 punto)
Vamos a realizar una aplicación de chat utilizando
servlets. En el directorio cweb-chat
de los fuentes de la
sesión podrás encontrar la base sobre la que construiremos
el chat. Cada mensaje de chat estará encapsulado en la clase Mensaje
,
y la lista de mensajes actual del chat se encontrará en la clase
ColaMensajes
.
Además se proporcionan los ficheros HTML necesarios
para la aplicación. El fichero index.html
contiene
el formulario de login para que un usuario introduzca el nick
con el que entrará en el chat (no se solicita ningún password
para validar). El login se hará efectivo por el servlet LoginUsuarioServlet
también proporcionado, que introducirá el nick
del usuario en la información de sesión y nos redirigirá
al chat. En el subdirectorio chat
tendremos los ficheros estáticos del chat:
|
Página principal de los frames de la aplicación chat. Mostrará un frame con el formulario para enviar mensajes, y otro con la lista de mensajes enviados. |
|
Formulario para enviar mensajes al chat. |
|
Página que nos muestra un mensaje de error cuando se intenta enviar un mensaje sin haber hecho login. |
|
Cabecera de la tabla de mensajes, a incluir al comienzo de la página de lista de mensajes. |
|
Pie de la tabla de mensajes, a incluir al final de la página de lista de mensajes. |
Ahora deberemos implementar los servlets para el envio de mensajes y para la consulta de la lista de mensajes enviados. Se pide:
a) La cola de mensajes será el objeto común al que acceden
los servlets para el envio y la consulta de estos mensajes. Por lo tanto
el objeto deberá añadirse como atributo del contexto.
Esto lo tendremos que hacer antes de que cualquier servlet se haya ejecutado.
Para ello debemos crear un objeto ServletContextListener
que en la creación del contexto inicialice la cola de mensajes
(ColaMensajes
) y la introduzca como atributo en el
contexto global (atributo org.expertojava.cweb.chat.mensajes
).
b) Una vez tenemos creada la cola de mensajes, deberemos implementar el servlet
EnviaMensajeServlet
, que tome un mensaje como parámetro (el nombre
del parámetro es texto
), y lo añada a la lista de mensajes
con el nick del usuario actual (obtenido del atributo org.expertojava.cweb.chat.nick
de la
sesión). Una vez enviado el mensaje, mostraremos en la salida el contenido
de enviaMensaje.html
, mediante un objeto RequestDispatcher
. Si
no hubiese ningún usuario en la sesión, no se registrará el mensaje y se deberá
redirigir la salida a error.html
c) Por último, deberemos implementar el servlet ListaMensajesServlet
que mostrará todos los mensajes del chat. Este servlet debe:
-
Para que la lista de mensajes se actualice periodicamente en el cliente, haremos que se recargue cada 5 segundos. Añadir la cabecera HTTP correspondiente a la respuesta para que esto ocurra (cabecera
Refresh
, indicando como valor el número de segundos que tardará en recargar). -
Incluir el contenido del fichero estático
cabecera.htmlf
al comienzo del documento generado, ypie.htmlf
al final, para enmarcar la zona donde aparecen los mensajes del chat.Se debe obtener el PrintWriter
para escribir la respuesta antes de hacer el primerinclude
, ya que de lo contrario se obtendría una excepción de tipoIllegalStateException
. Esto de debido a que elinclude
ya habría obtenido previamente el flujo de salida de la respuesta. -
Obtener el nick del usuario actual de la sesión. Los mensajes enviados con este nick se mostrarán en negrita, el resto se mostrarán de forma normal.
d) Comprobar que el chat funciona correctamente. Conectar desde varios clientes a un mismo servidor.
4.3.3. Inyección de dependencias (0.3 puntos)
Utiliza inyección de dependencias para gestionar la cola de mensajes del chat anterior. En este caso:
-
Deberás configurar correctamente los ficheros
web.xml
ybeans.xml
. -
Deberás crear un bean que gestione la cola de mensajes del chat.
-
Deberás especificar el ámbito adecuado en el bean anterior.
-
Ya no será necesario utilizar un listener del contexto para inicializarla, se inicializará la primera vez que se inyecte.
-
Ya no será necesario acceder al atributo de contexto con la cola de mensajes. La cola será inyectada en los servlets.