Spring Boot + JPA + Audit Listener

Natthapon Pinyo
Nov 11, 2020

Let’s say we need to keep simple Audit data like:

  • create date
  • update date
  • create by
  • update by

Spring Boot is already provided this solution for us.

Step 0 — Make sure you have JPA in your pom.xml

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Step 1 — Create Auditor.java

import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import java.util.Optional;

public class Auditor implements AuditorAware<String> {

@Override
public Optional<String> getCurrentAuditor() {
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();

return authentication != null ? Optional.of((String) authentication.getPrincipal()) : Optional.of("0");
}

}

It’s depends on your Principal object type you use.
This example use String to represent user id as Principal

Step 2— Add @EnableJpaAuditing and define Audit Bean in your Spring Boot application class

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing(auditorAwareRef = "auditor")
public class MyAwesomeApplication {
... @Bean
public AuditorAware<String> auditor() {
return new Auditor();
}
...}

Step 3 — Add @EntityListeners and @MappedSuperclass into your base entity

import lombok.Data;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.time.Instant;

@Data
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass

public class BaseEntity {
... @CreatedBy
@Column(length = 36)
private String createdBy;

@CreatedDate
private Instant created;

@LastModifiedBy
@Column(length = 36)
private String updatedBy;

@LastModifiedDate
private Instant updated;
...}

Step 4 — Extends BaseEntity

import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@EqualsAndHashCode(callSuper = true)
@Data
@Entity(name = "m_user")
public class User extends BaseEntity {

@Column(length = 60, nullable = false, unique = true)
private String username;

}

When saving via JPA, Spring Boot will be saved Audit Data for you automatically.

--

--