Porque deveria me preocupar com Progressive Web App (PWA)?

Antes de começar em Progressive Web App, primeiro vamos comentar o estado atual da World Wide Web.
A partir de janeiro de 2017, 8,05 bilhões de dispositivos estão conectados em todo o mundo (mais do que a população mundial atual, que é de 7,5 bilhões). Das quais 55% (4,42 bilhões) de conexões são usadas em smartphones.

O Chrome do celular está sendo consumindo em mais de 1 bilhão de usuários mensais, isso significa um enorme crescimento de 150% em  relação ao ano de 2016.

De acordo com estimativas em 2020, 40 a 50 bilhões de dispositivos serão conectados em todo o mundo.
A maioria dos usuários virá de áreas rurais e outros países em desenvolvimento onde os dados são caros ou com alta latência ou ambos.

Comportamento dos usuários:

Comportamento Usuarios

Fonte : comScore Mobile Metrix, U.S

Porque usuários preferem usar Apps ao invés de website?
É porque aplicativos nativos são:

  • Confiável
  • Rápida inicialização
  • Funcionam offline
  • Notificações Push trazem informações do App
  • Icone na tela “Home” mantém a visibilidade do App

Pesquisa Web Mobile

Fonte : comScore Mobile Metrix, U.S

Mas o alcance da Web móvel é 3 vezes maior que a de um App

Vantagens da web móvel

  • Imediação (Os sites móveis estão instantaneamente disponíveis)
  • Capacidade de encontrar (busca) (Os sites móveis podem ser facilmente encontrados)
  • Alcance (A média de visitas por usuário é de 100 sites/mês)
  • Compatibilidade (Sites móveis são compatíveis com todos dispositivos)
  • Lincável” (Compartilhamento facilitado via URL, não requer instalação complexa)
  • SEO (Os conteúdos do site móvel podem ser indexados pelos motores de busca)
  • Baixa fricção (Para usar um site móvel você precisa apenas de um navegador diferente dos aplicativos que têm fricção inicial muito alta)

Mas porque os App estão sendo mais utilizados que Web móvel, mesmo que a Web móvel tem alcance maior?

De acordo com a pesquisa do Google, o tempo médio de carregamento de um site móvel é de 19 segundos.
Mas um usuário espera carregar o site em 3 segundos. Então você perderá cerca de 40% do usuário se o site demorar mais de 3 segundos para carregar.
E 100% do usuário se demorar mais de 10 segundos.

Além disso, é fácil tocar em um ícone de tela inicial em vez de digitar o URL.

O site móvel não possui uma opção de notificação/Push.

Solução

Progressive web Apps (PWA)

O que é PWA?

PWA é experiências de usuário que combinam o melhor da web e o melhor dos aplicativos.

Eles são:

  • Progressivo (Trabalhe para todos os usuários, independentemente da escolha do navegador porque eles são construídos com aprimoramento progressivo como um princípio básico)
  • Responsivo (Ajustar qualquer forma: desktop, celular, tablet ou formulários ainda não emergentes)
  • Independente de conexão (Service workers permitem o trabalho off-line ou em redes de baixa qualidade)
  • App-like (Experiência um App com interações e navegação de estilo de aplicativo)
  • Recente (Sempre atualizado graças ao processo de atualização do serviço)
  • Seguro (Servido através de HTTPS para evitar espionagem e garantir que o conteúdo não tenha sido adulterado)
  • Descoberto (São identificáveis como “aplicativos” graças aos manifestos do W3C e ao escopo de registro do trabalhador de serviço, permitindo que os motores de busca os encontrem)
  • Re-engajável (Facilite o reengajamento através de recursos como notificações push)
  • Instalável (Permitir que os usuários “mantenham” aplicativos que acham mais úteis em sua tela inicial sem o incômodo de uma loja de aplicativos)
  • Linkable (Facilmente compartilhado via URL e não requer instalação complexa)

Como visto um PWA cria uma espécie de integração entre o mundo Web de sites e os Apps. Para o ano de 2018 existem alguns pontos a serem consolidados para tornar a união destas duas experiências padrão. É uma nova tendência que permitirá, principalmente países com baixa infra estrutura de redes móveis, a viabilidade e facilidade de utilização de diversos tipos de aplicações, das quais hoje só é permitido com uma conexão ativa.

Anúncios

O que é Spring Boot?

Sabe o que é Spring Boot?

Spring Boot é um conjuntos de configurações padrões que aceleram o processo de desenvolvimento no Spring, resumindo um ambiente semi pronto para iniciar o desenvolvimento.

Funcionalidades disponíveis:

  • Servidor de aplicação embarcado
  • Cria aplicação autônoma do Spring
  • Fornece poms mais intuitivos para a configuração do MAVEN
    Sempre que possível, automaticamente configura o Spring
  • Pré fornecer recursos para produção, como verificação de integridade, configurações externas e métricas
  • Nenhuma geração de código e nenhum requisito para configuração de XMLs

Para Startups é um modelo ideal para pegar a ideia e começar a implementar.

Pretendo começar a escrever uma série de artigos utilizando o Spring Boot e uma aplicação Web simples, demonstrando os passos para colocar uma aplicação em pouco tempo no ar.

O modelo adotado para aplicação deverá ter divisão clara de camadas e usar o máximo de recursos que o Spring permite.

A aplicação irá implementar uma lista de contatos, onde cada contato deverá possuir os seguintes atributos:

  • Nome (String)
  • Email (String)
  • Telefone (String), opcional
  • CEP (String)
  • UF (String)
  • Cidade (String)
  • Endereco (String)
  • Número (String), opcional

A tela principal ser responsiva em HTML5, utilizar Bootstrap e Thymeleaf. deverá ter dois botões. Um botão para salvar o contato e outro para realizar pesquisa.

A tela principal deverá ter a listagem dos contatos paginada por 50 contatos por página.

Em cada linha da grade de listagem deverá ter a opção de visualizar, excluir ou editar o contato.

Na listagem somente trazer informações de Nome, email, Telefone e Cidade.

O código estará disponibilizado no Github em: https://github.com/andremrezende/agenda

Nos próximos posts já teremos a configuração do projeto e download do mesmo.

Como ignorar erro de certificado no envio de email em Java

Lembra aquela situação que está na correria para criar um programa que envia e-mail, testa-lo e então garantir que o e-mail foi enviado a pessoa correta, com o assunto correto, com o corpo do email correto, certificar que o email está “responsivo” e o cliente ou gerente businando na sua orelha para entregar rápido?

Então cria um programa rápido, porém ao executar aparece o erro:

PKIX path building failed:

Essas situação não lhe proverá muito tempo para importar ou criar um certificado daquele provedor de email.

Caso se encontre em situação semelhante a descrita acima, segue as propriedades para adicionar no seu programa Java e ingorar.

Em SMTP:

props.put("mail.smtp.ssl.trust", "*");

Em IMAP:

prop.put("mail.imaps.ssl.trust", "*");

Lembrando sempre que estas propriedade deverá ser usada com cautela, pois irá comprometer a segurança.

Java broadcast message websocket

websocketAcredito que possa ser útil dar uma olhada no WebSockets, que é uma tecnologia relativamente nova que promete tornar sites mais reativos, permitindo menor latência entre os usuários e o servidor.
Neste artigo vou mostrar um simples exemplos de envio de mensagem a todos conectado no servidor utilizando Websocket e Java.

O que é WebSocket?

Antes de começar com o código fonte, mas descobrir o que é a tecnologia.
O WebSocket é um protocolo que permite a comunicação entre o cliente e o servidor / nó de extremidade usando uma única conexão TCP.
Parecido com o http. A vantagem que o WebSocket tem sobre o HTTP é que o protocolo é full-duplex (permite a comunicação simultânea em dois sentidos) e seu cabeçalho é muito menor que o de um cabeçalho HTTP,
permitindo uma comunicação mais eficiente mesmo em pequenos pacotes de dados.

O ciclo de vida de um WebSocket é fácil de entender também:

O cliente envia ao servidor uma solicitação de handshake na forma de um cabeçalho de atualização HTTP com dados sobre o WebSocket ao qual está tentando se conectar.
O servidor responde à solicitação com outro cabeçalho HTTP, esta é a última vez que um cabeçalho HTTP é usado na conexão WebSocket. Se o handshake foi bem sucedido, o servidor envia um
cabeçalho HTTP dizendo ao cliente que está mudando para o protocolo WebSocket.
Agora uma conexão constante é aberta e o cliente eo servidor podem enviar qualquer número de mensagens umas às outras até que a conexão seja fechada. Essas mensagens têm apenas cerca de 2 bytes de sobrecarga.

Um Exemplo

A API do WebSocket foi introduzida com o Java EE7, neste exemplo vamos criar dois clientes, uma aplicação web e outra standalone, que enviará uma mensagem para o servidor e o servidor deverá espalhar a mensagem e responder a quem enviou a mensagem.

Neste exemplo, usarei o Eclipse, servidor Tomcat 8 e a biblioteca do nv-websocket-client para o cliente standalone.
Para o seu servidor, crie um aplicação Web.
Converta para um projeto Maven e adicione as seguintes linhas no 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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>br.com.tsystems</groupId>
<artifactId>webSocket-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<java-version>1.8</java-version>
<tomcat.version>8.0.30</tomcat.version>
<debug.code>true</debug.code>
</properties>

<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>

<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>

<dependency>
<groupId>com.neovisionaries</groupId>
<artifactId>nv-websocket-client</artifactId>
<version>1.30</version>
</dependency>

<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Crie seu EndPoint, classe Java responsável por receber as mensagens e espalha:


/**
* @ServerEndpoint poderá ser acessado por ws://localhost:8080/webSocket-example/echo
*/
@ServerEndpoint("/echo")
public class WebSocketDemo {
private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());

@OnOpen
public void onOpen(final Session session) {
// Adicionar sessão
sessions.add(session);
}

@OnMessage
public String echo(Session currentSession, String message) {
synchronized (sessions) {
for (Session session : sessions) {
// enviar mensagens para todos os clientes com essão daquele que enviou.
if (session.isOpen() && !session.equals(currentSession)) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
return message;
}

@OnError
public void onError(Session session, Throwable thr) {
//Ocorrer erro
thr.printStackTrace();
}

@OnClose
public void onClose(final Session session) {
// remover a sessão
sessions.remove(session);
}
}

Crie o index.html com o código abaixo:

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head>

<body>
<meta charset="utf-8">
<title>Web Socket JavaScript Echo Client</title>
<script language="javascript" type="text/javascript">
 var wsUri = getRootUri() + "/webSocket-example/echo";

function getRootUri() {
 return "ws://" + (document.location.hostname == "" ? "localhost" : document.location.hostname) + ":" +
 (document.location.port == "" ? "8080" : document.location.port);
 }

function init() {
 output = document.getElementById("output");
 }

function send_echo() {

websocket = new WebSocket(wsUri);
 websocket.onopen = function (evt) {
 onOpen(evt)
 };
 websocket.onmessage = function (evt) {
 onMessage(evt)
 };
 websocket.onerror = function (evt) {
 onError(evt)
 };

}

function onOpen(evt) {
 writeToScreen("CONNECTED");
 doSend(textID.value);

}

function onMessage(evt) {
 writeToScreen("RECEIVED: " + evt.data);
 }

function onError(evt) {
 writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
 }

function doSend(message) {
 writeToScreen("SENT: " + message);
 websocket.send(message);
 }

function writeToScreen(message) {
 var pre = document.createElement("p");
 pre.style.wordWrap = "break-word";
 pre.innerHTML = message;
 //alert(output);
 output.appendChild(pre);
 }

window.addEventListener("load", init, false);

</script>
<h2 style="text-align: center;">WebSocket Echo Client</h2>
</br>
<div style="text-align: center;">
<form action="">
<input onclick="send_echo()" value="Press me" type="button">
<input id="textID" name="message" value="Hello WebSocket!" type="text">

</form>
</div>
<div id="output"></div>
</body>
</html>

Por fim, crie o código do cliente stantalone:


/**
* @author Andre Rezende
*/
public class EchoClient {
private static final String SERVER = "ws://localhost:8443/cms/app/echo";
private static final int TIMEOUT = 5000;

public static void main(String[] args) throws Exception {
EchoClient echoClient = new EchoClient();
WebSocket ws = null;
try {
ws = echoClient.connect();
ws.sendText(new Date() + " teste->1");
} finally {
// Close the WebSocket.
ws.disconnect();
}
}

/**
* Conectar no servidor de websocket.
*/
public WebSocket connect() throws IOException, WebSocketException {
return new WebSocketFactory().setConnectionTimeout(TIMEOUT).createSocket(SERVER)
.addListener(new WebSocketAdapter() {
// A text message arrived from the server.
public void onTextMessage(WebSocket websocket, String message) {
System.out.println(message);
}
}).addExtension(WebSocketExtension.PERMESSAGE_DEFLATE).connect();
}
}

Para testar primeiro realize o deploy do seu war no tomcat. Talvez o tomcat requisite a biblioteca tomcat-juli.jar. Ela poderá ser obtida pelo endereço http://www.java2s.com/Code/Jar/t/Downloadtomcatjulijar.htm.
Após realizar o download, descompacte-a no diretório lib do seu tomcat.
Servidor de aplicação (Tomcat) em execução, realizado o deploy sem qualquer erro no tomcat, está na hora de iniciarmos os testes.
Para executar o cliente standalone, basta executar a classe EchoClient. A classe enviará a mensagem “Data corrente ” + test->1.
Abra a aplicação WEB no seu browser pela URL: localhost:8080/webSocket-example/
Por último abra o site: http://www.websocket.org/echo.html. Ele permite realizar testes por web em seu servidor de Websocket. Em location adicione ws://localhost:8080/websocket-example/echo
Clique no botão Connect, escreva em Message a mensagem que deseja compartilhar e por fim clique em Send para enviar a mensagem. Instruções em inglês e um exemplo em HTML está disponível no mesmo link.
Sua aplicação web deverá receber a mesma mensagem enviada pelo último site.

Concluindo

Webscoket permite envio de mensagem de forma assincrona e com segurança.
Substitui a antiga abordagem de consultas aos dados através de refresh de tela ou de tempos em tempos, o que particularmente é ineficiente na maior parte dos casos. Torna a vida do desenvolvedor mais fácil.
É baseado no TCP, bi-derecional e full-duplex. Part do HTML5 e a W3C define a API Jscript. Suportador pela maior parte dos browsers e suas respectivas versões.
Sugestão, comece fazendo um teste simples e vá aumentando a complexidade de seu websocket. Adicione recursos de reconexão e mensagens do mais variados tipos como textos ou binários.
Boa diversão.
O código está disponível para download no Github 

Project Lombok

Cansado de ficar fazendo Gets/Sets em seu código java?
Veja o Project Lombok.
Uma simples anotação em seu código @Data (gerar ate hashCode, equals e toString()) ou @Getter / @Setter poderá obter facilitar essa vida de gerador. Sei que se usar uma IDE tem teclas de atalhos para gerar, mas nada melhor que somente anotar a classe e aguardar o resto.

Na página tem alguns videos explicativos.

Problemas de Upload de arquivos com Primefaces?

Problemas de Upload de arquivos com Primefaces?

Verifique se adicionou em seu web.xml:

    <!-- Muito importante -->
	<context-param>
		<param-name>primefaces.UPLOADER</param-name>
		<param-value>commons</param-value>
	</context-param>	
	
	<filter>
	 <filter-name>PrimeFaces FileUpload Filter</filter-name>
	 <filter-class>
	  org.primefaces.webapp.filter.FileUploadFilter
	 </filter-class>
	</filter>
	<filter-mapping>
	 <filter-name>PrimeFaces FileUpload Filter</filter-name>
	 <servlet-name>Faces Servlet</servlet-name>
	</filter-mapping>
	
	<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>/faces/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <context-param>
        <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <context-param>
        <param-name>primefaces.UPLOADER</param-name>
        <param-value>auto</param-value>
    </context-param>
    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>	
  

A dependencias para upload de arquivos são:

		
		<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <!-- Faces Implementation -->
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.2.4</version>
        </dependency>
        <!-- Faces Library -->
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.2.4</version>
        </dependency>
        <!-- Primefaces Version 5 -->
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>5.0</version>
        </dependency>
		<!-- File uploads -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.2.1</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>1.4</version>
		</dependency>  
		
        <!-- JSP Library -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <!-- JSTL Library -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.1.2</version>
        </dependency>		
	

index.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Journaldev Tutorial</title>
    </h:head>
    <h:body>
        <h:form enctype="multipart/form-data">
                <p:fileUpload value="#{fileUploadManagedBean.file}"  mode="simple"></p:fileUpload>
                <p:separator/>
                <h:commandButton value="Dummy Action" action="#{fileUploadManagedBean.dummyAction}"></h:commandButton>
        </h:form>
    </h:body>
</html>		

FileUploadManagedBean.java:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
 
import org.primefaces.model.UploadedFile;
 
@ManagedBean
@SessionScoped
public class FileUploadManagedBean {
    UploadedFile file;
 
    public UploadedFile getFile() {
        return file;
    }
 
    public void setFile(UploadedFile file) {
        this.file = file;
    }
 
    public String dummyAction(){
        System.out.println("O nome do arquivo é "+file.getFileName()+" :: Uploaded File Size :: "+file.getSize());
        return "";
    }
}

Conclusão
Este artigo tem intenção de prover uma explicação da utilização do FileUpload do Primefaces. Caso não esteja conseguindo realizar upload, tente verificar se todos os passos estão realizados e não falta nenhum detalhe. O componente FileUpload tem muitas funcionalidades e permite que o programador mantenha o foco do trabalho nas regras de negócio ao invés de ficar reinventando a roda.

Java 8 e StringJoiner

Na ultima versão do Java 8 foi adicionado o StringJoiner no pacote java.util.
É uma implementação juntar as pedaços em comparação, um facilitador da antiga abordagem usando StringBuffer / StringBuilder.
Vamos ver o uso do StringJoiner e como funciona a implementação.

Por exemplo, tenho duas cadeias como “Andre” e “Rezende” e eu quero juntar essas cadeias como [Andre, Rezende]. Neste caso, eu tenho o prefixo como “[“, o sufixo como “]” e o delimitador como “,”. StringJoiner tem dois construtores como dado abaixo.
StringJoiner (CharSequence delimitador)
StringJoiner (CharSequence delimitador, CharSequence prefixo, sufixo CharSequence)
Queremos ter prefixo e sufixo, portanto, vamos usar o segundo construtor para o nosso exemplo.

StringJoiner sjr = new StringJoiner(",", "[", "]");
sjr.add("Andre").add("Rezende");
System.out.println("A string final é " + sjr);

Resultado será a saída no console: A string final é [Andre,Rezende]

Se não quiser adicionar o prefixo e sufixo, então:

StringJoiner sjr1 = new StringJoiner(",");
sjr1.add("Andre").add("Rezende");
System.out.println("A string final é " + sjr1);

Resultado será a saída no console: A string final é [Andre,Rezende]

Conclusão, não é uma baita implementação, ainda pode-se utilizar a StringBuilder ou StringBuffer, mas ele facilita um pouco a vida do desenvolvedor.