Spring Cloud - Adicionando Angular 4

Spring Cloud - Adicionando Angular 4

1. Visão geral

Em nosso último artigo do Spring Cloud, adicionamos suporteZipkin em nosso aplicativo. Neste artigo, iremos adicionar um aplicativo front-end à nossa pilha.

Até agora, trabalhamos inteiramente no back-end para construir nosso aplicativo em nuvem. Mas de que serve um aplicativo da web se não houver IU? Neste artigo, vamos resolver esse problema integrando um aplicativo de página única em nosso projeto.

Estaremos escrevendo este aplicativo usandoAngulareBootstrap. O estilo do código Angular 4 parece muito com a codificação de um aplicativo Spring, que é um cruzamento natural para um desenvolvedor Spring! Embora o código do front-end esteja usando o Angular, o conteúdo deste artigo pode ser facilmente estendido para qualquer estrutura de front-end com o mínimo de esforço.

Neste artigo, iremos construir um aplicativo Angular 4 e conectá-lo aos nossos serviços em nuvem. Demonstraremos como integrar o login entre um SPA e o Spring Security. Também mostraremos como acessar os dados de nosso aplicativo usando o suporte do Angular para comunicação HTTP.

2. Mudanças de gateway

Com o front-end instalado, vamos mudar para o login baseado em formulário e partes seguras da IU para usuários privilegiados. Isso requer alterações na configuração de segurança do gateway.

2.1. AtualizarHttpSecurity

Primeiro, vamos atualizar o métodoconfigure(HttpSecurity http) em nossa classe de gatewaySecurityConfig.java:

@Override
protected void configure(HttpSecurity http) {
    http
      .formLogin()
      .defaultSuccessUrl("/home/index.html", true)
      .and()
    .authorizeRequests()
      .antMatchers("/book-service/**", "/rating-service/**", "/login*", "/")
      .permitAll()
      .antMatchers("/eureka/**").hasRole("ADMIN")
      .anyRequest().authenticated()
      .and()
    .logout()
      .and()
    .csrf().disable();
}

Primeiro, adicionamos uma URL de sucesso padrão para apontar para/home/index.html, pois é onde nosso aplicativo Angular reside. Em seguida, configuramos os ant matchers para permitir qualquer solicitação por meio do gateway, exceto para os recursosEureka. Isso delegará todas as verificações de segurança nos serviços de back-end.

Em seguida, removemos o URL de sucesso do logout, pois o redirecionamento padrão de volta para a página de login funcionará bem.

2.2. Adicionar um endpoint principal

A seguir, vamos adicionar um endpoint para retornar o usuário autenticado. Isso será usado em nosso aplicativo Angular para efetuar login e identificar as funções de nosso usuário. Isso nos ajudará a controlar quais ações eles podem executar em nosso site.

No projeto de gateway, adicione uma classeAuthenticationController:

@RestController
public class AuthenticationController {

    @GetMapping("/me")
    public Principal getMyUser(Principal principal) {
        return principal;
    }
}

O controlador retorna o objeto de usuário atualmente conectado ao chamador. Isso nos fornece todas as informações necessárias para controlar nosso aplicativo Angular.

2.3. Adicionar uma página de destino

Vamos adicionar uma página de destino muito simples para que os usuários vejam algo quando forem para a raiz de nosso aplicativo.

Emsrc/main/resources/static,, vamos adicionar um arquivoindex.html com um link para a página de login:




    
    Book Rater Landing


    

Book Rater

So many great things about the books

Login

3. CLI Angular e o Projeto Starter

Antes de iniciar um novo projeto Angular, certifique-se de instalar as versões mais recentes deNode.js and npm.

3.1. Instale o Angular CLI

Para começar, precisaremos usarnpm para baixar e instalar a interface de linha de comando Angular. Abra um terminal e execute:

npm install -g @angular/cli

Isso fará o download e instalará a CLI globalmente.

3.2. Instale um novo projeto

Enquanto ainda estiver no terminal, navegue até o projeto do gateway e vá para a pasta gateway / src / main. Crie um diretório chamado "angular" e navegue até ele. A partir daqui, execute:

ng new ui

Ser paciente; a CLI está configurando um novo projeto e baixando todas as dependências do JavaScript com o npm. Não é incomum que esse processo leve muitos minutos.

O comandong é o atalho para a CLI Angular, o parâmetronew instrui a CLI a criar um novo projeto e o comandoui dá um nome ao nosso projeto.

3.3. Execute o projeto

Assim que o comandonew for concluído. Navegue até a pastaui que foi criada e execute:

ng serve

Assim que o projeto for construído, navegue atéhttp://localhost:4200. Deveríamos ver isso no navegador:

image

Parabéns! Acabamos de criar um aplicativo Angular!

3.4. Instalar Bootstrap

Vamos usar o npm para instalar o bootstrap. No diretório ui, execute este comando:

npm install [email protected] --save

Isso fará o download da inicialização na pasta node_modules.

No diretórioui, abra o arquivo.angular-cli.json. Este é o arquivo que configura algumas propriedades sobre o nosso projeto. Encontre a propriedadeapps > styles e adicione um local de arquivo de nossa classe CSS Bootstrap:

"styles": [
    "styles.css",
    "../node_modules/bootstrap/dist/css/bootstrap.min.css"
],

Isso instruirá o Angular a incluir o Bootstrap no arquivo CSS compilado que é construído com o projeto.

3.5. Defina o diretório de saída da compilação

Em seguida, precisamos informar ao Angular onde colocar os arquivos de compilação para que nosso aplicativo de inicialização da primavera possa atendê-los. O Spring Boot pode servir arquivos de dois locais na pasta de recursos:

  • src/main/resources/static

  • src/main/resource/public

Como já estamos usando a pasta estática para servir alguns recursos para Eureka, e o Angular exclui essa pasta cada vez que uma compilação é executada, vamos construir nosso aplicativo Angular na pasta pública.

Abra o arquivo.angular-cli.json novamente e encontre a propriedadeapps > outDir. Atualize essestring:

"outDir": "../../resources/static/home",

Se o projeto Angular estiver localizado em src / main / angular / ui, ele será compilado na pasta src / main / resources / public. Se o aplicativo estiver em outra pasta, essa sequência precisará ser modificada para definir o local corretamente.

3.6. Automatize a construção com Maven

Por fim, configuraremos uma compilação automatizada para execução quando compilarmos nosso código. Essa tarefa ant executará a tarefa de construção da CLI Angular sempre que "mvn compile" for executado. Adicione esta etapa ao POM.xml do gateway para garantir que cada vez que compilamos, obtenhamos as alterações mais recentes da interface do usuário:


    maven-antrun-plugin
    
        
            generate-resources
            
                
                    
                        
                        
                        
                    
                    
                        
                        
                    
                
            
            
                run
            
        
    

Devemos observar que essa configuração exige que a CLI Angular esteja disponível no caminho de classe. Enviar esse script para um ambiente que não possui essa dependência resultará em falhas de compilação.

Agora vamos começar a construir nosso aplicativo Angular!

4. Angular

Nesta seção do tutorial, criamos um mecanismo de autenticação em nossa página. Usamos autenticação básica e seguimos um fluxo simples para fazê-lo funcionar.

Os usuários têm um formulário de login no qual podem inserir seu nome de usuário e senha.

Em seguida, usamos suas credenciais para criar um token de autenticação base64 e solicitar o ponto de extremidade“/me”. O ponto de extremidade retorna um objetoPrincipal contendo as funções deste usuário.

Por fim, armazenaremos as credenciais e o principal no cliente para usar em solicitações subsequentes.

Vamos ver como isso é feito!

4.1. Modelo

No projeto de gateway, navegue atésrc/main/angular/ui/src/appe abra o arquivoapp.component.html. Este é o primeiro modelo que o Angular carrega e será onde nossos usuários chegarão após o login.

Aqui, vamos adicionar algum código para exibir uma barra de navegação com um formulário de login:



Book Rater App

Anyone can view the books.

Users can view and create ratings

Admins can do anything!

Este código configura uma barra de navegação com classes Bootstrap. Incorporado à barra está um formulário de login embutido. Angular usa essa marcação para interagir dinamicamente com JavaScript para renderizar várias partes da página e controlar itens como o envio de formulários.

Declarações como(ngSubmit)=”onLogin(f)” simplesmente indicam que quando o formulário é enviado, chame o método“onLogin(f)”e passe o formulário para essa função. Dentro da divjumbotron, temos tags de parágrafo que serão exibidas dinamicamente dependendo do estado do nosso objeto principal.

A seguir, vamos codificar o arquivo Typescript que oferecerá suporte a este modelo.

4.2. Texto datilografado

No mesmo diretório, abra o arquivo app.component.ts. Neste arquivo, adicionaremos todas as propriedades e métodos tipográficos necessários para fazer nosso modelo funcionar:

import {Component} from "@angular/core";
import {Principal} from "./principal";
import {Response} from "@angular/http";
import {Book} from "./book";
import {HttpService} from "./http.service";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    selectedBook: Book = null;
    principal: Principal = new Principal(false, []);
    loginFailed: boolean = false;

    constructor(private httpService: HttpService){}

    ngOnInit(): void {
        this.httpService.me()
          .subscribe((response: Response) => {
              let principalJson = response.json();
              this.principal = new Principal(principalJson.authenticated,
              principalJson.authorities);
          }, (error) => {
              console.log(error);
        });
    }

    onLogout() {
        this.httpService.logout()
          .subscribe((response: Response) => {
              if (response.status === 200) {
                  this.loginFailed = false;
                  this.principal = new Principal(false, []);
                  window.location.replace(response.url);
              }
           }, (error) => {
               console.log(error);
       });
    }
}

Essa classe se conecta ao método de ciclo de vida angular,ngOnInit(). Neste método, chamamos o endpoint/me para obter a função e o estado atuais do usuário. Isso determina o que o usuário vê na página principal. Este método será disparado sempre que este componente for criado, o que é um ótimo momento para verificar as propriedades do usuário em busca de permissões em nosso aplicativo.

Também temos um métodoonLogout() que desconecta nosso usuário e restaura o estado desta página às configurações originais.

Há alguma mágica acontecendo aqui, no entanto. A propriedadehttpService que é declarada no construtor. Angular está injetando essa propriedade em nossa classe em tempo de execução. O Angular gerencia instâncias únicas de classes de serviço e as injeta usando injeção de construtor, assim como o Spring!

A seguir, precisamos definir a classeHttpService.

4.3. HttpService

No mesmo diretório, crie um arquivo chamado“http.service.ts”. Neste arquivo, adicione este código para oferecer suporte aos métodos de login e logout:

import {Injectable} from "@angular/core";
import {Observable} from "rxjs";
import {Response, Http, Headers, RequestOptions} from "@angular/http";
import {Book} from "./book";
import {Rating} from "./rating";

@Injectable()
export class HttpService {

    constructor(private http: Http) { }

    me(): Observable {
        return this.http.get("/me", this.makeOptions())
    }

    logout(): Observable {
        return this.http.post("/logout", '', this.makeOptions())
    }

    private makeOptions(): RequestOptions {
        let headers = new Headers({'Content-Type': 'application/json'});
        return new RequestOptions({headers: headers});
    }
}

Nesta aula, estamos injetando outra dependência usando a construção DI do Angular. Desta vez é a classeHttp. Essa classe lida com toda a comunicação HTTP e é fornecida a nós pela estrutura.

Cada um desses métodos executa uma solicitação HTTP usando a biblioteca HTTP do angular. Cada solicitação também especifica um tipo de conteúdo nos cabeçalhos.

Agora precisamos fazer mais uma coisa para obter oHttpService registrado no sistema de injeção de dependência. Abra o arquivoapp.module.ts e encontre a propriedade dos provedores. Adicione oHttpService a essa matriz. O resultado deve ficar assim:

providers: [HttpService],

4.4. Adicionar Principal

A seguir, vamos adicionar nosso objeto DTO Principal em nosso código Typescript. No mesmo diretório, adicione um arquivo chamado "principal.ts" e adicione este código:

export class Principal {
    public authenticated: boolean;
    public authorities: Authority[] = [];
    public credentials: any;

    constructor(authenticated: boolean, authorities: any[], credentials: any) {
        this.authenticated = authenticated;
        authorities.map(
          auth => this.authorities.push(new Authority(auth.authority)))
        this.credentials = credentials;
  }

    isAdmin() {
        return this.authorities.some(
          (auth: Authority) => auth.authority.indexOf('ADMIN') > -1)
    }
}

export class Authority {
    public authority: String;

    constructor(authority: String) {
        this.authority = authority;
    }
}

Adicionamos a classePrincipal e uma classeAuthority. Essas são duas classes de DTO, como POJOs em um aplicativo Spring. Por esse motivo, não precisamos registrar essas classes no sistema DI em angular.

A seguir, vamos configurar uma regra de redirecionamento para redirecionar solicitações desconhecidas para a raiz de nosso aplicativo.

4.5. Tratamento 404

Vamos navegar de volta para o código Java para o serviço de gateway. Em onde a classeGatewayApplication reside, adicione uma nova classe chamadaErrorPageConfig:

@Component
public class ErrorPageConfig implements ErrorPageRegistrar {

    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
          "/home/index.html"));
    }

}

Esta classe identificará qualquer resposta 404 e redirecionará o usuário para“/home/index.html”. Em um aplicativo de página única, é assim que lidamos com todo o tráfego que não vai para um recurso dedicado, já que o cliente deve lidar com todas as rotas navegáveis.

Agora estamos prontos para iniciar este aplicativo e ver o que construímos!

4.6. Construir e visualizar

Agora execute “mvn compile” da pasta do gateway. Isso irá compilar nossa fonte java e criar o aplicativo Angular na pasta pública. Vamos começar os outros aplicativos em nuvem:config,discovery ezipkin. Em seguida, execute o projeto do gateway. Quando o serviço iniciar, navegue atéhttp://localhost:8080 para ver nosso aplicativo. Deveríamos ver algo assim:

image

A seguir, vamos seguir o link para a página de login:

image

Efetue login usando as credenciais de usuário / senha. Clique em "Login" e devemos ser redirecionados para /home/index.html onde nosso aplicativo de página única é carregado.

image

Parece que nossojumbotron está indicando que estamos logados como um usuário! Agora saia clicando no link no canto superior direito e faça login usando as credenciaisadmin/admin desta vez.

image

Parece bom! Agora estamos logados como administrador.

5. Conclusão

Neste artigo, vimos como é fácil integrar um aplicativo de página única em nosso sistema de nuvem. Adotamos uma estrutura moderna e integramos uma configuração de segurança funcional ao nosso aplicativo.

Usando esses exemplos, tente escrever algum código para fazer uma chamada parabook-service ourating-service. Como agora temos exemplos de fazer chamadas HTTP e conectar dados aos modelos, isso deve ser relativamente fácil.

Se você gostaria de ver como o resto do site é construído como sempre, você pode encontrar o código-fonteover on Github.