Control navegación en Servlets

0
48840

Control de navegación en Servlets

Históricamente, un Web es era servidor bastante sencillo que sirve para
proporcionar ficheros estáticos, normalmente imagenes y páginas HTML. Podeis
ver incluso, en otro de nuestros tutoriales, como crear tu propio WebServer
en Java

Cuando se extindió el uso y empezó a demandarse la creación de estas
páginas de un modo dinámico, a través del denominado CGI (Common Gateway
Interface), se parcheó el sistema para permitir de un modo sencillo permitir
ejecutar programas en el servidor y redirigir la salida por pantalla al cliente,
pasando las peticiones a través de variables de entorno (la famosa QUERY_STRING).

  • Los que desarrollamos en su momento sistemas basados en CGI (sobre todo en
    C/C++), teníamos que hacérnoslo todo a mano: 
  • Leer las variables de entorno
  • Parsear las variables de entorno
  • Controlar la cantidad de instancias simultaneas de nuestro componente
  • Crear las cabeceras adecuadas para utilizar y mantener cookies
  • Saber trabajar con memoria compartida y semáforos (para comunicar
    procesos)
  • Crearnos sistemas propietarios de plantillas (lo que ahora serían los
    JSPs)

Menos mal, que a alguien se le ocurrió (y tenia medios para hacerlo) dividir
el esfuerzo en dos partes:

  • La parte control de peticiones, filtrado de parámetros, gestión de
    cookies y sesiones, etc. a través de un contenedor.
  • La parte de lógica pura de aplicación (capa de presentación)….

Esto es lo que ahora conocemos como servlets (en tecnología Java)

Un servlet es un componente que se ejecuta dentro de un contenedor Java y que
debe cumplir unas reglas (que lo consigue heredando de una clase base) para
poder ejecutarse en dicho contenedor.

Este contenedor Web se conecta al servidor Web como otro parche, utilizando
también la interfaz CGI …. por lo que todo lo que sabiamos, sigue siendo
útil y necesario cuando profundizamos en la tecnología.

Por lo tanto necesitamos tener un servidor Web y un contenedor de servlets
…… en este caso TOMCAT, nos proporciona ambas cosas en un mismo paquete.

Vamos a mostraros como desarrollar una aplicación basada en servlets y como
montar el esqueleto de una aplicación donde poder controlar la navegación y
poder tener separada la lógica de negocio y presentación. Para ello, podemos
usar NetBeans o Forte, que ya llevan integrados un servidor TOMCAT y sin
necesidad de hacer configuraciones adicionales, podemos probar lo que vamos
haciendo.

En otro tutorial, Aplicacionescon JSPs, podéis ver todas las pantallas para crear vuestra WebApp en Forte.
Vamos a partir de este punto.

Creamos un nuevo servlet

A través del asistente, creamos un servlet

Nuestro servlet será el encargado de controlar el Workflow de la
aplicación, haciendo ciertas validaciones e invocando a otros objetos para que
realicen el filtrado de los parámetros y la invocación de otros objetos de
negocio.

Rellenamos el resto de la información.

Y ya tenemos nuestra clase

import javax.servlet.*;
import javax.servlet.http.*;

public class servletsCentral extends HttpServlet {

/** Initializes the servlet.
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);

}

/** Destroys the servlet.
*/
public void destroy() {}

/** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
response.setContentType(«text/html»);
java.io.PrintWriter out = response.getWriter();
/* output your page here
out.println(«<html>»);
out.println(«<head>»);
out.println(«<title>Servlet</title>»);
out.println(«</head>»);
out.println(«<body>»);

out.println(«</body>»);
out.println(«</html>»);

*/
out.close();
}

/** Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}

/** Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}

/** Returns a short description of the servlet.
*/
public String getServletInfo() {
return «Short description»;
}

}

Sin saber mucho más, podemos ver que si cambiamos lo que hay en azul,
tenemos el espacio y un trozo de código de ejemplo para generar una página
dinámicamente. 

Descomentamos el código, introducimos algo en el cuerpo y ejecutamos el
servlet …

out.println(«<body>»);
out.println(«<center><h1>Primer Servlet</h1></center>»);
out.println(«</body>»);

Y ya estamos en marcha

Creación de sistema de acciones

Vamos a hacer una cosa, este servlet, vamos a querer usarlo para
muchas cosas … porque todas las aplicaciones tienen muchos servicios comunes

  • Control de seguridad

  • Contadores de peticiones

  • Estadísticas

Así que lo que podemos hacer, es crearnos unos objetos que
vamos a llamar acciones de tal modo que cuando algún usuario quiera
hacer algo en el sistema, llamará a este servlet y le dirá que acción quiere
ejecutar y los parámetros para ejecutarla. Nuestro servlet, controlará si el
usuario puede ejecutar dicha acción en base a dos cosas:

  1. Que tiene permisos para poder ejecutarla

  2. Que ha ejecutado anteriormente en nuestra aplicación alguna
    otra acción obligatoria.

Del mismo modo, podríamos ir contabilizando la cantidad de
peticiones que se realizan a cada acción.

Si os poneis a pensarlo ¿hace falta mucho más para un
control de WorkFlow básico y para capturar información para un sistema básico
de CRM operacional?

Bueno, vamos a crear una clase base abstracta, denominada
CAccionBase, y todas las demás acciones deberán heredar de esta para poder
ejecutarse. OJO, vamos a hacerlo simple y tratando de hacerlo medianamente bien,
aunque este código no debe servir de referencia … sobre todo, porque es un
paso intermedio para mostrar como llegar a donde queremos.

Estas acciones no poseerán la lógica
de negocio de la aplicación
….. solo se encargarán de invocar a
los componentes que realmente la posean y obtener grupos de variables sencillas,
que presentaremos en formato HTML a nuestros usuarios. 

En resultado es (en rojo la añadido a mano):

import javax.servlet.*;
import javax.servlet.http.*;

public abstract class CAccionBase {

public String Descripcion = «Esta debe ser la descripción de la acción«;

/** Creates a new instance of CAccionBase */
public CAccionBase() {
}

boolean procesaAccion(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException {
return false;
}

}

Vamos a crear dos acciones: 

  • mostrarhome (que será la de por defecto)
  • mostrarlistado (que mostrará una lista de links)

import javax.servlet.*;
import javax.servlet.http.*;
/**
*
* @author Roberto Canales
*/
public class CMostrarHome extends CAccionBase {

/** Creates a new instance of CMostrarHome */
public CMostrarHome() {
}

boolean procesaAccion(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException 
{
java.io.PrintWriter out = response.getWriter();
out.println(«<html>»);
out.println(«<head>»);
out.println(«<title>Servlet</title>»);
out.println(«</head>»);
out.println(«<body>»);
out.println(«<center><h1>Bienvenidos a la Home de nuestro tutorial</h1>»);
out.println(«<a href=\»servletsCentral?accion=mostrarlistado\»>pinchar para mostrar 
listado</a></center>»);

out.println(«</body>»);
out.println(«</html>»);
out.close();
return true;
}
}

Ahora creamos la clase que responderá a la acción mostrar listado

import javax.servlet.*;
import javax.servlet.http.*;
/**
*
* @author Roberto Canales
*/
public class CMostrarListado extends CAccionBase {

/** Creates a new instance of CMostrarHome */
public CMostrarListado() 
{
}

boolean procesaAccion(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException 
{
java.io.PrintWriter out = response.getWriter();
out.println(«<html>»);
out.println(«<head>»);
out.println(«<title>Servlet</title>»);
out.println(«</head>»);
out.println(«<body>»);
out.println(«<center><h1>Otros tutoriales</h1><br>»);

out.println(«<a href=\»https://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=seguridadtomcat\»>Seguridad en Tomcat</a><br>»);
out.println(«<a href=\»https://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=jspbasico\»>SAplicaciones con Jsps</a><br>»);
out.println(«<a href=\»https://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=taglibs\»>Librería de etiquetas en JSPs (Tag-libs)</a><br>»);
out.println(«</center>»);

out.println(«</body>»);
out.println(«</html>»);
out.close();
return true;
}

}

Tambien, vamos a crear una acción para especificar un estado
incorrecto

import javax.servlet.*;
import javax.servlet.http.*;

public class CAccionInvalida extends CAccionBase {

/** Creates a new instance of CMostrarHome */
public CAccionInvalida() {
}

boolean procesaAccion(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException 
{
java.io.PrintWriter out = response.getWriter();
out.println(«<html>»);
out.println(«<head>»);
out.println(«<title>Servlet</title>»);
out.println(«</head>»);
out.println(«<body>»);
out.println(«<center><h1>La accion es incorrecta</h1></center>»);
out.println(«</body>»);
out.println(«</html>»);
out.close();
return true;
}
}

Y ahora vemos la modificación del servlet, aunque los vamos a
explicar a trozos.

La idea es que cuando alguien realice una petición, comprobemos
si la acción que pide es válida o no y si ha ejecutado antes la acción
deseada por nosotros.

La petición que no hará será del tipo:

http://localhost:8081/servlet/servletsCentral?accion=mostrarlistado

Nosotros debemos saber leer este parámetro que se hace con:

String accionActual = request.getParameter(«accion»);

Para saber si el usuario a ejecutado antes la acción deseada,
debemos poder escribir en la sesión (para que se arrastren los datos entre cada
petición). Esto se hace con:

HttpSession sesionActual = request.getSession();
sesionActual.setAttribute(«ultimaaccion»,ultimaAccion);

y debemos saber leer el valor

HttpSession sesionActual = request.getSession();
Object ultimaAccionAlmacenado = sesionActual.getAttribute(«ultimaaccion»);

En función de la acción que nos pidan, crearemos el objeto
adecuado y ejecutaremos la petición (tambien validamos si se puede ejecutar):

if (accionActual.compareTo(«mostrarhome«) == 0)
{
return new CMostrarHome();
}
else if (accionActual.compareTo(«mostrarlistado«) == 0)
{
     if (accionAnterior.compareTo(«mostrarhome») != 0)
     {
          return new CAccionInvalida();
     }

return new CMostrarListado();
}
else
{
return new CAccionInvalida();
}

Y todo el código junto (organinado en metodos)

import javax.servlet.*;
import javax.servlet.http.*;

/**
*
* @author Roberto Canales
* @version
*/
public class servletsCentral extends HttpServlet {

/** Initializes the servlet.
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);

}

/** Destroys the servlet.
*/
public void destroy() {

}

boolean escribeEnSesionUltimaAccionValida(HttpServletRequest request,String ultimaAccion)
{
    HttpSession sesionActual = request.getSession();
    sesionActual.setAttribute(«ultimaaccion»,ultimaAccion);
    return true;

}

String leeDeSesionUltimaAccionValida(HttpServletRequest request)
{
    HttpSession sesionActual = request.getSession();
    Object ultimaAccionAlmacenado = sesionActual.getAttribute(«ultimaaccion»);

    if (ultimaAccionAlmacenado == null)
    {
        return «nula»;
    }

    return ultimaAccionAlmacenado.toString();
}

CAccionBase FactoriaAcciones(String accionActual, String accionAnterior)
{
// de momento escribimos a mano y luego iremos mejorando

if (accionActual.compareTo(«mostrarhome») == 0)
{
    return new CMostrarHome();
}
else if (accionActual.compareTo(«mostrarlistado») == 0)
{
    if (accionAnterior.compareTo(«mostrarhome») != 0)
    {
        return new CAccionInvalida();
    }

    return new CMostrarListado();
}
else
{
    return new CAccionInvalida();
}

}

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException 
{
    String accionActual = request.getParameter(«accion»);

    if(accionActual == null)
    {
           accionActual = «nula»;
    }

    String accionAnterior = leeDeSesionUltimaAccionValida(request);
    CAccionBase accion = FactoriaAcciones(accionActual,accionAnterior);

    if (!(accion instanceof CAccionInvalida))
    {
         escribeEnSesionUltimaAccionValida(request,accionActual);
    }

    accion.procesaAccion(request,response);
}

/** Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}

/** Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}

/** Returns a short description of the servlet.
*/
public String getServletInfo() {
return «Short description»;
}

}

Probamos invocar nuestro servlet y como no especificamos la
acción, nos muestra un error.

Si invocamos la acción mostrar Home

Y si pinchamos el link, vemos los tutoriales. 

Si tratamos de acceder a esta acción sin haber pasado por la home…
obtendremos un error.

Bueno, creo que básicamente hemos entendido la idea.

Creamos los JSPs

Ahora, si nos ponemos a pensar un poco….. podríamos mejorarlo
un poquito … podemos usar las acciones para ejecutar la lógica de negocio sin
pintar nada y delegar el pintado a un JSP.

Gracias a los JSPs, las páginas serían mucho más sencillas de
construir y podríamos dividir nuestros equipos de desarrollo en 2:

  • Programadores de acciones y lógica de negocio

  • Programadores de la capa de presentación

Solo tienen que poner se acuerdo en los objetos que deben
intercambiar. Esto puede garantizar una buena separación entre lógica de
negocio y presentación.

De este modo estamos aplicando el patrón ModeloVistaControlador
….(ver tutorial JSPsy MVC

En todos ellos incluimos un trozo de código para comprobar que la acción se
a ejecutado y que hemos sido capaces de pasar parámetros desde la acción al
JSP. <% out.print (request.getAttribute(«accion»).toString()); %>

JSP mostrarerror.jsp

<%@page contentType=»text/html»%>
<html>
<head>
<title>Servlet</title>
</head>
<body>
<center><h1>La accion es incorrecta</h1>
<br><BR>Vengo de la acción: <b>
<% out.print (request.getAttribute(«accion»).toString()); %>
</b>
</center>
</body>
</html>

JSP mostrarhome.jsp

<%@page contentType=»text/html»%>
<html>
<head>
<title>Servlet</title>
</head>
<body>
<center><h1>Pagina principal</h1>
<a href=»servletsCentral?accion=mostrarlistado»>pinchar para mostrar listado</a>

<br><BR>Vengo de la acción: <b>
<% out.print (request.getAttribute(«accion»).toString()); %>
</b>
</center>
</body>
</html>

JSP mostrarlistado.jsp

<%@page contentType=»text/html»%>
<html>
<head>
<title>Servlet</title>
</head>
<body>
<center><h1>Otros tutoriales</h1><br>
<a href=»../tutoriales/tutoriales.php?pagina=seguridadtomcat»>Seguridad en Tomcat</a><br>
<a href=»../tutoriales/tutoriales.php?pagina=jspbasico»>SAplicaciones con Jsps</a><br>
<a href=»../tutoriales/tutoriales.php?pagina=taglibs»>Librería de etiquetas en JSPs (Tag-libs)</a><br>

<br><BR>Vengo de la acción: <b>
<% out.print (request.getAttribute(«accion»).toString()); %>
</b>

</center>
</body>
</html>

Y ahora modificamos nuestras acciones … aunque solo vamos a mostrar una
porque las demás son iguales.

Lo que hacemos es enviar una cadena de caracteres a través del objeto
petición 

request.setAttribute («accion»,
«mostrarhome»);
 

import javax.servlet.*;
import javax.servlet.http.*;
/**
*
* @author Administrator
*/
public class CMostrarHome extends CAccionBase {

/** Creates a new instance of CMostrarHome */
public CMostrarHome() {
}

boolean procesaAccion(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException 
{
request.setAttribute («accion», «mostrarhome»);
return true;
}
}

Ahora vemos el servlet y marcamos en verde lo modificado

import javax.servlet.*;
import javax.servlet.http.*;

public class servletsCentral extends HttpServlet {

/** Initializes the servlet.
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);

}

/** Destroys the servlet.
*/
public void destroy() {

}

boolean escribeEnSesionUltimaAccionValida(HttpServletRequest request,String ultimaAccion)
{
HttpSession sesionActual = request.getSession();
sesionActual.setAttribute(«ultimaaccion»,ultimaAccion);
return true;
}

String leeDeSesionUltimaAccionValida(HttpServletRequest request)
{
HttpSession sesionActual = request.getSession();
Object ultimaAccionAlmacenado = sesionActual.getAttribute(«ultimaaccion»);

if (ultimaAccionAlmacenado == null)
{
return «nula»;
}

return ultimaAccionAlmacenado.toString();
}

CAccionBase FactoriaAcciones(String accionActual, String accionAnterior)
{
// de momento escribimos a mano y luego iremos mejorando

if (accionActual.compareTo(«mostrarhome») == 0)
{
return new CMostrarHome();
}
else if (accionActual.compareTo(«mostrarlistado») == 0)
{
if (accionAnterior.compareTo(«mostrarhome») != 0)
{
return new CAccionInvalida();
}

return new CMostrarListado();
}
else
{
return new CAccionInvalida();
}
}

String FactoriaJSPs(String accionActual, String accionAnterior)
{
    if (accionActual.compareTo(«mostrarhome») == 0)
    {
          return «mostrarhome.jsp»;
     }
     else if (accionActual.compareTo(«mostrarlistado») == 0)
     {
          return «mostrarlistado.jsp»;
     }
     else
     {
          return «mostrarerror.jsp»;
      }
}

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException 
{
String accionActual = request.getParameter(«accion»);

if(accionActual == null)
{
accionActual = «nula»;
}

String accionAnterior = leeDeSesionUltimaAccionValida(request);

CAccionBase accion = FactoriaAcciones(accionActual,accionAnterior);

if (!(accion instanceof CAccionInvalida))
{
escribeEnSesionUltimaAccionValida(request,accionActual);
}

accion.procesaAccion(request,response);

String jspPresentacion = FactoriaJSPs(accionActual,accionAnterior);
getServletConfig().getServletContext().getRequestDispatcher(«/» +
jspPresentacion).forward(request, response);

}

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}

/** Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException {
processRequest(request, response);
}

/** Returns a short description of the servlet.
*/
public String getServletInfo() {
return «Short description»;
}

}

Y si volvemos a navegar por las páginas, podremos ver que el JSP es quien
resuelve la página y es capaz de recuperar los datos deseados.

Podemos ver que esto va cogiendo forma ……

:Ahora, solo tendríamos que mejorar un poquito el sistema para que no este
tan acopladas al código:

  • Nombre de las acciones
  • Clase de la accion
  • Jsp de presentación
  • E incluso contadores (para estadísticas y CRM)

Para ello, podemos crear una clase que se encargue de retornarnos esta
información … que almacenaremos en un fichero o base de datos …… pero
esto …… es otra historia ….

Sobre el
Autor ..

Dejar respuesta

Please enter your comment!
Please enter your name here