O Spring Data é um conjunto de projetos do Spring para a manipulação de dados de diversas formas, entre elas em bancos de dados relacionais como o MySQL e o PostgreSQL e em bancos de dados NoSQL com o MongoDB e o Redis. Um desses projetos é o Spring Data JPA para o desenvolvimento de aplicações com a Java Persistence API (JPA), que permite a implementação do mapeamento objeto-relacional de um modelo de dados.

Além do mapeamento, esse framework permite também o desenvolvimento de métodos para o acesso aos dados com pouco ou nenhum código sendo necessário para o seu desenvolvimento, o que facilita muito o desenvolvimento das aplicações, e aumenta a produtividade dos programadores.

Combinado com o Spring Data JPA, é possível utilizar o Spring Boot para a configuração fácil e rápida da aplicação e para a disponibilização de um repositório de dados com uma API Rest. O Spring boot permite a execução da aplicação sem a necessidade de nenhuma ferramenta externa e com praticamente nenhuma configuração necessária. Por exemplo, essa ferramenta executa internamente o servidor de aplicação, sem ser necessário nenhuma configuração, ele também facilita a configuração do framework Spring na aplicação, entre muitas outras coisas.

Esse artigo mostrará como configurar a aplicação utilizando o Spring boot, e também como desenvolver uma aplicação utilizando o Spring Data JPA. Também será mostrado o servidor funcionando retornando dados no padrão JSON.

Configuração da Aplicação

A aplicação de exemplo desse artigo foi desenvolvida na IDE Eclipse e utilizando o maven para a configuração das dependências, a Listagem 1 mostra o arquivo pom.xml que deve conter as dependências spring-boot-starter-data-rest que é a biblioteca para a criação do servidor REST com o Spring Boot, a dependência spring-boot-starter-data-jpa que é a dependência do Spring Data e a dependência postgresql que é o Driver para a conexão com o banco de dados.

Listagem 1. Arquivo 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>com.santana.mobilab</groupId>
        <artifactId>server</artifactId>
        <version>0.0.1</version>      
   
      <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>1.3.1.RELEASE</version>
      </parent>
   
      <properties>
          <java.version>1.8</java.version>
      </properties>
   
      <dependencies>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-rest</artifactId>
          </dependency>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-jpa</artifactId>
          </dependency>
                    <dependency>
                    <groupId>org.postgresql</groupId>
                    <artifactId>postgresql</artifactId>
                    <version>9.4-1200-jdbc4</version>
              </dependency>
      </dependencies>
   
      <build>
          <plugins>
              <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
              </plugin>
          </plugins>
      </build>
   
      <repositories>
          <repository>
              <id>spring-releases</id>
              <url>https://repo.spring.io/libs-release</url>
          </repository>
      </repositories>
      <pluginRepositories>
          <pluginRepository>
              <id>spring-releases</id>
              <url>https://repo.spring.io/libs-release</url>
          </pluginRepository>
      </pluginRepositories>
  </project>

Para a execução da aplicação é necessário ter o banco de dados PostgreSQL instalado, caso o leitor prefira, é possível utilizar outro banco de dados como o MySQL ou SQL Server, basta alterar a configuração do pom para importar a dependência do Driver do banco desejado.

Desenvolvimento da Aplicação

Com tudo configurado, podemos começar a implementação da aplicação, para isso serão utilizadas duas classes de modelo, a classe Cliente e a classe Compra para representar os objetos que serão armazenados no banco de dados. A Listagem 2 mostra a classe cliente com os atributos id, nome, endereço e cpf e o relacionamento com uma lista de compras. Essa classe é uma entidade JPA, por isso as anotações @Entity @Id, @GeneratedValue, @OneToMany e @JoinColumn.

Listagem 2. Classe Cliente

  package com.devmedia.server.model;
   
  import java.util.List;
   
  import javax.persistence.Entity;
  import javax.persistence.FetchType;
  import javax.persistence.GeneratedValue;
  import javax.persistence.GenerationType;
  import javax.persistence.Id;
  import javax.persistence.JoinColumn;
  import javax.persistence.OneToMany;
   
  @Entity
  public class Cliente {
   
        @Id
      @GeneratedValue(strategy=GenerationType.AUTO)    
        private Long id;
        
        private String nome;
   
        private String endereco;
        
        private String cpf;
   
        @OneToMany(targetEntity=Compra.class, fetch=FetchType.EAGER)
        @JoinColumn(name="cliente_id")
        private List<Compra> compras;
        
        public Long getId() {
              return id;
        }
   
        public void setId(Long id) {
              this.id = id;
        }
   
        public String getNome() {
              return nome;
        }
   
        public void setNome(String nome) {
              this.nome = nome;
        }
   
        public String getEndereco() {
              return endereco;
        }
   
        public void setEndereco(String endereco) {
              this.endereco = endereco;
        }
   
        public String getCpf() {
              return cpf;
        }
   
        public void setCpf(String cpf) {
              this.cpf = cpf;
        }
   
        public List<Compra> getCompras() {
              return compras;
        }
   
        public void setCompras(List<Compra> compras) {
              this.compras = compras;
        }
        
  }

A classe Compra também é uma entidade JPA, e por isso tem as mesmas anotações da classe Cliente. A Listagem 3 mostra o código dessa classe, que tem os atributos id, valorTotal e numeroProdutos.

Listagem 3. Classe Compra

  package com.devmedia.server.model;
   
  import javax.persistence.Entity;
  import javax.persistence.GeneratedValue;
  import javax.persistence.GenerationType;
  import javax.persistence.Id;
   
  @Entity
  public class Compra {
   
        @Id
      @GeneratedValue(strategy=GenerationType.AUTO)    
        private Long id;
        
        private float valorTotal;
        private int numeroProdutos;
        
   
        public Long getId() {
              return id;
        }
   
        public void setId(Long id) {
              this.id = id;
        }
   
        public float getValorTotal() {
              return valorTotal;
        }
   
        public void setValorTotal(float valorTotal) {
              this.valorTotal = valorTotal;
        }
   
        public int getNumeroProdutos() {
              return numeroProdutos;
        }
   
        public void setNumeroProdutos(int numeroProdutos) {
              this.numeroProdutos = numeroProdutos;
        }
        
  }

Agora, com o Spring Data podemos desenvolver os repositórios que são interfaces onde são definidos os métodos de acesso aos dados, para isso é necessário extender a interface PagingAndSortingRepository, que já disponibiliza diversos métodos para o acesso aos dados, além disso também podemos criar novos métodos como o findByNome e o findByNomeOrderByNome. Com o Spring Data não é preciso implementar mais nada, seguindo o padrão de nomes, o framework já entende o que o método deve fazer. Caso o programador queira implementar alguma consulta muito diferente, é possível utilizar a anotação @Query como mostrado na Listagem 4.

Nessa interface também é necessário colocar a anotação @RepositoryRestResource que indica que será criado um servidor REST a partir dos métodos definidos na interface.

Listagem 4. Classe ClienteRepository

  package com.devmedia.server.repository;
   
  import java.util.List;
   
  import org.springframework.data.jpa.repository.Query;
  import org.springframework.data.repository.PagingAndSortingRepository;
  import org.springframework.data.repository.query.Param;
  import org.springframework.data.rest.core.annotation.RepositoryRestResource;
   
  import com.devmedia.server.model.Cliente;
   
  @RepositoryRestResource(collectionResourceRel = "cliente", path = "clientes")
  public interface ClienteRepository extends PagingAndSortingRepository<Cliente, Long> {
        
        /**
         * Método que retorna uma lista de clientes fazendo a busca pelo nome passado como parâmetro.
         *  
         * @param name
         * @return lista de clientes
         */
        List<Cliente> findByNome(@Param("name") String name);
        
        /**
         * Método que retorna o cliente com apenas seu nome fazendo a busca com o id passado como parâmetro.
         * 
         * @param id
         * @return cliente do id passado como parâmetro.
         */   
        @Query("SELECT c.nome FROM Cliente c where c.id = :id") 
      Cliente findNomeById(@Param("id") Long id);
        
        /**
         * Método que retorna uma lista de clientes fazendo a busca pelo nome passado como parâmetro e ordenando os 
         * clientes pelo nome.
         *  
         * @param name
         * @return lista de clientes
         */
        List<Cliente> findByNomeOrderByNome(@Param("name") String name);
   
  }

O servidor está praticamente pronto, falta apenas criar a classe para iniciar a aplicação, para isso será utilizado o Spring Boot, basta colocar a linha SpringApplication.run(Application.class, args) no método main da classe, que o Spring Boot inicia o tomcat com a aplicação criada já funcionando. Para indicar que essa é uma classe do Spring Boot, é necessário colocar a anotação @SpringBootApplication. A anotação @EntityScan indica o pacote onde estão as classes JPA e a anotação @EnableJpaRepositories indica o pacote onde estão as classes de repositório. A Listagem 5 mostra o código dessa classe.

Listagem 5. Classe Application

  package com.devmedia.server.run;
   
  import org.springframework.boot.SpringApplication;
  import org.springframework.boot.autoconfigure.SpringBootApplication;
  import org.springframework.boot.orm.jpa.EntityScan;
  import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
   
  @SpringBootApplication
  @EntityScan(basePackages = {
              "com.devmedia.server.model"
              })
  @EnableJpaRepositories(basePackages = {
              "com.devmedia.server.repository"
              })
  public class Application {
   
      public static void main(String[] args) {
          SpringApplication.run(Application.class, args);    
      }
      
  }

O último passo no desenvolvimento da aplicação é configurar o banco de dados, para isso é necessário criar o arquivo application.properties, que deve ser criado no diretório src/main/resources do projeto. Nesse arquivo são configurados o driver, a url, o nome de usuário e a senha do banco de dados e a porta que o tomcat será executado. A Listagem 6 mostra um exemplo desse arquivo, caso você esteja usando outro banco de dados, será necessário trocar o driverClasseName e a URL de conexão.

Listagem 6. Arquivo application.properties

  spring.jpa.database=POSTGRESQL
  spring.datasource.platform=postgres
  spring.jpa.show-sql=true
  spring.jpa.hibernate.ddl-auto=create-drop
  spring.database.driverClassName=org.postgresql.Driver
  spring.datasource.url=jdbc:postgresql://localhost:5432/priview
  spring.datasource.username=postgres
  spring.datasource.password=postgres
  server.port=8080
  

Para testar a aplicação foi criado um script para a inserção de uma mass de dados. A Listagem 7 mostra esse script, que deve ser executado em alguma interface do PostgreSQL como o PgAdmin.

Listagem 7. Inserts para teste da aplicação

  insert into cliente(id, cpf, endereco, nome) values(1, '1275634645', 'Avenida Paulista 1020', 'Eduardo');
  insert into cliente(id, cpf, endereco, nome) values(2, '1234345423', 'Avenida Rebouças 1500', 'Luiz');
  insert into cliente(id, cpf, endereco, nome) values(3, '6545645654', 'Rua dos Pinheiros 2000', "Bruna");
  insert into cliente(id, cpf, endereco, nome) values(4, '6452345234', 'Alameda Santos 120', "Sonia");
  insert into cliente(id, cpf, endereco, nome) values(5, '7565345325', 'Rua XV de Novembro 2012', "Brianda");
  insert into cliente(id, cpf, endereco, nome) values(6, '6456563454', 'Rua 7 de Setembro 2001', "Enio");
  insert into cliente(id, cpf, endereco, nome) values(7, '7565345645', 'Avenida Brasil 201', "Marcelo");
   
   
  insert into compra (id, numero_produtos, valor_total, cliente_id) values (1, 5, 100, 1);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (2, 2, 500, 1);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (3, 7, 600, 2);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (4, 2, 200, 2);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (5, 8, 300, 2);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (6, 9, 400, 3); 
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (7, 3, 300, 4);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (8, 2, 200, 4);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (9, 9, 400, 4);
  insert into compra (id, numero_produtos, valor_total, cliente_id)  values (10, 8, 1000, 5);

Se tudo funcionou corretamente, basta executar a aplicação, o banco de dados será criado automaticamente por causa da opção create-drop colocada no arquivo application.properties. Para acessar os serviços pode ser acessado um browser como o Chrome ou pode ser feita a implementação de um cliente REST também. Por exemplo, o método findByNome foi exposto como um serviço, para acessa-lo basta utilizar a URL http://localhost:8080/clientes/search/findByNome?name=Eduardo. A resposta dessa chamada está na Listagem 8, e ela é enviada na forma de um arquivo JSON. É possível observar que além do cliente, foi retornado também as compras que estão relacionadas ao cliente Eduardo.

Listagem 8. Resposta da chamada ao serviço findByNome

  {
    "_embedded" : {
      "cliente" : [ {
        "nome" : "Eduardo",
        "endereco" : "'Avenida Paulista 1020",
        "cpf" : "1275634",
        "compras" : [ {
          "valorTotal" : 100.0,
          "numeroProdutos" : 5
        }, {
          "valorTotal" : 500.0,
          "numeroProdutos" : 2
        } ],
        "_links" : {
          "self" : {
            "href" : "http://localhost:8080/clientes/1"
          },
          "cliente" : {
            "href" : "http://localhost:8080/clientes/1"
          }
        }
      } ]
    },
    "_links" : {
      "self" : {
        "href" : "http://localhost:8080/clientes/search/findByNome?name=Eduardo"
      }
    }
  }

Para consultar todos os serviços disponíveis é possível acessar a URL http://localhost:8080/clientes/search, que retorna todos os serviços disponíveis. A Listagem 9 mostra a resposta dessa solicitação. É possível observar que foram retornados os serviços findNomeByID, findByNomeOrderByNome e findByNome que são os métodos declarados na interface do repositório. Além disso, no arquivo retornado são mostrados os parâmetros necessário para cada serviço, como por exemplo o {?id} e o {?name}.

Listagem 9. Resposta da requisição para descobrir serviços disponíveis

  {
  "_links" : {
    "findNomeById" : {
      "href" : "http://localhost:8080/clientes/search/findNomeById{?id}",
      "templated" : true
    },
    "findByNomeOrderByNome" : {
      "href" : "http://localhost:8080/clientes/search/findByNomeOrderByNome{?name}",
      "templated" : true
    },
    "findByNome" : {
      "href" : "http://localhost:8080/clientes/search/findByNome{?name}",
      "templated" : true
    },
    "self" : {
      "href" : "http://localhost:8080/clientes/search"
    }
  }
}

Além dos serviços criado, é possível também fazer a busca pelo id do cliente, para isso basta utilizar a URL http://localhost:8080/clientes/id que o servidor retorna um arquivo JSON com todos os dados do cliente daquele id. Por exemplo, na Listagem 10 foi feita a requisição para http://localhost:8080/clientes/2, que retornou os dados do cliente que tem o id=2.

Listagem 10. Resposta da requisição para o cliente de id=2

  {
  "nome" : "Luiz",
  "endereco" : "'Avenida Rebouças 1500",
  "cpf" : "1234345",
  "compras" : [ {
    "valorTotal" : 600.0,
    "numeroProdutos" : 7
  }, {
    "valorTotal" : 200.0,
    "numeroProdutos" : 2
  }, {
    "valorTotal" : 300.0,
    "numeroProdutos" : 8
  } ],
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/clientes/2"
    },
    "cliente" : {
      "href" : "http://localhost:8080/clientes/2"
    }
  }
}

É possível fazer essa pesquisa em todos os clientes cadastrados na base, por exemplo, na Listagem 11 está o retorno se fizermos com id=3.

Listagem 11. Resposta da requisição para o cliente de id=3

  {
  "nome" : "Bruna",
  "endereco" : "'Rua dos Pinheiros 2000",
  "cpf" : "6545645",
  "compras" : [ {
    "valorTotal" : 400.0,
    "numeroProdutos" : 9
  } ],
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/clientes/3"
    },
    "cliente" : {
      "href" : "http://localhost:8080/clientes/3"
    }
  }
}

Não é possível fazer requisições diretamente para os objetos da classe Compra porque não foi implementado um repositório dessa classe, porém, caso o leitor queira, basta criar a classe CompraRepository da mesma forma que foi criada a ClienteRepository, e aí será possível criar serviços também para que o usuário posso acessar diretamente as compras.

Esse artigo mostrou que é bastante simples o desenvolvimento de um servidor REST utilizando os frameworks Spring Data e Spring Boot. A aplicação desenvolvida nesse artigo utilizou o banco de dados PostgreSQL, porém qualquer banco de dados relacional pode ser usado sem praticamente nenhuma alteração no código. Para mostrar o funcionamento do servidor desenvolvido foram mostradas diversas requisições realizadas e o resultado retornado.

Espero que esse artigo seja útil! Até mais!

Links

Spring Data – Página oficial do projeto Spring Data
http://projects.spring.io/spring-data/

Spring Data REST – Pagina oficial do projeto Spring Data REST
http://projects.spring.io/spring-data-rest/

PostgreSQL – Pagina oficial do banco de dados PostgreSQL
http://www.postgresql.org/

Spring Boot – Página oficial do projeto Spring Boot
http://projects.spring.io/spring-boot/