jueves, 5 de octubre de 2017

Introduction to Spring Web MVC with NetBeans


  Este laboratorio muestra la forma en como crear una simple aplicación web MVC con el framework de spring desde el IDE de NetBeans, y esta guiado de la página de NetBeans https://netbeans.org/kb/docs/web/quickstart-webapps-spring.html

  Necesitamos tener el software de Spring en nuestra computadora, para ello lo obtenemos con una busqueda spring download o de https://spring.io/tools/sts/all, el archivo zip resutante se desempaca en algun lugar.

  Ahora desde NetBeans creamos
New Project -> Java Web -> Web Application
con nombre HelloSpring


  Se deselecciona la opcion Enable Context and Dependency Injection option, ya que no se utilizará para este ejemplo el uso de la especificación JSR-299, y utilizaremos para este simple ejemplo de spring la versión de spring 3.2.7, ya que SimpleFormController es soportado por esta versión, además no requeriremos la libreria JSTL (JavaServer Page Standard Tag Library). al deseleccionarla no la agregara al classpath.


    La automatización de netbeans me genera la siguiente estructura del projecto, lista para ejecutarse

   La ejecución de este template sin modificación alguna nos da

Veamos que esta pasando, veamos el deployment descriptor (web.xml) en WEB-INF->web.xml, vemos que el punto de entrada por default es el archivo redirect.jsp

    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>

Dentro del archivo redirect.jsp hay una sentencia que redirecciona todas las request a index.htm

<% response.sendRedirect("index.htm"); %>

En el archivo deployment descriptor (web.xml) vemos que todos los request con patron URL que coincidan con *.htm son mapeados al DispatcherServlet de Spring.

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>

Observemos en la libreria esta clase

El DispatcherServlet maneja los request entrantes según la configuración en el archivo dispatcher-servlet.xml. veamos el código

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="index.htm">indexController</prop>
            </props>
        </property>
    </bean>

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <!--
    The index controller.
    -->
    <bean name="indexController"
          class="org.springframework.web.servlet.mvc.ParameterizableViewController"
          p:viewName="index" />

Hay tres bean definidos en este archivo urlMapping, viewResolver, indexController. Cuando el DispatcherServlet recibe un request que coincide con *.htm  tal como index.htm, Este va al controlador especificado en urlMapping que procesa el request. se puede observar la propiedad mappings que enlaza index.htm a indexController.

  El runtime environment entonces busca por un bean llamado indexController el cual es provisto convenientemente por la estructura del projecto. este extiende ParametrizableViewController. esta es otra clase de Spring, la cual simplemente regresa una vista. notese que p:viewName="index" establece el nombre lógico de la vista, la cual es resuelta por el bean viewResolver anteponiendo
/WEB-INF/jsp/ y .jsp agregando   a este. Esto permite al runtime ubicar el archivo dentro del directorio de la aplicación, y así responder con la vista de página de bienvenida.

Extracto de la Aplicación


  la aplicación está compuesto por dos páginas JSP, o vistas desde el punto de vista MVC.

Implementando un Servicio

  Ahora que el ambiente está bien instalado, podemos extender la estructura del projecto de acuerdo a las necesidades.
  Creamos una java class llamada HelloService y con paquete service.

package service;

public class HelloService {
    public static String sayHello(String name){
        return "Hello" + name + "!.";
    }
}


Implementando el Controller y el Model

  Podemos usar SimpleFormController para manejar los datos de usuario y determinar que vista regresar.


Se nombra a la clase HelloController y el paquete controller.

  Se especificaran propiedades del controlador, aprovechando el template que nos da el netbeans, simplemente descomentamos los métodos setter, y los modificamos a estos nombres

        setCommandClass(Name.class);
        setCommandName("name");
        setSuccessView("helloView");
        setFormView("nameView");

la Name.class nos mandara un error de no definición, así que creamos una clase Name con paquete controller. el error desaparece y completamos la clase Name con

package controller;

public class Name {
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

En la clase HelloController borramos el método onSubmitAction(), y descomentamos el método onSubmit o click derecho -> insert Code...  -> Override method...-> onSubmit(), este método permite crear nuestra propia clase ModelAndView. y debe quedar como sigue

    @Override
    protected ModelAndView onSubmit(HttpServletRequest request,
            HttpServletResponse response,
            Object command,
            BindException errors) throws Exception {
       
        Name name = (Name) command;
        ModelAndView mv = new ModelAndView(getSuccessView());
        mv.addObject("helloMessage", HelloService.sayHello(name.getValue()));
       
        return mv;
    }

Observamos que el objeto command es casteado a la clase que creamos Name, que es una propiedad de HelloController, creamos una instancia de ModelAndView, y la construimos con una vista successView de un método getter de la clase SimpleFormController->HelloController. Finalmente este modelo es llenado con datos. El unico elemento en nuestro modelo es helloMessage, obtenido del servicio que creamos HelloService. esto con el método addObject bajo el nombre "helloMessage".

Cabe mencionar que la clase SimpleFormController esta deprecada. En la documentación la clase ModelAndView representa el Modelo y la Vista regresado por un handler, que será resuleto por un DispatcherServlet. La vista puede tomar la forma de un String view name la cual necesitará ser resuelta por un objeto ViewResolver, alternativamente el objeto View puede ser especificado directamente. El modelo es un Map, permitiendo el uso de multiples objetos accesados por name.

En el HelloController hemos utilizado HelloService en addObject, ahora hay que agragarlo como propiedad y su setter correspondiente.

private HelloService helloService;

public void setHelloService(HelloService helloService) {
    this.helloService = helloService;
}

Registramos HelloService en applicationContext.xml

<bean name="helloService" class="service.HelloService" />

Registramos HelloController en dispatcher-servlet.xml

<bean class="controller.HelloController" p:helloService-ref="helloService" />

Implementando las Vistas

   Para implementar la vista en este projecto, crearemos dos JSP, uno llamado nameView.jsp, que servirá de página de bienvenida y permitirá al usuario capturar un nombre, y la otra helloView.jsp, que desplegará un mensaje de bienvenida con el nombre capturado.

1. ventana Project, click derecho en WEB-INF -> new.. -> JSP..., le ponemos el nombre helloView.

2. click finish.

3. le cambiamos el title a Hola, cambiamos el mensaje de salida objetiendo el valor de helloMessage del objeto ModelAndView que es creado en HelloController.
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Hola</title>
    </head>
    <body>
        <h1>${helloMessage}</h1>
    </body>

4. Creamos otro JSP con el nombre nameView.

5. agregamos en el editor la sigiente declaracion de libreria de tags de spring en el archivo nameView.jsp.

<%@taglib uri="http://www.springframework.org/tags" prefix="spring" %>
6. Cambiamos el contenido de <title> y <h1>
        <title>Introduce Tus Datos</title>
    </head>
    <body>
        <h1>
            <spring:nestedPath path="name">
                <form action="" method="post">
                    Nombre:
                    <spring:bind path="value">
                        <input type="text" name="${status.expression}" value="${status.value}">
                    </spring:bind>
                        <input type="submit" value="OK">
                </form>
            </spring:nestedPath> </h1>
    </body>

spring:bind nos permite enlazar una propiedad del bean. el tag bind provee un status y un value, los cuales se usarán en el nombre y valor del campo de entrada. Así cuando la forma es submited, Spring sabrá como extraer los datos enviados. Nuestra command class (controller.Name) tiene una propiedad value asi que ponemos el path a value.

spring:netstedPath nos permite anteponer un path al bean. asi que nuestro path al bean sería name.value. el command name de  HelloController es name. de tal forma este path hace referencia a la propiedad value del bean llamado name.

7. Cambiamos el punto de entrada relativo de la aplicación. actualmente es index.htm, y se redirecciona a WEB-INF/jsp/index.jsp. Especifiquemoslo a /hello.htm con window Project -> click derecho al nodo del projecto -> properties , en la categor[ia Run, en el campo Relative URL.

En este momento nos estaríamos preguntando donde está el mapeo de hello.htm a HelloController. No hemos hecho un mapeo al bean urlMapping, como en el caso de index.htm. Esto es posible gracias a un poco el trabajo interno de Spring dandole la definicion del bean in dispatcher-servlet.xml.
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

Este bean es responsable de crear el URL mapping para todos los controladores registrados en el archivo. Este toma el nombre largo de clase del controlador (en nuestro caso controller.HelloControler) y quita el nombre del paquete, y el sufijo Controller, y usa el resultado como URL mapping. Entonces para HelloController y nos quesa un mapping a hello.htm.
Sin enbargo esta mágia no sirve para controladores que están integrados en el framework de Spring. como por ejemplo ParametrizableViewController, este requiere un mapeo explícito.

8. En la ventana de projecto damos click derecho -> run. Esto compila, deploya y corre el projecto, habre el borwser, despliega hello.htm como nameView.


Tecleamos algún nombre, Ok. y la helloView despliega el mensaje.


y listo.

No hay comentarios:

Publicar un comentario