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.
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.
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 estender 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.
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.
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.
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.
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.
{
"_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}.
{
"_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.
{
"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.
{
"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.
- Spring Data – Página oficial do projeto Spring Data
- Spring Data REST – Pagina oficial do projeto Spring Data REST
- PostgreSQL – Pagina oficial do banco de dados PostgreSQL
- Spring Boot – Página oficial do projeto Spring Boot