Tuesday, May 12, 2015

Combinando Spring Data, QueryDSL e JPA / Hibernate para persistência em Java

Mais um post falando sobre persistência em Java com QueryDSL, mas agora explorando também o Spring Data. O Spring Data é uma tecnologia criada para facilitar a criação de componentes de acesso a dados via: bancos relacionais, NoSQL,  
map-reduce e serviços baseados em cloud.

Olhando para base de dados relacionais, o Spring Data oferece componentes para JPA e JDBC. Em outro post escrevi sobre o QueryDSL, uma ferramenta para produzir consultas flexíveis encima da JPA (e outros mecanismos de persistência) com uma DSL bem interessante. Evoluindo aquela abordagem, meu objetivo é apresentar outra estratégia para persistência unindo o QueryDSL e Spring Data para JPA / Hibernate.

Compartilhei no Github um projeto que pode ser referência para esse post. Outro detalhe importante é que o projeto foi construído com o Spring Boot, que disponibiliza um Tomcat embutido. A classe Application é o ponto de entrada da aplicação, aonde ficam contidas as configurações do projeto. É o caso da anotação EnableJpaRepositories, que indica o pacote base dos componentes Repositories. O código a seguir demonstra o componente MercadoriaRepository, uma interface anotada como Repository responsável pela operações de persistência da entidade Mercadoria.
@Repository
public interface MercadoriaRepository
  extends JpaRepository<Mercadoria, Long>,
    QueryDslPredicateExecutor<Mercadoria> {
  …
}

JpaRepository é uma interface do Spring que define operações básicas de persistência sobre uma determinada entidade. Operações para CRUD, paginação e ordenação. Já a interface QueryDslPredicateExecutor atua como uma bridge entre o Spring Data e QueryDSL. Através dela é possível usar Predicates construídos via QueryDSL em consultas via Spring Data.

É possível e válido definir uma classe concreta como Repository. Mas prefiro definir esses componentes como contratos, sendo o Spring o responsável por escrever código que implementa (proxy) as interfaces. Mesmo em interface, o Spring Data permite a definição de métodos para consultas customizados.

No controller, o proxy de MercadoriaRepository é injetado pelo Spring, via anotação Autowired. A seguir trecho de código do componente MercadoriaController, com destaque para a definição do Repository e o método list, responsável por realizar a consulta de Mercadorias de acordo com os filtros informados:
@RestController
@RequestMapping(value="/")
public class MercadoriaController {
  
  @Autowired
  private MercadoriaRepository repository;
   
  @RequestMapping(method = RequestMethod.GET)
  public PesquisaMercadorias list(FiltrosPesquisaMercadoria filtros) {
    Pageable page = buildPageRequest(filtros.getPagina(), 
      filtros.getLinhas(), filtros.getOrdem());
    
    Predicate predicate = whereByCriterio(filtros);
    long total = repository.count(predicate);
    List<Mercadoria> mercadorias =
      Lists.newArrayList(repository.findAll(predicate, page));
    return new PesquisaMercadorias(total, mercadorias);
  }
  ...
}

O primeiro passo é construir Pageable com as configurações para paginação e ordenação via buildPageRequest. Depois construir o Predicate com as condições da consulta, via whereByCriterio, que será utilizado no contador de registros (informação para paginação) e para processar a consulta das mercadorias. Ambos os métodos count(Predicate) e findAll(Predicate) são definidos em QueryDSLPredicatorExecutor.

Os métodos save e delete, definidos em JpaRepository (CrudRepository), também são acionados pelo controller:
  @RequestMapping(method = RequestMethod.POST)
  public void save(Mercadoria m) {
    repository.save(m);
  }
 
  @RequestMapping(method = RequestMethod.DELETE)
  public void delete(Long mercadoriaId) {
    repository.delete(mercadoriaId);
  }

Todas as operações de persistência foram centralizadas na interface MercadoriaRepository, mas ela delega o update em batch e consulta de tuplas para MercadoriaQuery, via métodos default do Java 8.

Outros detalhes sobre o projeto:
  • O build e as dependências do projeto são controladas pelo Maven e/ou Gradle;
  • Spring MVC atua como framework web;
  • JQuery e Foundation no front-end da aplicação

1 comment:

Pedro said...

Excelente seu exemplo! Obrigado por compartilhar. Ajudou muito no processo de incluir API queryDSL no meu projeto.