Servlets
Notas iniciales
Son clases normales y corrientes de java que han de heredar de: javax.servlet.http.HttpServlet
Cuando un servlet es añadido, editado y\o compilado Tomcat ha de ser actualizado; para ello puede ser reiniciado o símplemente usar algún metodo para la recarga del contexto de la aplicación (Reload the context).
Para acceder a un Servlet es necesario que exista el archivo web.xml de la aplicación, donde encontremos la
URL del Servlet.
Pasos para la creación de un servlet
Creamos una aplicación en Tomcat con su carpetita /WEB-INF, /WEB-INF/src y /WEB-INF/classes.
En WEB-INF/src creamos nuestros archivos .java que luego compilaremos. Si la clase que utilizamos es MyServlet y está en el paquete mypck.mysvl el archivo deberá de ser el siguiente: WEB-INF/src/mypck/mysvl/MyServlet.java. Una vez lo compilasemos deberíamos de colocar la clase en WEB-INF/classes/mypck/mysvl/MyServlet.class.
En WEB-INF deberemos de colocar el archivo web.xml que enlace nuestro servlet con el nombre mi_servlet:
<?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">
<servlet>
<servlet-name>prueba</servlet-name>
<servlet-class>mypck.mysvl.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>prueba</servlet-name>
<url-pattern>/mi_servlet</url-pattern>
</servlet-mapping>
</web-app>
</xml>
Estructura
Los servlets heredan de la clase HttpServlet y sobreescriben los métodos doGet o doPost según si el formulario usado en el html ha enviado los datos por GET o por POST. Los dos métodos reciben dos parámetros: un javax.servlet.http.HttpServletRequest (para la entrada de datos) y un javax.servlet.http.HttpServletResponse (para la salida de datos). Este último tiene un método llamado getPrinter que devuelve un objeto PrintWriter, perfecto para hacer la escritura de datos en html en la respuesta del cliente.
El objeto HttpServletResponse tiene un método llamado setContentType, con este elegimos el tipo de datos (y por tanto como han de ser tratados estos) que enviaremos al cliente, si lo que queremos es enviar en html pondremos: text/html.
Antes de que alguno de los métodos doGet o doPost sean llamados, se llama a service, otro método de la clase HttpServlet. Este es el que elige a qué método llamar, este método no deberíamos sobreescribirlo.
Otro método importante a tener en cuenta es el método init, este se llama cuando se crea el servlet (la primera vez que se llama a este), sólo una vez.
Los servlets pueden ser llamados desde distintos sitios a la vez, esto puede dar problemas debido a que están desarrollados con multithreading y tal vez se necesite bloquear alguna que otra variable. Podemos forzar al sistema a ejecutar nuestros servlets en forma de thread simple implementando en ellos la interface: SingleThreadModel.
Un formulario como el siguiente enviaría los datos al servlet prueba ubicado en la misma ruta en la que este esté:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<BODY BGCOLOR="#FDF5E6">
<CENTER>
<FORM ACTION="prueba">
First name:
<INPUT TYPE="TEXT" NAME="firstName" VALUE="Joe"><BR>
Last name:
<INPUT TYPE="TEXT" NAME="lastName" VALUE="Hacker"><P>
<INPUT TYPE="SUBMIT">
</FORM>
</CENTER>
</BODY></HTML>
Podremos recoger los valores introducidos por el usuario mediante el método del request llamado getParameter. request.getParameter(“firstName”); Si viniese más de un solo valor podríamos usar el método getParameterValues.
Para recoger el nombre de los parametros usaremos el método getParameterNames (en el request).
Para recoger los datos en formato raw utilizaremos los métodos del request getReader o getInputStream. Uno de los casos en los que esto pueda ser útil es al recoger un fichero (para subir ficheros podremos utilizar la librería fileupload de jakarta).
Cabeceras HTTP 1.1
Estas cabeceras te dan la posivilidad de acceder a información de la transferencia de datos cliente-servidor. Para acceder a ellas únicamente utilizaremos los métodos getHeader y getHeaderNames que devolverán los strings correspondientes a los valores de estas. Podemos encontrarnos con las siguientes:
host: Correspondiente a la dirección del cliente.
user-agent: Indica información sobre la plataforma del cliente, el SO, el navegador…
accept-language, accept-encoding y accept-charset: Sobre el tipo de carácteres que usa el cliente.
referer: La página web desde la que ha sido llamado.
…
Variables CGI
Otra forma de recoger información de la conexión con tu cliente es la de usar algunos métodos que contiene el objeto request:
getAuthType: Tipo de autorización.
getContentLength: El número de bytes que se te ha enviado.
getPathInfo, getServletContext().getRealPath y getPathTranslated: Recoger la ruta usada para llamar a tu servlet.
getRemoteAddr y getRemoteHost: Dirección del cliente.
…
Response
Veamos los métodos que pueden sernos útiles en el objeto HttpServletResponse:
sendRedirect: Le pasamos un string y redirige la web en la que está el usuario a otra nueva con dirección correspondiente al string.
setStatus: Indica un estado al cliente (existen ciertos códigos para ello).
sendError: Devuelve un estado de error al navegador del cliente.
Cookies
Las cookies, con las que podemos guardar información en el mismo ordenador cliente (logins y passwords, identificadores en una compra, preferencias de una web…), son fáciles de utilizar mediante servlets. Para ello en el objeto response existe un método llamado setCookie al que se le pasa un objeto Cookie; no hay mucho destacable en este objeto, tal vez el método setMaxAge por el que indicamos mediante segundos cuanto tiempo permanecerá válida la cookie. Bueno, sí… Otro método curioso es getPath que se combina con setPath, estos nos permitirán indicar en qué rutas será válida la cookie, por defecto es en la que se envia pero podemos indicar que se use en toda nuestra web pasándole el directorio raíz: cookie.setPath(“/”).
El objeto request tiene un método llamado getCookies que recoge las cookies correspondientes a tu web en el cliente; si getCookies devuelve null es porque el cliente no ha recogido anteriormente cookies en tu web.
Sesiones
Recogeremos la sesión del objeto request mediante el método getSession, este retorna un objeto HttpSession
Para ver los datos asociados a una sesión usaremos el método getAttribute
De la misma forma, también podremos guardar datos mediante el método setAttribute
Para eliminar la información de la sesión lo que haremos será llamar a removeAttribute (para eliminar un dato concreto), invalidate (para eliminar todos los datos de la sesión) o logout (para destruir la sesión).
Nosotros no debemos de crear ningún objeto sesión, se crea automáticamente con la primera petición a nuestra página (sólo debemos de llamar al request.getSession()) aunque si queremos si la sesión se acaba de crear, getSession permite pasarsele un boolean, si este es false retornará null si la sesión no existía anteriormente. Aunque también existe el método isNew.
Los atributos, o datos adjuntos a una sesión, son objetos que tienen como id un string y que se almacenan en el mismo objeto HttpSession. Para recogerlos deberemos hacer un cast de Object al tipo deseado.
Los métodos getCreationTime, getLastAccessedTime, getMaxInactiveIntervall y setMaxInactiveIntervall nos permiten controlar la caducidad de la sesión, cuando fue creada, cuando fue usada por última vez…
Una vez utilices los objetos sesiones todas las páginas de tu dominio se generarán dinámicamente, no tendrás ninguna página estática (hasta que no hagas un logout de la sesión), para poder manejar las nuevas urls deberás parsearlas tanto para añadirlas en tus links como para hacer una redirección, gracias a Dios existen los métodos encodeURL y encodeRedirectURL que se usan de la siguiente forma:
String url = "laquesea.html";
String newUrl = response.encodeURL(url);
response.getWriter().print("<A HREF='/" + newURL + ">Link</A>");
String url = "laquesea.html";
String newUrl = response.encodeRedirectURL(url);
response.sendRedirect(newUrl);
Xtras
public static String filter(String input) {
if (!hasSpecialChars(input)) {
return(input);
}
StringBuffer filtered = new StringBuffer(input.length());
char c;
for(int i=0; i<input.length(); i++) {
c = input.charAt(i);
switch(c) {
case '<': filtered.append("<"); break;
case '>': filtered.append(">"); break;
case '"': filtered.append("""); break;
case '&': filtered.append("&"); break;
default: filtered.append(c);
}
}
return(filtered.toString());
}
private static boolean hasSpecialChars(String input) {
boolean flag = false;
if ((input != null) && (input.length() > 0)) {
char c;
for(int i=0; i<input.length(); i++) {
c = input.charAt(i);
switch(c) {
case '<': flag = true; break;
case '>': flag = true; break;
case '"': flag = true; break;
case '&': flag = true; break;
}
}
}
return(flag);
}
Cómo generar imágenes?
Indicaremos que se va a enviar una imágen: response.setContentType(“image/jpeg”);
No usaremos el PrintWriter (recogido mediante el método getWriter) sino un stream: OutputStream out = response.getOutputStream();
Usaremos un objeto BufferedImage para ir dibujando sobre él.
Mediante el método write de la clase ImageIO volcaremos el BufferedImage sobre el OutputStream: ImageIO.write(image, “jpg”, out); (siendo image el BufferedImage).
Redirigir página
Método que según la cuenta bancacria de un cliente redirigirá la salida a una página o a otra:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BankCustomer customer = BankCustomer.getCustomer(request.getParameter("id"));
String address;
if (customer == null) {
address = "/WEB-INF/bank-account/UnknownCustomer.jsp";
} else if (customer.getBalance() < 0) {
address = "/WEB-INF/bank-account/NegativeBalance.jsp";
request.setAttribute("badCustomer", customer);
} else if (customer.getBalance() < 10000) {
address = "/WEB-INF/bank-account/NormalBalance.jsp";
request.setAttribute("regularCustomer", customer);
} else {
address = "/WEB-INF/bank-account/HighBalance.jsp";
request.setAttribute("eliteCustomer", customer);
}
RequestDispatcher dispatcher = request.getRequestDispatcher(address);
dispatcher.forward(request, response);
}