Spring Boot + Vue JS

cafe-151346_640

En esta ocasión veremos como usar Vue JS en una aplicación Spring Boot.

Creamos nuestra tabla contacto.

contacto.sql

CREATE DATABASE IF NOT EXISTS prueba;

USE prueba;

CREATE TABLE IF NOT EXISTS contacto(id int auto_increment primary key, nombre varchar(100), telefono varchar(12) not null, fecha datetime);

Insertamos algunos valores.

INSERT INTO contacto (nombre,telefono,fecha) VALUES ('Daniel Alcantara','76662323', now()), ('Tomas Torres','5559099', now());

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>com.codemonkey</groupId>
	<artifactId>servidor</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>servidor</name>
	<description>Servidor de servicio web</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web-services</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		
		<dependency>
		    <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-starter-web-services</artifactId>
		</dependency>
		<dependency>
		    <groupId>wsdl4j</groupId>
	        <artifactId>wsdl4j</artifactId>
		</dependency>

        <dependency>
		   <groupId>org.slf4j</groupId>
           <artifactId>slf4j-api</artifactId>
           <version>1.6.1</version>
		</dependency>

        <dependency>
		  <groupId>org.springframework.data</groupId>
		  <artifactId>spring-data-rest-core</artifactId>
		  <version>3.1.1.RELEASE</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>


<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <version>1.6</version>
    <executions>
      <execution>
        <id>xjc</id>
        <goals>
          <goal>xjc</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <schemaDirectory>${project.basedir}/src/main/resources</schemaDirectory>
      <outputDirectory>${project.basedir}/src/main/java/com/codemonkey/clases</outputDirectory>
      <clearOutputDir>false</clearOutputDir>
    </configuration>
  </plugin>


		</plugins>
	</build>


</project>

Nuestro archivo application.yml tendrá el siguiente aspecto:
application.yml

#BANNER
banner:
   charset: UTF-8
   location: banner.txt

spring:
   thymeleaf:
      cache: false
      check-template: true
      check-template-location: true
      content-type: text/html
      enabled: true
      encoding: UTF-8
      suffix: .html
   jpa:
      generate-ddl: true
      database-platform: org.hibernate.dialect.MySQL5Dialect
      show-sql: false
      hibernate.ddl-auto: update
      hibernate.naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
   servlet.multipart.max-file-size: 128KB
   servlet.multipart.max-request-size: 128KB
   http.multipart.enabled: false
   datasource.url: jdbc:mysql://localhost:3306/prueba?useSSL=false
   datasource.driver-class-name: com.mysql.jdbc.Driver
   datasource.username: root
   datasource.password: root

Nuestra entidad Contacto.java. Usaremos la librería lombok para ahorrar escribir código.

package com.codemonkey.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;
import lombok.ToString;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.GenerationType;
import javax.persistence.Table;


@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Table(name="contacto")
@Entity(name="Contacto")
public class Contacto implements java.io.Serializable{
    private static final long serialVersionUID = 7526472295622776147L;
    
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    @Getter @Setter public int id;
    @Column(name="nombre")
    @Getter @Setter public String nombre;
    @Column(name="telefono")
    @Getter @Setter public String telefono; 
    @Column(name="fecha")
    @Getter @Setter public LocalDate fecha;
}

Ahora un repositorio.
ContactoCrudRepository.java

package com.codemonkey.repository;

import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import com.codemonkey.model.Contacto;

public interface ContactoCrudRepository extends CrudRepository{

    @Query(value="SELECT * FROM contacto ORDER BY id ",nativeQuery=true)
    public List<Contacto> getAllContactos(); 
}

Es necesario notar que dentro de la anotación @Query podemos declarar una consulta SQL nativa. En est caso SELECT * FROM contacto ORDER BY id.

El siguiente paso es declarar un servicio y su implementación.

package com.codemonkey.service;

import java.util.List;
import com.codemonkey.model.Contacto;

public interface ContactoCrudService{
    public List<Contacto> getAllContactos();
}

La implementación de este servicio sería el siguiente:

package com.codemonkey.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;

import com.codemonkey.repository.ContactoCrudRepository;
import com.codemonkey.service.ContactoCrudService;
import com.codemonkey.model.Contacto;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


@Service("contactoCrudService")
public class ContactoCrudServiceImpl implements ContactoCrudService{
    private final Logger LOGGER = LoggerFactory.getLogger(ContactoCrudServiceImpl.class);

    @Autowired
    private ContactoCrudRepository contactoCrudRepository;
    
    @Override
    public List<Contacto&gt getAllContactos(){
        LOGGER.info("--Has entrado a getAllContactos");
        return contactoCrudRepository.getAllContactos();
    }
} 

Creamos el ContactoRestController.java

package com.codemonkey.controller;

//import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import com.codemonkey.model.Contacto;
import com.codemonkey.service.ContactoCrudService;


@RestController
@RequestMapping("/rest")
public class ContactoRestController{

    private final Logger LOGGER = LoggerFactory.getLogger(ContactoRestController.class);
       
    //@Qualifier("contactoService")
    @Autowired
    private ContactoCrudService contactoCrudService;

    //http:localhost:8080/rest/contactosRest
    @GetMapping("/contactosRest")
    public List<Contacto&gt getAllContactos(){
        LOGGER.info("--Has entrado a http://localhost:8080/rest/contactosRest");
        return contactoCrudService.getAllContactos();
    }
}

Ahora una vista. Antes deberíamos aclarar que debemos la importar tres archivos necesarios para trabajar con Vue JS.

<!--Vue JS -->
<script
  src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js">
</script>
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js">
</script>
<!--axios-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

contactosVueJS.html

<!DOCTYPE html>
<html lang="es"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
    <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <title>Contactos</title>
        <script type="text/javascript" src="/js/funciones.js"></script>
        <link rel="stylesheet" type="text/css" media="all" href="css/estilos.css" th:href="@{css/estilos.css}" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"/>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
  <!--Vue JS -->
<script
  src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js">
</script>
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js">
</script>
<!--axios-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

    </head>
    <body>
<div class="jumbotron text-center">
   <h1 align="center" class="bg-dark text-white">Contactos</h1><br/>
   <a href="#" th:href="@{/proyecto/home}" title="regreso">Home</a>
</div>

<div id="my_app">    
    <div class="table-responsive">
        <table class="table table-dark table-striped" style="font-family: Chakra Petch">
            <thead >
                <tr>
                    <th>Nombre</th>
                    <th>Teléfono</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="data in contactos">
                    <td> <p contenteditable="true">{{ data.nombre }} </p></td>
                    <td><p contenteditable="true">{{ data.telefono }}</p></td>
                    
                </tr>
            </tbody>
        </table></div>

</div>

<script>
var my_app = new Vue({
    el:'#my_app',
    data(){
        return {
            contactos:[]
        };
    },
    methods:{
        getContactos(){
            axios
            .get('http://localhost:8080/rest/contactosRest')
            .then((data) => {
                this.contactos = data.data
            });
        }
    },
    mounted(){
        this.getContactos()
    },
});
</script>
</body>
</html>

En el fragmento de código javascript podemos analizar lo siguiente

//Creamos un objeto tipo Vue y sus atributos, en este caso el id será "my_app"
   var my_app = new Vue({
    el:'#my_app',
    data(){
        return {
            contactos:[]
        };
    },   //Declaramos un método getContactos() que hace una invocación
// al método get(URL) de axios, en esa URL esta nuestro servicio rest
    methods:{
        getContactos(){
            axios
            .get('http://localhost:8080/rest/contactosRest')
            .then((data) => {
                this.contactos = data.data
            });
        }
    },
    mounted(){
        this.getContactos()
    },
});

Dentro del fragmento HTML se puede observar lo siguiente:

<div id="my_app">    
    <div class="table-responsive">
        <table class="table table-dark table-striped" style="font-family: Chakra Petch">
            <thead >
                <tr>
                    <th>Nombre</th>
                    <th>Teléfono</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="data in contactos">
                    <td> <p contenteditable="true">{{ data.nombre }} </p></td>
                    <td><p contenteditable="true">{{ data.telefono }}</p></td>
                    
                </tr>
            </tbody>
        </table></div>

</div>

En esta parte accedemos a los atributos nombre y telefono:

{{ data.nombre }}
{{ data.telefono }}

¡Feliz código!

Advertisements

Git para incipientes

c2cd9-seleccic3b3n_008

En esta ocasión veremos cómo clonar un repositorio desde Bitbucket (antes deberías crear una cuenta).

Creamos un directorio, yo lo he denominado testRepositorios.

$ mkdir testRepositorios && cd testRepositorios

$ pwd
$ git --version

Iniciamos nuestro git.

$ git init

Se te pedirá agregar tu nombre de usuario y correo, son los mismos que tu cuenta en Bitucket.

$ git config --global user.name "TuNombreDeUsuario"

$ git config --global user.email "TuEmail"

Clonamos el repo.

$ git clone https://Super_Usser@bitbucket.org/Super_Usser/simpleapp.git

Nos ubicamos en la carpeta y listamos el contenido.

$ cd simpleapp && ls

Ver estado.

$ git status

Agregar algún archivo y vemos el estado.

$ touch nuevo.txt

$ git status

Agregar nuevo archivo.

$ git add nuevo.txt

Comentar el cambio.

$ git commit -m "Se ha agregado un nuevo archivo."

Ver de nuevo el estado.

$ git status

Enviar cambio.

$ git push

En caso que desde el repositorio raíz exista un cambio debemos obtener antes ese cambio y agregarlo a nuestro “clon”.

$ git pull

 
¡Feliz código!

 

 

Spring + Maven

user-154199_640

En está serie de post hemos visto como crear y ejecutar aplicaciones Java y Spring con Maven. He aguí otro ejemplo más.

pom.xml

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.codemonkey</groupId>
  <artifactId>Inicio</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Inicio</name>
  <url>http://maven.apache.org</url>
  <properties>
    <spring.version>3.0.5.RELEASE</spring.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  <!-- Spring 3 dependencies -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <!-- JavaConfig need this library -->
  <dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
  </dependency>
  </dependencies>
</project>

HelloWorld.java

package com.codemonkey.interfaces;

public interface HelloWorld{
    void printHelloWorld(String msg);
}

HelloWorldImpl.java

package com.codemonkey.clases;

import com.codemonkey.interfaces.HelloWorld;

public class HelloWorldImpl implements HelloWorld{

    public void printHelloWorld(String msg) {
        System.out.println("Hola : " + msg);
    }
}

AppConfig.java

package com.codemonkey.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.codemonkey.interfaces.HelloWorld;
import com.codemonkey.clases.HelloWorldImpl;

@Configuration
public class AppConfig {

    @Bean(name="helloBean")
    public HelloWorld helloWorld() {
        return new HelloWorldImpl();
    }
}

App.java

package com.codemonkey;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.codemonkey.interfaces.HelloWorld;
import com.codemonkey.config.AppConfig;

public class App {
    public static void main( String[] args ){
        helloWorld();
    }

    public static void helloWorld(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        HelloWorld obj = (HelloWorld) context.getBean("helloBean");
        obj.printHelloWorld("Hola, mundo!!!");
    }
}

Ejecutar:

mvn exec:java -Dexec.mainClass="com.codemonkey.App"

Visto en: http://www.java2s.com/Tutorials/Java/Spring/0035__Spring_3_JavaConfig.htm

Crear proyecto Java con Maven

mug-524103_1920

Generar proyecto.

mvn archetype:generate -DgroupId=com.codemonkey -DartifactId=Inicio -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Ubicarnos en el proyecto.

cd Inicio

Compatibilidad con eclipse.

mvn eclipse:eclipse

Archivos generados.

pom.xml

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.codemonkey</groupId>
  <artifactId>Inicio</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Inicio</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring</artifactId>
    <version>2.5.6</version>
  </dependency>   
  </dependencies>
</project>

App.java


package com.codemonkey;

/**
 * Hola mundo!
 *
 */
public class App {
    public static void main( String[] args ){
        System.out.println( "Hola mundo!" );
    }
}

Compilar.

mvn compile

Ejecutar.

mvn exec:java -Dexec.mainClass="com.codemonkey.App"  

Grails … un ejemplo

ec564-shomecode4

En este post crearemos un mini sistema para la gestión de tickets de soporte técnico.

¿Qué necesitamos?

  1. Tener instalado el JDK 8
  2. Tener instalado Grails
  3. Tener una BD (usaremos PostgreSQL en este ejemplo)

Tenemos los departamentos o áreas ).

areas

Se levantan los tickets

tickets

El encargado de dar soporte técnico responderá a las peticiones.

respuesta

Analizamos las relaciones.

Un Departamento tiene muchos Ticket(s)

Un Ticket pertenece a un Departamento

Una Respuesta pertenece a un Ticket

Tendremos en total tres clases:

  1. Departamento.groovy
  2. Ticket.groovy
  3. Respuesta.groovy

c2cd9-seleccic3b3n_008

Primer paso: crear el proyecto

$ grails create-app crud-app

Segundo paso: ubicarnos en la carpeta del proyecto creado

$ cd crud-app

Tercer paso: crear las tres clases

$ grails create-domain-class com.codemonkey.model.Departamento
$ grails create-domain-class com.codemonkey.model.Ticket
$ grails create-domain-class com.codemonkey.model.Respuesta

Departamento.groovy

package com.codemonkey.model

class Departamento {
    int iddepartamento
    String nombre
    String responsable

    static constraints = {
        nombre(blank: false)
        responsable(blank: false)
    }

    //Un Departamento tiene muchos Tickets
    static hasMany = [tickets: Ticket]

    String toString(){
        "**Departamento\nId:"+id+"\nNombre:"+nombre+"\nResponsable:"+responsable
    }
}

Ticket.groovy

package com.codemonkey.model

class Ticket {
    int idticket
    Date fecha
    String asunto
    String descripcion

    static constraints = {
        asunto(blank: false)
        descripcion(black: false)
    }

    //Una Tickets pertenece a un Departamento
    static belongsTo = [departamentos: Departamento]

    String toString(){
        "**Ticket\nId:"+id+"\nFecha:"+fecha+"\nAsunto:"+asunto+"\nDescripcion:"+descripcion
    }
}

Respuesta.groovy

package com.codemonkey.model

class Respuesta {
    int idrespuesta
    boolean solucionado
    String descripcion

    static constraints = {
        descripcion(blank: false)
    }

    //Una Respuesta pertenece a un Tickets
    static belongsTo = [tickets: Ticket]

    String toString(){
        String result = solucionado == true? "Solucionado" : "En espera"
        "**Respuesta\nId:"+id+"\nDescripcion:"+descripcion+"\nSolucionado:"+result
    }
}

Cuarto paso: configurar las dependencias necesarias y la conexión a la BD

build.gradle

 buildscript {
repositories {
mavenLocal()
maven { url “https://repo.grails.org/grails/core&#8221; }
}
dependencies {
classpath “org.grails:grails-gradle-plugin:$grailsVersion”
classpath “org.grails.plugins:hibernate5:${gormVersion-“.RELEASE”}”
classpath “com.bertramlabs.plugins:asset-pipeline-gradle:2.14.8”
}
}

version “0.1”
group “crud.app”

apply plugin:”eclipse”
apply plugin:”idea”
apply plugin:”war”
apply plugin:”org.grails.grails-web”
apply plugin:”asset-pipeline”
apply plugin:”org.grails.grails-gsp”

repositories {
mavenLocal()
maven { url “https://repo.grails.org/grails/core&#8221; }
}

dependencies {
runtime(‘org.postgresql:postgresql’)

compile “org.springframework.boot:spring-boot-starter-logging”
compile “org.springframework.boot:spring-boot-autoconfigure”
compile “org.grails:grails-core”
compile “org.springframework.boot:spring-boot-starter-actuator”
compile “org.springframework.boot:spring-boot-starter-tomcat”
compile “org.grails:grails-web-boot”
compile “org.grails:grails-logging”
compile “org.grails:grails-plugin-rest”
compile “org.grails:grails-plugin-databinding”
compile “org.grails:grails-plugin-i18n”
compile “org.grails:grails-plugin-services”
compile “org.grails:grails-plugin-url-mappings”
compile “org.grails:grails-plugin-interceptors”
compile “org.grails.plugins:cache”
compile “org.grails.plugins:async”
compile “org.grails.plugins:scaffolding”
compile “org.grails.plugins:events”
compile “org.grails.plugins:hibernate5”
compile “org.hibernate:hibernate-core:5.1.5.Final”
compile “org.grails.plugins:gsp”
console “org.grails:grails-console”
profile “org.grails.profiles:web”
runtime “org.glassfish.web:el-impl:2.1.2-b03”
runtime “com.h2database:h2”
runtime “org.apache.tomcat:tomcat-jdbc”
runtime “com.bertramlabs.plugins:asset-pipeline-grails:2.14.8”
testCompile “org.grails:grails-gorm-testing-support”
testCompile “org.grails:grails-web-testing-support”
testCompile “org.grails.plugins:geb:1.1.2”
testRuntime “org.seleniumhq.selenium:selenium-chrome-driver:2.47.1”
testRuntime “org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1”
testRuntime “net.sourceforge.htmlunit:htmlunit:2.18”
}

bootRun {
jvmArgs(‘-Dspring.output.ansi.enabled=always’)
addResources = true
String springProfilesActive = ‘spring.profiles.active’
systemProperty springProfilesActive, System.getProperty(springProfilesActive)
}

tasks.withType(Test) {
systemProperty “geb.env”, System.getProperty(‘geb.env’)
systemProperty “geb.build.reportsDir”, reporting.file(“geb/integrationTest”)
systemProperty “webdriver.chrome.driver”, System.getProperty(‘webdriver.chrome.driver’)
systemProperty “webdriver.gecko.driver”, System.getProperty(‘webdriver.gecko.driver’)
}

assets {
minifyJs = true
minifyCss = true
}

configurations.all {
resolutionStrategy.cacheDynamicVersionsFor 10, ‘minutes’
}

project.configurations.compile.resolvedConfiguration.resolvedArtifacts.each {
println ‘ [Dependencias] ‘
println ‘artifact: ‘+it.name
println ‘referencia: ‘+it.file
println ‘**************************’
}

application.yml

---
grails:
    profile: web
    codegen:
        defaultPackage: crud.app
    gorm:
        reactor:
            # Whether to translate GORM events into Reactor events
            # Disabled by default for performance reasons
            events: false
info:
    app:
        name: '@info.app.name@'
        version: '@info.app.version@'
        grailsVersion: '@info.app.grailsVersion@'
spring:
    main:
        banner-mode: "off"
    groovy:
        template:
            check-template-location: false

# Spring Actuator Endpoints are Disabled by Default
endpoints:
    enabled: false
    jmx:
        enabled: true

---
grails:
    mime:
        disable:
            accept:
                header:
                    userAgents:
                        - Gecko
                        - WebKit
                        - Presto
                        - Trident
        types:
            all: '*/*'
            atom: application/atom+xml
            css: text/css
            csv: text/csv
            form: application/x-www-form-urlencoded
            html:
              - text/html
              - application/xhtml+xml
            js: text/javascript
            json:
              - application/json
              - text/json
            multipartForm: multipart/form-data
            pdf: application/pdf
            rss: application/rss+xml
            text: text/plain
            hal:
              - application/hal+json
              - application/hal+xml
            xml:
              - text/xml
              - application/xml
    urlmapping:
        cache:
            maxsize: 1000
    controllers:
        defaultScope: singleton
    converters:
        encoding: UTF-8
    views:
        default:
            codec: html
        gsp:
            encoding: UTF-8
            htmlcodec: xml
            codecs:
                expression: html
                scriptlets: html
                taglib: none
                staticparts: none
endpoints:
    jmx:
        unique-names: true

---
hibernate:
    cache:
        queries: false
        use_second_level_cache: false
        use_query_cache: false
dataSource:
    pooled: true
    jmxExport: true
    driverClassName: org.postgresql.Driver # org.h2.Driver
    username: postgres #sa
    password: 5432 #''

environments:
    development:
        dataSource:
            dbCreate: update
            url: jdbc:postgresql://localhost:5432/inventario #jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
    test:
        dataSource:
            dbCreate: update
            url: jdbc:postgresql://localhost:5432/inventario #jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
    production:
        dataSource:
            dbCreate: none
            url: jdbc:postgresql://localhost:5432/inventario #jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
            properties:
                jmxEnabled: true
                initialSize: 5
                maxActive: 50
                minIdle: 5
                maxIdle: 25
                maxWait: 10000
                maxAge: 600000
                timeBetweenEvictionRunsMillis: 5000
                minEvictableIdleTimeMillis: 60000
                validationQuery: SELECT 1
                validationQueryTimeout: 3
                validationInterval: 15000
                testOnBorrow: true
                testWhileIdle: true
                testOnReturn: false
                jdbcInterceptors: ConnectionState
                defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED

Quinto paso: generar las vistas, etc.

$ grails generate-all "*"

Sexto paso: ejecutar aplicación

$ grails run-app

Abrir el navegador en: http://127.0.0.1:8080/

Es todo por el momento.

Un vistazo a Grails Framework

cropped-hunger-413685_960_7201.jpg

¿Qué es Grails Framework?

  1. Es un framework para desarrollo de aplicaciones web.
  2. Permite usar Java y Groovy.
  3. Funciona bajo el paradigma Modelo-Vista-Controlador.
  4. Se considera la versión de Ruby on Rails de Java.

Si usas SDKMAN! puedes instalarlo así:

$ sdk install grails

Comprobamos la versión instalada:

$ grails -version

Para crear un proyecto tecleamos lo siguiente:

$ grails create-app my-app

Nos colocamos en la carpeta creada:

$ cd my-app

Creamos un controller:

$ grails create-controller com.codemonkey.controller.Hola

La clase creada (Hola.groovy) se encontrará en:

grails-app/controller/com/codemonkey/controller

Hola.groovy

package com.codemonkey.controller

class Hola{

def index(){

render "Hola, amigos !!"

}

}

Para ejecutar la aplicación:

$ grails run-app

Abrimos nuestro navegador en:

http://127.0.0.1:8080/my-app

Por el momento es todo. En posteriores post escribiremos una aplicación más compleja.

Links

http://codigoprogramacion.com/articulos/programacionweb/ique-es-grails-framework-de-desarrollo-web.html#.Wz1_4-ZG3Dc

https://grails.org/

 

 

Servicio REST Api con Spring Data

Creamos un Proyecto Nuevo en https://start.spring.io/

Elegiremos Maven para la creación del ejemplo.

Screenshot_1

En la sección SQL elegimos JPA y PostgreSQL.

Screenshot_2

En la sección WEB elegimos Web y Rest Repositories

Screenshot_3

Finalizamos y descargamos el ejemplo. Debe quedar así en nuestro directorio.

Screenshot_4

Abrimos una terminal en el directorio y tecleamos:

mvn clean install

Maven se encargará de descargar las librerías necesarias para el proyecto.

Agregamos plugin para Eclipse IDE

mvn eclipse:eclipse

Ahora abrimos Eclipse e importamos proyecto Maven existente

Screenshot_5

Elegimos nuestro proyecto

Screenshot_6

Revisamos dependencias necesarias en el pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>com.codemonkey</groupId>
    <artifactId>api-rest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>api-rest-ejemplo</name>
    <description>Uso de API Rest Spring Data</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope> </dependency> -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project><span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

Creamos una tabla alumno.
Screenshot_7

Insertamos valores.

INSERT INTO public.alumno(nombre, apellidos, direccion, telefono, email)
	VALUES ('Zuzanne', 'Waller', 'Tomahawk no. 100', '555-766', 'zuzanewll@gmail.com'),('Yohanan', 'Diaz', 'Toluca, Edo. Mex.', '555-111', 'genaro.amaro@latinmail.com');

Screenshot_8

Creamos clase Alumno.java

package com.codemonkey.entity;

import java.io.Serializable;

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

@Entity
@Table(name="alumno")
public class Alumno implements Serializable{
	private static final long serialVersionUID = 1L;
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
	private int id;
	@Column(name = "nombre")
	private String nombre;
	@Column(name = "apellidos")
	private String apellidos;
	@Column(name = "direccion")
	private String direccion;
	@Column(name = "telefono")
	private String telefono;
	@Column(name = "email")
	private String email;

	public Alumno() {}

	public Alumno(int id, String nombre, String apellidos, String direccion, String telefono, String email) {
		super();
		this.id = id;
		this.nombre = nombre;
		this.apellidos = apellidos;
		this.direccion = direccion;
		this.telefono = telefono;
		this.email = email;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public String getApellidos() {
		return apellidos;
	}

	public void setApellidos(String apellidos) {
		this.apellidos = apellidos;
	}

	public String getDireccion() {
		return direccion;
	}

	public void setDireccion(String direccion) {
		this.direccion = direccion;
	}

	public String getTelefono() {
		return telefono;
	}

	public void setTelefono(String telefono) {
		this.telefono = telefono;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	@Override
	public String toString() {
		return "Alumno [id=" + id + ", nombre=" + nombre + ", apellidos=" + apellidos + ", direccion=" + direccion
				+ ", telefono=" + telefono + ", email=" + email + "]";
	}

}

Creamos un Repositorio de datos

package com.codemonkey.repository;

import org.springframework.data.repository.PagingAndSortingRepository;

import com.codemonkey.entity.Alumno;

public interface AlumnoRepository extends PagingAndSortingRepository<Alumno, Integer>{
}

Clases principales de la aplicación.
ApiRestEjemploApplication.java

package com.codemonkey;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ApiRestEjemploApplication {

	public static void main(String[] args) {
		SpringApplication.run(ApiRestEjemploApplication.class, args);
	}
}

SpringApplicationBuilder.java

package com.codemonkey;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(ApiRestEjemploApplication.class);
	}

}

application.properties

spring.data.rest.basePath=/api

#MySQL
#spring.datasource.url=jdbc:mysql://localhost:3306/proyecto
#spring.datasource.username=root
#spring.datasource.password=root
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver

#POSTGRESQL
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/proyecto
spring.datasource.username=postgres
spring.datasource.password=5432
#spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.ddl-auto=update
#spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy

# JPA (JpaBaseConfiguration, HibernateJpaAutoConfiguration)
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

Ejecutamos la aplicación y abrimos el navegador en la dirección

http://localhost:8080/api/alumnoes

Links:

https://geeks-mexico.com/2018/01/04/crea-un-api-rest-de-la-forma-mas-simple-con-java-y-spring-data-rest/

https://start.spring.io/

Instalando Spring y Gradle en Eclipse

¿Qué necesitamos? Descargar Eclipse for Java EE Developers aquí: http://www.eclipse.org/downloads

Una vez abierto el ide. Ir a la pestaña Help y elegir Eclipse Marketplace. Teclear Spring Framework y dar enter. Elegir Spring Tools.

Screenshot_1

Dar clic en botón Install. Se inicializará la instalación:

Screenshot_2

Confirmar y finalizar:

Screenshot_3

Finalizar:

Screenshot_4

Comprobamos instalación:

Screenshot_5

Instalando Gradle.

Help -> Marketpplace y teclear Gradle. Elegir Buildship Gradle Integration y dar clic en Install. También podemos elegir el editor Gradle.

Screenshot_6

El proceso finalizará y reiniciamos el IDE.

 

Spring MVC … primer ejemplo (REST)

Para este ejemplo crearemos una base de datos (yo uso postgresql) llamada proyecto, agregaremos una tabla usuario con los siguientes campos: id, nombre, password, logeado y area.

CREATE TABLE public.usuario
(
    id integer NOT NULL,
    nombre character varying NOT NULL,
    password character varying  NOT NULL,
    logeado boolean,
    area character varying,
    CONSTRAINT usuario_pkey PRIMARY KEY (id)
);

Ahora agregaremos unos datos:

INSERT INTO public.usuario(
	id, nombre, password, logeado, area)
	VALUES (1, 'Antony Yung', 00T$@l12', true, 'sistemas'),(2, 'Adrian Uribe', '3EvBb00', false, 'administracion'),
    (3,'Ernestina Pedroza','@22GgHQll',true,'recursos humanos');

Una vez creado la base de datos y su correspondiente tabla nos enfocaremos a crear el ejemplo con Spring MVC.

¿Qués es lo que necesitaremos?

  1. Archivo: build.gradle , para configurar las dependencias necesarias
  2. Archivo: application.properties, para configurar el acceso a la BD,entre otras cosas
  3. Dentro del paquete controller: UsuarioRestController.java y MainController.java
  4. Dentro del paquete config: WebSecurityConfig.java y MvcConfig.java
  5. Dentro del paquete entity: Usuario.java
  6. Dentro del paquete repository: UsuarioRepository.java
  7. Dentro del paquete service: UsuarioService.java y UsuarioServiceImpl.java
  8. Dentro de la subcarpeta src/main/resouces/templates: test_template.html , home.html , login.html y hello.html
  9. Dentro de la carpeta src/main/resources/static/js el archivo *.js: datatable.js (https://datatables.net/)

Comencemos

Este archivo nos servirá para configurar las dependencias necesarias pra nuestro proyecto (acceso a web, security, bases de datos, en este caso postgresql, etc.)

build.gradle

/**
*
*
*@description Ejemplo
*@version 1.1.0
*
*
*
* 1. Construir proyecto: gradle build
* 2. Ver tareas disponibles: gradle task
* 3. Ejecutar: gradle run รณ gradle bootRun
*/

buildscript {

        ext {
                springBootVersion = '1.5.6.RELEASE'
        }

        repositories {
                mavenCentral()
                maven {
                        url "https://plugins.gradle.org/m2/"
                }
        }
        dependencies {
                classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        }
}

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
apply plugin: 'project-report'
apply plugin: 'org.springframework.boot'

version = '1.0.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
mainClassName = "com.codemonkey.Application"
description ="""
Ejemplo de proyecto hecho con Gradle build

"""

jar {

        baseName='principal'

        manifest{
                attributes 'Main-Class': 'com.codemonkey.Application'
        }
}

repositories {
        mavenCentral()
}

dependencies {
        compile('org.springframework.boot:spring-boot-starter')
        compile('org.springframework.boot:spring-boot-starter-web')
		compile('org.springframework.boot:spring-boot-starter-actuator')
		compile('org.springframework.boot:spring-boot-starter-thymeleaf')
		providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
		testCompile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.25'
		compile("com.fasterxml.jackson.core:jackson-databind")
		compile("org.springframework.boot:spring-boot-starter-data-jpa")
		compile("org.springframework.boot:spring-boot-starter-data-rest")
		runtime('org.postgresql:postgresql')
		compile("org.springframework.boot:spring-boot-starter-security")
}

configurations.all {
    resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
}

project.configurations.compile.resolvedConfiguration.resolvedArtifacts.each {
 println '   [Dependencias] '
 println 'artifact: '+it.name
 println 'referencia: '+it.file
 println '**************************'
}

Este archivo se usará para configurar el acceso a la base de datos en postgresql, indicar el uso de las plantillas Thymeleaf.
application.properties

#BANNER
banner.charset=UTF-8
banner.location=banner.txt

#THYMELEAF TEMPLATES
spring.thymeleaf.cache=false
spring.thymeleaf.check-template=true
spring.thymeleaf.check-template-location=true
spring.thymeleaf.content-type=text/html
spring.thymeleaf.enabled=true
spring.thymeleaf.encoding=UTF-8
#spring.thymeleaf.excluded-view-names= # Comma-separated list of view names that should be excluded from resolution.
#spring.thymeleaf.mode=HTML5 # Template mode to be applied to templates. See also StandardTemplateModeHandlers.
#spring.thymeleaf.prefix=classpath:/templates/ # Prefix that gets prepended to view names when building a URL.
spring.thymeleaf.suffix=.html
#spring.thymeleaf.template-resolver-order= # Order of the template resolver in the chain.
#spring.thymeleaf.view-names= # Comma-separated list of view names that can be resolved.

#POSTGRESQL
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/proyecto
spring.datasource.username=postgres
spring.datasource.password=5432
#spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.ddl-auto=update
#spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy

# JPA (JpaBaseConfiguration, HibernateJpaAutoConfiguration)
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

No debemos olvidar las clases principales del programa: Application.java y ServletInitializer.java
ServletInitializer.java

package com.codemonkey;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(Application.class);
	}

}

Application.java

package com.codemonkey;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

Nuestro @Controller principal.
MainController.java.java

package com.codemonkey.controller;

import java.util.HashMap;
import java.util.Map;

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

@Controller
public class MainController {

      @RequestMapping(path="/", method=RequestMethod.GET)
	public String goHome(){
		return "index";
	}

}

El @RestController de la aplicación.
UsuarioRestController.java

package com.codemonkey.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import com.codemonkey.entity.Usuario;
import com.codemonkey.service.UsuarioService;

@RestController
@RequestMapping("/testUsuarios")
public class UsuarioRestController {

	@Autowired
	private UsuarioService usuarioService;

	//REST
    //http://localhost:8080/testUsuarios/usuarios
	@RequestMapping(path="/usuarios", method=RequestMethod.GET)
	public List<Usuario> getAllUsuarios(){
		return usuarioService.getAllUsuarios();
	}

	//http://localhost:8080/testUsuarios/usuario/1/
    @RequestMapping(value = "/usuario/{id}", method = RequestMethod.GET)
	public Usuario getUsuarioById(@PathVariable("id") long id){
		return usuarioService.getUsuarioById(id);
	}

	//http://localhost:8080/testUsuarios/testUsuarios
	@GetMapping("/testUsuarios")
    public ModelAndView test_template(){
        ModelAndView mav= new ModelAndView("test_template");
        return mav;
    }

}

El @Configuration de seguridad, donde indicamos el usuario y clave de acceso (root/123)
WebSecurityConfig.java

package com.codemonkey.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("root").password("123").roles("USER");
    }
}

El @Configuration de vistas home -> login -> hello.
MvcConfig.java

package com.codemonkey.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/home").setViewName("home");
        registry.addViewController("/").setViewName("home");
        registry.addViewController("/hello").setViewName("hello");
        registry.addViewController("/login").setViewName("login");
    }

}

La clase Entidad que servirá para enlazar los datos de la tabla ‘usuario’.

Usuario.java

package com.codemonkey.entity;

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

@Entity
public class Usuario {
	@Id
	@GeneratedValue
	@Column(name="id")
	private long id;
	@Column(name="nombre")
	private String nombre;
	@Column(name="password")
	private String password;
	@Column(name="logeado")
	private boolean logeado;
	@Column(name="area")
	private String area;

	public Usuario(){super();}

	public Usuario(String nombre, String password,
	boolean logeado, String area){
		super();
		this.nombre=nombre;
		this.password=password;
		this.logeado=logeado;
		this.area=area;
	}

	public void setId(long id){
		this.id=id;
	}

	public long getId(){
		return id;
	}

	public void setNombre(String nombre){
		this.nombre=nombre;
	}

	public String getNombre(){
		return nombre;
	}

	public void setPassword(String password){
		this.password=password;
	}

	public String getPassword(){
		return password;
	}

	public void setLogeado(boolean logeado){
		this.logeado=logeado;
	}

	public boolean isLogeado(){
		return logeado;
	}

	public void setArea(String area){
		this.area=area;
	}

	public String getArea(){
		return area;
	}

}

El @Repository, para hacer uso de los métodos necesarios para manipular los datos.
UsuarioRepository.java

package com.codemonkey.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.codemonkey.entity.Usuario;

@Repository("usuarioRepository")
public interface UsuarioRepository extends JpaRepository<Usuario, Long>{

}

La interface que nos permite crear métodos para obtener los registros de la tabla ‘usuario’.
UsuarioService.java

package com.codemonkey.service;

import java.util.List;

import com.codemonkey.entity.Usuario;

public interface UsuarioService {

	public List<Usuario> getAllUsuarios();
	public Usuario getUsuarioById(long id);

}

Esta clase nos permitirá descoplar el código.
UsuarioServiceImpl.java

package com.codemonkey.service;

import java.util.List;

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

import com.codemonkey.entity.Usuario;
import com.codemonkey.repository.UsuarioRepository;

@Service("usuarioService")
public class UsuarioServiceImpl implements UsuarioService {

	@Autowired
	private UsuarioRepository usuarioRepository;

	@Override
	public List<Usuario> getAllUsuarios() {
		return usuarioRepository.findAll();
	}

	@Override
	public Usuario getUsuarioById(long id) {
		return usuarioRepository.findOne(id);
	}

}

Ahora pasemos a los templates o vistas.

Página de bienvenida.
home.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Bienvenido</title>
        <style type="text/css">
           #centro {
    margin: auto;
    width: 50%;
    border: 0.8em solid #2f5777;
    padding: 10px;
}

h1{
    text-align: center;
}
        </style>
    </head>
    <body>
<div id="centro">
<h1>Bienvenido</h1>
Da clic en el  <a th:href="@{/hello}">enlace</a> para entrar.</div>
</body>
</html>

Página de login (root/123) para acceder la vista hello.
login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Formulario de entrada </title>
<style type="text/css">
   #centro {
    margin: auto;
    width: 50%;
    border: 0.8em solid #2f5777;
    padding: 10px;
}

#my_input{
    border: 1px solid #2f5777;
    font-size: medium;
    background-color: #2f5777;
    color: white;
}

h1{
    text-align: center;
}

</style>
    </head>
    <body>
<div th:if="${param.error}" id="centro">
            Nombre de usuario y/o clave incorrectos.</div>
<div th:if="${param.logout}" id="centro">
            Logeado.</div>
<div id="centro">
<h1>Formulario de entrada</h1>
<form th:action="@{/login}" method="post">
<div><label> Nombre de usuario : <input type="text" name="username"/> </label></div>
<div><label> Clave de acceso: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Entrar" id="my_input"/></div>
</form></div>
</body>
</html>

La página hello.html nos permitirá acceder a nuestro ejemplo.
hello.html

<!DOCTYPE html>
 <html lang="es">
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <title>Has entrado</title>
        <script type="text/javascript" src="/js/funciones.js"></script>
        		<link rel="stylesheet" type="text/css" media="all" href="css/estilos.css" th:href="@{css/estilos.css}" />

        		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    		<link rel="stylesheet" href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css"/>
    <script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
    <script src="/js/datatable.js"></script>
        </head>
    <body>


<div id="centro">


<h1>Bienvenido</h1>


Hola [[${#httpServletRequest.remoteUser}]]!
           <form th:action="@{/logout}" method="post">
            <input type="submit" value="Salir" id="my_input"/>
        </form>
</div>


Da clic <a th:href="@{/testUsuarios/testUsuarios}">aquí</a> para entrar y ver los usuarios.
    </body>
</html>

Esta página muestra una tabla con los datos de los usuarios registrados en la tabal ‘usuario’.
test_template.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="utf-8" />
	<title>Spring Boot + JPA + Datatables</title>
			<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
			<link rel="stylesheet" href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css"/>
	<script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
	<script src="/js/datatable.js"></script>
</head>

<body>
<h1>Usuarios</h1>
<table id="usuariosTable" class="display">
<thead>
<tr>
<th>Id</th>
<th>Nombre</th>
<th>Password</th>
<th>Logeado</th>
<th>Área</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Id</th>
<th>Nombre</th>
<th>Password</th>
<th>Logeado</th>
<th>Área</th>
</tr>
</tfoot>
</table>
</body>
</html>

Este archivo *.js nos permite recoger los datos del JSON creado y desplegarlo en una tabla html
datatable.js

$(document).ready( function () {
	 var table = $('#usuariosTable').DataTable({
			"sAjaxSource": "/testUsuarios/usuarios",
			"sAjaxDataProp": "",
			"order": [[ 0, "asc" ]],
			"aoColumns": [
			    { "mData": "id"},
		      { "mData": "nombre" },
				  { "mData": "password" },
				  { "mData": "logeado" },
				  { "mData": "area"},
			]
	 })
});

Construir:

gradle build

Ejecutar:

gradle bootRun

Visualizar:
http://localhost:8080/testUsuarios/usuarios
Saldrá la página de bienvenida, debes dar clic en el enlace y aparecerá el formulario, introduce el usuario (root) y clave (123). Al acceder debes dar clic en el enlace y ver el resultado.

Spring MVC

¿Qué es Spring Framework?

Es un marco de trabajo que se apoya en algunos estándares Java EE para el desarrollo de aplicaciones y contenedor de inversión de control. Nos permite, entre otras cosas, crear aplicaciones web, servicios REST, persistencia de bases de datos relacionales y no relacionales, etc. En este post hablaremos de Spring MVC, el cual es un marco de trabajo que nos permite crear aplicaciones web con la arquitectura MVC.

Arquitectura Modelo-Vista-Controlador (Model-View-Control)

Esta arquitectura se compone de tres principales conceptos:

  • A. Modelo: Objetos Java.
  • B. Vista: Plantilla que genera la HTML.
  • C. Controlador: Controlador que atiende las peticiones HTTP que llegan al servidor desde el navegador; si resuelve la petición, devuelve una respuesta, en este caso la página HTML.

Supongamos que un cliente quiere saber el estado actual de sus movimientos bancarios.

  1. El cliente hace una solicitud al servidor.
  2. El servidor atiende esa solicitud, verifica si puede atenderla y en caso afirmativo prepara un objeto.
  3. Ese objeto contiene los datos solicitados y con eso el controlador genera una vista (HTML) que verá el cliente en su pantalla.

¿Por qué usar Spring MVC en vez de otras tecnologías (EJB)?
Eso es cuestión de enfoques y necesidades del desarrollador (o jefes del desarrollador).

¿Qué necesito saber para aprender Spring MVC?
Comprender la lógica de la programación (principalmente la orientada a objetos). Entender qué son los patrones de diseño (IoC= Inversión de Control) y comprender como funciona el protocolo HTTP y los métodos GET y POST. Y un sinfín de cosas más.

¿Qué herramientas necesito para comenzar?
Por el momento dos cosas:

  1. Un editor de textos
  2. Descargar e instalar Gradle

Comencemos. Crearemos un proyecto llamado Test. Con la siguiente estructura de directorios:

Test/src/main/java
Test/src/main/resources

Carpeta src/main/java

src/main/java/com/codemonkey/Application.java
src/main/java/com/codemonkey/model/Usuario.java
src/main/java/com/codemonkey/controller/ControllerUsuario.java

Carpeta src/main/resources

src/main/resources/templates
src/main/resources/static
src/main/resources/application.properties
src/main/resources/banners.txt

Para descargar e instalar Gradle podemos usar SKDMAN!
$ sdk install gradle

Una vez instalado crearemos un archivo *.gradle. Este archivo contendrá las dependencias necesarias para crear nuestro ejemplo (disculpen si no lo describo detalladamente).

build.gradle

/**
*
*
*@description Ejemplo
*@version 1.1.0
*
*
*
* 1. Construir proyecto: gradle build
* 2. Ver tareas disponibles: gradle task
* 3. Ejecutar: gradle run ó gradle bootRun
*/

buildscript {

ext {
springBootVersion = '1.5.6.RELEASE'
}

repositories {
mavenCentral()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'war'
apply plugin: 'eclipse-wtp'
apply plugin: 'project-report'
apply plugin: 'org.springframework.boot'

version = '1.0.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
mainClassName = "com.codemonkey.Application"
description ="""
Ejemplo de proyecto hecho con Gradle build

"""

jar {

baseName='principal'

manifest{
attributes 'Main-Class': 'com.codemonkey.Application'
}
}

repositories {
mavenCentral()
}

dependencies {
compile('org.springframework.boot:spring-boot-starter')
compile group: 'org.projectlombok', name: 'lombok', version: '1.16.16'
testCompile('org.springframework.boot:spring-boot-starter-test')
compile('org.springframework.boot:spring-boot-starter-mustache')
compile('org.springframework.boot:spring-boot-starter-web')

}

configurations.all {
resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
}

//Ver dependencias
project.configurations.compile.resolvedConfiguration.resolvedArtifacts.each {
println ' [Dependencias] '
println 'artifact: '+it.name // << the artifact name
println 'referencia: '+it.file // << the file reference
println '**************************'
}

Ejemplo. Crearemos un servicio REST sencillo con las clases Usuario y Area.

  1. Clase principal: Application.java
  2. Clase Usuario.java
  3. Clase Area.java
  4. Controlador ControllerUsuario.java

Application.java


package com.codemonkey;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

Usuario.java

package com.codemonkey.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;
import lombok.Getter;

@Data
@AllArgsConstructor
public class Usuario{
@Getter @Setter private int id;
@Getter @Setter private String nombre_usuario;
@Getter @Setter private String password;
@Getter @Setter private boolean logeado;
@Getter @Setter private Area area;
}

Area.java

package com.codemonkey.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Setter;
import lombok.Getter;

@Data
@AllArgsConstructor
public class Area {
@Getter @Setter private int id;
@Getter @Setter private String responsable_area;
@Getter @Setter private int piso;
}

Como pueden notar nos ayudamos de Lombok para generar los getter y setter de ambas clases.

ControllerUsuario.java

package com.codemonkey.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Date;

import com.codemonkey.model.Usuario;
import com.codemonkey.model.Area;

@RestController
@RequestMapping("/nodo")
public class ControllerUsuario {

//http://127.0.0.1:8080/nodo/usuarios
@RequestMapping("/usuarios")
public List getUsuarios(){
List listaUsuario = new ArrayList();
listaUsuario.add(new Usuario(1, "Sr. Negativo", "1234", true, new Area(1, "sistemas",10)));
listaUsuario.add(new Usuario(2, "OscarRyz", "ryz123", false, new Area(2, "informatica",12)));
listaUsuario.add(new Usuario(3, "Benek", "secreta", true, new Area(3, "manager",9)));
return listaUsuario;
}

}

Construimos el proyecto:

$ gradle build

Ejecutamos:

$ gradle bootRun

Abrimos cualquier navegador en la siguiente dirección:
http://127.0.0.1:8080/nodo/usuarios

Cabecera de la respuesta

Content-Type application/json;charset=UTF-8
Date Sun, 13 Aug 2017 02:19:22 GMT
Transfer-Encoding chunked

Cabeceras de la petición

Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Host 127.0.0.1:8080
Upgrade-Insecure-Requests 1
User-Agent Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0

Datos obtenidos:

[{“id”:1,”nombre_usuario”:”Sr. Negativo”,”password”:”1234″,”logeado”:true,”area”:{“id”:1,”responsable_area”:”sistemas”,”piso”:10}
},
{“id”:2,”nombre_usuario”:”OscarRyz”,”password”:”ryz123″,”logeado”:false,”area”:{“id”:2,”responsable_area”:”informatica”,”piso”:12}
},
{“id”:3,”nombre_usuario”:”Benek”,”password”:”secreta”,”logeado”:true,”area”:{“id”:3,”responsable_area”:”manager”,”piso”:9}}
]

Nota: Firefox muestra mejor esos datos.