Auditoria de dados com Hibernate Envers

A auditoria de dados é uma parte crucial de muitas aplicações, geralmente quando se lida com informações sensíveis é obrigatório ter algum mecanismos que permita rastrear as alterações de informações do sistema.

Para aplicações que usam Java podemos facilitar nosso trabalho através da biblioteca Hibernate Envers, que facilitará nossa implementação.

O Hibernate Envers é uma extensão do ORM Hibernate, que oferece recursos de auditoria de dados e controle de histórico para entidades que serão persistidas.

Configurando o ambiente

Vamos usar como base um projeto Spring Boot que faz a conexão com um banco de dados Postgres, vamos partir do principio que você já possui o projeto configurado.

Para adicionar a biblioteca precisamos editar o arquivo pom.xml e adicionar a dependência abaixo:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-envers</artifactId>
</dependency>
pom.xml

Depois de adicionar a dependência, é necessário a reconstrução do projeto, para garantir o download das novas bibliotecas.

Configuração do application.properties

No arquivo application.properties, será necessário adicionar algumas configurações para garantir o correto funcionamento do Hibernate Envers.

# Configuração de conexão com banco de dados
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.url=jdbc:postgresql://localhost:5432/seu_banco
spring.datasource.username=usuario_banco
spring.datasource.password=senha_banco
spring.jpa.hibernate.ddl-auto=update
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.show-sql=true

# Configuração do Hibernate Envers
spring.jpa.properties.org.hibernate.envers.audit_table_suffix=_AUD
spring.jpa.properties.org.hibernate.envers.audit_strategy=org.hibernate.envers.strategy.ValidityAuditStrategy
spring.jpa.properties.org.hibernate.envers.audit_strategy_validity_end_rev_field_name=end_revision
application.properties

É necessário ajustar as configurações para fazer sentido com as do seu banco de dados.

Anotando as entidades

Feito essas configurações estamos prontos para auditar nossas entidades para isso é bem simples basta adicionar a anotação @Audited na sua entidade.

Abaixo demostramos como fazer isso com uma entidade de exemplo:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.hibernate.envers.Audited;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Audited
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	
	private String name;
	
	private Integer age;
	
	private Double wage;
}
Java

Após ter anotado a classe de entidade, toda vez que você fizer alguma alteração na entidade, será gravado informações em uma outra tabela, seguindo as configurações do application.properties, a tabela de auditoria terá o mesmo nome seguido do prefixo _aud

Exemplo das tabelas criadas:

Tabela: employee:

|id |age|name      |wage    |
|---|---|----------|--------|
|1  |43 |João Silva|1.230,44|
Terminal

Tabela: employee_aud:

|id |rev|revtype|end_revision|age|name      |wage    |
|---|---|-------|------------|---|----------|--------|
|1  |3  |1      |            |43 |João Silva|1.230,44|
|1  |2  |0      |3           |43 |João Silva|1.200,43|
Terminal

Para gerar esses valores foi feito atualizações na entidade, cada nova alteração é gerado uma revisão na tabela, guardando as informações anteriores.

Recuperando as revisões

Além de visualizar as revisões via banco de dados, podemos acessá-las via código, para isso é bem simples, podemos utilizar a interface AuditReader, essa interface nos disponibiliza alguns métodos bem úteis:

Recuperando o número das revisões:

auditReader.getRevisions(Employee.class, id);
Java

Recuperando a foto da entidade com número da revisão:

auditReader.find(Employee.class, id, revision);
Java

Configurando a injeção de dependência Hibernate Envers

Se ao tentar utilizar a classe AuditReader, estiver recebendo algum erro de null pointer, deve ser porque o Spring não está conseguindo injetar corretamente a dependência, para solucionar esse problema é simples, precisamos apenas criar uma classe de configuração que será responsável por fazer essa injeção:

import javax.persistence.EntityManagerFactory;

import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AuditConfiguration {
	
	private final EntityManagerFactory entityManagerFactory;

	public AuditConfiguration(EntityManagerFactory entityManagerFactory) {
		this.entityManagerFactory = entityManagerFactory;
	}
	
	@Bean
	public AuditReader auditReader() {
		return AuditReaderFactory.get(entityManagerFactory.createEntityManager());
	}
}
Java

O Hibernate Envers é uma ferramenta realmente poderosa, guardar todas essas informações sem precisar ficar fazendo inúmeras implementações e usar isso de forma transparente é realmente fantástico.

Caso queira conhecer mais conteúdo sobre Spring Framework clique aqui.

Lembre-se de personalizar e aprimorar essas consultas de acordo com as necessidades específicas do seu aplicativo. Além disso, certifique-se de que suas entidades estejam devidamente marcadas com a anotação @Audited para que o Hibernate Envers rastreie as revisões de forma apropriada.

Mauricio Lima
Mauricio Lima

Bacharel em Ciência da Computação, profissional dedicado ao desenvolvimento de software e entusiasta da tecnologia.

Artigos: 65