1.23k likes | 1.52k Views
Servlets. Introducción. Necesidad de mecanismos para desarrollar “aplicaciones web” contenido dinámico Cuando escribes una URL en tu navegador: El navegador establece una conexión TCP/IP con el servidor El navegador envía una petición al servidor
E N D
Introducción • Necesidad de mecanismos para desarrollar “aplicaciones web” contenido dinámico • Cuando escribes una URL en tu navegador: • El navegador establece una conexión TCP/IP con el servidor • El navegador envía una petición al servidor • El servidor devuelve una respuesta al cliente • El servidor cierra la conexión • Los mensajes intercambiados entre el cliente y el servidor son HTTP
HTTP • Especificación de HTTP: http://www.w3.org/Protocols/rfc2616/rfc2616.html • Básicamente debemos saber que los comandos principales son HTTP GET y POST.
Tecnología Servlet • Piedra angular del desarrollo de aplicaciones web en Java • Los JSPs son de hecho servlets “disfrazados”
Características de los Servlets • Pensados para reemplazar a los CGIs • Cada petición de un cliente hacía al servidor lanzar un nuevo proceso con el programa CGI • No es la única tecnología disponible: • ASP.NET • PHP (plataforma LAMP)
Ventajas • Rendimiento cada petición es procesada por un único proceso en el contenedor de servlets • Portabilidad heredado de Java • Rápido desarrollo acceso a las riquísimas librerías de Java • Robustez gestionados por la máquina virtual de Java (garbage collection) • Amplio soporte muchos desarrolladores y compañías utilizan esta tecnología
Servlet Container HTTP Request Servlet Browser HTTP Server HTTP Response Contenido Estático Arquitectura • Servlet Container = servidor web capaz de ejecutar servlets • En una aplicación JSP, el contenedor se corresponde a un JSP container.
Contenedor Tomcat 5 • El contenedor de Servlets más popular • Actualmente en la versión 5.0 • Open source, disponible en: http://jakarta.apache.org/tomcat/ • Vamos a instalarlo ...
Instalando Tomcat 5 • Requisitos: • Haber instalado Java 5 • Extraer fichero: downloads\Tomcat5.5\jakarta-tomcat-5.5.7.zip • Crear las siguientes variables de entorno, por medio de Panel de Control->Sistema->Avanzado->Variables de Entorno: • TOMCAT_HOME=<TOMCAT_INSTALL_DIR>
6 Pasos Para Crear tu Primer Servlet • Crear una estructura de directorios bajo Tomcat para tu aplicación • Escribir el código del servlet • Compilar el código • Crear un descriptor de explotación (deployment descriptor) • Ejecutar Tomcat • Invocar el servlet desde un navegador
Crear directorio bajo Tomcat para tu aplicación • El directorio %TOMCAT_HOME%/webapps es dónde cuelgas tus aplicaciones • Una aplicación web es un conjunto de servlets y otros recursos instalados bajo el espacio URL de un servidor • Pasos: • Crear un directorio bajo webapps con el nombre de tu aplicación ‘myapp’, que aparecerá en la url a tu aplicación • Crear el directorio WEB-INF debajo de ‘myApp’ • Crear subdirectorio clases • Crear subdirectorio lib • Podéis hacer copy/paste del contenido del directorio examples\servlets\ej1_holamundo_servlet bajo %TOMCAT_HOME\webapps\myapp • Vamos a reutilizar continuamente el contexto myapp
Escribir el Código del Servlet // HelloWorldExample.java import java.io.*; import java.text.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloWorldExample extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ResourceBundle rb = ResourceBundle.getBundle("LocalStrings",request.getLocale()); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); String title = rb.getString("helloworld.title"); out.println("<title>" + title + "</title>"); out.println("</head>"); out.println("<body bgcolor=\"white\">"); out.println("<h1>" + title + "</h1>"); out.println("</body>"); out.println("</html>"); } }
Compilar el Código • Guardar el código en %TOMCAT_HOME%\webapps\myapp\WEB-INF\classes • Compilar el código: javac –classpath %TOMCAT_HOME%\common\lib\servlet-api.jar HelloWorldExample.java
Crear el web.xml • Nombre recibido por el deployment descriptor • Debe colocarse en el directorio WEB-INF • web.xml es un documento XML que tiene como elemento raíz: <web-app> • Se pueden encontra n elementos <servlet> que cuelgan de él
Crear el web.xml <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>Servlet 2.4 Examples</display-name> <description> Servlet 2.4 Examples. </description> <servlet> <servlet-name>HelloWorldExample</servlet-name> <servlet-class>HelloWorldExample</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloWorldExample</servlet-name> <url-pattern>/HelloWorldExample</url-pattern> </servlet-mapping> </web-app>
Ejecutar el Código • Arrancar Tomcat si es necesario, mediante el comando: %TOMCAT_HOME%\bin\catalina.bat run • Invocar al servlet: http://localhost:8080/myapp/HelloWorldExample
Servlets: Jerarquía • La jerarquía de clases java es... • Únicamente hay que hacer polimorfismo de los métodos que se quieran tratar.
Las APIs • Dos paquetes permiten la programación de servlets: • javax.servlet • javax.servlet.http • Revisar documentación: • Arrancar Tomcat • Visitar: http://localhost:8080
Servlets: Ciclo de vida • Ciclo de vida de un servlet:
Servlets: Ciclo de vida • Viene dado por tres métodos: init, service y destroy • INICIALIZACIÓN: Una única llamada al método “init” por parte del servidor. Incluso se pueden recoger unos parametros concretos con “getInitParameter” de “ServletConfig”. • SERVICIO: una llamada a service() por cada invocación al servlet • ¡Cuidado! El contenedor es multihilo • DESTRUCCIÓN: Cuando todas las llamadas desde el cliente cesen o un temporizador del servidor así lo indique. Se usa el método “destroy” • Revisar documentación de la clase javax.servlet.Servlet
Demostrando el Ciclo de Vida // examples\servlets\ej2_ciclovida_servlet import javax.servlet.*; import java.io.IOException; public class CicloVidaServlet implements Servlet { public void init(ServletConfig config) throws ServletException { System.out.println("init"); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("service"); } public void destroy() { System.out.println("destroy"); } public String getServletInfo() { return null; } public ServletConfig getServletConfig() { return null; } }
Servlets: Operaciones duraderas • Respuestas a peticiónes de clientes que requieran de un tiempo de proceso muy largo. • Puede que el servlet deba destruirse y estas operaciones aun no hayan concluido. • Es responsabilidad del programador encargarse de su gestión.
Servlets: Operaciones duraderas • Necesitaremos por tanto: • Mantener un seguimiento de las tareas (threads) que se estén ejecutando en el método “service” • Proporcionar una finalización correcta haciendo que los procesos largos que aun no hayan concluido puedan terminar correctamente en el método “destroy” del servlet. • En ciertos casos poder terminar los procesos que aun siguen en ejecución si es necesario.
Servlets: Operaciones duraderas • Posible solución: Contador public ShutdownExample extends HttpServlet { private int serviceCounter = 0; private Object lock = new Object(); protected void enteringServiceMethod() { synchronized(lock) { serviceCounter++; } } protected void leavingServiceMethod(){ synchronized(lock) { serviceCounter--; if (serviceCounter == 0 && isShuttingDown()) notifyAll(); } } protected int numServices() { synchronized(lock) { return serviceCounter; } } protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { enteringServiceMethod(); try { super.service(req, resp); } finally { leavingServiceMethod(); } }
Servlets: Operaciones duraderas • Falta indicar la terminación. public ShutdownExample extends HttpServlet { private boolean shuttingDown; protected void setShuttingDown(boolean flag) { shuttingDown = flag; } protected boolean isShuttingDown() { return shuttingDown; } public void destroy() { synchronized(lock) { if (numServices() > 0) { setShuttingDown(true); } while(numServices() > 0) { try { wait(); } catch (InterruptedException e) { } } } } }
Recuperando Configuración • Recuperando información de configuración del fichero web.xml <servlet> <servlet-name>ConfigDemoServletExample</servlet-name> <servlet-class>ConfigDemoServlet</servlet-class> <init-param> <param-name>adminEmail</param-name> <param-value>dipina@ilargi.org</param-value> </init-param> <init-param> <param-name>adminContactNumber</param-name> <param-value>6542214213</param-value> </init-param> </servlet>
Recuperando Configuración • Recuperando información de configuración del fichero web.xml, revisar ejemplo examples\servlets\ej3_configinfo_servlet public class ConfigDemoServlet implements Servlet { ServletConfig cfg; public void init(ServletConfig config) throws ServletException { this.cfg = config; Enumeration parameters = config.getInitParameterNames(); while (parameters.hasMoreElements()) { String parameter = (String) parameters.nextElement(); System.out.println("Parameter name : " + parameter); System.out.println("Parameter value : " + config.getInitParameter(parameter)); } } // ... }
Contexto del Servidor • ServletContext representa el entorno donde se ejecuta el servidor, es decir, el Servlet Container • Se puede obtener una referencia a él mediante el método ServletConfig.getServletContext() • Algunos métodos que se pueden utilizar son: • getMajorVersion de la Servlet API soportada por el contenedor • getMinorVersion • setAttribute guarda un objeto en el ServletContext • getAttributeNames • getAttribute • removeAttribute • A través del contexto de un servlet se puede compartir estado entre varios servlets. • Revisar ejemplo examples\servlets\ej4_contextinfo_servlet
Contexto del Servidor ServletConfig servletConfig; public void init(ServletConfig config) throws ServletException { servletConfig = config; } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { ServletContext servletContext = servletConfig.getServletContext(); 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()); }
Peticiónes y Respuestas • En el método service() los parámetros: • ServletRequest representa la petición del cliente y • ServletResponse la respuesta del servidor • ServletRequest tiene los siguientes métodos: • getParameterNames • getParameter • getRemoteAddress • getRemoteHost • ServletResponse tiene entre otros el método: • getWriter • Revisar examples\servlets\ej5_requestresponse_servlet
Ejemplo ServletRequest y ServletResponse public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<HTML>"); // ... out.println("<BR>Server Port: " + request.getServerPort()); out.println("<BR>Server Name: " + request.getServerName()); out.println("<BR>Protocol: " + request.getProtocol()); out.println("<BR>Character Encoding: " + request.getCharacterEncoding()); out.println("<BR>Content Type: " + request.getContentType()); out.println("<BR>Content Length: " + request.getContentLength()); out.println("<BR>Remote Address: " + request.getRemoteAddr()); out.println("<BR>Remote Host: " + request.getRemoteHost()); out.println("<BR>Scheme: " + request.getScheme()); Enumeration parameters = request.getParameterNames(); while (parameters.hasMoreElements()) { String parameterName = (String) parameters.nextElement(); out.println("<br>Parameter Name: " + parameterName); out.println("<br>Parameter Value: " + request.getParameter(parameterName)); } Enumeration attributes = request.getAttributeNames(); while (attributes.hasMoreElements()) { String attribute = (String) attributes.nextElement(); out.println("<BR>Attribute name: " + attribute); out.println("<BR>Attribute value: " + request.getAttribute(attribute)); } out.println("</BODY>"); out.println("</HTML>"); }
Clase GenericServlet • El uso de la interfaz Servlet tiene dos inconvenientes: • Hay que proveer implementaciones de los cinco métodos de Servlet • Hay que cachear la referencia a ServletConfig pasada como parámetro • La clase GenericServlet provee una implementación vacía de los 5 métodos de Servlet y recuerda ServletConfig
Ejemplo GenericServlet import javax.servlet.*; import java.io.IOException; import java.io.PrintWriter; public class SimpleServlet extends GenericServlet { public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>"); out.println("Extending GenericServlet"); out.println("</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("Extending GenericServlet makes your code simpler."); out.println("</BODY>"); out.println("</HTML>"); } }
Paquete javax.servlet.http • Normalmente siempre vamos a trabajar con él cuando programemos servlets. • Sus miembros y métodos son más convenientes y ofrecen más funcionalidad • Principalmente vamos a tratar con tres clases: • HttpServlet • HttpServletRequest • HttpServletResponse
HttpServlet • Hereda de GenericServlet • Tiene 6 métodos doXXX que son invocados cada vez que el correspondiente comando HTTP es recibido: • doPost • doPut • doGet • doDelete • doOptions • doTrace
Servlets: Explicación de métodos HTTP • GET: Paso de parámetros en la propia URL de acceso al servicio o recurso del servidor. Método “doGet” GET /query.html?keyword='diego' HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */* Accept-Language: es,eu;q=0.7,en-gb;q=0.3 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) Host: localhost:9999 Connection: Keep-Alive
Servlets: Explicación de métodos HTTP • POST: Lo mismo que GET pero los parámetros van en línea aparte dentro del cuerpo de la petición. El manejo es idéntico pero a través del método “doPost”. POST /cgi-bin/search.sh HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */* Referer: http://localhost:9999/search.html Accept-Language: es,eu;q=0.7,en-gb;q=0.3 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322) Host: localhost:9999 Content-Length: 13 Connection: Keep-Alive Cache-Control: no-cache keyword=diego
Servlets: Métodos • Por defecto retornan BAD_REQUEST(400) • Son llamados desde el método “service”. • Reciben interfaces instanciadas: • “HttpServletRequest” para manejo de la informacion enviada por el usuario. • “HttpServletResponse” para poder enviar una respuesta en forma de pagina web.
Servlets: Respondiendo en HTML • 2 pasos: • Indicar una cabecera de respuesta de contenido (antes de cualquier tipo de respuesta) • Una manera es usando el método “setHeader” de “HttpServletResponse”. • Al ser un proceso tan común existe un método que nos lo soluciona directamente: “setContentType” de “HttpServletResponse”. • Crear y enviar código HTML válido. • Revisar examples\servlets\ej6_dogetdopost_servlet
Ejemplo doGet() y doPost() // compile: javac -classpath %TOMCAT_HOME%\common\lib\servlet-api.jar DoGetDoPostServlet.java import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class DoGetDoPostServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>The GET method</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("The servlet has received a GET. " + "Now, click the button below."); out.println("<BR>"); out.println("<FORM METHOD=POST>"); out.println("<INPUT TYPE=SUBMIT VALUE=Submit>"); out.println("</FORM>"); out.println("</BODY>"); out.println("</HTML>"); }
Ejemplo doGet() y doPost() public void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>The POST method</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("The servlet has received a POST. Thank you."); out.println("</BODY>"); out.println("</HTML>"); } }
Servlets: Recogiendo la información de usuario. • 2 formas de envío de información: • En la línea URL mediante una ‘?’ • En una línea separada. • En los antiguos CGIs el parseo era muy complejo. En Servlets usar “getParameter” de “HttpServletRequest” que devuelve “” (si no hay valor) o null (si no existe).
Servlets: Recogiendo la información de usuario • Si el parametro tiene mas de un valor se usa “getParameterValues” de “HttpServletRequest” que devuelve un array de strings. • Los nombres de los parametros son accesibles mediante “getParameterNames” de “HttpServletRequest” que devuelve un Enumeration de strings. • Se puede leer la línea directamente con “getReader” o “getInputStream” de “HttpServletRequest”. • Revisar: examples\servlets\ej7_listparams_servlet
Listando Parámetros Recibidos // compile: javac -classpath %TOMCAT_HOME%\common\lib\servlet-api.jar PruebaServlet.java import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class PruebaServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>Obtaining the Parameter</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); out.println("The request's parameters are:<BR>");
Listando Parámetros Recibidos Enumeration enumeration = request.getParameterNames(); while (enumeration.hasMoreElements()){ String parameterName = (String) enumeration.nextElement(); out.println(parameterName + ": " + request.getParameter(parameterName) + "<BR>" ); } out.println("<FORM METHOD=GET>"); out.println("<BR>First Name: <INPUT TYPE=TEXT NAME=FirstName>"); out.println("<BR>Last Name: <INPUT TYPE=TEXT NAME=LastName>"); out.println("<BR><INPUT TYPE=SUBMIT VALUE=Submit>"); out.println("</FORM>"); out.println("</BODY>"); out.println("</HTML>"); } }
Servlets: Recogiendo la información de usuario • Cabeceras: Además de la información de la línea de petición, datos añadidos opcionales (excepto “Content-Length” en los métodos POST). Accept Los tipos del formato MIME que acepta el navegador cliente. Accept-Charset Los sets de caracteres que el navegador cliente espera. Accept-Encoding Las codificaciónes de datos (por ejemplo gzip) que el navegador cliente soporta y conoce. Así el servlet puede consultar explícitamente información de codificación y así aprovechar las ventajas de HTML gzipeado indicándolo en la cabecera de respuesta Content-Encoding.
Servlets: Recogiendo la información de usuario Accept-Language El lenguaje que el navegador cliente espera. Authorization Información de autentificación, que generalmente se crea como respuesta a una cabecera WWW Authenticate enviada desde el servidor. Connection Indica si se va a usar conexión persistente. Si un servlet recibe el valor Keep-Alive o una petición con una línea indicando HTTP 1.1 podrá hacer uso de las ventajas que estas ofrecen ahorrando tiempo en páginas con muchos elementos pequeños como imágenes o applets. El servlet ha de indicar el tamaño del contenido a enviar como respuesta mediante la cabecera Content-Length. Para ello se puede usar la clase ByteArrayOutputStream y al final enviar todos los datos. Content-Length Usada en los mensajes POST para indicar el tamaño de los datos.
Servlets: Recogiendo la información de usuario Cookie Una cabecera muy importante para envío de información. From La dirección de email del cliente. Host El host y el puerto sacados de la URL original. If-Modified-Since Para indicar que solo han de enviarse documentos posteriores al actual. Si no es así, se envía una respuesta 304 "Not Modified". Pragma Si contiene el valor no-cache indica que el servidor ha de enviar una nueva copia del documento. Referer La URL de la página que contenía el link que el cliente siguió para llegar a la pagina actual. User-Agent El tipo de navegador que usa el cliente. Es útil si se va enviar contenido especifico para un tipo de navegador. UA-Pixels, UA-Color, UA-OS, UA-CPU Cabeceras no estándar enviadas desde IE indicando el tamaño de pantalla, la profundidad de color, el SO y el tipo de cpu usado en el cliente.