Documentos de Académico
Documentos de Profesional
Documentos de Cultura
1 Tutorial de servlets
Introducción (1)
Un servlet es una clase Java que puede recibir
peticiones (normalmente HTTP) y generar una salida
(normalmente HTML, WML o XML)
Los servlets que conforman una aplicación web se
ejecutan en un servidor de aplicaciones web
(contenedor)
Cada servlet se puede asociar a una o más URLs
Paquetes javax.servlet y
javax.servlet.http
Introducción (y 2)
Hasta la aparición de JSP, el uso principal de los
servlets era generar la vista de una aplicación web
Recibir petición HTTP asociada a una URL
Leer parámetros
Invocar operación sobre el modelo
Generar salida HTML
Motivos para aprender servlets
Para usar JSP y Struts es preciso conocer parte del API de
los servlets, dado que aunque JSP y Struts están en un nivel
superior, no ocultan el API de los servlets
Son útiles para implementar el controlador de una aplicación
web
Apache Struts proporciona un servlet genérico que constituye
la parte principal del controlador
Visión global del framework de servlets (1)
<<interface>>
javax.servlet.Servlet
javax.servlet.GenericServlet
javax.servlet.http.HttpServlet
<<interface>> <<interface>>
javax.servlet.ServletRequest javax.servlet.ServletResponse
<<interface>> <<interface>>
javax.servlet.http.HttpServletRequest javax.servlet.http.HttpServletResponse
Visión global del framework de servlets (3)
javax.servlet.http.HttpServletRequest
getParameter
Permite obtener el valor de un parámetro univaluado
getParameterValues
Permite obtener el valor de un parámetro multivaluado
También se puede usar con parámetros univaluados
IMPORTANTE: cuando el usuario no selecciona ningún valor
(ej.: en una lista desplegable múltiple o una lista de
checkboxes en HTML), el navegador no envía el parámetro, y
en consecuencia, esta operación devuelve null
javax.servlet.http.HttpServletResponse
setContentType debe llamarse antes de escribir en el
PrintWriter que devuelve getWriter
Página principal del tutorial
Index.jsp
<html>
...
<ul>
<li><a href="Hello1/HelloUser?userName=Fernando+Bellas">
HelloUser by GET (userName = Fernando Bellas)</a></li>
<li><a href="Hello1/HelloUserByPost.html">HelloUser by POST</a></li>
<li><a href="Portal1/MainPage">Portal-1 main page</a></li>
</ul>
...
</html>
Portal1/HelloUserByPost.html
<html>
...
<form method="POST" action="HelloUser">
<table width="100%" border="0" align="center" cellspacing="12">
<tr>
<th align="right" width="50%">User name</th>
<td align="left">
<input type="text" name="userName" size="16“
maxlength="16">
</td>
</tr>
<tr>
<td width="50%“></td>
<td align="left" width="50%">
<input type="submit" value="Say me hello">
</td>
</tr>
</table>
</form>
...
</html>
Demo HelloUser (1)
package es.udc.fbellas.j2ee.servjsptutorial.hellouser1;
import java.io.PrintWriter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/* Generate response. */
response.setContentType("text/html; charset=ISO-8859-1");
es.udc.fbellas.j2ee.servjsptutorial.hellouser1.HelloUserServlet (y 2)
out.println("<html><head><title>");
out.println("HelloUser response");
out.println("</title></head>");
out.println("<body text=\"#000000\" bgcolor=\"#ffffff\">");
out.println("<h1>Hello " + userName + "! </h1>");
out.println("</body></html>");
out.close();
doGet(request, response);
}
Empaquetamiento de una aplicación web (1)
Portal2/MainPage.jsp
Portal2/ShowLogin.jsp
Portal2/ProcessLogin.jsp
Portal2/ProcessLogout.jsp
Hello2/HelloUserByPost.html
Hello2/HelloUser.jsp
Hello1/HelloUserByPost.html
Index.jsp
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal1/
ShowLoginServlet.class
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal1/
MainPageServlet.class
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal1/
LoginManager.class
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal1/
ProcessLoginServlet.class
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal1/
ProcessLogoutServlet.class
jar tvf ServJSPTutorial.war (y 2)
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal2/
LoginManager.class
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal2/
IncorrectPasswordException.class
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/portal2/
LoginForm.class
WEB-INF/classes/es/udc/fbellas/j2ee/servjsptutorial/hellouser1/
HelloUserServlet.class
WEB-INF/web.xml
WEB-INF/web.xml (1)
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<distributable/>
<servlet>
<servlet-name>HelloUser</servlet-name>
<servlet-class>es.udc.fbellas.j2ee.servjsptutorial.hellouser1.
HelloUserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloUser</servlet-name>
<url-pattern>/Hello1/HelloUser</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>Index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Comentarios (1)
Desde la versión 2.4 de la especificación de servlets,
los tags que se pueden usar dentro del fichero
web.xml están especificados en un esquema
(anteriormente lo estaban en un DTD)
Espacios de nombres
Concepto similar al de paquete en Java
Permiten evitar conflictos de nombres cuando en un
documento XML se usan tags de distintas aplicaciones XML
Cada espacio de nombres está asociado a una URI, que
debe ser única
Se aconseja usar URLs
No tienen porque tener una existencia real (y de hecho, no
suelen tenerla)
Comentarios (2)
En el fichero web.xml se usa
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
xmlns="http://java.sun.com/xml/ns/j2ee" permite
especificar que el elemento web-app y los que éste contiene
pertenecen al espacio de nombres definido por la URI
http://java.sun.com/xml/ns/j2ee
“Similar a package”
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance" permite especificar que el elemento web-app y los
que éste contiene pueden usar los atributos y elementos del
espacio de nombres asociado con la URI
http://www.w3.org/2001/XMLSchema-instance,
prefijándolos con xsi:
“Similar a import”
Es la URI la que define el espacio de nombres y no el prefijo
Distintas documentos XML pueden usar distintos prefijos para referirse a un
mismo espacio de nombres
Comentarios (3)
En el fichero web.xml se usa (cont)
El atributo xsi:schemaLocation permite especificar las
ubicaciones de los esquemas asociados a un conjunto de
espacios de nombres
Contiene una lista de pares de valores separados por blancos
(xsi:schemaLocation="en1 ue1 ... enN ueN")
El primer miembro especifica un espacio de nombres (en)
El segundo miembro especifica la ubicación del esquema (ue)
que define los elementos y atributos de ese esquema
El procesador del documento XML no está obligado a hacer uso
de las ubicaciones especificadas (e.g. puede tener copias
locales de los esquemas)
Cualquier procesador tiene una copia del esquema
correspondiente al espacio de nombres
http://www.w3.org/2001/XMLSchema-instance, y por eso
no se especifica en xsi:schemaLocation
Cualquier contenedor de aplicaciones web J2EE posiblemente
tendrá una copia del esquema correspondiente al espacio de
nombres http://java.sun.com/xml/ns/j2ee
Comentarios (y 4)
El anterior fichero web.xml sólo muestra algunos
tags típicos
Existe un gran número de tags (la mayoría opcionales) que
permiten expresar muchas opciones de configuración
Iremos viendo ejemplos de los tags más típicos a medida
que nos hagan faltan
distributable
La aplicación puede funcionar en cluster
Nuestras aplicaciones siempre deberían estar diseñadas e
implementadas para que puedan funcionar en cluster
Los servidores de aplicaciones comerciales suelen
generar el fichero web.xml automáticamente
El usuario utiliza un cómodo wizard para especificar la
información de configuración
Tipos de URLs en HTML (1)
Servlet and JSP Tutorial Main Page Servlet and JSP Tutorial Main Page
HttpS ervlet
(fro m h ttp )
M ainP ageS ervlet S howLoginS ervlet P rocess LoginS ervlet P roc es sLogoutS ervlet
doGet(request, response);
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.MainPageServlet (y 2)
response.setContentType("text/html; charset=ISO-8859-1");
PrintWriter out = response.getWriter();
out.println("<html><head><title>");
out.println("Portal-1 main page");
out.println("</title></head>");
out.println("<body text=\"#000000\" bgcolor=\"#ffffff\" " +
"link=\"#000ee0\" vlink=\"#551a8b\" alink=\"#000ee0\">");
out.println("<h1>Hello " + loginName + "! </h1>");
out.println("<br><br><br>");
out.println("<a href=\"../Index.jsp\">Servlet and JSP tutorial " +
"main page</a><br>");
out.println("<a href=\"ProcessLogout\">Logout</a><br>");
out.println("</body></html>");
out.close();
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.ShowLoginServlet (1)
if (errors != null) {
if (errors.containsKey("loginName")) {
loginName = request.getParameter("loginName");
loginNameErrorMessage = errorHeader +
errors.get("loginName") + errorFooter;
}
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.ShowLoginServlet (2)
/* Generate response. */
response.setContentType("text/html; charset=ISO-8859-1");
PrintWriter out = response.getWriter();
/* Begin of form. */
out.println("<form method=\"POST\" action=\"ProcessLogin\">");
/* Begin of table. */
out.println("<table width=\"100%\" border=\"0\" align=\"center\" " +
"cellspacing=\"12\">");
es.udc.fbellas.j2ee.servjsptutorial.portal1.ShowLoginServlet (3)
/* Login name. */
out.println("<tr>");
out.println("</tr>");
out.println("<tr>");
out.println("<td width=\"50%\"></td>");
out.println("<td align=\"left\" width=\"50%\"> " +
"<input type=\"submit\" value=\"Login\"></td>");
out.println("</tr>");
es.udc.fbellas.j2ee.servjsptutorial.portal1.ShowLoginServlet (y 4)
/* End of table. */
out.println("</table>");
/* Close "out". */
out.close();
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.ProcessLoginServlet (1)
forwardToShowLogin(request, response);
} else {
LoginManager.login(request, loginName.trim());
response.sendRedirect("MainPage");
}
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.ProcessLoginServlet (y 2)
doPost(request, response);
RequestDispatcher requestDispatcher =
request.getRequestDispatcher("/Portal1/ShowLogin");
requestDispatcher.forward(request, response);
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.ProcessLogoutServlet
LoginManager.logout(request);
response.sendRedirect("../Index.jsp");
doGet(request, response);
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.LoginManager (1)
public final class LoginManager {
private LoginManager() {}
session.setAttribute(LOGIN_NAME_SESSION_ATTRIBUTE, loginName);
if (session != null) {
session.invalidate();
}
}
es.udc.fbellas.j2ee.servjsptutorial.portal1.LoginManager (y 2)
if (session == null) {
return null;
} else {
return (String) session.getAttribute(
LOGIN_NAME_SESSION_ATTRIBUTE);
}
}
Comentarios (1)
El ejemplo, aparte de ilustrar el uso de sesiones,
hace énfasis en el uso de sendRedirect y
forward
sendRedirect
Le decimos al navegador que nos haga una nueva petición a
otra URL
forward
Nos movemos a otra URL
Ocurre dentro del servidor
Se conserva todo lo que había en la request
Útil para tratar errores en formularios
Los servlets de procesamiento enganchan el atributo errors
(un Map) en la request
Los servlets que muestran formularios comprueban si la
request incluye el atributo errors
Comentarios (2)
Más sobre tipos de URLs
Los tipos de URLs que hemos visto al principio de este
apartado se refieren a las URLs en ficheros HTML, páginas
JSP o respuestas generadas
¿ Qué tipos de URLs acepta sendRedirect ?
Los tres tipos que conocemos hasta ahora
Lógico, pues un sendRedirect se usa para informar al
navegador que nos haga una petición a otra URL
¿ Qué tipos de URLs acepta forward ?
De tipo path relativo (sin salir de la aplicación)
De tipo path relativo a contexto
Empiezan por “/” y no incluyen el nombre de la aplicación
Ej.: /Portal1/MainPage
Existe otra manera de hacer forwards distinta a la mostrada
en el ejemplo, que sólo acepta URLs de tipo path relativo a
contexto
Servlet.getServletContext().getRequestDispatcher
(String)
Comentarios (y 3)
¿ Cuándo usar forward y cuándo sendRedirect ?
En principio, un forward siempre es más rápido (ocurre en
el servidor)
Un forward es preciso cuando queremos enganchar
atributos a la request
Ej.: Tratamiento de errores en formularios
Para el resto de situaciones, es mejor usar un
sendRedirect, dado que forward no cambia la URL que
muestra la caja de diálogo del navegador (el navegador no
se entera de que se hace un forward), lo que será confuso
si el usuario decide recargar la página (se invocará a la URL
antigua que todavía muestra la caja de diálogo del
navegador)