Herramientas de usuario

Herramientas del sitio


unidades:08_spring:03_spring_mvc

Spring MVC

Entramos por fin en la parte del desarrollo de una aplicación web. Spring MVC es parte de la funcionalidad de Spring framework pero dedicada a la parte de los Servlets y JSP.

Hemos elegido Spring MVC para la parte web por dos motivos:

  • Mejora el uso del API de Servlets pero sin estar muy alejados de ellos. Usar Spring MVC es como usar los Servlets pero con mejoras que nos hacen la vida mas fácil. En Spring en vez de usar Servlets usaremos clases Java llamadas controladores.
  • Se integra perectamente con la parte de Inyección de Dependencias de Spring.

No vamos a entrar en detalles sobre cómo funciona Spring MVC sino que vamos a explicar lo mínimo para que se pueda usar Spring MVC.

Ficheros de configuración

Veamos ahora los ficheros que es necesario modificar/crear para poder usar Spring MVC

web.xml

Añadir al fichero web.xml el siguiente fragmento xml:

1 | Fragmento del web.xml
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> 
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>    
 
<servlet>
    <servlet-name>dispatcher</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup> 
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name> 
    <url-pattern>*.html</url-pattern>
</servlet-mapping>

Este código XML hay que copiarlo tal cual está en el web.xml pero hay 2 líneas que pueden modificarse para personalizar la aplicación.

  • Línea 6: Vemos como se especifica el nombre del fichero de configuración de Spring. En este caso es el mismo que usamos en el tema anterior classpath:applicationContext.xml.
  • Línea 16: Es el patrón que tendrán las URL para que se redireccionen a nuestros controladores de Spring. En nuestro caso , cualquier petición que acabe con “.html” será redirigida hasta los controladores definidos en Spring, pero podemos especificar cualquier patrón para nuestros controladores.
En muchos tutoriales se pone como valor a <url-pattern> el valor de *.jsp. Nunca se debe usar ese valor ya que se producirá un error puesto que no sabrá correctamente redireccionar desde los controladores a las páginas JSP de la vista.

dispatcher-servlet.xml

Se deberá crear el fichero dispatcher-servlet.xml en la carpeta /WEB-INF. El contenido del mismo será el siguiente:

1 | dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:mvc="http://www.springframework.org/schema/mvc" 
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd 
">
 
    <mvc:annotation-driven/> 
    <context:component-scan base-package="ejemplo02.presentacion" />
 
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
        <property name="prefix" value="/WEB-INF/jsp/"/> 
        <property name="suffix" value=".jsp"/> 
    </bean> 
</beans>

Este código XML hay que copiarlo tal cual está en el dispatcher-servlet.xml pero hay 2 líneas que deben modificarse para personalizar la aplicación:

  • Línea 13: Se debe indicar el paquete donde se encuentran los controladores web.
  • Línea 16: Se indica dónde deben estar las páginas JSP a las que se redirecciona desde los controladores. Se ha elegido /WEB-INF/jsp/.Normalmente este valor no es necesario modificarlo ya que las páginas JSP deberían estar dentro de la carpeta WEB-INF para que desde el navegador no se pueda tener acceso directo a ellas. Debe hacerse a través de los controladores.
Recuerda modificar el tag <context:component-scan> para indicar dónde se encuentra el paquete con los controladores web.

context.xml

Este fichero no tiene nada que ver con Spring MVC. El fichero se utiliza para configurar el javax.sql.DataSource que usará el pool de conexiones.

Si no recuerdas que es el pool de conexiones se recomienda ver el tutorial pool de conexiones.
1 | context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/Ejemplo02">
    <Resource
        name="jdbc/hibernate1" 
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/hibernate1"
        username="hibernate1" 
        password="hibernate1"
        maxActive="100" 
        maxIdle="30" 
        maxWait="10000"
        auth="Container" 
        type="javax.sql.DataSource"
        validationQuery="SELECT 1 FROM dual"
     /> 
</Context>      

hibernate.cfg.xml

El fichero hibernate.cfg.xml es necesario modificarlo para indicarle a Hibernate que obtenga la conexiones a través del DataSource en vez de crearlas él directamente.

1| hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="connection.datasource">java:/comp/env/jdbc/hibernate1</property>
    <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
    <property name="hibernate.show_sql">true</property>
    <mapping resource="ejemplo02/persistencia/dao/impl/Profesor.hbm.xml"/>
    <mapping resource="ejemplo02/persistencia/dao/impl/Usuario.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

Vemos en la línea 6 como se ha incluido la propiedad connection.datasource y se ha eliminado toda referencia a la base de datos.

applicationContext.xml

No es necesario modificar el fichero applicationContext.xml de configuración de Spring

SessionFactory e Hibernate

En las aplicaciones de escritorio vimos como se debía llamar a distintos métodos de HibernateUtil para gestionar el objeto SessionFactory. En las aplicaciones Web debemos hacer lo mismo para lo que simplemente crearemos la clase Java HibernateContextListenerAndFilter

1 | HibernateContextListenerAndFilter.java
@WebListener()
@WebFilter(urlPatterns = {"*.html"})
public class HibernateContextListenerAndFilter implements Filter,ServletContextListener {
 
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        HibernateUtil.buildSessionFactory();
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            HibernateUtil.openSessionAndBindToThread();
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            HibernateUtil.closeSessionAndUnbindFromThread();
        }
    }
 
    @Override
    public void destroy() {
    }
 
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        HibernateUtil.closeSessionFactory();
    }
}

Esta clase se ejecutará al inicio y final de la aplicación y en cada petición web cuya URL tenga el patrón “*.html”.Para conseguirlo se han añadido anotaciones de Java EE 6 Web @WebListener y @WebFilter

No se va a explicar nada de Java EE 6 ya que está fuera del ámbito de este curso pero os dejo el Tutorial Java EE 6 y concretamente sobre la anotación @WebListener en Servlet Lifecycle y sobre la anotación @WebFilter en Filtering Requests and Responses

Lo que sí vamos a comentar son la líneas referidas a HibernateUtil que tiene ésta clase.

  • Línea 7: Al inicio de la aplicación web se inicializa Hibernate con la llamada a HibernateUtil.buildSessionFactory()
  • Línea 33: Al finalizar la aplicación web se cierra Hibernate con la llamada a HibernateUtil.closeSessionFactory().
  • Línea 18: Al inicio de la petición web se crea la sesión de Hibernate con la llamada a HibernateUtil.openSessionAndAttachToThread()
  • Línea 22: Al finalizar la petición web se destruye la sesión de hibernate con la llamada a HibernateUtil.closeSessionAndDeattachFromThread()

Como vemos, el patrón utilizado con HibernateUtil es exactamente igual al usado en las aplicaciones de escritorio con lo que ha sido muy sencillo utilizar HibernateUtil en una aplicación web.

Para que funcione la clase HibernateContextListenerAndFilter es necesario usar Tomcat 7 con la versión de Java EE 6 Web.

Si se quisiera usar con con Java EE 5 se podría hacer eliminado las anotaciones y modificando el fichero web.xml

tomcat7_javaee6.png

web.xml

En vez de usar la anotaciones:

@WebListener()
@WebFilter(urlPatterns = {"*.html"})

Se puede modificar el web.xml añadiendo las siguientes líneas:

<listener>
    <listener-class>com.fpmislata.persistencia.hibernate.HibernateContextListenerAndFilter</listener-class>
</listener>
<filter>
    <filter-name>HibernateContextListenerAndFilter</filter-name>
    <filter-class>com.fpmislata.persistencia.hibernate.HibernateContextListenerAndFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HibernateContextListenerAndFilter</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>    
 

Controllers

Ahora veamos las clases Java que usaremos como controladores en nuestra aplicación web. Estas clases son muy parecidas a los Servlets de Java EE pero más sencillas de usar. Recuerda que usamos estas clases gracias a que estamos usando el framework Spring MVC.

Siguiendo la moda actual, no es necesario que los controladores en Spring MVC extiendan de ninguna otra clase ni que implementen ningún interfaz. Únicamente deben incluir la anotación @Controller la principio de la clase.

1 | ProfesorController.java
@Controller
public class ProfesorController {
 
    @Autowired
    private ProfesorDAO profesorDAO;
 
    @RequestMapping({"/index.html"})
    public ModelAndView read(HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> model = new HashMap<>();
        String viewName;
 
        try {
            Profesor profesor = profesorDAO.get(1001);          
            model.put("texto", profesor.toString());
            viewName = "profesor";
        } catch (BussinessException ex) {
            model.put("msgError", "No es posible obtener los datos");
            viewName = "error";
        }
 
        return new ModelAndView(viewName, model);
    } 
 
}

Pasemos ahora a explicar el código de controlador.

Como ya hemos dicho lo principal que debe tener un controller de Spring MVC es la anotación @Controller al principio de la clase (Línea 1). Con ésto sabrá Spring MVC que es un controlador.

Manejo de peticiones

El manejo de peticiones web se realiza a través de los métodos del controlador. Cada método gestionará las peticiones de una o más URLs y puede haber tantos métodos como se desee. Ésto es una gran ventaja respecto a un Servlet ya que hace mucho más sencillo procesar una serie de URL relacionadas en un único controlador. Recuerda que en un Servlet había un único método para todas las peticiones.

Cada método que controla peticiones Web tendrá la anotación @RequestMapping (Línea 7). Esta anotación tendrá como argumento un Array de Strings con todas las URLs que va a manejar. Por ello nótese que hay una llaves “{ }” antes y después del String de la URL que maneja ya que se permite más de una.

Los argumentos de entrada del método son los objetos HttpServletRequest y HttpServletResponse al igual que en un Servlet.

Spring MVC tiene muchas funcionalidades relativas las URL que controla, parametros de entrada y de salida.Aquí se han utilizado únicamente HttpServletRequest y HttpServletResponse para asemejarlos mas a los Servlets y no complicar el uso de Spring MVC pero se recomienda al programador ver todas las opciones que dispone Spring MVC. Mas información en 16.3 Implementing Controllers

El método retorna una clase de Spring MVC llamada ModelAndView. Esta clase contendrá un String con la página jsp a mostrar ( es decir la Vista ) y un Map con los datos que necesita la vista para mostrarse (es decir el Modelo).

Podemos ver en la línea 22:

return new ModelAndView(viewName, model);

como se crea un nuevo objeto ModelAndView que tiene como argumentos un String con el nombre de la página JSP a mostrar y el Map con los datos para la vista.

Recuerda que en el String con el nombre de la vista que se retorna en ModelAndView no se debe incluir el sufijo “.jsp” ya que en el fichero dispatcher-servlet.xml , la línea 17 , ya se indica que se añadirá como sufijo el texto “.jsp”.

La página JSP

Las páginas JSP se deben colocar en la carpeta WEB-INF/jsp tal y como se ha definido en el fichero dispatcher-servlet.xml , en la línea 16.

La vista tiene acceso a los elementos del Map del modelo que se creó en la clase ModelAndView mediante el siguiente código:

Object texto=request.getAttribute("texto");

Siendo el String “texto” la clave del Map con la que se guardó el valor.

Un ejemplo de página JSP es la siguiente:

1 | profesor.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%
Object texto=request.getAttribute("texto");
%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Profesor</title>
    </head>
    <body>
        <h1><%=texto %></h1>
    </body>
</html>

Vemos en la línea 3 cómo se accede a los datos del modelo.

unidades/08_spring/03_spring_mvc.txt · Última modificación: 2023/04/07 21:26 por 127.0.0.1