Aplicativo AngularJS CRUD com Spring Data REST

Aplicativo AngularJS CRUD com Spring Data REST

*1. Visão geral *

Neste tutorial, criaremos um exemplo de um aplicativo CRUD simples usando AngularJS para o front-end e Spring Data REST para o back-end.

===* 2. Criando o serviço de dados REST *

Para criar o suporte à persistência, usaremos a especificação Spring Data REST que nos permitirá executar operações CRUD em um modelo de dados.

Você pode encontrar todas as informações necessárias sobre como configurar os pontos de extremidade REST no link:/spring-data-rest-intro [introdução ao Spring Data REST]. Neste artigo, reutilizaremos o projeto existente que configuramos para o tutorial de introdução.

Para persistência, usaremos o H2 no banco de dados de memória.

Como modelo de dados, o artigo anterior define uma classe WebsiteUser, com as propriedades id, name e email e uma interface de repositório chamada UserRepository.

A definição dessa interface instrui o Spring a criar o suporte para a exposição de recursos de coleção REST e recursos de itens. Vamos dar uma olhada nos pontos de extremidade disponíveis para nós agora que mais tarde ligaremos de AngularJS.

====* 2.1 Os recursos de coleta *

Uma lista de todos os usuários estará disponível para nós no terminal /users. Essa URL pode ser chamada usando o método GET e retornará objetos JSON do formulário:

{
  "_embedded" : {
    "users" : [ {
      "name" : "Bryan",
      "age" : 20,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/users/1"
        },
        "User" : {
          "href" : "http://localhost:8080/users/1"
        }
      }
    },
...
    ]
  }
}

====* 2.2 Os Recursos do Item *

Um único objeto WebsiteUser pode ser manipulado acessando URLs no formato _/users/\ {userID} _ com diferentes métodos HTTP e solicitando cargas úteis.

Para recuperar um objeto WebsiteUser, podemos acessar _/users/\ {userID} _ com o método GET. Isso retorna um objeto JSON do formulário:

{
  "name" : "Bryan",
  "email" : "[email protected]",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/users/1"
    },
    "User" : {
      "href" : "http://localhost:8080/users/1"
    }
  }
}

Para adicionar um novo WebsiteUser, precisaremos chamar /users com o método POST. Os atributos do novo registro WebsiteUser serão adicionados no corpo da solicitação como um objeto JSON:

{name: "Bryan", email: "[email protected]"}

Se não houver erros, esse URL retornará um código de status 201 CREATED.

Se queremos atualizar os atributos do registro WebsiteUser, precisamos chamar a URL _/users/\ {UserID} _ com o método PATCH e um corpo de solicitação contendo os novos valores:

{name: "Bryan", email: "[email protected]"}

Para excluir um registro WebsiteUser, podemos chamar a URL _/users/\ {UserID} _ com o método DELETE. Se não houver erros, isso retornará o código de status 204 SEM CONTEÚDO.

====* 2.3 Configuração MVC *

Também adicionaremos uma configuração básica do MVC para exibir arquivos html em nosso aplicativo:

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {

    public MvcConfig(){
        super();
    }

    @Override
    public void configureDefaultServletHandling(
      DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

====* 2.4. Permitindo solicitações de origem cruzada *

Se quisermos implantar o aplicativo front-end AngularJS separadamente da API REST - precisamos habilitar solicitações de origem cruzada.

O Spring Data REST adicionou suporte para isso a partir da versão 1.5.0.RELEASE. Para permitir solicitações de um domínio diferente, tudo o que você precisa fazer é adicionar a anotação _ @ CrossOrigin_ ao repositório:

@CrossOrigin
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends CrudRepository<WebsiteUser, Long> {}

Como resultado, em todas as respostas dos pontos de extremidade REST, será adicionado um cabeçalho de Access-Control-Allow-Origin.

===* 3. Criando o cliente AngularJS *

Para criar o front end do nosso aplicativo CRUD, usaremos AngularJS - uma estrutura JavaScript bem conhecida que facilita a criação de aplicativos front-end.

Para usar AngularJS, primeiro precisamos incluir o arquivo angular.min.js em nossa página html que será chamada users.html:

<script
  src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js">
</script>

Em seguida, precisamos criar um módulo, controlador e serviço Angular que chamarão os pontos de extremidade REST e exibirão os dados retornados.

Eles serão colocados em um arquivo JavaScript chamado app.js que também precisa ser incluído na página users.html:

<script src="view/app.js"></script>

====* 3.1 Serviço Angular *

Primeiro, vamos criar um serviço Angular chamado UserCRUDService que fará uso do serviço AngularJS _ $ http_ injetado para fazer chamadas para o servidor. Cada chamada será feita em um método separado.

Vamos dar uma olhada na definição do método para recuperar um usuário pelo ID usando o terminal _/users/\ {userID} _:

app.service('UserCRUDService', [ '$http', function($http) {

    this.getUser = function getUser(userId) {
        return $http({
            method : 'GET',
            url : 'users/' + userId
        });
    }
} ]);

Em seguida, vamos definir o método addUser que faz uma solicitação POST para a URL /users e envia os valores do usuário no atributo data:

this.addUser = function addUser(name, email) {
    return $http({
        method : 'POST',
        url : 'users',
        data : {
            name : name,
            email: email
        }
    });
}

O método updateUser é semelhante ao método acima, exceto que ele possui um parâmetro id e faz uma solicitação PATCH:

this.updateUser = function updateUser(id, name, email) {
    return $http({
        method : 'PATCH',
        url : 'users/' + id,
        data : {
            name : name,
            email: email
        }
    });
}

O método para excluir um registro WebsiteUser fará uma solicitação DELETE:

this.deleteUser = function deleteUser(id) {
    return $http({
        method : 'DELETE',
        url : 'users/' + id
    })
}

E, finalmente, vamos dar uma olhada nos métodos para recuperar a lista inteira de usuários:

this.getAllUsers = function getAllUsers() {
    return $http({
        method : 'GET',
        url : 'users'
    });
}

Todos esses métodos de serviço serão chamados por um controlador AngularJS.

====* 3.2 Controlador angular *

Criaremos um controlador UserCRUDCtrl AngularJS que terá um UserCRUDService injetado e usaremos os métodos de serviço para obter a resposta do servidor, manipular os casos success e error e definir as variáveis ​​_ $ scope_ contendo os dados de resposta para exibi-los no HTML página.

Vamos dar uma olhada na função getUser () _ que chama a função de serviço _getUser (userId) _ e define dois métodos de retorno de chamada em caso de êxito e erro. Se a solicitação do servidor for bem-sucedida, a resposta será salva em uma variável _user; caso contrário, as mensagens de erro são tratadas:

app.controller('UserCRUDCtrl', ['$scope','UserCRUDService',
  function ($scope,UserCRUDService) {
      $scope.getUser = function () {
          var id = $scope.user.id;
          UserCRUDService.getUser($scope.user.id)
            .then(function success(response) {
                $scope.user = response.data;
                $scope.user.id = id;
                $scope.message='';
                $scope.errorMessage = '';
            },
            function error (response) {
                $scope.message = '';
                if (response.status === 404){
                    $scope.errorMessage = 'User not found!';
                }
                else {
                    $scope.errorMessage = "Error getting user!";
                }
            });
      };
}]);

A função _addUser () _ chamará a função de serviço correspondente e manipulará a resposta:

$scope.addUser = function () {
    if ($scope.user != null && $scope.user.name) {
        UserCRUDService.addUser($scope.user.name, $scope.user.email)
          .then (function success(response){
              $scope.message = 'User added!';
              $scope.errorMessage = '';
          },
          function error(response){
              $scope.errorMessage = 'Error adding user!';
              $scope.message = '';
        });
    }
    else {
        $scope.errorMessage = 'Please enter a name!';
        $scope.message = '';
    }
}

As funções _updateUser () _ e _deleteUser () _ são semelhantes às acima:

$scope.updateUser = function () {
    UserCRUDService.updateUser($scope.user.id,
      $scope.user.name, $scope.user.email)
      .then(function success(response) {
          $scope.message = 'User data updated!';
          $scope.errorMessage = '';
      },
      function error(response) {
          $scope.errorMessage = 'Error updating user!';
          $scope.message = '';
      });
}

$scope.deleteUser = function () {
    UserCRUDService.deleteUser($scope.user.id)
      .then (function success(response) {
          $scope.message = 'User deleted!';
          $scope.User = null;
          $scope.errorMessage='';
      },
      function error(response) {
          $scope.errorMessage = 'Error deleting user!';
          $scope.message='';
      });
}

E, finalmente, vamos definir a função que recupera uma lista de usuários e a armazena na variável users:

$scope.getAllUsers = function () {
    UserCRUDService.getAllUsers()
      .then(function success(response) {
          $scope.users = response.data._embedded.users;
          $scope.message='';
          $scope.errorMessage = '';
      },
      function error (response) {
          $scope.message='';
          $scope.errorMessage = 'Error getting users!';
      });
}

====* 3.3 Página HTML *

A página users.html utilizará as funções do controlador definidas na seção anterior e as variáveis ​​armazenadas.

Primeiro, para usar o módulo Angular, precisamos definir a propriedade ng-app:

<html ng-app="app">

Então, para evitar digitar UserCRUDCtrl.getUser () _ toda vez que usamos uma função do controlador, podemos agrupar nossos elementos HTML em um _div com um conjunto de propriedades ng-controller:

<div ng-controller="UserCRUDCtrl">

Vamos criar o formulário _ que introduzirá e exibirá os valores para o objeto _WebiteUser que queremos manipular. Cada um deles terá um conjunto de atributos ng-model, que o vincula ao valor do atributo:

<table>
    <tr>
        <td width="100">ID:</td>
        <td><input type="text" id="id" ng-model="user.id"/></td>
    </tr>
    <tr>
        <td width="100">Name:</td>
        <td><input type="text" id="name" ng-model="user.name"/></td>
    </tr>
    <tr>
        <td width="100">Age:</td>
        <td><input type="text" id="age" ng-model="user.email"/></td>
    </tr>
</table>

Vincular a entrada id à variável user.id, por exemplo, significa que sempre que o valor da entrada é alterado, esse valor é definido na variável user.id e vice-versa.

Em seguida, vamos usar o atributo ng-click para definir os links que acionarão a chamada de cada função do controlador CRUD definida:

<a ng-click="getUser(user.id)">Get User</a>
<a ng-click="updateUser(user.id,user.name,user.email)">Update User</a>
<a ng-click="addUser(user.name,user.email)">Add User</a>
<a ng-click="deleteUser(user.id)">Delete User</a>

Por fim, vamos exibir a lista de usuários inteiramente e por nome:

<a ng-click="getAllUsers()">Get all Users</a><br/><br/>
<div ng-repeat="usr in users">
{{usr.name}} {{usr.email}}

===* 4. Conclusão*

Neste tutorial, mostramos como você pode criar um aplicativo CRUD usando AngularJS e a especificação Spring Data REST.

O código completo do exemplo acima pode ser encontrado no GitHub project.

Para executar o aplicativo, você pode usar o comando mvn spring-boot: run e acessar a URL /users.html.