Spring Data JPA faz parte da família Spring Data. Spring Data facilita a criação de aplicativos impulsionados pelo Spring que utilizam novas formas de acessar dados, como bancos de dados não relacionais, frameworks de map-reduce, serviços em nuvem, além de oferecer suporte avançado a bancos de dados relacionais. Este artigo discutirá sobre o Spring Data JPA. Também examinaremos um exemplo de aplicativo usando o Spring Data JPA.
Algumas das características interessantes fornecidas pelo Spring Data JPA são:
- Criação e suporte a repositórios criados com Spring e JPA
- Suporte a QueryDSL e consultas JPA
- Auditoria de classes de domínio
- Suporte para carregamento em lote, ordenação, consultas dinâmicas
- Suporta mapeamento XML para entidades
- Redução do tamanho do código para operações genéricas de CRUD usando CrudRepository
Quando usar o Spring Data JPA?
I would say that if you need to quickly create a JPA-based repository layer that is mainly for CRUD operations, and you do not want to create abstract DAO, implementing interfaces, Spring Data JPA is a good choice.
Exemplo de Spring Data JPA
Para o nosso exemplo de Spring Data JPA, criaremos um serviço web RESTful que se conectará ao banco de dados Postgresql. Implementaremos operações básicas de CRUD e trabalharemos com dados de exemplo que já foram criados.
Dados de Exemplo do Spring JPA
Utilize a consulta abaixo para criar a tabela no banco de dados Postgresql e adicionar alguns dados de teste.
create table people (
id serial not null primary key,
first_name varchar(20) not null,
last_name varchar(20) not null,
age integer not null
);
insert into people (id, first_name, last_name, age) values
(1, 'Vlad', 'Boyarskiy', 21),
(2,'Oksi', ' Bahatskaya', 30),
(3,'Vadim', ' Vadimich', 32);
Estrutura do Projeto Maven do Spring Data JPA
A imagem abaixo mostra a estrutura final do projeto Spring JPA. Investigaremos cada um dos componentes detalhadamente posteriormente.
Dependências do Maven do Spring Data JPA
Precisamos adicionar as seguintes dependências para o nosso projeto de exemplo do Spring Data JPA.
postgresql
: Driver Java do Postgresql.spring-core
,spring-context
: Dependências do núcleo do Spring Framework.spring-webmvc
,jackson-databind
: Para aplicação Spring REST.spring-data-jpa
,hibernate-entitymanager
: para suporte ao Spring Data JPA e Hibernate.
Abaixo está o conteúdo do arquivo de construção pom.xml final.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev</groupId>
<artifactId>springData</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Spring Data JPA Maven Webapp</name>
<url>https://maven.apache.org</url>
<properties>
<spring.framework>4.3.0.RELEASE</spring.framework>
<postgres.version>42.1.4</postgres.version>
<serializer.version>2.8.1</serializer.version>
<spring.data>1.3.4.RELEASE</spring.data>
<hibernate.manager>4.2.5.Final</hibernate.manager>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgres.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring.data}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.manager}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${serializer.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
Classes de Configuração Spring
package com.journaldev.spring.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.ejb.HibernatePersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories("com.journaldev.spring.repository")
@PropertySource("classpath:database.properties")
public class DataConfig {
private final String PROPERTY_DRIVER = "driver";
private final String PROPERTY_URL = "url";
private final String PROPERTY_USERNAME = "user";
private final String PROPERTY_PASSWORD = "password";
private final String PROPERTY_SHOW_SQL = "hibernate.show_sql";
private final String PROPERTY_DIALECT = "hibernate.dialect";
@Autowired
Environment environment;
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lfb = new LocalContainerEntityManagerFactoryBean();
lfb.setDataSource(dataSource());
lfb.setPersistenceProviderClass(HibernatePersistence.class);
lfb.setPackagesToScan("com.journaldev.spring.model");
lfb.setJpaProperties(hibernateProps());
return lfb;
}
@Bean
DataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setUrl(environment.getProperty(PROPERTY_URL));
ds.setUsername(environment.getProperty(PROPERTY_USERNAME));
ds.setPassword(environment.getProperty(PROPERTY_PASSWORD));
ds.setDriverClassName(environment.getProperty(PROPERTY_DRIVER));
return ds;
}
Properties hibernateProps() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_DIALECT, environment.getProperty(PROPERTY_DIALECT));
properties.setProperty(PROPERTY_SHOW_SQL, environment.getProperty(PROPERTY_SHOW_SQL));
return properties;
}
@Bean
JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
-
@Configuration
: esta anotação spring indica que é uma classe de configuração. -
@EnableTransactionManagement
: esta anotação permite que os usuários utilizem o gerenciamento de transações na aplicação. -
@EnableJpaRepositories("com.journaldev.spring.repository")
: indica onde as classes dos repositórios estão presentes. -
@PropertySource("classpath:database.properties")
: indica que temos um arquivo de propriedades em nosso classpath. Os valores deste arquivo serão injetados na variável de ambiente. O conteúdo do arquivo database.properties é mostrado abaixo.driver=org.postgresql.Driver url=jdbc:postgresql://127.0.0.1:5432/postgres user=postgres password=postgres hibernate.dialect=org.hibernate.dialect.PostgreSQL82Dialect hibernate.show_sql=true
-
Para usar o Spring Data, primeiro precisamos configurar o bean
DataSource
. Em seguida, precisamos configurar o beanLocalContainerEntityManagerFactoryBean
. Precisamos deste bean para controlar as entidades. Nestes beans, você deve especificar o provedor de persistência, ou seja,HibernatePersistence
no nosso caso. -
O próximo passo é configurar o bean para gerenciamento de transações. No nosso exemplo, é o
JpaTransactionManager
. Note que sem configurar o gerenciador de transações, não podemos usar a@Transactional
anotação.
As classes AppInitializer
e WebConfig
servem para configurar nossa aplicação como uma aplicação web sem usar o arquivo web.xml.
Classe Modelo
package com.journaldev.spring.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "people")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "age")
private Integer age;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
public Person() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "Person{" + "id=" + id + ", age=" + age + ", firstName='" + firstName + '\'' + ", lastName='" + lastName
+ '\'' + '}';
}
}
Aqui temos algumas novas anotações. Vamos falar sobre elas em mais detalhes.
- @Entity: Esta anotação permite que o gerenciador de entidades use esta classe e a coloque em contexto.
- @Table(name = “people”): associa uma classe a uma tabela no banco de dados.
@Id
: diz que este campo é a chave primária.@GeneratedValue(strategy = GenerationType.IDENTITY)
: Define a estratégia para gerar a chave primária.@Column(name = "age")
: indica uma coluna no banco de dados à qual este campo estará associado.
Repositório Spring Data JPA
O próximo passo é criar o repositório JPA.
package com.journaldev.spring.repository;
import org.springframework.data.repository.CrudRepository;
import com.journaldev.spring.model.Person;
import java.util.List;
public interface PersonRepository<P> extends CrudRepository<Person, Long> {
List<Person> findByFirstName(String firstName);
}
Ao herdar de CrudRepository
, podemos chamar muitos métodos sem a necessidade de implementá-los. Alguns desses métodos são:
- save
- findOne
- exists
- findAll
- count
- delete
- deleteAll
Também podemos definir nossos próprios métodos. Esses nomes de método devem usar palavras-chave especiais como “find”, “order” com o nome das variáveis. Os desenvolvedores do Spring Data JPA tentaram levar em consideração a maioria das opções possíveis que você pode precisar. Em nosso exemplo, o método findByFirstName(String firstName)
retorna todas as entradas da tabela onde o campo first_name
é igual a firstName
. Esta é uma das características mais importantes do Spring Data JPA, pois reduz muito o código repetitivo. Além disso, as chances de erros são menores porque esses métodos do Spring são bem testados por muitos projetos que já os utilizam.
Classe de Serviço Spring
Agora que nosso código Spring Data JPA está pronto, o próximo passo é criar uma classe de serviço e definir os métodos com os quais teremos que trabalhar na tabela do banco de dados.
package com.journaldev.spring.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.repository.PersonRepository;
@Service
public class PersonService {
@Autowired
PersonRepository<Person> personRepository;
@Transactional
public List<Person> getAllPersons() {
return (List<Person>) personRepository.findAll();
}
@Transactional
public List<Person> findByName(String name) {
return personRepository.findByFirstName(name);
}
@Transactional
public Person getById(Long id) {
return personRepository.findOne(id);
}
@Transactional
public void deletePerson(Long personId) {
personRepository.delete(personId);
}
@Transactional
public boolean addPerson(Person person) {
return personRepository.save(person) != null;
}
@Transactional
public boolean updatePerson(Person person) {
return personRepository.save(person) != null;
}
}
@Transactional
A anotação indica que o método será executado na transação. O Spring cuidará do gerenciamento da transação.
Classe de Controlador Spring
O último passo é criar a classe de controlador para expor nossas APIs para o mundo exterior.
package com.journaldev.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.journaldev.spring.model.Person;
import com.journaldev.spring.services.PersonService;
@RestController
public class PersonController {
@Autowired
PersonService personService;
@RequestMapping(value = "/person/{id}", method = RequestMethod.GET)
public @ResponseBody Person getAllUsers(@PathVariable Long id) {
return personService.getById(id);
}
@RequestMapping(value = "/personByName/{name}", method = RequestMethod.GET)
public List<Person> getPersoneByName(@PathVariable String name) {
return personService.findByName(name);
}
@RequestMapping(value = "/person", method = RequestMethod.GET)
public List<Person> getAll() {
return personService.getAllPersons();
}
@RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE)
public HttpStatus deletePersnone(@PathVariable Long id) {
personService.deletePerson(id);
return HttpStatus.NO_CONTENT;
}
@RequestMapping(value = "/person", method = RequestMethod.POST)
public HttpStatus insertPersone(@RequestBody Person person) {
return personService.addPerson(person) ? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
}
@RequestMapping(value = "/person", method = RequestMethod.PUT)
public HttpStatus updatePerson(@RequestBody Person person) {
return personService.updatePerson(person) ? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
}
}
Teste do Spring Data JPA
Apenas construa e implante o projeto em seu contêiner de servlet favorito, como o Tomcat. As imagens abaixo mostram a resposta para algumas das chamadas de API.
Spring Data JPA Ler Todos
Spring Data JPA Obter por Nome
Spring Data JPA Criar
Spring Data JPA Atualizar
Spring Data JPA Excluir
Isso é tudo para o tutorial de exemplo do Spring Data JPA. Você pode baixar o projeto final a partir do link abaixo.
Baixar Projeto de Exemplo do Spring Data JPA
Referência: Site Oficial
Source:
https://www.digitalocean.com/community/tutorials/spring-data-jpa