domingo, 12 de febrero de 2017

Tutorial: Hola Mundo: Capa de Persistencia

Hasta ahora se construyó una aplicación  básica para mostrar los conceptos básicos de Spring Framework.


En ésta entrada se mostrará la integración de la capa de persistencia, haciendo énfasis únicamente en la persistencia sin detalle de los conceptos ya mencionados.

Contenido


Crear Proyecto
En Eclipse Crear proyecto Dynamic Web Project.
Convertir el proyecto a Proyecto Maven.

Modificar el POM.XML: Las siguientes son las dependencias necesarias para completar el tutorial.
<dependencies>
    <!-- Spring -->
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-core</artifactId>
     <version>4.3.2.RELEASE</version>
 </dependency>
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>4.3.2.RELEASE</version>
 </dependency>
 <!-- Servlet -->
 <dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
 </dependency>
 <!-- Hibernate -->  
 <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-entitymanager</artifactId>
     <version>5.2.2.Final</version>
 </dependency>  
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-orm</artifactId>
     <version>4.3.2.RELEASE</version>
 </dependency>
 <!-- Oracle, instalado localmente en Archiva --> 
 <dependency>
   <groupId>com.oracle</groupId>
   <artifactId>ojdbc7</artifactId>
   <version>12.1.0.1</version>
 </dependency>  
</dependencies>

Dentro de las dependecias se incluye el módulo ORM (Object Relational Mapping) de Spring, y en EntityManager de Hibernate.

IMPORTANTE: La dependencia del JDBC de Oracle (ojdbc7) NO se encuentra en el repositorio central de Maven.
Es necesario descargarla del sitio de Oracle y adicionarla manualmente a Maven o como librería de la aplicación. Si se está haciendo uso de un gestor como Apache Archiva, simplemente se puede subir la libería a Archiva, asignarle un GAV y se podrá acceder normalmente desde el POM. Por ejemplo para el ejercicio se subió a Archiva con el siguiente GAV:
<!-- Oracle, instalado localmente en Archiva --> 
 <dependency>
   <groupId>com.oracle</groupId>
   <artifactId>ojdbc7</artifactId>
   <version>12.1.0.1</version>
 </dependency>

Crear una clase java para el controlador:Crear una clase básica con el siguiente contenido:
package pkg.sw.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/")
public class PersistenceController {

 @RequestMapping("/hello") 
 public ModelAndView viewDate () {    
  return new ModelAndView("hello");
 }

}

Crear JSP: Crear dos JSP uno inicial llamado index.jsp y otro dentro del directorio jsp: jsp/hello.jsp.

index.jsp


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Soluciones Web</title>
</head>
<body>
 <h1>Hola mundo - Capa Persistencia</h1>
 <a href="hello">Dar Click acá</a>
</body>
</html>

jsp/hello.jsp

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Soluciones Web</title>
</head>
<body>
 <h2>Respuesta desde el controlador Spr</h2> 
</body>
</html>

Crear los archivos de configuración de Spring que se mostraron en la entrada anterior y de la misma forma relacionarlos en el Web.xml.


  • web.xml
  • applicationContext.xml
  • spring-servlet.xml
Probar la aplicación a éste punto: Al cargarla muestra el index.jsp a dar clic en el enlace muestra hello.jsp.
Servicio:
Ahora se creará el servicio con su interfaz. Se creará una operación que envíe un mensaje al JSP mediante la inyección en el controlador:
Interfaz servicio:
package pkg.sw.service;

public interface ProductService {

 public String getProducts();

}


Implementación Servicio:
package pkg.sw.service.impl;

import org.springframework.stereotype.Service;
import pkg.sw.service.ProductService;


@Service
public class ProductServiceImpl implements ProductService{

 public ProductServiceImpl() {}
 
 public String getProducts()
 {
  return "Product1 <br/> Product2 <br/> Product3";
 }

}


Modificar Controlador:
package pkg.sw.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import pkg.sw.service.ProductService;

@Controller
@RequestMapping("/")
public class PersistenceController {

 @Autowired
 private ProductService productService;
 
 @RequestMapping("/hello") 
 public ModelAndView viewDate () {  
  
 return new ModelAndView("hello", 
                   "listProducts", productService.getProducts());
 }

}


Mostrar la variable enviada en el modelo desde en controlador en el JSP:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Soluciones Web</title>
</head>
<body>
 <h2>Respuesta desde el controlador Spr</h2> 
 <div>${listProducts}</div>
</body>
</html>

IMPORTANTE: Para efectos de éste ejercicio, con el fin de mostrar fácilmente el resultado, se envía dentro de la cadena las etiquetas BR de salto de línea, en vez de hacerlos con un objeto y con JSTL o AngularJS, pero en aplicaciones reales no es recomendable ésta práctica.

Probar la aplicación a éste punto:

Procedimiento Persistencia:
A éste punto se ha repasado lo construido en el tutorial anterior, a partir de ahora se inicia la construcción y configuración de la capa de persistencia.
Con el ejercicio se pretende mostrar la configuración necesaria para Hibernate, y no se tiene en cuenta el paso de parámetros, simplemente se manejarán cadenas de texto (String). Tampoco se tiene en cuenta el flujo de excepciones/validaciones para efectos del ejercicio.

Configuración:
Configuración del archivo applicationContext.xml: Este archivo es de configuración de la aplicación y se adicionará la configuración de persistencia de Hibernate, se recomienda separar en un archivo exclusivo, pero para éste ejercicio se manejará sobre el mismo archivo. Se adiciona también a la cabecera los esquemas necesarios.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:jee="http://www.springframework.org/schema/jee"
 xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/jee 
        http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">        
   
    <!-- enabling annotation driven configuration /-->
    <context:annotation-config/>
 
  <!-- DataSource -->
  <jee:jndi-lookup id="dataSource" jndi-name="jdbc/SWTEST"/>  
    
 <!-- EntityManager -->
 <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <property name="dataSource" ref="dataSource" />
   <property name="packagesToScan" value="pkg.sw.repository" />
   <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
      </property>
      <property name="jpaProperties">
         <props>            
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>                       
         </props>
      </property>      
   </bean>
   
   <!-- Transaction Manager -->
   <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
      <property name="entityManagerFactory" ref="myEmf" />
   </bean>
   
   <tx:annotation-driven />  
   
<!-- Exception translation bean post processor -->
   <bean id="persistenceExceptionTranslationPostProcessor"
      class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> 
    
    <!-- Scans the classpath of this application for @Components to deploy as beans -->
    <context:component-scan base-package="pkg.sw.repository" />
    <context:component-scan base-package="pkg.sw.service" />

</beans>

En el archivo se ha creado:

  • El Data Source por JNDI. Significa que la administración de la conexión a la base de datos se le delegó al servidor de aplicaciones Weblogic Server. Por lo tanto se debe crear previamente el DataSource 'jdbc/SWTEST' en Weblogic.
    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/SWTEST"/>
    



    NOTA: Si se desea también se puede hacer la conexión manualmente desde la aplicación así:

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
           <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
           <property name="url" value="jdbc:oracle:thin:@10.85.84.142:1521:DSFSPE" />
           <property name="username" value="user" />
           <property name="password" value="pass" />
     </bean>
    


  • La definición del EntityManager
    Hibernate SessionFactory vs. EntityManagerFactory
    Es preferible EntityManagerFactory y EntityManager porque están definidos por el estándar JPA. SessionFactory y Session son específicos de Hibernate. El EntityManager invoca Session de Hibernate internamente.
    <!-- EntityManager -->
        <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
          <property name="dataSource" ref="dataSource" />
          <property name="packagesToScan" value="pkg.sw.repository" />
          <property name="jpaVendorAdapter">
             <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
          </property>
          <property name="jpaProperties">
             <props>            
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>                       
             </props>
          </property>      
       </bean>
    


    Donde se referencia al datasource creado, se especifican los paquetes a escanear, y se configura Hibernate, en este caso el dialecto para la base de datos Oracle.

  • Configuración del Transacción Manager. Donde se referencia el Bean del Entity Manager creado.
    <!-- Transaction Manager -->
       <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
          <property name="entityManagerFactory" ref="myEmf" />
       </bean>
  • Habilitar Transacción Manager y anotaciones @Transactional.
    <tx:annotation-driven />
  • Finalmente el bean que actúa como traductor de manejo de excepciones para los beans que tengan la anotación @Repository.
    (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html )
    <!-- Exception translation bean post processor -->
    <bean id="persistenceExceptionTranslationPostProcessor"
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
    

Weblogic.xml: Para evitar problemas de compatibilidad de las librerías existentes en Weblogic vs las librerías incluidas en el POM.XML se indicará en el archivo weblogic.xml de la aplicación preferencia a las librerías del WEB-INF:
<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.8/weblogic-web-app.xsd">
<wls:weblogic-version>12.2.1</wls:weblogic-version>
<wls:context-root>SWHelloWorlPersistence</wls:context-root>
    
<wls:container-descriptor>
    <wls:prefer-web-inf-classes>true</wls:prefer-web-inf-classes>
</wls:container-descriptor>
    
</wls:weblogic-web-app>

Se pone a TRUE el tag prefer-web-inf-classes, lo que hará que las clases ubicadas en el directorio WEB-INF de la aplicación Web, se carguen con preferencia sobre las clases cargadas en el contenedor.
Crear entidad: Se crea una entidad en la base de datos a donde se hizo la conexión. Para el ejercicio se creará una tabla PRODUCTO con los atributos ID, MARCA, NOMBRE, PRECIO.

Se crea la clase java para la entidad, con las anotaciones correspondientes como se hace normalmente JPA.
package pkg.sw.repository;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="SW_TEST_PRODUCTS") 
public class Product implements Serializable {

 private static final long serialVersionUID = 1L; 
 @Id
    @Column(name = "ID")    
    private Integer id; 
 @Column(name = "NOMBRE")
    private String nombre;
    @Column(name = "PRECIO")
    private Integer precio;
    @Column(name = "MARCA")
    private String marca;
    
 public Integer getID() {
  return id;
 }
 public void setID(Integer id) {
  id = id;
 }
 public String getNOMBRE() {
  return nombre;
 }
 public void setNOMBRE(String nombre) {
  nombre = nombre;
 }
 public Integer getPRECIO() {
  return precio;
 }
 public void setPRECIO(Integer precio) {
  precio = precio;
 }
 public String getMARCA() {
  return marca;
 }
 public void setMARCA(String marca) {
  marca = marca;
 }
 
 public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("nombre: " + nombre + ",");
        buffer.append("precio: " + precio + ",");
        buffer.append("marca: " + marca);
        return buffer.toString();
    }

}

Adicionalmente se hizo la operación toString, simplemente para devolver la información del objeto en una cadena.

Crear el DAO

Interface: ProductDao.java 


package pkg.sw.repository;

public interface ProductDao {

 public String getProductList();
 public void persistProduct(Product prod);

}

Implementación: ProductDaoImpl.java: Donde se pone la anotación @Repository que es el estereotipo de Spring para la capa de persistencia, se inicializa el EntityManager para luego ser usado en las operaciones, por ejemplo para éste caso de consulta y de persistencia.
package pkg.sw.repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import pkg.sw.repository.ProductDao;
import pkg.sw.repository.Product;

import java.util.List;

@Repository(value = "productDaoSW")
public class ProductDaoImpl implements ProductDao {
 
 private EntityManager em = null;

    /*
     * Sets the entity manager.
     */
    @PersistenceContext
    public void setEntityManager(EntityManager em) {
        this.em = em;
    }
    
    @Transactional(readOnly = true)
 public String getProductList()
 {     
     List _products = em.createQuery("select p from Product p order by p.ID").getResultList();
     
     StringBuffer buffer = new StringBuffer();        
        
     for (Product p : _products)
     {
      buffer.append(p.toString() + "
");
     }
          
     return  buffer.toString();     
 }    
    
    @Transactional(readOnly = false)
    public void persistProduct(Product prod) {
        em.persist(prod);
    }

}

Para el ejercicio se crearon dos operaciones una de consulta a la tabla y otra de inserción.


Ajustar el Servicio
Las clase del servicio se ajustan para utilizar las dos operaciones expuestas en el DAO, se inyectará el DAO con @Autowired de la misma forma como se ha hecho antes.
Interface: ProductService.java


package pkg.sw.service;

import pkg.sw.repository.Product;

public interface ProductService {

 public String getProducts();
 public void saveProduct(Product prod);

}

Implementación: ProductServiceImpl.java: Donde se inyecta el DAO y se crean las operaciones para mostrar la lista de productos desde la tabla de la base de datos y para guardar un nuevo registro.
package pkg.sw.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import pkg.sw.repository.Product;
import pkg.sw.repository.ProductDao;
import pkg.sw.service.ProductService;


@Service
public class ProductServiceImpl implements ProductService{
 
  @Autowired
  private ProductDao productDao;
  
  public void setProductDao(ProductDao productDao) {
        this.productDao = productDao;
     }
  
 public String getProducts()
 {
  String _products = productDao.getProductList();
  return _products;
 }
 
 public void saveProduct(Product prod)
 {
  productDao.persistProduct(prod);
 }
}

Ajustar el controlador:
Como ya se tenía inyectado el servicio en el controlador, ahora se va a actualizar para que invoque las nuevas operaciones creadas, se redireccionará al JSP hello para mostrar la lista de productos desde la base de datos, y se enviará al JSP addProduct para registrar un nuevo registro en la base de datos.

PersistenceController.java
package pkg.sw.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import pkg.sw.repository.Product;
import pkg.sw.service.ProductService;

@Controller
@RequestMapping("/")
public class PersistenceController {

 @Autowired
 private ProductService productService;
 
 @RequestMapping("/hello") 
 public ModelAndView viewDate () {  
  
  return new ModelAndView("hello", "listProducts", productService.getProducts());
 }
 
 @RequestMapping(value="/addProduct", method = RequestMethod.GET)
    protected Product formBackingObject(HttpServletRequest request) throws ServletException {
   Product product = new Product();         
        return product;
    }

 @RequestMapping(value="/addProduct", method = RequestMethod.POST)
 public ModelAndView onSubmit(@Valid Product product, BindingResult result)
 {  
  product.setID(5);
  productService.saveProduct(product);
  
  ModelAndView mv = new ModelAndView("hello");
  mv.addObject("listProducts", productService.getProducts());
  mv.addObject("msg", "Producto insertado.");  
  return mv;
  
 }
}


Hay que anotar que se hicicron dos operaciones en el controlador para "/addProduct", una por POST y otra por GET
La que va por GET es la que se invoca al inicio, simplemente en el link del JSP index hacia el JSP addProduct, ésta devuelve un nuevo objeto del tipo de la entidad Product. En el siguiente paso del JSP se explicará más al respecto.


@RequestMapping(value="/addProduct", method = RequestMethod.GET)
    protected Product formBackingObject(HttpServletRequest request) throws ServletException {
   Product product = new Product();         
        return product;
    }

La que va por POST onSumit, se ejecutará al oprimir el botón submit del formulario en el JSP, es en ésta operación donde se persiste el producto que se recibe en el parámetro y finalmente se direcciona a el JSP hello para ver la lista de los productos de la base de datos.
@RequestMapping(value="/addProduct", method = RequestMethod.POST)
 public ModelAndView onSubmit(@Valid Product product, BindingResult result)
 {  
  productService.saveProduct(product);
  
  ModelAndView mv = new ModelAndView("hello");
  mv.addObject("listProducts", productService.getProducts());
  mv.addObject("msg", "Producto insertado.");  
  return mv;
  
 }



Ajuste de JSPs:

hello.jsp: Simplemente muestra los dos parámetros que recibe desde el modelo:
  • listProducts
  • msg

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Soluciones Web</title>
</head>
<body>
 <h2>Respuesta desde el controlador Spr</h2> 
 <div>${listProducts}</div>
 <br/>
 <br/>
 <div>${msg}</div>
 <br/>
 <a href="/SWHelloWorlPersistence/">Home</a>
</body>
</html>


Creación de addProduct.jsp: para éste JSP se va a utilizar <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> que son las etiquetas de Formulario de Spring, las cuales tienen atributos que permitirán mapear la entidad Product para pasarla al controlador. No se profundzará el uso de Formulario de Spring en ésta entrada.

addProduct.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Soluciones Web</title>
</head>
<body>
 <h3>Add Product</h3> 
 <form:form method="post" commandName="product">
  ID<form:input path="ID"/>
  Marca<form:input path="MARCA"/>
  Nombre<form:input path="NOMBRE"/>
  Precio<form:input path="PRECIO"/>
  <input type="submit" value="Enviar">
 </form:form>
 <a href="/SWHelloWorlPersistence/">Home</a>
</body>
</html>

Formulario de Spring: El atributo commandName="product" de la etiqueta form, es el parámetro que se recibe desde la invocación get, e inicializa el objeto.
<form:form method="post" commandName="product">


Product product = new Product();         
        return product;



Los atributos path de los input así mismo deben ser los nombres de los atributos del objeto, para éste caso de Product:
ID<form:input path="id"/>
Marca<form:input path="marca"/>
Nombre<form:input path="nombre"/>
Precio<form:input path="precio"/>
<input type="submit" value="Enviar">


     @Id
    @Column(name = "ID")    
    private Integer id; 
 @Column(name = "NOMBRE")
    private String nombre;
    @Column(name = "PRECIO")
    private Integer precio;
    @Column(name = "MARCA")
    private String marca;

De ésta manera se envía el objeto Product seteado al controlador, y como el formulario está con método POST se dispara la operación de persistencia en el controlador.

Probar la aplicación:

Lista de productos:

Adicionar Producto:

Comprobar la inserción en la base de datos:

Conclusión
Se ha mostrado la configuración de la capa de persistencia y se obtienen los conceptos de las configuraciones XML de Spring para una aplicación completa:




domingo, 5 de febrero de 2017

Tutorial: Hola Mundo Spring - Conceptos básicos

Se creará una aplicación básica “Hola Mundo”, que permita mostrar los componentes básicos de una aplicación con spring MVC. Se creará una pantalla inicial con un enlace a una segunda pantalla que devuelva la hora y fecha del sistema.

Se muestra la configuración de Spring en XML para tratar de explicar los conceptos con claridad, más adelante se mostrará la configuración de Spring con Java que es como se trabajará finalmente.

Contenido
Crear proyecto en Eclipse
Configuración del POM
Controlador Web
Creación de JSP
Configuración de Spring
El servicio
Inyección de Dependencias
Prueba en Weblogic

Procedimiento

Crear proyecto en Eclipse
Cambiar a la perspectiva JEE en Eclipse:

Crear un nuevo proyecto: Dynamic Web Project:

Seleccionar un nombre, seleccionar el Runtime creado para Weblogic 12C en el capitulo de configuración:

Finalizar, el proyecto creado aparecerá en el Project Explorer:

Convertir  proyecto a Maven: Clic derecho sobre el proyecto creado, --> Configure --> Convert to Maven Project:

Dejar los valores por defecto. Finalizar. Se ha convertido el proyecto a Maven:

Navegar en el proyecto, que tendrá una estructura similar a:

Configuración del POM
Abrir el archivo de configuración de Maven POM.XML:


Pasar a la pestaña pom.xml para ver el archivo de configuración en XML:

Por defecto el POM se verá así:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>SWHelloWorld</groupId>
  <artifactId>SWHelloWorld</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Este archivo contiene la información de la complicación y de las dependencias de librerías que necesite el proyecto.

A groso modo: Las etiquetas iniciales son de información del proyecto, la etiqueta <packaging> indica el tipo de despliegue, y la etiqueta <build> indica el directorio y los artefactos de compilación.

La parte de configuración <configuration> <source>1.8</source> <target>1.8</target> </configuration> indica la versión de java.

Para empezar a usar Spring MVC, en éste archivo se debe indicar las dependencias a las librerías de Spring adicionándolas dentro de la etiqueta <dependencies> así:
        <dependencies>
    <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>4.3.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-aop</artifactId>
   <version>4.3.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>4.3.1.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>4.3.1.RELEASE</version>
  </dependency>  
 </dependencies>

Guardar y cerrar el POM.

Controlador Web
Todas las aplicaciones en Spring deben contar con un Controlador Web, para crear la clase del controlador, clic derecho sobre la carpeta Java Resources --> src del proyecto:

Crear un paquete.

Clic derecho sobre el paquete creado: New --> Class:

Se creará la clase HelloWorldController dentro de un paquete llamado controller:

Para hacer que ésta sea la clase ce controlador de Spring se debe adicionar las anotaciones respectivas:
  • @Controller: Que indica que es el controlador web.
  • @RequestMapping("/"): Para éste caso "/" indica que es para  las solicitudes root. RequestMapping puede ser usado en el nivel de clase o en el nivel de método. (Ver Anotación RequestingMapping). Cuando se usa RequestMapping en un método significa que se ejecutará en las solicitudes provenientes de esa URL, por ejemplo: @RequestMapping("/login") se ejecutará por el controlador con las solicitudes a "/login". Es importante tener en cuenta que si se define un RequestMapping de clase, actuará como padre de los RequestMapping de los métodos, ejemplo: Si en la clase se usa @RequestMapping("/paper"), y en el método de esa clase se usa: @RequestMapping("/add"), se ejecutará con las solicitudes a "/paper/add". 
La clase HelloWorldController se verá así:
package package.sw.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/")
public class HelloWorldController {

 public HelloWorldController() {
  // TODO Auto-generated constructor stub
 }

}

Dentro de la clase se crea el método viewDate con la anotación RequestMapping: @RequestMapping("/welcome"), para éste caso significa que se ejecuta con las solicitudes hacia welcome.

El Método retornará el objeto org.springframework.web.servlet.ModelAndView de Spring, que tiene varias sobrecargas de constructor y permite devolver al navegador la respuesta y si es necesario el paso de parámetros. Por ejemplo: return new ModelAndView("welcome"); envía al recurso (jsp) llamado welcome.
La clase deberá quedar así:
package package.sw.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/")
public class HelloWorldController {

 @RequestMapping("/welcome")
 public ModelAndView viewDate () { 
  return new ModelAndView("welcome");
 }

}

Lo que significa que al hacer una petición GET desde "/welcome" de la aplicación se ejecuta el método viewDate() que envía al recurso welcome.


Creación de JSP
La aplicación tiene por defecto in index.html, el cual se borrará para crear el index.JSP.

Borrar el index.html.
Click derecho en la carpeta WebContent --> New à JSP File
Nombrarlo como "index.jsp", crear el contenido con un enlace hacia welcome así: 
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
 <h1>Esta es la prueba de Hola Mundo Spr</h1>
 <a href="welcome">Dar Click acá</a>
</body>
</html>

IMPORTANTE: El nombre welcome en el enlace debe ser el que se mapeó en el controlador @RequestMapping("/welcome").

Ahora se creará el welcome.jsp, se debe crear en WEB-INF/jsp.
Clic derecho en la carpeta WEB-INF-->New-->Folder nombrarlo como jspClic derecho en la carpeta jsp creada, --> New --> JSP File. Nombrarlo como "welcome.jsp" con el siguiente contenido:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
 <h2>Respuesta desde el controlador Spr</h2>
 <h3>Esta es la fecha y hora actual: ${fechaHora} }</h3>
</body>
</html>

A este punto el proyecto se verá similar a:


Configuración de Spring

Archivo de aplicación Web.xml:


Verificar si existe el archivo web.xml dentro de la carpeta WEB-INF. Si no existe crearlo: Clic derecho en la raíz del proyecto --> Java EE Tools --> Generate Deployment Descriptor Stub:

Abrir el archivo creado:

Se ha creado el archivo con el siguiente contenido:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  <display-name>SWHelloWorld</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

A éste archivo es necesario adicionarle la configuración de Servlets de Spring:
<servlet>
        <servlet-name>springServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
        <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/spring-servlet.xml</param-value>
  </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>


Donde se define, un nombre de servlet, por ejemplo springServlet o el que se desee. 
La clase del servlet, que para spring es org.springframework.web.servlet.DispatcherServlet, y en las etiquetas de parámetros el nombre del archivo donde se manejará la configuración de spring, en el ejemplo /WEB-INF/spring-servlet.xml archivo que se debe crear más adelante.

En el web.xml se define también el archivo de contexto para la aplicación, que aunque puede ser el mismo lo recomendable es manejar los archivos separados por su función. Este es el archivo donde se definen temas de aplicación como definiciones de anotaciones, etc.
<!-- Configuración global del contexto -->
    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


En el ejemplo /WEB-INF/applicationContext.xml archivo que se debe crear más adelante.

El web.xml deberá verse similar a:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  <display-name>SWHelloWorld</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
        <servlet-name>springServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
        <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/spring-servlet.xml</param-value>
  </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- Configuración global del contexto -->
    <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
  
</web-app>

Archivo de Spring spring-servlet.xml:


Click derecho en el directorio WEB-INF --> New --> File
En Filename: spring-servlet.xml --> Finish

En éste archivo se definen los beans de la aplicación dentro de las etiquetas <beans>.
El archivo debe tener la siguiente estructura:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
        
    <context:component-scan base-package="package.sw.controller" />
 
 <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
 </bean>
 
 <mvc:annotation-driven />
</beans>

Donde se define el paquete base de búsqueda para el controlador, para el ejemplo "package.sw" y se define el bean del controlador indicándole el directorio de búsqueda, para el caso "/WEB-INF/jsp/".  También el tag <mvc:annotation-driven /> que permite el envío de solicitudes al controlador.


Archivo de Spring applicationContext.xml:

Click derecho en el directorio WEB-INF --> New --> File
En Filename: applicationContext.xml --> Finish
Es otro archivo de beans con la estructura similar, pero donde irán las etiquetas asociadas a la aplicación.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
        
     <context:component-scan base-package="package.sw.*" />

</beans>

Para éste caso el component-scan, que define el paquete de búsqueda de anotaciones (ej: @Service, @Repository etc. en "package.sw.*".



El servicio

Normalmente se definen clases de servicio en donde está la lógica de la aplicación Web. En éste tutorial se creará una clase de servicio que tendrá un único método que devuelve una cadena con la fecha y hora. 


Dar clic derecho sobre el directorio Java Resources --> src del proyecto, New --> Class
Crear la clase HelloWorldService en el paquete package.sw.service


Esta clase servirá como interface, y se verá así:
package package.sw.service;

public interface HelloWorldService {

 public String getDateTime();

}


Se creará una clase Java con la implementación de la lógica del servicio, para éste caso la clase tendrá la implementación del método que devuelve el String con la fecha y hora.

Dar click derecho sobre el directorio Java Resources --> src del proyecto. --> New --> Class
Crear la clase HelloWorldServiceImpl en el paquete package.sw.service.impl


Esta clase implementa HelloWorldService y debe tener la anotación @Service.
La clase se verá similar a:
package package.sw.service.impl;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.stereotype.Service;

import package.sw.service.HelloWorldService;

@Service
public class HelloWorldServiceImpl implements HelloWorldService{

 public HelloWorldServiceImpl() {}
 
 public String getDateTime()
 {
  SimpleDateFormat sdf = new SimpleDateFormat("dd/M/yyyy hh:mm:ss");
  String date = sdf.format(new Date());
  
  return date;
 }

}

En éste punto ya se tienen los componentes de configuración y de implementación.


Inyección de Dependencias


Ahora se hará la invocación del servicio que devuelve la fecha y hora, desde el controlador.
Modificar la clase del controlador: Se usará la anotación @autowired para que Spring busque un bean que cumpla los requisitos para ser inyectado, en este caso el único requisito es que sea del tipo HelloWorldService.
        
@Autowired
private HelloWorldService helloWorldService;

Y se modifica la operación del controlador controlador para que devuelva el parámetro fechaHora que espera el welcome.jsp.
String fechaHora = helloWorldService.getDateTime();
return new ModelAndView("welcome", "fechaHora", fechaHora);

Con ésto ya se ha inyectado la clase del Servicio en el controlador y se puede hacer uso de las Operaciones del Servicio.

La clase se deberá ver similar a:
package package.sw.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import package.sw.service.HelloWorldService;

@Controller
@RequestMapping("/")
public class HelloWorldController {

 @Autowired
 private HelloWorldService helloWorldService;
 
 @RequestMapping("/welcome") 
 public ModelAndView viewDate () { 
  String fechaHora = helloWorldService.getDateTime();  
  return new ModelAndView("welcome", "fechaHora", fechaHora);
 }

}

Prueba en Weblogic 12c


Para probar el proyecto en Weblogic se debe tener en ejecución el servidor, mediante Start o Debug.

Click derecho en el proyecto --> Maven --> Update Project --> OK

Luego ir al servidor en la pestaña Servers, Click derecho --> Add and Remove

Adicionar el proyecto y Finalizar.


Inicia la publicación y va mostrando el avance tanto en la pestaña de ErrorLog como en la de Console si se llegan a presentar errores. Al finalizar la publicación aparece:


Una vez publicada la aplicación, se puede acceder a través de un navegador mediante la URL teniendo en cuenta el puerto usado en Weblogic Server (WLS), para éste caso se usó el puerto por defecto del WLS integrado 7101.
http://localhost:7101/SWHelloWorld/


Clic en el enlace, si no existe ningún inconveniente, debe aparecer:

Resumen:

Se hizo una aplicación con Spring MVC básica en donde se pudo ver la inversión de control con el servlet controlador de spring, antes se enviaba la petición desde la vista, ahora el controlador de spring dependiendo de la solicitud mapeada (Request Mapping) dispara la lógica del controlador, y la inyección de dependencias a través del uso de un servicio y el manejo del flujo de la aplicación.