sexta-feira, 22 de março de 2019

Pegando o RealPath em uma aplicação JEE


As vezes precisamos do RealPath da nossa aplicação para lermos e/ou escrevermos arquivos através do Java, e em aplicações JavaEE uma boa forma de fazermos isso é através de um ServletContextListener, uma vez que este listener escuta quando sua aplicação inicializa ou finaliza no container web ou servidor de aplicação.

Usando o ServletContextListener ao invés do FacesContext para pegar o RealPath não ficamos presos ao JSF por exemplo, ou outra tecnologia, e podemos usar o RealPath em processos e situações diversas.

Geralmente tenho uma classe em um pacore br.com.meudominio.utils chamada Constants onde guardo algumas constantes e variáveis estáticas com algumas configurações do sistema (embora prefira usar um cadastro de Parâmetros Gerais do Sistema para a maioria das configurações), e ao pegar o RealPath é nessa classe que seto essa configuração. Veja o código do listener abaixo:

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebFilter;

import br.com.meudominio.Constants;

@WebListener
public class RealPath implements ServletContextListener{

    @Override
    public void contextDestroyed( ServletContextEvent sce ) {
       
       
    }

    @Override
    public void contextInitialized( ServletContextEvent sce ) {
         Constants.REAL_PATH = sce.getServletContext().getRealPath( "/" );
       
    }

}

Na classe Constants tenho algo como:

public final class Constants
{
      ...

public static String REAL_PATH = "";

     ...
}

Pronto, em qualquer lugar do sistema basta usar Constants.REAL_PATH para pegar o RealPath da minha aplicação.

terça-feira, 19 de março de 2019

Criando uma biblioteca de componentes com Angular 7, utilizando em projetos externos e publicando no NPM


Frameworks JavaScript estão sempre mudando, e geralmente são mudanças complexas que nos obrigam a reaprender como fazemos as coisas. Não foi diferente com a questão da criação de bibliotecas do Angular, que até a versão 5 era apenas um projeto comum, o qual empacotávamos no formato NPM e publicávamos. Agora, a partir da versão 7 em diante o Angular cria uma espécie de workspace, onde é possível criar vários projetos e bibliotecas, e são essas bibliotecas internas que podemos exportar e podemos usar em outros projetos, e até publicar no NPM.

Com isso, muita coisa mudou, porque essa biblioteca interna, (pelo menos por enquanto, até a versão 7.1.2 do Angular), não contém os arquivos environments.prod.ts e environments.ts para tratarmos a diferença entre algumas configurações de produção e o ambiente de desenvolvimento, também não existe a estrutura da pasta assets para colocarmos nossas imagens e o Angular conseguir encontrá-las de forma fácil.

Essas dificuldades eu contornei da seguinte forma: as imagens eu coloco em texto base64 direto na tag <img> e quando preciso pegar uma URL em uma biblioteca uso JavaScript para obter a URL de forma dinâmica: (window.location.protocol + window.location.hostname;).

Outra mudança que houve foi o arquivo angular-cli.json que teve seu nome alterado para angular.json e sua estrutura mudou um pouco, passando a conter múltiplos projetos (como o de testes e as bibliotecas) pois como disse, o que criamos com “ng new” a partir da versão 7 do Angular se comporta como um workspace.

Agora que já falamos das mudanças e alguns contratempos que tive com elas, vamos a criação do projeto. Abrindo no terminal a pasta do seu workspace, digite:

$        ng new teste --create-application=false

          Quando indagado sobre a criação do Router e do CSS escolha as opções padrão.

A opção --create-aplication usada acima também é nova, e faz com que o Angular não crie o projeto inicial, bem com a pasta src, criando apenas o Workspace Angular por assim dizer. Basicamente isso é útil para criarmos bibliotecas, pois gera um workspace de mesmo nome da biblioteca. Note que o Angular aceita tanto comandos com camelCase quanto separados por ífem (-), então poderia ser --createApplication=false.

          Aproveite e dê uma olhada nos arquivos package.json que continua com as dependências do projeto  e angular.json, que está praticamente vazio aguardando a criação de um projeto ou biblioteca.

          Vamos criar a biblioteca, posicione o terminal na nova pasta criada (teste):

$        cd ..

E crie a biblioteca com o seguinte comando:

$        ng g library teste --prefix=lib

          Na linha acima, foi criada a biblioteca “teste” e ao invés de usarmos o prefixo “app” como de costume, dissemos para o Angular usar o prefixo “lib”. Fique à vontade para escolher o prefixo que desejar, isso é importante para evitar conflitos entre a biblioteca e os apps que a usam.
         
          Note que o conteúdo do arquivo angular.json mudou, temos nele a propriedade que indica a versão do projeto: “version”, a propriedade que indica o pacote raiz que contém os projetos: “newProjectRoot”, e então temos a propriedade que indica os nossos projetos: “projects”. Dentro da propriedade “projects” há uma propriedade para cada projeto que criarmos, nesse caso haverá apenas o projeto “teste”, e dentro da propriedade “teste” teremos as propriedades de configuração deste projeto específico, como o tipo do projeto, o prefixo usado, a raiz do projeto, o source do projeto e outras configurações pertinentes.

A estrutura do projeto também foi alterada, agora existe uma pasta “projects” com a pasta “teste” que é o nosso projeto dentro dela; e dentro da pasta “teste” temos o diretório “src” que conterá tudo que pertencer a lib propriamente dita, o arquivo “package.json” da lib que especificará suas dependências que serão compiladas e posteriormente instaladas junto com ela quando um cliente usar npm install e também o arquivo ng-package.json. Os demais arquivos são de menor importância. É também no arquivo “package.json” da lib que especificamos o autor, a licença, o repositório, etc.

       A lib já foi criada contendo um componente e um service dentro de src/lib . Também vemos outro arquivo importante dentro da pasta src: public_api.ts. Nesse arquivo devemos exportar todos os módulos, componentes e services que criarmos, para que possam ser usados por quem instalar nossa biblioteca.

          export * from './lib/teste.service';
export * from './lib/teste.component';
export * from './lib/teste.module';

No diretório principal, o arquivo “tsconfig.json” tem as configurações de transpilação e build do projeto. Ele recebe o path da biblioteca que criamos para podermos usar nesse projeto, enquanto que em projetos externos ela será instalada com npm install e o conteúdo ficará em node_modules.

"paths": {
      "teste": [
        "dist/teste"
      ],
      "teste/*": [
        "dist/teste/*"
      ]
}

          Vamos buildar o projeto:

$        ng build teste   

          Veja que o projeto é buildado normalmente. Mas a frente vamos ver como usá-lo em outro projeto e também como publicar no npm. Agora vamos ver como criar novos componentes para a biblioteca. Digite o comando abaixo:

$        ng g c meu-componente --project=teste

Veja que a única coisa que mudou foi que especificamos em qual projeto o componente seria gerado pelo AngularCli. O novo componente deve ser declarado no módulo da nossa biblioteca e também no arquivo de entrada, o public_api.ts.

Com isso podemos re-buildar nossa aplicação. Uma novidade desde a versão 6.2 é o re-build pode ser automático a medida que arquivos forem alterados, para isso basta acrescentar a opção --watch no momento do build, a partir de então os demais serão disparados sozinhos.

$        ng build teste --watch

Agora vamos ver como usar a biblioteca em um projeto externo e como publicar no npm.

Para isso temos que empacotar nossa biblioteca em uma arquivo .tgz, por tanto, vamos criar um script no “package.json” raiz para facilitar este trabalho. Na seção “scripts” adicione o seguinte trecho de código:

"scripts": {
    ...
    "npm_pack_teste": "cd dist/teste && npm pack"
 }

Agora podemos usar o seguinte comando para empacotar a biblioteca “teste”:

$        npm run npm_pack_teste

Isto criou o arquivo “teste-0.0.1.tgz” dentro de “dist/teste” com a versão especificada no arquivo “package.json” da lib como já dito anteriormente. Podemos inclusive criar um script que faz o build e o empacotamento de uma só vez:

"scripts": {
    ...
    "npm_pack_teste": "cd dist/teste && npm pack",
    "package_teste": "ng build teste && npm run npm_pack_teste "
 }

E agora basta executar:

$        npm run package_teste

Pronto, temos nossa biblioteca buildada e empacotada para usarmos onde quisermos! Para usarmos em projetos próprios não precisamos publicar no npm. Isso é bom para empresas que não querem expor suas bibliotecas, pode-se criar um repositório interno para elas e quando for usar o npm install basta passar o caminho completo de onde a biblioteca está.

Uma vez instalada a biblioteca, o uso é normal como qualquer pacote npm instalado na aplicação.

Agora vamos a publicação no npm. Antes de criar uma biblioteca, se é sua intenção publicá-la no npm é bom checar se o nome que pretende dar a sua biblioteca já não existe lá, para evitar ter que mudar depois de criado todo o projeto.

O arquivo “package.json” deve estar com as informações de nome, versão, autor, licença, repositório, palavras chaves e outras além das dependências, scripts, etc... como abaixo:

...
"name": "teste",
"version": "1.0.0",
"license": "MIT",
"author": {
    "name": "seu_nome",
    "email": "seu_email",
    "url": "seu_site_ou_blog"
 },
 "bugs": {
 "url":"url_issues_git"
  },
 "homepage":"url_git",
 "keywords": [
    "angular",
    "angular2",
    "angular4",
    "p-calendar",
    "p-calendar-ptbr",
    "primeNG",
    "datepicker",
    "calendar",
    "pt-BR"
 ],
 "repository": {
    "type": "git",
    "url": "git+https://endereço_rep_git"
 },
...

O npm usará sua página de README.md com a página inicial da sua biblioteca no servidor. Como agora estamos tratando de mais de uma biblioteca por workspace, o README.md deve ser copiado para o destino onde a biblioteca é buildada. Caso haja um arquivo LICENSE também deve ser colocado lá.

É preciso criar uma conta caso você não tenha, ou fazer login para poder compartilhar seus pacotes. A criação da conta é bem simples e eles pedem um username, password e e-mail. É necessário a confirmação do e-mail antes de publicar algo caso a conta seja nova. O comando para criar uma conta é:

$       npm adduser

Ao criar a conta ele já loga no NPM. Para efetuar logins posteriores, os mesmos dados são pedidos, e o comando é:

$       npm login

Agora podemos publicar nossa biblioteca, digitando o comando npm publish e passando o caminho do arquivo .tgz gerado:

$        npm publish .\dist\teste\teste-0.0.1.tgz

Bom, o artigo ficou um pouco grande porque expliquei algumas coisas com detalhes, mas espero ter ajudado! Abraços!




Links de referência: