Un servlet maneja peticiones de los clientes a través de su método service.
Con él se pueden manejar peticiones HTTP (entre otras), reenviando las
peticiones a los métodos apropiados que las manejan. Por ejemplo, una
petición GET puede redirigirse a un método doGet. Veremos ahora
los elementos principales que intervienen en una interacción vía HTTP.
Como hemos visto anteriormente, los objetos ServletRequest se emplean para obtener información sobre la petición de los clientes. Más en concreto, el subtipo HttpServletRequest se utiliza en las peticiones HTTP. Proporciona acceso a los datos de las cabeceras HTTP, cookies, parámetros pasados por el usuario, etc, sin tener que parsear nosotros a mano los datos de formulario de la petición.
La clase dispone de muchos métodos, pero destacamos los siguientes:
Enumeration getParameterNames() String getParameter (String nombre) String[] getParameterValues (String nombre)Con getParameterNames() se obtiene una lista con los nombres de los parámetros enviados por el cliente. Con getParameter() se obtiene el valor del parámetro de nombre nombre. Si un parámetro tiene varios valores (por ejemplo, si tenemos un array de cuadros de texto con el mismo nombre en un formulario), se pueden obtener todos separados con getParameterValues(). Los nombres de los parámetros normalmente sí distinguen mayúsculas de minúsculas, deberemos tener cuidado al indicarlos.
String getQueryString()que devuelve toda la petición en una cadena, que deberemos parsear nosotros como nos convenga.
BufferedReader getReader() ServletInputStream getInputStream()Con getReader() se obtiene un BufferedReader para peticiones donde esperemos recibir texto. Si esperamos recibir datos binarios, se debe emplear getInputStream().
String getMethod() String getRequestURI() String getProtocol()Con getMethod() obtenemos el comando HTTP solicitado (GET, POST, PUT, etc), con getRequestURI() obtenemos la parte de la URL de petición que está detrás del host y el puerto, pero antes de los datos del formulario. Con getProtocol() obtenemos el protocolo empleado (HTTP/1.1, HTTP/1.0, etc).
Los objetos ServletResponse se emplean para enviar el resultado de procesar una petición a un cliente. El subtipo HttpServletResponse se utiliza en las peticiones HTTP. Proporciona acceso al canal de salida por donde enviar la respuesta al cliente.
La clase dispone de muchos métodos, pero destacamos:
Writer getWriter() ServletOutputStream getOutputStream()
Con getWriter() se obtiene un Writer para enviar texto al cliente. Si queremos enviar datos binarios, se debe emplear getOutputStream().
Si queremos especificar información de cabecera, debemos establecerla ANTES de obtener el Writer o el ServletOutputStream. Hemos visto en algún ejemplo el método setContentType() para indicar el tipo de contenido. Veremos las cabeceras con más detenimiento más adelante.
Como se ha visto anteriormente, el método doGet() se emplea para procesar peticiones GET. Para realizar nuestro propio procesamiento de petición, simplemente sobreescribimos este método en el servlet:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // ... codigo para una peticion GET }
Podemos utilizar los métodos del objeto HttpServletRequest vistos antes. Así podremos, entre otras cosas:
String nombreUsuario = request.getParameter("nombre");
String query = request.getQueryString(); ...
BufferedReader r = request.getReader(); ...Esta, sin embargo, no es una buena idea para tomar parámetros de peticiones u otras cosas. Se suele emplear sobre todo para transferencias de ficheros, pero hay que tener en cuenta que si obtenemos un canal de entrada, luego no podremos obtener parámetros u otros valores con métodos getParameter() y similares.
También podemos utilizar los métodos del objeto HttpServletResponse para, entre otras cosas:
response.setContentType("text/html");
PrintWriter out = response.getWriter(); out.println ("Enviando al cliente");
response.sendRedirect("http://localhost:8080/pag.html");
De forma similar, el método doPost(), se emplea para procesar peticiones POST. Igual que antes, debemos sobreescribir este método para definir nuestro propio procesamiento de la petición:
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // ... codigo para una peticion POST }
Las posibilidades de los parámetros HttpServletRequest y HttpServletResponse son las mismas que para GET. Normalmente muchos servlets definen el mismo código para uno y otro método (hacen que doPost() llame a doGet() y definen allí el código, o al revés), pero conviene tenerlos separados para poder tratar independientemente uno y otro tipo de peticiones si se quiere.
Los servlets normalmente pueden gestionar múltiples peticiones de clientes concurrentemente. Pero puede suceder que, si los métodos que definimos acceden a un recurso compartido, no nos interese que varios clientes accedan a dicho recurso simultáneamente. Para solucionar este problema, podemos definir bloques de código synchronized, o bien hacer que el servlet sólo atienda una petición cada vez.
Para esto último, lo único que hay que hacer es que el servlet, además de heredar de HttpServlet, implemente la interfaz SingleThreadModel. Esto no supone definir más métodos, simplemente añadimos el implements necesario al definir la clase Servlet, y ya está:
public class MiServlet extends HttpServlet implements SingleThreadModel { ... }
Los datos que se envían como parámetros en una petición (tras el interrogante si es una petición GET, o por otro lado si es POST) se llaman datos de formulario. Una vez enviados estos datos como petición, ¿cómo se extraen en el servidor?
Si trabajáramos con CGI, los datos se tomarían de forma distinta si fuese una petición GET o una POST. Para una GET, por ejemplo, tendríamos que tomar la cadena tras la interrogación, y parsearla convenientemente, separando los bloques entre '&', y luego separando el nombre del parámetro de su valor a partir del '='. También hay que descodificar los valores: los alfanuméricos no cambian, pero los espacios se han convertido previamente en '+', y otros caracteres se convierten en '%XX'.
Con servlets todo este análisis se realiza de forma automática. La clase HttpServletRequest dispone de métodos que devuelve la información que nos interesa ya procesada, e independientemente de si es una petición GET o POST. Hemos visto antes los métodos:
Enumeration getParameterNames() String getParameter (String nombre) String[] getParameterValues (String nombre)
Veamos un ejemplo: supongamos que tenemos este formulario:
<html> <body> <form action="/ejemploform/servlet/ServletForm"> Valor 1: <input type="text" name="texto1"> <br> Valor2: <select name="lista"> <option name="lista" value="Opcion 1">Opcion 1</option> <option name="lista" value="Opcion 2">Opcion 2</option> <option name="lista" value="Opcion 3">Opcion 3</option> </select> <br> Valores 3: <br> <input type="text" name="texto2"> <input type="text" name="texto2"> <input type="text" name="texto2"> <input type="submit" value="Enviar"> </form> </body> </html>
Al validarlo se llama al servlet ServletForm, que muestra una página HTML con los valores introducidos en los parámetros del formulario:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ServletForm extends HttpServlet { // Metodo para GET public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); // Mostramos los datos del formulario out.println ("<HTML>"); out.println ("<BODY>"); out.println ("<H1>Datos del formulario</H1>"); out.println ("<BR>"); String valor1 = request.getParameter("texto1"); String valor2 = request.getParameter("lista"); String[] valor3 = request.getParameterValues("texto2"); out.println ("Valor 1:" + valor1); out.println ("<BR>"); out.println ("Valor 2:" + valor2); out.println ("<BR>"); out.println ("Valor 3:"); out.println ("<BR>"); if (valor3 != null) for (int i = 0; i < valor3.length; i++) { out.println (valor3[i]); out.println ("<BR>"); } out.println ("</BODY>"); out.println ("</HTML>"); } // Metodo para POST public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Aquí tenéis el WAR con el ejemplo comprimido. Copiadlo en el directorio webapps y probad el ejemplo con:
http://localhost:8080/ejemploform/index.html