Aplicação completa usando um front moderno e uma plataforma de back poderosa, irei explanar tudo sobre “como” implementei, com mais volume no front (pois o back é simples).
O que a aplicação faz?
Existe um login, listagem de usuários existentes (gerados automaticamente), listagem de empresas, listagem de ciclos por empresas, inclusão de ciclos.
Front end — Angular 4, JWT, Typescript ebootstrap
Onde o front começa? App.router
Define oroteamento da aplicação que possui ‘login’ e ‘ciclos’ aos respectivos componentes.
Temos a implementação de uma url “protegida”, que será acessada somente com usuário logado, utilizo o conceito de AuthGuard.
{path: ‘ciclos’, component: CicloListComponent, canActivate: AuthGuard]}
Inicio da aplicação app.component.html
Este html será o primeiro executado pelo Angular, aqui na linha 19 estará a variação do Router (Classe interna do angular que é usada para fazermos a navegação)
<router-outlet></router-outlet>
Sendo assim, o router-outlet irá mostrar o componente de login, pois é a primeira url do sistema.
Funcionalidade de login

A dinâmica do login é comum, a diferença é que o backend gera um Json Web Token após validação de usuário e senha no H2.
O front armazena o token no , verifica se está válido e o logout remove. Estas são responsabilidades definidas no .
Para ver se o usuário está logado, uso a biblioteca do JwtHelper que valida otoken, já o logout simplesmente remove o item do local storage. Demonstração do AuthService.
isLogged() { const token = localStorage.getItem('token'); if (token) { return new JwtHelper().isTokenExpired(token) == false; } return false; }
logout() { localStorage.removeItem('token'); }
Após o login, o redirecionamento para a tela de ciclos é realizado, sendo que o AuthGuard irá ‘interceptar’ e validará que o token está válido.
this.router.navigate([‘ciclos’]);
Funcionalidade de listagem de ciclo
Tela principal com uma listagem de empresas, os ciclos da empresa selecionada e inclusão de um novo ciclo.
No Componente de listagem estão os requisições ao backend, que no Angular elas são assíncronas, usando o RxJS e o operador subscribe a atribuição as listas retornadas do backend seguem o mesmo padrão.
this.empresaService.getList() .subscribe( data => this.empresas = data );
Entretanto, após a inclusão de um novo ciclo, um evento é enviado e o ouvinte é acionado, atualizando a tabela de ciclos.
listenerCicloListChanged() { this.eventsService.ciclosEvent .subscribe( (novoCiclo: Ciclo) => { if (novoCiclo.codigo) { this.loadCiclosByEmpresa( this.empresaSelecionada.codigoEmpresa); } }); }
Funcionalidade de listagem de inclusão de ciclo
Na listagem de ciclo, a ação de inserir um novo ciclo é controlada pelo componente de listagem, sendo exibido em um modal, usando o conceito de property binding vistos nos dois trechos abaixo.
// Variável definida no typescript @ViewChild('cicloSaveItem') private cicloSaveComponent: CicloSaveComponent;
// Componente definido no html
Na inclusão a principal funcionalidade é a gerência do modal através do typescript, repare o uso do jquery com os trechos abaixo:
declare var $: any;
// Elemento injetado pelo construtor private rootNode: ElementRef
// Inicialização da variável referência do modal this.saveModal = $(this.rootNode.nativeElement).find('#saveModal');
// Close modal this.saveModal.modal('hide');
Back end — Java, Spring boot, Swagger e H2
O Backend está estruturado para na sua inicialização incluir empresas e usuários, toda persistência é realizada no h2.
Todos endpoints (API) recebem a request e devolve com Json. Sem guardar a sessão do usuário.
CQRS — Command Query Responsibility Segregation.
As services que terminam com CommandService (escrita) e QueryService (leitura) implementam o conceito acima.
JWT — Json Web token
JWT.create() .withClaim(“login”, user.getLogin()) .withExpiresAt( Timestamp.valueOf(LocalDateTime.now().plusMinutes(5))) .sign(Algorithm.HMAC256(user.getPassword()));
Banco de dados
O banco de dados usado nesta aplicação é o H2, a persistência é com hibernate gerenciado pelo spring data.
Docker Back
From centos Run yum install -y java VOLUME /tmp ADD /target/vestibular-backend-1.0.0.jar vestibular-backend.jar RUN sh -c 'touch /vestibular-backend.jar' ENTRYPOINT ["java","-Djava.security.egd=file:/dev/;/urandom","-jar","/vestibular-backend.jar"]
Docker Front — Nginx
Nginx faz o proxy da porta 80 para a aplicação, configurado aqui.
### STAGE 1: Build ### # We label our stage as 'builder' FROM node:9-alpine as builder COPY package.json package-lock.json ./ RUN npm set progress=false && npm config set depth 0 && npm cache clean --force ## Storing node modules on a separate layer will prevent unnecessary npm installs at each build RUN npm i && mkdir /ng-app && cp -R ./node_modules ./ng-app WORKDIR /ng-app COPY . . ## Build the angular app in production mode and store the artifacts in dist folder RUN $(npm bin)/ng build --prod ### STAGE 2: Setup ### FROM nginx:1.13.3-alpine ## Copy our default nginx config COPY nginx/default.conf /etc/nginx/conf.d/ ## Remove default nginx website RUN rm -rf /usr/share/nginx/html/* ## From 'builder' stage copy over the artifacts in dist folder to default nginx public folder COPY --from=builder /ng-app/dist /usr/share/nginx/html CMD ["nginx", "-g", "daemon off;"]
User guide
BackEnd
git clone https://github.com/lelodois/vest-backend.gitmvn install
docker build -t vestback-docker .
docker run -d -p 9099:9099 vestback-docker
Front
git clone https://github.com/lelodois/vest-frontend.gitsudo docker build -t vestfront-docker .
sudo docker run -d -p 80:80 vestfront-docker
Url’s
Links e Referências
- [Aplicação] — http://localhost/login
- [Swagger] — http://localhost:9099/swagger-ui.html
- [Frontend] — https://github.com/lelodois/vest-frontend
- [Backend] — https://github.com/lelodois/vest-backend
- [Curso de angular] — The-complete-angular-master-class
- [Curso de docker] — Docker-for-java-developers
- [JWT] — Json Web Token
- [Spring boot] — Spring boot documentation
Bem, tentei explanar os pontos que considero mais importantes do projeto, que está funcional e próximo de uma aplicação do mundo real.
Deixe um comentário