DEV Community

Oum
Oum

Posted on

Auditing in Spring Boot

What's auditing?

Auditing means tracking and logging transactions related to data, which simply means logging insert, update and delete operations (user and/or date of action).

How to add creation/update date of an @Entity in Spring?

This can be achieved using different approaches:

  • Database built-in solutions: Oracle Database 12c, Db2, MySQL Enterprise Audit...
  • Creating database triggers,
  • Use a third party tool,
  • Create columns of update and create for each entity, and log every change manually to the database (write it completely on your own),
  • Using Spring Auditing 💡

This last choice doesn't require touching our entities business logic to add tracking logic, and doesn't require adding additional columns to the entity or additional tables to log changes.

A headless solution to track your entity, if you are using Spring. We configure it once and use it everywhere:

Spring Data provides sophisticated support to transparently keep track of who created or changed an entity and the point in time this happened. (spring)

Implementation

The possible approaches:

1. Implementation using standard JPA:
Uses the entity's table itself to log changes, in this case we can't audit delete operations.
2. Implementation using auditing functionality provided by Hibernate:
It logs into tables other than the entity's table, which allows to log delete operations.
3. Implementation using auditing functionality provided by Spring Data JPA💡:
Provides handy annotations for auditing properties, ready for integration with Spring Security, and also cannot be used to log delete operations since it inherits the same flaws of the JPA approach.

Next we will cover the implementation of auditing with Spring Data JPA.

📝 Checkpoints/Todos:

  • Auditing Author Using AuditorAware and Spring Security (allows adding @CreatedBy, and @LastModifiedBy).
  • Enable JPA Auditing by Using @EnableJpaAuditing
  • Create Generic Auditable Class with Spring Data Annotations @CreatedDate, and @LastModifiedDate.
  • Add Extends from Auditable Class to the entity we want to track.

1- Create AuditorAware implementation that will be used to configure auditing:

import org.springframework.data.domain.AuditorAware;
import java.util.Optional;

public class AuditorAwareImpl implements AuditorAware<String> {

        // Returning empty instead of user since we're tracking just dates not users
    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.empty();
    }

        // Use the following to get the actual connected user
        /*
    public User getCurrentAuditor() {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }

        return ((MyUserDetails) authentication.getPrincipal()).getUser();
    }
    */
}
Enter fullscreen mode Exit fullscreen mode

2- Enable auditing, by adding this configuration class to the spring boot project's configuration directory:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class JpaAuditingConfig {
    @Bean
    AuditorAware<String> auditorProvider() {
        return new AuditorAwareImpl();
    }
}
Enter fullscreen mode Exit fullscreen mode

3- Once auditing is enabled we create the Auditable class, that we will extend wherever we want (in our model classes):

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class Auditable<U>
{
    @CreatedDate
    @Column(name = "created_date")
    protected Date createdDate;

    @LastModifiedDate
    @Column(name = "last_modified_date")
    protected Date lastModifiedDate;

    // To track the user that modified or created use @LastModifiedBy and @CreatedBy

    //@LastModifiedBy
    //protected U lastModifiedBy;

    //@CreatedBy
    //protected U createdBy;

}
Enter fullscreen mode Exit fullscreen mode

4- Last, extend from Auditable class to track changes, example:

@Data
@Entity
@NoArgsConstructor
@Table(name = "products")
public class Product extends Auditable<String> {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
}
Enter fullscreen mode Exit fullscreen mode

The columns created_date and last_modified_date are automatically added to products table in the database, and since Product class extends Auditable class the createdDate and lastModifiedDate attributes can be used in the same way Product's other attributes are used.

More on:
Official docs

Top comments (0)