domingo, 21 de julio de 2019

Ejemplo con JSF 2.1 con Maven, Primefaces 7 y Eclipse 2019-06

Hola a todos, todos saben que me siento más del mundo .Net. Pero por cosas de la vida, debo aprender Java. Hasta ahora me está gustando poco a poco. Es más disperso por así decirlo, muchas formas de hacer algo, y mucha gente la hace de una u otra forma y llega a lo mismo.

Vamos a crear un proyecto de cero en Eclipse, Maven, Primefaces 7 y JSF 2.1. Esto ya que cuando partí no encontré nada consolidado, sino puros videos por acá y o tutoriales por allá del año 2012 o 2014.

Estoy usando Windows 10 Pro de 64 bit.
RAM: 16 GB.
Core i7.

Me di cuenta que Eclipse 2019-06 es un 20 a 30% más pesado que Visual Studio Community 2019. Gasta más RAM y es más lento el proceso de volver a correr algo (iniciar, restart server local). Eso fue un cambio ya que en mi trabajo tengo un i3, con 8 GB RAM y noté la diferencia. Ahí el proceso de corregir y probar algo con Eclipse es un 40 a 50% más lento que con Visual Studio Community.

Java
Eclipse con JSF 2 y Maven
JSF 2 es como Windows Form con MVC unidos.
  • Bajar última versión de Eclipse IDE, en mi caso usaré la versión 2019-06. https://www.eclipse.org/downloads/
  • Instalar el IDE y crear un Worskpace. En mi caso quedará en D:\naldo\workspace.
  • Configurar Eclipse para que use use JDK. Ve a Windows - Preferences. Busca "JRE" y agrégalo en sección "Installed JREs"
  • Crear Proyecto. Botón derecho, crear Nuevo Proyecto
  • Seleccionar Maven Project
  • Aquí solo siguiente.
  • Escribe "webapp" en el archetype y selecciona el único valor de la lista y Next.
  • Group ID: demo. Artifact Id: primefaces. El resto por defecto. Presiona Finish.
  • Se creará el proyecto y mostrará errores.
  • Agregar dependencias a Jars. Primero a JSF, peri JSF usa por debajo Servlets.
    Doble clic en pom.xml, pestaña Dependencies. Add (al centro) buscar "javax.servlet".
  • También agrega el Framework JSF (jsf-api). Gropu Id javax.faces.
  • Agrega JSF-IMPL (jsf-impl) dentro de GroupIP java.sun.faces.
  • Listo, si vemos el pom.xml como fuente se verá así:
  • Agrega igual esta otra Dependencia para que funcione la anotación @PostConstruct que la usarás luego.
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
  • Selecciona el proyecto, botón derecho - Maven - Update Project. Presiona Ok.
  • Agrega a pom que Maven compile usando Java 11 usa 1.11.
  • Ir al proyecto, Update Project.
  • Cambiar versión de servlet. Ir a Windows - Show View - Navigator
  • Abre org.eclipse.wst.common.project.facet.core.xml y cambiar
    <installed facet="jst.web" version="2.3"/>
    por
    <installed facet="jst.web" version="3.1"/>
  • Grabar y colocar Project - Clean.
  • Project - Maven - Update Project
  • Editar web.xml de
    /primefaces/src/main/webapp/WEB-INF/web.xml
    Cambio lo que está por este otro:
<web-app 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-app_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
</web-app>
  • Luego Eliminar archivo index.jsp
  • Te paras en WebApp. Botón derecho - New - Other - Busca por "Html" - Selecciona Html File - Colócale por nombre "index.xhtml". Next.
  • Usa el template que diga "New XHTML file (1.0 transitional) y presiona Finish.
  • Cambia el código de adentro por este:
<!DOCTYPE html>
<html 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>test</title>
</h:head>
<h:body>
<h2>JSF 2</h2>
</h:body>
</html>
  • Ejecútalo y debes ver:
  • También lo puedes ejecutar directo del navegador usando
    http://localhost:8080/primefacesdemo/index.xhtml
  • Ahora párate en el proyecto - botón derecho - Build Path - Configure Build Path - check "Maven Dependences".
  • Ahora dentro de Java Resources se verán carpetas src/main/java y src/main/resources.
  • Con esto el proyecto debe funcionar si te paras en el proyecto, botón derecho - Run As - Run on Server.
Videos para entender
En este punto recomiendo primero entender como opera muy bien JSF 2 con Eclipse antes de pasar a Primefaces. Recomiendo este video de un buen teacher que explica muy paso a paso con varios ejemplo simples. Canal de Luv2Code.


Agregando Primefaces 7
Primefaces es como un Telerik KendoUI pero para Java.
<dependency>
     <groupId>org.primefaces</groupId>
     <artifactId>primefaces</artifactId>
     <version>7.0</version>
 </dependency>
  • Ve a una página xhtml y agrega el código:
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:p="http://primefaces.org/ui">

 <h:head>
 </h:head>

 <h:body>
  <p:spinner />
 </h:body>
</html>
Extra: como hacer para usar url con .jsf y no con .xhtml

Para darle un "caché" podemos hacer que se acceda por la URL, por ejemplo, usando ej5.jsf y no ej5.xhtml.

Ojo, la páginas físicas siguen siendo .xhtml.
Por la URL se accede usando .jsf

Cambia el archivo: /primefaces/src/main/webapp/WEB-INF/web.xml

Solo estas líneas:

<servlet-mapping>
   <servlet-name>Faces Servlet</servlet-name>
   <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
...
<welcome-file-list>
   <welcome-file>ej1.jsf</welcome-file>
</welcome-file-list>

Ahora, si entras al navegador y colocas por ejemplo un caso que hice (al final están los fuentes)
http://localhost:8080/primefacesdemo/ej5.jsf
Verás esto:
Ejemplo de ajax
Este es un extra, lo investigué hace poco.
Se muestra un texto por Ajax sin recargar toda la página.
Se muestra sólo si hay un PostBack y no en el primer request.

ej1.xhtml

<h:form>
        <h:outputLabel value="Escribe algo: ">
            <h:inputText id="message" value="#{loginbean.message}"/>
        </h:outputLabel>

        <h:commandButton value="Mensaje fuera de form Ajax">
            <f:ajax execute="message" render="idSalida" />
        </h:commandButton>
        
        <br />
        <h:inputText id="valor" value="#{loginbean.username}"/>
        <h:commandButton value="Mensaje2 fuera de form Ajax">
            <f:ajax execute="valor" render="idSalida2" />
        </h:commandButton>
    </h:form>

    <p><h:outputText id="idSalida" value="#{loginbean.message}" /></p>
    <p><h:outputText id="idSalida2" value="#{loginbean.accion}" /></p>

Clase LoginBean

package cl.demo;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

@ManagedBean(name = "loginbean")
@RequestScoped
public class LoginBean implements Serializable {

private static final long serialVersionUID = 1L;

private String message;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

private String username = "";
private String password = "";

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

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

public String login(String type) {

if (this.username.isEmpty() == false && this.username.equalsIgnoreCase("naldo")
&& this.password.isEmpty() == false && this.password.equals("123")) {
return "success";
}
return "error";
}

public String getAccion() {

FacesContext facesContext = FacesContext.getCurrentInstance();
Boolean esPostback = facesContext.isPostback();

if (esPostback) { // solo si hay una accion
if (this.username.equals("111")) {
return "success";
} else
return "error";
}
else
return ""; // primer request no hace nada
}
}

Así se ve:

Cambiar el Theme Primefaces
Agrega en tu POM.xml estas dos entradas. 
En mi caso lo dejaré con theme "dark-hive" versión 1.0.10.

<repositories>
<repository>
<id>prime-repo</id>
<name>PrimeFaces Maven Repository</name>
<url>http://repository.primefaces.org</url>
</repository>
</repositories>

<dependency>
<groupId>org.primefaces.themes</groupId>
<artifactId>dark-hive</artifactId>
<version>1.0.10</version>
</dependency>

Luego en el web.xml lo seleccionas:

<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>dark-hive</param-value>
</context-param>

Puedes ver más estilos y sus versiones en este link oficial: https://repository.primefaces.org/org/primefaces/themes/

Así se ve el theme:


Localización (pendiente)
Permite, por ejemplo, tener textos en dos idiomas.

Conclusión
El código fuente está acá. Lo subí al sitio de mi página personal.

Si tienen dudas del código podré ayudar lo que pueda. No soy experto aún. Estoy recién partiendo en el mundo Java.

Saludos.