Java EE 8 - MVC 1.0
MVC es una nueva característica que vendrá en Java EE 8. No reemplaza al JSF, ya que es otra filosofía. JSF está basado en estados de la aplicación, mientras que MVC es justamente la implementación del patrón Modelo Vista Controlador. Uno mismo va a crear el Modelo, también la vista (generalmente JSP) y el controlador.
Cuando comencemos a verlo, notaremos que tiene un parecido a Spring MVC (para ver una pequeña introducción de Spring MVC, puedes ver el post anterior: Conociendo Spring MVC. La diferencia es que este está más Java EE, con más anotaciones que archivos de configuración, y más Oracle.
MVC está especificado en el JSR 371. Está basado en JAX-RS, por lo que veremos que se parece muchísimo a los servicios RESTful, además que se puede incluir tecnologías Java EE como CDI y Bean Validation.
Existe una implementación de este JSR y es el proyecto Ozark.
Como vemos, se puede trabajar tranquilamente sobre Java EE 7.
Y, como se mencionó anteriormente, está basado en JAX-RS (RESTful), por lo que las notaciones nos serán muy naturales. ¿Quieres conocer más sobre RESTful? Mira en la sección "Series" y verás la colección de post relacionados con RESTful.
Por tanto, necesitamos configurar la aplicación principal del RESTful: Creamos una clase que extiende a
Por ahora no necesitamos más que esa definición, sin más contenido.
Miremos la siguiente clase:
La línea 10 donde se declara la notación
Esto ya nos hace la idea de que para este controlador podemos tener los cuatro métodos HTTP como GET, POST, DELETE y UPDATE. Además, podemos tener subrutas de este controlador por cada método, ya que en cada método se le pondrá otras anotaciones
Vemos también en la línea 14 que devuelve una ruta, que es el jsp que será la vista de respuesta del controlador. Aquí también podemos pensar que podemos poner cualquier JSP, y no necesariamente tiene que ser la misma página de respuesta (ahora vemos que la filosofía de JSF es diferente de la de MVC).
Y al ejecutarlo, nos mostrará esta página.
Y al hacer clic en el enlace, nos mostrará esto. Notar el URL
Es más natural, más fácil de entender y con menos archivos de configuración.
Veamos la línea 9. Así es como se hace para recibir el valor del model.
Además, necesitamos el formulario. Este estará en nuestro index.html al que le agregaremos las siguientes líneas:
Al ejecutarse, este será nuestro formulario.
Y esta será la respuesta.
¿También el controlador puede convivir con métodos JAX-RS? Pues, la verdad.. Sí! solo diferencia quién lo puede llamar. Solo pruébalo.
Como se mencionó antes, ese "modelo" es una alternativa a los request/response. Por tanto, los valores del mapa se guardan como atributos del requerimiento. Eso significa que podemos hacer lo siguiente.
O si queremos usar JSTL, agregamos la dependencia...
... y lo invocamos de una manera natural.
Cuando comencemos a verlo, notaremos que tiene un parecido a Spring MVC (para ver una pequeña introducción de Spring MVC, puedes ver el post anterior: Conociendo Spring MVC. La diferencia es que este está más Java EE, con más anotaciones que archivos de configuración, y más Oracle.
MVC está especificado en el JSR 371. Está basado en JAX-RS, por lo que veremos que se parece muchísimo a los servicios RESTful, además que se puede incluir tecnologías Java EE como CDI y Bean Validation.
Existe una implementación de este JSR y es el proyecto Ozark.
Software utilizado
Para este post he utilizado
- NetBeans 8.1
- GlassFish 4.1.1
- Maven (que ya viene incluido en el IDE)
Creando el proyecto
Para probar este framework, crearemos nuestro proyecto web con Maven, y debemos considerar la siguiente dependencia.
<dependencies> <dependency> <groupId>com.oracle.ozark</groupId> <artifactId>ozark</artifactId> <version>1.0.0-m01</version> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> </dependencies>
Como vemos, se puede trabajar tranquilamente sobre Java EE 7.
Y, como se mencionó anteriormente, está basado en JAX-RS (RESTful), por lo que las notaciones nos serán muy naturales. ¿Quieres conocer más sobre RESTful? Mira en la sección "Series" y verás la colección de post relacionados con RESTful.
Por tanto, necesitamos configurar la aplicación principal del RESTful: Creamos una clase que extiende a
javax.ws.rs.core.Application
y con la anotación javax.ws.rs.ApplicationPath
indicando el subcontexto raíz de la aplicación MVC.package com.apuntesdejava.demomvc; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("main-app") public class Main extends Application{ }
Por ahora no necesitamos más que esa definición, sin más contenido.
La clase controladora
Nuevamente, necesitamos usar las notaciones REST tales comojavax.ws.rs.Path
y javax.ws.rs.GET
, además de otras anotaciones.Miremos la siguiente clase:
package com.apuntesdejava.demomvc.controller; import javax.mvc.Controller; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.QueryParam; @Path("/saludo") @Controller public class HolaController { @GET public String hola(){ return "/WEB-INF/jsp/saludo.jsp"; } }
La línea 10 donde se declara la notación
@javax.mvc.Controller
indica que este servicio REST se comportará como un controlador de la aplicación bajo la ruta "/saludo" que está declarada en la línea 9. El método hola de la línea 13 se ejecutará cuando sea invocado vía método GET, tal como está declarado en la línea 12.Esto ya nos hace la idea de que para este controlador podemos tener los cuatro métodos HTTP como GET, POST, DELETE y UPDATE. Además, podemos tener subrutas de este controlador por cada método, ya que en cada método se le pondrá otras anotaciones
javax.ws.rs.Path
para indicar su ubicación dentro del controlador.Vemos también en la línea 14 que devuelve una ruta, que es el jsp que será la vista de respuesta del controlador. Aquí también podemos pensar que podemos poner cualquier JSP, y no necesariamente tiene que ser la misma página de respuesta (ahora vemos que la filosofía de JSF es diferente de la de MVC).
Creando la vista
Ahora, crearemos la vista. Esta será un JSP común y corriente. Luego le pondremos más cosas.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>Hello World!</h1> </body> </html>
Ejecutando la aplicación
Ahora, para poder ejecutarlo, necesitamos crear un HTML que invocará a nuestra aplicación MVC. En la raíz del módulo web pondremos el siguiente index.html.<!DOCTYPE html> <html> <head> <title>Start Page</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <h1>Ejemplo de MVC</h1> <a href="main-app/saludo">Hola mundo</a> </body> </html>
Y al ejecutarlo, nos mostrará esta página.
Y al hacer clic en el enlace, nos mostrará esto. Notar el URL
Es más natural, más fácil de entender y con menos archivos de configuración.
Parámetros y valores de respuesta
Ahora bien, en una aplicación web normal contamos siempre con dos objetos principales: el que maneja las peticiones del cliente Request, y el que prepara las respuestas al cliente Response. En JSF todo es a través de los atributos del Managed Bean.
Aquí en MVC, las peticiones del cliente son recibidas como parámetros del método (sí, como RESTful) y las respuestas se guardan en un contenedor de datos llamado Modelo. El modelo consiste en la clase
javax.mvc.Models
que es una extensión a la clase java.util.Map
Por tanto, podemos guardar todas los valores del modelo de la aplicación como mapa. El alcance que tendrá el modelo de este controlador estará definido por la anotación javax.enterprise.context.RequestScoped
que se pondrá en la declaración de la clase controladora. Esta es la misma anotación que se utiliza para el alcance de los EJB.
Agreguemos un método a nuestra clase controladora. Para no tocar el método actual, crearemos otro que recibirá el parámetro por medio de un formulario.
package com.apuntesdejava.demomvc.controller; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.mvc.Controller; import javax.mvc.Models; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; @Path("/saludo") @Controller @RequestScoped public class HolaController { @Inject Models models; @GET public String hola() { return "/WEB-INF/jsp/saludo.jsp"; } @POST @Path("/nombre") public String holaNombre( @FormParam("nombre") String nombre) { String mensaje = "Hola " + nombre; models.put("mensaje", mensaje); return "/WEB-INF/jsp/saludo-nombre.jsp"; } }
- En las líneas 17 y 18 se declara el modelo del controlador.
- En la línea 25 indica que se invocará usando el método HTTP POST
- En la línea 26 está la ruta dentro del controlador.
- En la línea 27 se indica el parámetro que recibirá el método y será enviado por formulario. Muy JAX-RS
- En la línea 29 se guarda el valor en el modelo. Como vemos, es un Mapa común de Java. Sí, hasta aquí es muy Java puro.
Y necesitamos crear nuestro jsp donde mostrará el contenido del mensaje. Este tendrá el siguiente contenido.
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <h1>${mensaje}</h1> </body> </html>
Además, necesitamos el formulario. Este estará en nuestro index.html al que le agregaremos las siguientes líneas:
<h2>Probando con método POST</h2> <form action="main-app/saludo/nombre" method="post"> Nombre: <input type="text" name="nombre" placeholder="Escribe tu nombre aquí"/><br/> <button type="submit">Enviar</button> </form>Notar la línea 11 la manera cómo se invoca al controlador, tanto la ruta como el método.
Al ejecutarse, este será nuestro formulario.
Y esta será la respuesta.
Un poco más sobre los controladores
¿Solo permite que devuelva tipo String? La verdad, no, también se puede hacer que devuelva void, pero se le debe indicar cuál es la vista en una anotación. También se puede usar tipo Response, y la respuesta será mismo JAX-RS. Aquí veamos unos ejemplos.
@GET @View("/WEB-INF/jsp/saludo.jsp") @Path("/void") public void metodoVoid(){ LOG.info("Método de tipo void"); } @GET @Path("/viewable") public Viewable metodoViewable(){ LOG.info("Método de tipo Viewable"); return new Viewable("/WEB-INF/jsp/saludo.jsp"); } @GET @Path("/response") public Response metodoResponse(){ LOG.info("Método de tipo Response. Bien JAX-RS"); return Response.status(Response.Status.OK) .entity("/WEB-INF/jsp/saludo.jsp") .build(); }
Un poco más sobre la vista
Hemos visto cómo mostrar un simple mensaje, pero si guardo en el modelo una colección ¿Cómo se podrá obtener ese arreglo?Como se mencionó antes, ese "modelo" es una alternativa a los request/response. Por tanto, los valores del mapa se guardan como atributos del requerimiento. Eso significa que podemos hacer lo siguiente.
@GET @Path("/lista-nombres") @View("/WEB-INF/jsp/lista-nombres.jsp") public void listaNombres() { ListY en nuestro JSP podemos invocarlo asínombres = Arrays.asList("Ann", "Bernard", "Carl"); models.put("nombres", nombres); }
<%List<String> nombres= (List<String>) request.getAttribute("nombres") %>y lo trabajamos como scriplet.
O si queremos usar JSTL, agregamos la dependencia...
<dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2-rev-1</version> </dependency>
... y lo invocamos de una manera natural.
<ul> <c:forEach items="${nombres}" var="n"> <li>${n}</li> </c:forEach> </ul>
Código fuente
El código fuente de este proyecto, con todos sus ejemplos, lo puedes descargar aquí: https://bitbucket.org/apuntesdejava/java-ee-8-demo-mvc/get/514936ee3e45.zip
Y también está disponible como Git aquí: https://bitbucket.org/apuntesdejava/java-ee-8-demo-mvc/
Comentarios
Publicar un comentario
Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups
Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/