4.3 Problemas con servlets y páginas JSP. Patrones Situación a la que queremos llegar n n n Poder usar directamente herramientas de diseño de páginas web para implementar la vista Las actualizaciones al aspecto gráfico no deben provocar un re-arranque del servidor Separación de roles n Informáticos n n Diseñadores gráficos o similares n n Modelo, controlador y partes de la vista no relacionados con el aspecto gráfico Implementación del aspecto gráfico de la aplicación Esta separación en muchos puede ser sólo ideal (depende de la cultura de la empresa), pero la idea es tender hacia ella ¿ Son los Servlets la solución ? n ¿ Podemos usar directamente herramientas de diseño de páginas web ? n n ¿ Se pueden hacer actualizaciones al aspecto gráfico sin re-arrancar el servidor ? n n No No ¿ Es posible una separación de roles ? n n Las personas que desarrollan el modelo no tienen porque ser las mismas que las que hacen los servlets Sin embargo, las personas que desarrollan los servlets necesitan conocimientos de programación ¿ Es JSP la solución ? n ¿ Podemos usar directamente herramientas de diseño de páginas web ? n n ¿ Se pueden hacer actualizaciones al aspecto gráfico sin re-arrancar el servidor ? n n Sí Sí ¿ Es posible una separación de roles ? n n Las personas que desarrollan el modelo no tienen porque ser las mismas que las que hacen las páginas JSP Sin embargo, las personas que desarrollan las páginas JSP necesitan conocimientos de programación para incrustar el código Java (scriptlets y expresiones) ¿ Cuál es la solución ? n n Una que permita construir páginas JSP sin código Java (o de otro lenguaje de programación) ¿ Cómo podemos conseguirlo ? n n Con un buen diseño Model-View-Controller Usando el mecanismo de extensión de tags de JSP n n n n Permite implementar “acciones a medida” (custom actions) Paquete javax.servlet.jsp.tagext Podríamos implementar un buen número de acciones para eliminar una parte importante de los scriptlets y expresiones de las páginas JSP Un diseñador gráfico podría aprender a usarlas n n Al fin y al cabo, tienen el aspecto de los tags HTML (un nombre y atributos) Muchos editores de HTML permiten integrar librerías de acciones para desarrollar páginas JSP Problema 1: URL rewriting n Para que una aplicación que use sesiones sea robusta, necesita aplicar URL rewriting a todas las URLs que genera o hace un sendRedirect n Ej.: Extracto de Portal2/MainPage.jsp <a href="<%= response.encodeURL("../Index.jsp") %>"> Servlet and JSP tutorial main page</a> <br> <a href="<%= response.encodeURL("ProcessLogout.jsp") %>">Logout</a> n Sería más sencillo disponer de una acción que lo hiciese automáticamente <html:link page="../Index.jsp">Servlet and JSP tutorial main page </html:link> <br> <html:link page="ProcessLogout.jsp">Logout</html:link> Problema 2: Mostrar formularios (1) n Repasar Portal2/ShowLogin.jsp n n n n Necesidad de un scriptlet muy grande para recuperar posibles errores Necesidad de usar expresiones para insertar los posibles mensajes de errores Necesidad de aplicar URL rewriting en el atributo action del formulario Sería más sencillo disponer de acciones que ocultasen todo este código Problema 2: Mostrar formularios (2) <html> <head> <title>Portal-2 login form</title> </head> <body text="#000000" bgcolor="#ffffff"> <html:form action="ProcessLogin.jsp"> <table width="100%" border="0" align="center" cellspacing="12"> <%-- Login name --%> <tr> <th align="right" width="50%">Login name</th> <td align="left"> <html:text property="loginName" size="16" maxlength="16"/> <html:errors property="loginName"/> </td> </tr> Problema 2: Mostrar formularios (3) <%-- Password --%> <tr> <th align="right" width="50%">Password</th> <td align="left"> <html:password property="password" size="16" maxlength="16"/> <html:errors property="password"/> </td> </tr> <%-- Remember my password --%> <tr> <th align="right" width="50%"> Remember my password (cookies must be enabled) </th> <td align="left"> <html:checkbox property="rememberMyPassword"/> </td> </tr> Problema 2: Mostrar formularios (y 4) <tr> <td width="50%"></td> <td align="left" width="50%"> <input type="submit" value="Login"> </td> </tr> </table> </html:form> </body> </html> Patrón View Helper n n n Este tipo de acciones JSP a medida que estamos viendo (problemas 1 y 2), y que nos ayudan a generar la vista, corresponden a la aplicación del patrón View Helper Facilitan el acceso a objetos Java (en cualquiera de los cuatro ámbitos) Generan HTML, WML, etc. sin aspecto gráfico n n Ej.: Campos de entrada en formularios, URLs (para hacer más transparente el paso de parámetros, URL rewriting, etc.) Nunca deben generar HTML, WML, etc. centrado en aspecto gráfico n n Ejemplo de mala idea: tener un acción que imprime un objeto Java en una tabla Precisamente lo que queremos evitar es código Java mezclado con HTML, WML, etc. Problema 3: Procesar peticiones (1) n Las páginas JSP de procesamiento suelen tener el siguiente esquema n (1.1) Recuperar los valores de los parámetros n n n (1.2) Validar los parámetros n n n Directamente de la request Usando JavaBeans En caso de tratarse del procesamiento de un formulario, si hay errores, se hace un forward al formulario con los errores insertados en la request En caso de que ocurra algún error “inesperado” => sendRedirect a una página que indique “error interno” (1.3) Invocar una operación sobre un Business Delegate del modelo o una fachada del controlador n Si se produce una excepción, mismo tratamiento que en la validación de parámetros Problema 3: Procesar peticiones (2) n (1.4) Hacer un sendRedirect a otra página o generar una respuesta n (1.4.1) sendRedirect n n (1.4.2) Generar una respuesta n n Ej.: En el procesamiento de un formulario de login Ej.: En el procesamiento de una búsqueda Variantes n En muchas situaciones reales el paso 1.3 se implementa sin hacer uso de Business Delegates y lanzado queries directamente contra la BD vía JDBC n ¡ Modelo mezclado con la vista ! n n Quizás sería mejor decir: ¡ modelo inexistente ! Difícil de mantener en aplicaciones de tamaño medio y grande Problema 3: Procesar peticiones (3) n Análisis n Páginas de procesamiento que son del tipo 1.4.1 n n n No generan aspecto gráfico Sólo contienen un scriptlet grande Páginas de procesamiento que son del tipo 1.4.2 n n Contiene un scriptlet grande al principio La última parte de la página genera la respuesta HTML, WML, etc. n n Suelen hacer uso de scriptlets para iterar sobre los resultados devueltos por la operación del modelo y darles formato HTML, WML, etc. Ej.: Imprimir los resultados de una búsqueda en una tabla Problema 3: Procesar peticiones (4) n ¿ Cómo podemos eliminar el código Java en las páginas de tipo 1.4.1 ? n n Implementándolas como servlets (controlador) y no como páginas JSP ¿ Cómo podemos eliminar el código Java en las páginas de tipo 1.4.2 ? n n Implementándolas como un servlet (controlador) y una página JSP (vista) Servlet n n n Ejecuta el código que antes iba en el scriptlet En caso de errores => forward a la página JSP que muestra el formulario (con errores insertados en la request) o sendRedirect a una página de error interno En otro caso, deja el valor de retorno de la operación del Business Delegate en la request como atributo y hace un forward a la página JSP de visualización de resultados Problema 3: Procesar peticiones (5) n ¿ Cómo podemos eliminar el código Java en las páginas de tipo 1.4.2 ? (cont) n Página JSP de visualización de resultados n n Recupera los resultados de la request con acciones JSP Hace uso de acciones JSP para iterar sobre los resultados de tipo Collection o similar Problema 3: Procesar peticiones (6) n El enfoque anterior requiere un servlet por cada petición que haya que procesar n Si deseamos saber cuál es la siguiente URL a la que se salta tras invocar una petición de procesamiento, hay que examinar el servlet en cuestión n n Flujo de control difícil de seguir Si se necesita aplicar políticas globales a todos los servlets, es necesario programarlas en cada uno n Ej.: Hacer log de cada petición que se recibe, imprimiendo la URL invocada, los nombres de los parámetros y sus valores Problema 3: Procesar peticiones (7) n Patrón Front Controller n Emplea un solo servlet javax.servlet.http.HttpServlet Action FrontController 0..n + process # doGet # doPost doGet llama a doPost (o alrevés) Action1 ActionN ... Problema 3: Procesar peticiones (8) n Patrón Front Controller (cont) n n Configuramos el servidor de aplicaciones para que las peticiones a URLs que terminen en .do se redirijan al servlet FrontController En WEB-INF/web.xml <servlet> <servlet-name>FrontController</servlet-name> <servlet-class>FrontController</servlet-class> </servlet> <servlet-mapping> <servlet-name>FrontController</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> Problema 3: Procesar peticiones (9) n Patrón Front Controller (cont) n n Ej.: Portal-2 Acciones: ProcessLoginAction y ProcessLogoutAction n n n Funcionalmente equivalentes a Portal2/ProcessLogin.jsp y Portal2/ProcessLogout.jsp Las peticiones a las URLs Portal2/ProcessLogin.do y Portal2/ProcessLogout.do llegan al FrontController Cuando el FrontController arranca (init) n Lee un fichero de configuración que especifica n n n n Portal2/ProcessLogin.do => Action = ProcessLoginAction, Success = /Portal2/MainPage.jsp, Input = /Portal2/ShowLogin.jsp Portal2/ProcessLogout.do => Action = ProcessLogoutAction, Success = /Index.jsp InternalError = /Portal2/InternalError.jsp Crea una instancia por cada acción existente Problema 3: Procesar peticiones (10) n Patrón Front Controller (cont) n n Cuando al FrontController le llega una petición, la pasa a la acción correspondiente El método process de la acción (1) recupera los valores de los parámetros, (2) invoca una operación sobre un Business Delegate o una fachada del controlador, (3) deja los resultados en la request, y (4) hace un forward o sendRedirect a Success, Input o InternalError n La clase base Action (u otra en un framework más complejo) le facilita el hacer el forward/sendRedirect n n n Usa nombre lógicos (Success, Input o InternalError) y no los nombres de las URLs reales El sendRedirect aplica URL rewriting automáticamente El fichero de configuración deja claro el flujo de control Problema 3: Procesar peticiones (y 11) n Si quisiésemos aplicar una política global (ej.: trazar peticiones en un log para depuración) a todas las acciones o un subconjunto de ellas n n n doGet/doPost (FrontController) pueden hacerlo antes de llamar a la acción También puede hacerlo la clase base Action O aún mejor, podemos aplicar Chain Of Responsability en doGet / doGet (o en la clase base Action) antes y/o después de ejecutar la acción n n n Cadena del filtros de pre-procesamiento Cadena de filtros de post-procesamiento Sun Java Center llama Decorating Filter a este patrón Otros problemas n Hay que tener cuidado cuando se escribe el valor de un atributo de un objeto Java en el HTML generado n n n Podría contener caracteres especiales para HTML: <, >, ', " y& Es preciso convertirlos a referencias internas: &lt, &gt, &#39, &#34 y &amp; En los ejemplos del tutorial de servlet no se trata este caso n n ¿ Y si queremos internacionalizar la aplicación ? n n n Ej.: Elegir <hola> como nombre de login y observar el valor que imprime MainPage.jsp Ej.: que el usuario pueda elegir el idioma: español, gallego, inglés, etc. Problema: en los ejemplos que hemos visto los mensajes están dentro de las páginas JSP Y más problemas, y más problemas, y más problemas ... Conclusión (1) n Necesitamos un framework que nos proporcione n n Un servlet FrontController y clases relacionadas Un buen número de acciones JSP a medida (custom tags) que actúen como View Helpers para n n n n n n n Facilitar la construcción de las páginas que muestran formularios (campos de entrada y errores) Imprimir URLs (con URL rewriting automático) Acceso a objetos Java en cualquiera de los posibles ámbitos (request, session, page y application) Imprimir el valor de atributos de objetos Java Iterar sobre objetos de tipo Collection o similar Soporte para internacionalización Etc. Conclusión (y 2) n Con este framework una aplicación web tendrá el siguiente aspecto n Modelo n n n n Controlador n Servlet FrontController y clases acción n Desacopla la vista del modelo Vista n n n Conjunto de clases que implementan la lógica de negocio Independiente de la vista Páginas JSP sin código Java Usan muchas acciones JSP a medida (la mayor parte proporcionados por el framework) Jakarta Struts n n ¡ Es el framework que queremos ! La versión 1.0 (estable) vio la luz en Julio del 2001