Mostrando entradas con la etiqueta Java EE. Mostrar todas las entradas
Mostrando entradas con la etiqueta Java EE. Mostrar todas las entradas

miércoles, 8 de julio de 2020

CRUD con RESTful API y JSON

Las aplicaciones de diversos sistemas en diversos casos no pueden acceder directamente a servidores de bases de datos por diversos motivos como las aplicaciones de Android, estas pueden tener sus bases de datos locales como SQLite, pero si desean interactuar con una base de datos externa como un MySQL requieren un puente que les permita ducha conexión. En este entorno aparecen los Servicios Web, que tienen muchas más aplicaciones y funcionalidades, que permitirán a las aplicaciones acceder a esas bases de datos y realizar operaciones CRUD.

Para crear un WebService se siguen los pasos comunes en su construcción (Clic aquí para ver como crear un WebService desde cero). El siguiente paso es crear la conexión a la base de datos.

Para poder ejecutar las operaciones de CRUD mediante un Servicio Web REST con java debemos definir una conexión mediante una clase Java (clic aquí para ver la conexión de Java a MySQL) o mediante JPA


Código

NOTA: En este ejemplo no se usará la unidad de persistencia (persistence.xml).

Teniendo como base a la tabla "Inquilinos"(clic aquí para ver el DTO) a la que le realizaremos un mantenimiento (CRUD) teniendo como DAO a "DaoInquilinos" y su correspondiente implementación (clic aquí para ver el DAO).Además, las pruebas a las funciones declaradas en el DAO (clic aquí para ver el DAO).

Se creará un punto de partida para el WebService llamado RestApi que tendrá el siguiente código

package apiRest;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/service")
public class RestApi extends Application {

}

Luego debemos de crear las funciones REST que se emplearán para las diversas funcionalidades del CRUD, como vamos a emplear JSON se puede optar por usar alguna biblioteca para manipular este formato de intercambio, pero se puede realizar este mismo procedimiento sin agregar ninguna bilbioteca adicional a Jersey y JAX-RS 2.0. Tendríamos una clase llamada JSONRest

package apiRest.services;

import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/inquilino")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class JSONRest {
    /* Dentro se colocan los métodos 
    	-GET
        -POST
        -PUT
        -DELETE
    */    
}

SELECT

Tendremos dos casos, cuando recibimos todos los registros(inquilinosSEL) y cuando se recibe solo uno de los registros(inquilinosGET)

La clase JSONRest contiene el siguiente código

@GET
@Path("/{id}")
public Response inquilinosGET(@PathParam("id") int id) {
    DaoInquilinos dao = new DaoInquilinosImpl();
    Inquilinos inquilino=  dao.inquilinosGet(id);
    if (inquilino == null) {
        String msg = "Inquilino no encontrado con id: " + id;
        return Response.ok(msg, MediaType.TEXT_PLAIN).build();
    } else {
        return Response.ok(inquilino).build();
    }
}

@GET
public Response inquilinosSEL() {
    DaoInquilinos dao = new DaoInquilinosImpl();
    List<Inquilinos> lista = dao.inquilinosSel();
    if (lista == null) {
        String msg = "Sin usuarios";
        return Response.ok(msg, MediaType.TEXT_PLAIN).build();
    } else {
        GenericEntity<List<Inquilinos>> entity
                = new GenericEntity<List<Inquilinos>>(lista) {
        };
        return Response.ok(entity).build();
    }
}

Probando desde el navegador

  • http://localhost:8082/WebService/service/inquilinos/1
  • http://localhost:8082/WebService/service/inquilinos/

Nota: la dirección (localhost) y el puerto (8082) variarán dependiendo de la ubicación y puerto empleado por el servidor de Java EE.

En el caso de la función "inquilinoGET" que requiere un valor para hacer la búsqueda. Otra forma es usar la anotación que es @QueryParam en lugar de @PathParam y esa anotación a su vez tiene como parámetro el nombre que tendrá desde la petición, similar a:
http://localhost:8082/WebService/service/inquilino/?id=1

INSERT

Se emplea el método POST, indicado mediante una anotación, para enviar la información a insertar, en nuestro caso es la BD la que genera automáticamente el código

La clase JSONRest contiene el siguiente código

@POST
@Produces(MediaType.TEXT_PLAIN)
public Response inquilinosINS(Inquilinos inquilino) {
    DaoInquilinos dao = new DaoInquilinosImpl();
    String msg = dao.inquilinosIns(inquilino);
    return Response.ok(msg).build();
}

UPDATE

Se emplea el método PUT, indicado mediante una anotación, para enviar la información que se desea modificar.

La clase JSONRest contiene el siguiente código

@PUT
@Produces(MediaType.TEXT_PLAIN)
public Response inquilinosUPD(Inquilinos inquilino) {
    DaoInquilinos dao = new DaoInquilinosImpl();
    String msg = dao.inquilinosUpd(inquilino);
    return Response.ok(msg).build();
}

DELETE

Urilizando la anotación DELETE se envía los identificadores de los registros a eliminar separados por comas. También se puede relizar eliminaciones individuales

La clase JSONRest contiene el siguiente código

@DELETE
@Path("/{ids}")
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
public Response inquilinosDEL(@PathParam("ids") String ids) {
    List<Integer> list = Arrays.stream(ids.split(","))
            .map(Integer::parseInt)
            .collect(Collectors.toList());
    DaoInquilinos dao = new DaoInquilinosImpl();
    String msg = dao.inquilinosDel(list);
    return Response.ok(msg).build();
}

Código completo

package apiRest.services;

import dao.DaoInquilinos;
import dao.impl.DaoInquilinosImpl;
import dto.Inquilinos;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/inquilinos")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class JSONRest {

    @GET
    @Path("/{id}")
    public Response inquilinosGET(@PathParam("id") int id) {
        DaoInquilinos dao = new DaoInquilinosImpl();
        Inquilinos inquilino = dao.inquilinosGet(id);
        if (inquilino == null) {
            String msg = "Inquilino no encontrado con id: " + id;
            return Response.ok(msg, MediaType.TEXT_PLAIN).build();
        } else {
            return Response.ok(inquilino).build();
        }
    }

    @GET
    public Response inquilinosSEL() {
        DaoInquilinos dao = new DaoInquilinosImpl();
        List<Inquilinos> lista = dao.inquilinosSel();
        if (lista == null) {
            String msg = "Sin usuarios";
            return Response.ok(msg, MediaType.TEXT_PLAIN).build();
        } else {
            GenericEntity<List<Inquilinos>> entity
                    = new GenericEntity<List<Inquilinos>>(lista) {
            };
            return Response.ok(entity).build();
        }
    }

    @POST
    @Produces(MediaType.TEXT_PLAIN)
    public Response inquilinosINS(Inquilinos inquilino) {
        DaoInquilinos dao = new DaoInquilinosImpl();
        String msg = dao.inquilinosIns(inquilino);
        return Response.ok(msg).build();
    }

    @PUT
    @Produces(MediaType.TEXT_PLAIN)
    public Response inquilinosUPD(Inquilinos inquilino) {
        DaoInquilinos dao = new DaoInquilinosImpl();
        String msg = dao.inquilinosUpd(inquilino);
        return Response.ok(msg).build();
    }

    @DELETE
    @Path("/{ids}")
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    public Response inquilinosDEL(@PathParam("ids") String ids) {
        List<Integer> list = Arrays.stream(ids.split(","))
                .map(Integer::parseInt)
                .collect(Collectors.toList());
        DaoInquilinos dao = new DaoInquilinosImpl();
        String msg = dao.inquilinosDel(list);
        return Response.ok(msg).build();
    }
}

Se puede apreciar en este caso que en la anotación @Produces y @Consumes se indica explícitamente que se trabajará con JSON, pero en las respuestas de las funciones el tipo de retorno no es String, sino "Response", esto permite formatear correctamente el contenido capturado por las funciones DAO y transformarlo a JSON sin emplear otra biblioteca.

RESTful API

Crear un Web Service

Bibliotecas requeridas

  • JAX-RS 2.0
  • Jersey 2.5.1


Estructura del proyecto



Persona.java
package entity;

import java.time.LocalDate;

public class Persona {

    private String dni;
    private String name;
    private LocalDate birthday;
    private Float weight;

    public Persona() {
    }

    public String getDni() {
        return dni;
    }

    public void setDni(String dni) {
        this.dni = dni;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public LocalDate getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDate birthday) {
        this.birthday = birthday;
    }

    public Float getWeight() {
        return weight;
    }

    public void setWeight(Float weight) {
        this.weight = weight;
    }    
}

RestApi.java
package apiRest;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/service")
public class RestApi extends Application {

}

TextRest.java
package apiRest.services;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/texto")
@Produces(MediaType.TEXT_PLAIN)
public class TextRest {

    @GET
    @Path("/prueba")
    public String dataGet() {
        return "Probando un Web Service";
    }
}

JsonRest.java
package apiRest.services;

import entity.Persona;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/json")
@Produces(MediaType.APPLICATION_JSON)
public class JsonRest {

    @GET
    @Path("/objeto")
    public Response getObject() {
        Persona p = new Persona();
        p.setDni("96584422");
        p.setName("Paul");
        p.setBirthday(LocalDate.of(1993, 5, 17));
        p.setWeight(62.7f);
        return Response.ok(p).build();
    }
    
    @GET
    @Path("/lista")
    public Response getList() {
        Persona p1 = new Persona();
        p1.setDni("10084422");
        p1.setName("Milagros");
        p1.setBirthday(LocalDate.of(1993, 2, 7));
        p1.setWeight(52.7f);
        Persona p2 = new Persona();
        p2.setDni("00084422");
        p2.setName("Yadira");
        p2.setBirthday(LocalDate.of(1992, 10, 1));
        p2.setWeight(57f);
        Persona p3 = new Persona();
        p3.setDni("41557422");
        p3.setName("Alejandra");
        p3.setBirthday(LocalDate.of(1990, 1, 21));
        p3.setWeight(49.9f);
        List<Persona> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        GenericEntity<List<Persona>> ge = new GenericEntity<List<Persona>>(list){};
        return Response.ok(ge).build();
    }
}

Si colocamos http://localhost:8082/RestApi/service/texto/prueba en el navegador obtendremos la respuesta:

  • Probando un Web Service


Para consumir los Web Services que devuelven Json se debe invocar a sus URI en los clientes REST que serían:
  • http://localhost:8082/RestApi/service/json/lista
  • http://localhost:8082/RestApi/service/json/objeto


Nota: la dirección (localhost) y el puerto (8082) variarán dependiendo de la ubicación y puerto empleado por el servidor de Java EE.

viernes, 19 de junio de 2020

Java Server Faces - DataTable

Las tablas de HTML en una aplicación web con Java Server Faces se construye mediante la etiqueta h:dataTable en los Facelets.

Los datos que se pueden mostrar mediante un h:dataTable son:
  • Arrays
  • Instancias del Java Colletion Framework
  • Instancias de java.sql.ResultSet
  • Instancias de javax.servlet.jsp.jstl.sql.Result
  • Instancias de javax.faces.model.DataModel

Supongamos el siguiente bean llamado "LibroBean":
package proyectoJSF.model;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class LibroBean {

 private Integer id = 105;
 private String nombre = "JSF EL";
 private AutorBean autor = new AutorBean();
 private String[] idiomas = { "Español", "Inglés", "italiano" };
 private List<String> paises;
 private Map<String, LocalDate> ediciones;

 public LibroBean() {
  cargarPaises();
  cargarEdiciones();
 }

 public String[] getIdiomas() {
  return idiomas;
 }

 public List<String> getPaises() {
  return paises;
 }

 public Map<String, LocalDate> getEdiciones() {
  return ediciones;
 }

 private void cargarPaises() {
  paises = new ArrayList<>();
  paises.add("Perú");
  paises.add("Canadá");
  paises.add("Japón");
 }

 private void cargarEdiciones() {
  ediciones = new TreeMap<>();
  ediciones.put("Primera", LocalDate.of(2012, 12, 30));
  ediciones.put("Segunda", LocalDate.of(2015, 2, 12));
  ediciones.put("Tercera", LocalDate.of(2020, 6, 7));
 }

 public Integer getId() {
  return id;
 }

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

 public String getNombre() {
  return nombre;
 }

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

 public AutorBean getAutor() {
  return autor;
 }

 public void setAutor(AutorBean autor) {
  this.autor = autor;
 }

}


Se aprecia que contiene diversas estructuras de datos, vamos a mostrar la estructura MAP mediante un h:dataTable de la siguiente manera:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://xmlns.jcp.org/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core">
<h:head>
 <title>Prueba 04 - DataTable</title>
</h:head>
<h:body>
 <h1>Ediciones de los libros</h1>
 <h:dataTable value="#{libroBean.ediciones}" var="edicion" border="1">
  <h:column>
   <f:facet name="header">
    Edición
   </f:facet>
   <h:outputText value="#{edicion.key}" />
  </h:column>
  <h:column>
   <f:facet name="header">
    Fecha de publicación (aaaa/mm/dd)
   </f:facet>
   <h:outputText value="#{edicion.value}" />
  </h:column>
 </h:dataTable>
</h:body>
</html>


Tenemos las siguientes etiqeutas y sus atributos:
  • h:dataTable, se convierte posteriormente en una tabla HTML
    • value, es el atributo cuyo valor es el que se itera dentro de la tabla
    • var, es el nombre de la variable que usaremos dentro de la estructura
    • border, similar a la propiedad "border" de una tabla HTML
  • h:column, en contraste con HTML no es necesario definir las filas, se hacen directamente las columnas. Dentro tendremos:
    • f:facet name="header", dentro de esta etiqueta con este "name" se coloca el texto que irá en dicha columna.
    • h:outputText value="#{edicion.key}", tendremos una etiqueta de texto que mostrará la clave de cada elemento del MAP
    • h:outputText value="#{edicion.value}", tendremos una etiqueta de texto que mostrará el valor de cada elemento del MAP

El resultado visual sería:
Edición Fecha de publicación (aaaa/mm/dd)
Primera 2012-12-30
Segunda 2015-02-12
Tercera 2020-06-07


Java Server Faces Expression Language (JSF EL)

Los Facelets no soportan las secuencias de comandos de Java Server Pages. Por ello, se requiere de una forma de indirectamente invocar al código Java. Así JSP y Facelets son dos tecnologías diferentes.

JSF permite la utilización de ambas incluso conjuntamente. A ello se debe acotar que Facelets es más reciente y específica para JSF ofreciendo más posibilidades al desarrollador. Se recomenda el uso de los Facelets en JSF.

El lenguaje de expresión de JSF fue inspirado en la tecnología JSTL mediante el uso de prefijos en sus bibliotecas estándar. Este se encuentra entre las capas de modelo y vista mediante la aplicación de las propiedades Setter y Getter.

Formatos

Emplear minúsculas al hacer referencia a un Bean. 
Tipo de bean EL
Atributo de un Bean Simple
#{nombre.atributo}
Ejemplo: Supongamos un Bean llamado "Mascota" que tiene un atributo llamado "peso", para llamarlo usaríamos
#{mascota.peso}
Método de un Bean Simple con retorno
#{nombre.metodo()}
Ejemplo: Supongamos un Bean llamado "Mascota" que tiene un método llamado "ladrido" que devuelve un valor String, para llamarlo usaríamos
#{mascota.ladrido()}
Atributo o método de un atributo tipo objeto de un Bean Simple
#{nombre.atrib1.atrib2}
Ejemplo: Supongamos un Bean llamado "Mascota" que tiene un atributo que es del tipo "Propietario" llamado "propietario" que devuelve un objeto y este objeto en su declaración tiene "id" y "nombre", para llamar al nombre del propietario usaríamos
#{mascota.propietario.nombre}


Aplicación

Nota: Para este caso se usa la versión JSF 2.3 y Java EE 8 con un servidor Payara

Supongamos que tenemos el siguiente "bean" llamado "AutorBeans"
package proyectoJSF.model;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class AutorBean {

 private Integer idAutor = 1;
 private String nombre = "Jhon";

 public AutorBean() {
 }
 
 public Integer getIdAutor() {
  return idAutor;
 }

 public void setIdAutor(Integer idAutor) {
  this.idAutor = idAutor;
 }

 public String getNombre() {
  return nombre;
 }

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

}


A partir de la versión 2.0 de JSF se puede emplear las EL desde cualquier parte del Facelet, ya no es necesario hacerlo dentro de sus etiquetas JSF. Para invocar a sus métodos Getter y Setter desde un Facelet debemos colocar lo siguiente:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
 <title>Prueba 03</title>
</h:head>
<h:body>
  <h1>Autor - Método GET</h1>
  <ul>
    <li>Id del autor: #{autorBean.idAutor}</li>
    <li>Nombre: #{autorBean.nombre}</li>
  </ul>
  <hr/>
  <h1>Autor - Método SET</h1>
  <h:form>
    <h:outputLabel value="Ingrese ID: "/>
    <h:inputText value="#{autorBean.idAutor}"/>
    <br/><br/>
    <h:outputLabel value="Ingrese nombre: "/>
    <h:inputText value="#{autorBean.nombre}"/>
    <br/><br/>
    <h:commandButton type="submit" value="Cambiar"/> 
  </h:form>
</h:body>
</html>


Se observa los siguiente, en este caso se modifico las cajas de texto con "10001" y "Jhon Paul" que originalmente tenían los mismos valores "1" y "Jhon":

La expresión #{autorBean.idAutor} invoca automáticamente al método GET del atributo "idAutor" y lo mismo en el caso de "nombre". Si se hace clic en el botón "Cambiar" se obtendrá el siguiente resultado:

En este caso la expresión #{autorBean.idAutor} dentro de los "h:inputText" invoca automáticamente al método SET del atributo "idAutor" y lo mismo en el caso de "nombre", que luego se ve reflejado en la primera sección del Facelet. Esto permite mucha simplicidad para el manejo de los atributos.



Manejando estructuras de datos con EL

Podemos visualizar Array y colecciones. Supongamos la siguiente clase "LibroBean" que emplea la anterior
package proyectoJSF.model;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class LibroBean {

 private Integer id = 105;
 private String nombre = "JSF EL";
 private AutorBean autor = new AutorBean();
 private String[] idiomas = { "Español", "Inglés", "italiano" };
 private List<String> paises;
 private Map<String, LocalDate> ediciones;

 public LibroBean() {
  cargarPaises();
  cargarEdiciones();
 }

 public String[] getIdiomas() {
  return idiomas;
 }

 public List<String> getPaises() {
  return paises;
 }

 public Map<String, LocalDate> getEdiciones() {
  return ediciones;
 }

 private void cargarPaises() {
  paises = new ArrayList<>();
  paises.add("Perú");
  paises.add("Canadá");
  paises.add("Japón");
 }

 private void cargarEdiciones() {
  ediciones = new TreeMap<>();
  ediciones.put("Primera", LocalDate.of(2012, 12, 30));
  ediciones.put("Segunda", LocalDate.of(2015, 2, 12));
  ediciones.put("Tercera", LocalDate.of(2020, 6, 7));
 }

 public Integer getId() {
  return id;
 }

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

 public String getNombre() {
  return nombre;
 }

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

 public AutorBean getAutor() {
  return autor;
 }

 public void setAutor(AutorBean autor) {
  this.autor = autor;
 }

}

Si deseamos mostrar el Array "idiomas", usaremos el siguiente código:
<h1>Libro - Idiomas disponibles</h1>
<ul>
 <li>#{libroBean.idiomas[0]}</li>
 <li>#{libroBean.idiomas[1]}</li>
 <li>#{libroBean.idiomas[2]}</li>
</ul>

Si deseamos mostrar la colección List "paises", usaremos el siguiente código:

<h1>Libro - Países de venta disponibles</h1>
<ul>
 <li>#{libroBean.paises[0]}</li>
 <li>#{libroBean.paises[1]}</li>
 <li>#{libroBean.paises[2]}</li>
</ul>

Si deseamos mostrar la colección Map "ediciones", usaremos el siguiente código:

<h1>Libro - Ediciones y fechas</h1>
<ul>
 <li>#{libroBean.ediciones["Primera"]}</li>
 <li>#{libroBean.ediciones["Segunda"]}</li>
 <li>#{libroBean.ediciones["Tercera"]}</li>
</ul>


Obteniendo el siguiente resultado:


Operaciones con EL

Podemos emplear operaciones de comparación, aritméticas, lógicas y el operador "empty".

Operaciones aritméticas
Expresión Resultado
Suma (+) #{2+2} 4
Resta (-) #{2-12} -10
Producto (*) #{7*5} 35
División ("div" o "/") #{4/5} 0.8
Residuo ("mod" o "%") #{12 mod 5} 2
Operación combinada #{(5 % 3)*2-1} 3

Operaciones de comparación
Expresión Resultado
Igual ("==" o "eq") #{"hola" eq "hola"} true
Diferente ("!=" o "ne") #{20 ne 20} false
Mayor ("gt") #{30 gt 20} true
Menor ("lt") #{10 lt 20} true
Mayor o igual ("ge") #{11 ge 22} false
Menor o igual ("le") #{12 le 12} true

Nota evitar el uso de los símbolos < y > para las comparaciones por las reglas de XML

Operaciones lógicas
Expresión Resultado
Disyunción ("or") #{(1 ne 1) or (5 ne 6)} true
Conjunción ("and") #{(1 ne 1) and (5 ne 6)} false
Negación ("!") #{!(1 eq 2)} true

El operador "empty" verifica si un contenido es vacío o nulo y retornará verdadero o falso según sea el caso. Se puede ejemplificar mediante
  • #{empty ""}
  • #{empty null}
Ambos ejemplos devolverán "true", si tenemos un valor capturado que es nulo entonces la siguiente expresión también devolverá "true"
  • #{empty clase.atributo}


Condicionales en EL

Para hacer uso de estos se emplea el operador ternario con la sintaxis:
  • #{ condición ? valorTrue : valorFalse}

Ejemplo:

<p class=" #{clase.atributo eq 5 ? 'class5' : 'class10'} ">
 
Del ejemplo se comprueba si el atributo recuperado es 5, de ser el caso la clase será "class5", sino será "class10". Tener mucha atención en el uso de comillas simples y dobles.

Otra manera de emplear los condicionales es el atributo "rendered", si este tiene como valor una condición verdadera, el elemento que posee este atributo se hará visible, de lo contrario tendrá visibilidad oculta.

Ejemplo:
<!--  Elemento invisible, porque 11 no es igual a 10 -->
<h:outputText value="Primer saludo" rendered="#{11 eq 10}"/>
<br/>
<!--  Elemento visible porque 10 es igual a 10 -->
<h:outputText value="Segundo saludo" rendered="#{10 eq 10}"/>


Resultado visual:
  • Segundo saludo




miércoles, 17 de junio de 2020

Mostrar imágenes en JSP con Servlet

Consideramos la clase "Espacios" que proviene de la siguiente estructura SQL (Se ha obviado intencionalmente a la clave foránea en el campo "tipo"):
-- -----------------------------------------------------
-- Table espacios
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS espacios (
  idespacios INT NOT NULL AUTO_INCREMENT,
  piso TINYINT NOT NULL,
  precio DOUBLE(6,2) NOT NULL,
  ubicacion VARCHAR(25) NULL,
  tipo TINYINT NULL,
  imagen BLOB NULL,
  PRIMARY KEY (idespacios)
  )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;


Su clase en Java con el patrón DTO sería:
package dto;

public class Espacios {

    private Integer idespacios;
    private Integer piso;
    private Double precio;
    private String ubicacion;
    private Integer tipo;
    private byte[] imagen;

    public Espacios() {
    }

    /* Métodos Setter y getter */

}


El atributo imagen no se emplea, pero será de utilidad si convertimos el proyecto a uno de escritorio.
Su Interfaz e implementación DAO son:
package dao;

import java.util.List;
import dto.Espacios;

public interface DaoEspacios {

    public byte[] espaciosImg(Integer id);

    public String getMessage();
}

package dao.impl;

import biblioteca.ConectaBD;
import dao.DaoEspacios;
import dto.Espacios;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class DaoEspaciosImpl implements DaoEspacios {

    private final ConectaBD conectaDb;
    private String mensaje;

    public DaoEspaciosImpl() {
        this.conectaDb = new ConectaBD();
    }

    @Override
    public byte[] espaciosImg(Integer id) {
        byte[] img = null;
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ")
                .append("imagen")
                .append(" FROM espacios WHERE idespacios = ?");
        try (Connection cn = conectaDb.conexionDB()) {
            PreparedStatement ps = cn.prepareStatement(sql.toString());
            ps.setInt(1, id);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    Blob blob = rs.getBlob(1);
                    if (blob != null) {
                        byte[] bytes = blob.getBytes(1, (int) blob.length());
                        blob.free();
                        img = bytes;
                    }
                } else {
                    img = null;
                }
            } catch (SQLException e) {
                mensaje = e.getMessage();
            }
        } catch (SQLException e) {
            mensaje = e.getMessage();
        }
        return img;
    }

    @Override
    public String getMessage() {
        return mensaje;
    }
}


El servlet que permite mostrar la imagen sería:
package web.servlet;

import biblioteca.DeString;
import dao.DaoEspacios;
import dao.impl.DaoEspaciosImpl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "ImagenServlet", urlPatterns = {"/Imagen"})
public class ImagenServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("image/jpg");
        DaoEspacios daoEspacios = new DaoEspaciosImpl();
        Integer id = DeString.aInteger(request.getParameter("id"));
        try {
            byte[] data = daoEspacios.espaciosImg(id);
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            output.write(data, 0, data.length);
            response.setContentLength(output.size());
            try (OutputStream out = response.getOutputStream()) {
                output.writeTo(out);
                out.flush();
            }
        } catch (IOException ex) {
            System.err.println(String.format("%s - %s", daoEspacios.getMessage(), ex.getMessage()));
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }
}


El URL para mostrar una imagen sería por ejemplo: http://localhost:8084/Demo/Imagen?id=8 donde el valor que cambia es el número "8" por el "id" del registro del que se desea mostrar la imagen.

Ejemplo:

Dentro de un JSP el código tendría la siguiente forma:

      <img src="Imagen?id=8" alt="img"/>
   


Ese valor 8 se puede reemplazar con código de manera que recibe el "id" esperado como en esta porción de código que captura el id mediante una estructura que lista todos los espacios con JSTL.

      <img src="Imagen?id=${f.idespacios}" alt="img"/>
   




miércoles, 10 de junio de 2020

Java Server Faces Page Navigation

Antes de la versión 2.0 de JSF se debía crear reglas de navegación en el archivo faces-config.xml y declarar el destino en el método, pero desde esta versión se puede reemplazar ambos simplemente declarando un valor de retorno String como se muestra en el siguiente "Bean"

package proyectoJSF.view;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class NavigationView {

   private String mensaje;

   public String viaje1() {
      mensaje = "Llego al destino #1";
      return "destino1"; // return "destino.xhtml"
   }
 
   public String viaje2() {
      mensaje = "Llego al destino #2";
      return "destino2?faces-redirect=true";
   }
 
   public void viaje3() {
      mensaje = "Llego al destino #3";
      //retorno vacío o "null"
   }

   /* Métodos Setter y Getter*/
   public String getMensaje() {
      return mensaje;
   }

   public void setMensaje(String mensaje) {
      this.mensaje = mensaje;
   } 

}

Y tendríamos la siguiente estructura de archivos html y xhtml

Donde los códigos son:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Proyecto Demo de JSF</title>
</head>
<body>
   <h1>Probando JSF</h1>
   <hr />
   <a href="prueba1.xhtml">Prueba #1</a>
   <br/><br/>
   <a href="prueba2.xhtml">Prueba #2</a>
</body>
</html>

prueba2.xhtml
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:f="http://xmlns.jcp.org/jsf/core"
 xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
   <title>Prueba 02</title>
</h:head>
<h:body>
   <h1>Navegación</h1>
   <h:form>
      <h:commandButton value="Viaje 1" action="#{navigationView.viaje1()}">
      </h:commandButton>
      <br/><br/>
      <h:commandButton value="Viaje 2" action="#{navigationView.viaje2()}">   
      </h:commandButton>
      <br/><br/>
      <h:commandButton value="Viaje 3" action="#{navigationView.viaje3()}">
         <f:ajax execute="@form" render=":salida" />
      </h:commandButton>
   </h:form>
   <h:outputText id="salida" value="#{navigationView.mensaje}" />
</h:body>
</html>

destino1.xhtml y destino2.xhtml tienen un código similar
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
   <title>Destino 01</title>
</h:head>
<h:body>
   <h1>Bienvenido al destino 01</h1>
   <h:outputText id="output" value="#{navigationView.mensaje}" />
</h:body>
</html>

Con el siguiente resultado visual en prueba2.xhtml:

Clic en la miniatura para ver la imagen completa


Y los resultados de cada uno de los botones, mostrando la navegación entre páginas.


Clic en la miniatura para ver la imagen completa

Java Server Faces Tag Library

Componentes estándar de HTML 

JSF proporciona un conjunto de componentes para crear HTML con la ayuda de la tecnología de visualización Facelets.

Esos componentes HTML están disponibles en el URI (Uniform Resource Identifier) http://xmlns.jcp.org/jsf/html que debe asignarse al prefijo "h" del espacio de nombres XML como se muestra en el siguiente código en la línea 4:
<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Título</title>
    </h:head>
    <h:body>
        <!--Cuerpo de la página-->
    </h:body>
</html>

Los elementos más importantes para una página JSF deben ser los de <h:head> y <h:body> para luego incluir dentro los demás componentes HTML, sin estos la tecnología JSF no podrá incluir a los recursos de JS u hojas de estilo que se asocian con determinados componentes.

El código anterior generaría una página HTML como la siguiente:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Título</title>
    </head>
    <body>
        <!--Cuerpo de la página-->
    </body>
</html>

Tabla de componentes HTML de JSF
Component tag (Etiqueta del componente) Superclase del componente Salida en HTML
U<h:column> UIColumn <td>
U<h:commandButton> UICommand <input type="submit">
U<h:commandLink> UICommand <a onclick="form.submit()">
U<h:commandScript> UICommand <script>
U<h:dataTable> UIData <table>
U<h:form> UIForm <form method="post">
U<h:graphicImage> UIGraphic <img>
U<h:inputFile> UIInput <input type="file">
U<h:inputHidden> UIInput <input type="hidden">
U<h:inputSecret> UIInput <input type="password">
U<h:inputText> UIInput <input type="text">
U<h:inputTextarea> UIInput <textarea>
U<h:selectBooleanCheckbox> UIInput <input type="checkbox">
U<h:selectManyCheckbox> UIInput <table><input type="checkbox">
U<h:selectManyListbox> UIInput <select multiple size="n"><option>
U<h:selectManyMenu> UIInput <select multiple size="1"><option>
U<h:selectOneListbox> UIInput <select size="n"><option>
U<h:selectOneMenu> UIInput <select size="1"><option>
U<h:selectOneRadio> UIInput <table><input type="radio">
U<h:selectOneRadio group> UIInput <input type="radio" name="group">
U<h:message> UIMessage <span>
U<h:messages> UIMessages <ul>
U<h:messages layout=table> UIMessages <table>
U<h:button> UIOutcomeTarget <button onclick="window.location">
U<h:link> UIOutcomeTarget <a>
U<h:body> UIOutput <body>
U<h:doctype> UIOutput <!DOCTYPE>
U<h:head> UIOutput <head>
U<h:outputFormat> UIOutput <span>
U<h:outputLabel> UIOutput <label>
U<h:outputText> UIOutput <span>
U<h:outputScript> UIOutput <script>
U<h:outputStylesheet> UIOutput <link rel="stylesheet">
U<h:panelGrid> UIPanel <table>
U<h:panelGroup> UIPanel <span>
U<h:panelGroup layout=block> UIPanel <div>


Componentes estándar del Core

JSF proporciona un conjunto de componentes "Core" que dan soporte a configurar declarativamente uno o más componentes de destino HTML.

Esos componentes HTML están disponibles en el URI (Uniform Resource Identifier) http://xmlns.jcp.org/jsf/core que debe asignarse al prefijo "f" del espacio de nombres XML como se muestra en el siguiente código en la línea 5:
<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Título</title>
    </h:head>
    <h:body>
        <!--Cuerpo de la página-->
    </h:body>
</html>

Dentro del tenemos:
Core tag Constructores o manejadores Componente destino
<f:actionListener> javax.faces.event.ActionListener ActionSource
<f:ajax> javax.faces.component.behavior.AjaxBehavior ClientBehaviorHolder(s)
<f:attribute> UIComponent#getAttributes() UIComponent
<f:attributes> UIComponent#getAttributes() UIComponent
<f:convertDateTime> javax.faces.convert.DateTimeConverter (Editable)ValueHolder
<f:convertNumber> javax.faces.convert.NumberConverter (Editable)ValueHolder
<f:converter> javax.faces.convert.Converter (Editable)ValueHolder
<f:event> javax.faces.event.ComponentSystemEvent UIComponent
<f:facet> UIComponent#getFacets() UIComponent
<f:importConstants> javax.faces.component.UIImportConstants UIViewRoot
<f:loadBundle> java.util.ResourceBundle UIViewRoot
<f:metadata> javax.faces.view.ViewMetadata UIViewRoot
<f:param> javax.faces.component.UIParameter UIComponent
<f:passthroughAttribute> UIComponent#getPassthroughAttributes() UIComponent
<f:passthroughAttributes> UIComponent#getPassthroughAttributes() UIComponent
<f:phaseListener> javax.faces.event.PhaseListener UIViewRoot
<f:selectItem> javax.faces.component.UISelectItem UISelectOne/UISelectMany
<f:selectItems> javax.faces.component.UISelectItems UISelectOne/UISelectMany
<f:setPropertyActionListener> javax.faces.event.ActionListener ActionSource
<f:subview> javax.faces.component.NamingContainer UIComponents
<f:validateBean> javax.faces.validator.BeanValidator UIForm
<f:validateDoubleRange> javax.faces.validator.DoubleRangeValidator EditableValueHolder
<f:validateLength> javax.faces.validator.LengthValidator EditableValueHolder
<f:validateLongRange> javax.faces.validator.LongRangeValidator EditableValueHolder
<f:validateRegex> javax.faces.validator.RegexValidator EditableValueHolder
<f:validateRequired> javax.faces.validator.RequiredValidator EditableValueHolder
<f:validateWholeBean> javax.faces.validator.BeanValidator UIForm
<f:validator> javax.faces.validator.Validator EditableValueHolder
<f:valueChangeListener> javax.faces.event.ValueChangeListener EditableValueHolder
<f:view> javax.faces.component.UIViewRoot UIComponents
<f:viewAction> javax.faces.component.UIViewAction UIViewRoot
<f:viewParam> javax.faces.component.UIViewParameter UIViewRoot
<f:websocket> javax.faces.component.UIWebsocket UIViewRoot

JSF con Eclipse

Se requiere tener instalados o configurados los siguientes componentes:


Al final tendremos un proyecto Maven de JSF 2.3 con JPA 2.2, Servlets versión 4, JDK 1.8 y Java EE 8

Primer paso: crear un proyecto web dinámico Maven

Crear un nuevo proyecto como se muestra


Seleccionar la opción Maven y luego Maven Project como se muestra


Configurar el proyecto con las siguientes especificaciones


Elegir el Group Id y Artifact Id de su preferencia. Seleccionar la opción war para indicar que se trata de un proyecto Web


Finalmente se obtendrá un proyecto con la siguiente estructura:



Segundo paso: Modificar el archivo pom.xml

El archivo pom.xml se debe modificar de la siguiente manera para indicar la versión 4 de los Servlets, el JDK 1.8 y la versión 8 de Java EE:

<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.jsf</groupId>
   <artifactId>proyectoJSF</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>war</packaging>
   <properties>
      <project.build.sourceEncoding>
         UTF-8
      </project.build.sourceEncoding>
      <project.reporting.outputEncoding>
         UTF-8
      </project.reporting.outputEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
      <failOnMissingWebXml>false</failOnMissingWebXml>
   </properties>
   <dependencies>
      <dependency>
         <groupId>javax</groupId>
         <artifactId>javaee-api</artifactId>
         <version>8.0</version>
         <scope>provided</scope>
      </dependency>
   </dependencies>
</project>

El proyecto se actualizará.


Tercer paso: Configurar el proyecto

Vamos a la opción propiedades haciendo clic derecho sobre el nombre del proyecto y buscamos la opción Project Facets y modificamos los checkbox dela siguiente manera:



Las versiones de JSF y JPA se modificarán manualmente, pero debemos hacer clic en "Further configuration required..." para realizar los siguientes cambios:



Esto provocará que se genere un archivo XML llamado "persistence.xml", pero usualmente en un lugar incorrecto y debemos modificar su ubicación de "src/main/java" a "src/main/resources". Además, de agregar y/o modificar tres archivos XML más llamados "beans.xml", "web.xml" y "faces-config.xml" dentro de la carpeta WEB-INF


El archivo web.xml se debe modificar de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
 version="4.0">
 <display-name>proyectoJSF</display-name>
 <servlet>
  <servlet-name>facesServlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>facesServlet</servlet-name>
  <url-pattern>*.xhtml</url-pattern>
 </servlet-mapping>
</web-app>


El archivo faces-config.xml se debe modificar de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
 http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd"
 version="2.3">
</faces-config>


El archivo persistence.xml se debe modificar de la siguiente manera para indicar la versión 2.2 de JPA:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
 version="2.2">
 <persistence-unit name="proyectoJSF">
 </persistence-unit>
</persistence>


El archivo beans.xml se debe modificar de la siguiente manera:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
 http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
 version="2.0" bean-discovery-mode="annotated">
</beans>


Opcionalmente podemos desactivar la validación del JPA para que no se muestre un error en "persistence.xml". Para ello, vamos a las propiedades, luego a "Validation" y realizamos las siguientes modificaciones.


Cuarto paso: crear un Bean y un XHTML

Se ha creado un proyecto que sigue el patrón de diseño MVC donde el controlador es el archivo "web.xml", para tener la vista enlazada a un Bean, crearemos un nuevo paquete llamado: "proyectoJSF/view" y dentro crearemos un nuevo Bean con la herramienta CDI instalada previamente.



Modificamos el código del Bean creado por:

package proyectoJSF.view;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class SaludoView {

 private String input;
 private String output;

 public void submit() {
  output = "Hola estimado " + input;
 }

 public String getInput() {
  return input;
 }

 public void setInput(String input) {
  this.input = input;
 }

 public String getOutput() {
  return output;
 }

}


En la carpeta webapp crearemos dos archivos: "index.html" y "prueba1.xhtml" con los siguientes códigos:
  • index.html
<!DOCTYPE html>
<html>
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Proyecto Demo de JSF</title>
 </head>
 <body>
   <h1>Probando JSF</h1>
   <hr />
   <a href="prueba1.xhtml">Prueba #1</a>
 </body>
</html>

  • prueba1.xhtml
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
   xmlns:f="http://xmlns.jcp.org/jsf/core"
   xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
   <title>Prueba 01</title>
</h:head>
<h:body>
   <h1>Saludando</h1>
   <h:form>
      <h:outputLabel for="input" value="Input" />
      <h:inputText id="input" value="#{saludoView.input}" />
      <h:commandButton value="Submit" action="#{saludoView.submit}">
         <f:ajax execute="@form" render=":output" />
      </h:commandButton>
   </h:form>
   <h:outputText id="output" value="#{saludoView.output}" />
</h:body>
</html>


Tendremos la siguiente estructura en el proyecto:


Quinto paso: Iniciar el proyecto

Debemos agregar el proyecto al servidor una vez que se encuentre activo como se indica:


Luego debe quedar así


Una vez ejecutado el proyecto debemos ir al enlace de prueba #1 e introducir un nombre para ver la respuesta de la página



martes, 2 de junio de 2020

Bootstrap con JSP

La implementación del framework de Front-end Bootstrap en los JSP es idéntica que en los archivos .html. para ver esta hacer clic aquí


Incluir Bootstrap en un JSP

Consideremos la estructura básica de un JSP:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <!--Cuerpo de la página-->
    </body>
</html>


Modificamos la sección "head" para añadir el marco de trabajo:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
        <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
        <!-- jQuery library -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <!-- Popper JS -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
        <!-- Latest compiled JavaScript -->
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script> 
    </head>
    <body>
        <div class="container-fluid">
            <h1>La clase columna</h1>
            <p>Nota: Se autodimensionan automáticamente en una fila de manera que tienen el mismo tamaño</p>
            <div class="row">
                <div class="col" style="background-color:lavender;">.col</div>
                <div class="col" style="background-color:orange;">.col</div>
                <div class="col" style="background-color:lavender;">.col</div>
                <div class="col" style="background-color:orange;">.col</div>
                <div class="col" style="background-color:lavender;">.col</div>
                <div class="col" style="background-color:orange;">.col</div>
            </div>
        </div>
        <div class="container-fluid">
            <h2>Hoverable Dark Table</h2>
            <div class="table-responsive">
                <table class="table table-dark table-hover">
                    <thead>
                        <tr>
                            <th>Columna 1</th>
                            <th>Columna 2</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>Dato 1.1</td>
                            <td>Dato 2.1</td>
                        </tr>
                        <tr>
                            <td>Dato 1.2</td>
                            <td>Dato 2.2</td>
                        </tr>
                    </tbody>
                </table>
            </div> 
        </div>
    </body>
</html>

sábado, 16 de mayo de 2020

Java Standard Tag Library

JSTL es la biblioteca de etiquetas estándar de Java, que darán soporte a los JSP y es uno de los componentes de JAVA EE.

Su utilizad radica en que permite la creación de páginas web dinámicas de forma más eficiente que si no se les usara. Además,  aprovecha el "request", donde almacena variables, datos, etc. para dar soporte a la página JSP desde un servlet.

Cuenta con 6 bibliotecas que la componen:
  • core, iteraciones, condicionales, manipulación de URL y otras funciones generales.
  • biblioteca de funciones
  • xml, para la manipulación de XML y para XML-Transformation.
  • sql, para gestionar conexiones a bases de datos.
  • TLV
  • fmt, para la internacionalización y formateo de las cadenas de caracteres como cifras.

Para agregar esta biblioteca a un proyecto web en Netbeans se sigue los siguientes pasos:

Primero se debe agregar una nueva biblioteca:

Luego seleccionar JSTL y agregar

Dentro de los archivos JSP podemos emplear la paleta que provee Netbeans. Para ello, se hace los siguiente

Aparecerá una barra lateral donde se debe ubicar los siguiente


JSTL CORE


<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSTL - JavaJhon</title>        
    </head>
    <body>
        <strong>Usando JSTL IF</strong>
        <!--Suponemos que hemos capturado o recibido un valor 
        numérico y lo almacenamos en una variable "nota", luego 
        realizamos una comparación con otro valor.-->
        <% Double nota = 20d;%>
        <c:if test="<%= nota>11.5d %>">
            <p>Felicidades ustes ha aprobado con nota: <%= nota%></p>
        </c:if>
        <hr/>
        <br/>        
        <strong>Usando JSTL CHOOSE</strong>
        <!--Suponemos que hemos capturado o recibido un valor 
        numérico y lo almacenamos en una variable "dia", luego 
        realizamos una comparación con otros valores.-->
        <% Integer dia = 6;%>
        <c:choose>
            <c:when test="<%= dia== 1%>">
                <p>Es lunes</p>
            </c:when>
            <c:when test="<%= dia== 2%>">
                <p>Es martes</p>
            </c:when>
            <c:when test="<%= dia== 3%>">
                <p>Es miércoles</p>
            </c:when>
            <c:when test="<%= dia== 4%>">
                <p>Es jueves</p>
            </c:when>
            <c:when test="<%= dia== 5%>">
                <p>Es viernes</p>
            </c:when>
            <c:when test="<%= dia== 6%>">
                <p>Es sábado</p>
            </c:when>
            <c:when test="<%= dia== 7%>">
                <p>Es domingo</p>
            </c:when>
            <c:otherwise>
                <p>Valor erróneo</p>
            </c:otherwise>
        </c:choose>        
        <hr/>
        <br/>
        <strong>Usando JSTL FOR</strong><br/>
        <!--Suponemos que hemos capturado o recibido un valor 
        numérico y lo almacenamos en una variable "n", luego 
        creamos una lista desplegable con valores del 1 a "n"-->
        <% Integer n = 12;%>
        <select>
            <c:forEach var="i" begin="1" end="<%= n %>">
                    <option value="${i}">Item ${i}</option>
            </c:forEach>   
        </select>     
        <hr/>
        <br/>
    </body>
</html>

Obtendremos el siguiente resultado:


Usando JSTL IF
Felicidades ustes ha aprobado con nota: 20.0


Usando JSTL CHOOSE
Es sábado


Usando JSTL FOR



Patrón de diseño de Software MVC

El patrón Modelo Vista Controlador

El patrón MVC nos permite separar:
  • La lógica de control (las funcionalidades del proyecto)
  • La lógica de negocio (como se llevarán a cabo esas funcionalidades)
  • La lógica de presentación (cómo interactúa el usuario con el proyecto)

Utilizando patrón de separación en capas es posible conseguir:
  • Mayor calidad en el producto a desarrollar.
  • Un mantenimiento más sencillo y por ende menos costoso (recordemos que es la etapa del ciclo de vida más costosa).
  • Partir de un modelo base. 
  • Normalizar y estandarizar el desarrollo de Software.

Esto es gracias a que:
  • Existe una bien marcada separación entre los componentes (capas) de un programa; lo cual permite implementar estos por separado.
  • Existen varios Frameworks como JSF, Spring MVC, etc. que permiten reemplazar el modelo, la vista o el controlador, sin demasiada dificultad. Incluso sin un Framework es relativamente sencillo cambiar uno de los componentes del MVC sin afectar a los demás.
  • La conexión entre la capa de modelo y la capa que contiene las vistas es dinámica, pues se produce en tiempo de ejecución, no de compilación.

Ejemplo de aplicación con JAVA Web

En el lenguaje Java, específicamente un proyecto web dinámico tendríamos las siguientes consideraciones.
  • Model: el lenguaje SQL impera sobre el java.
  • Controller: el lenguaje java impera
  • View: el lenguaje HTML impera


La capa de la vista: La capa de persistencia (modelo) La capa de control

 
 


Adicionalmente tenemos:
Bibliotecas externas Bibliotecas internas Clases o entidades

 
 

martes, 12 de mayo de 2020

Instalando Payara Server con Eclipse IDE

Oracle detuvo el soporte comercial para GlassFish hace unos años, en respuesta la comunidad libre al mismo estilo de MariaBD con MySQL creo Payara, que es un servidor de aplicaciones Java EE de código abierto que se bifurcó en 2014. De esta manera, las compañías que anteriormente usaban GlassFish comercialmente podrían cambiar sin esfuerzo a Payara y continuar disfrutando del soporte comercial. Gracias al soporte comercial para clientes comerciales que anteriormente usaban GlassFish, el software del servidor de aplicaciones Payara se puede corregir y mejorar continuamente.

Descargar Payara Server

Ingresar a su página web: https://www.payara.fish/  y buscar la sección de descargas donde se debe elegir la opción de Payara Server Full, lo bueno es que es gratis.

Se obtendrá un archivo comprimido .zip que se debe descomprimir en el disco. Eso es todo.

Pasos para configurar en Eclipse

Desde el Marketplace de Eclipse descargamos e instalamos el GlassFish Tool o Payara Tool, con ambos se puede realizar la configuración. En este caso se emplea la segunda opción, el proceso es prácticamente el mismo.



Se crea un nuevo servidor siguiendo esta secuencia



Se selecciona la opción Server



En la selección se marca Payara, si usan el GlassFish Tool se debe ubicar en Oracle. Colocar un nombre, en este caso Payara5



Ingresar la ubicación donde está descomprimido el archivo descargado.



Verificar los siguientes datos, no es necesario realizar cambios, darle clic a finalizar.



En la pestaña de Servers se puede ubicar el nuevo servidor, para iniciarlo solo le damos clic derecho y la opción Start o Iniciar.



El servidor se iniciará



Para probar un proyecto se debe ejecutar en un servidor como se indica a continuación:


Si todo fue correctamente instalado y configurado se iniciará en el navegador el proyecto

Fuentes:

  • Schotlz, B. y Tijms, A. (2018). The Definitive Guide to JSF in Java EE 8:Building Web Applications with JavaServer Faces. United States of America: Apress.