Spring Data JPA Auditing Example
Welcome, in this tutorial, we will see how to implement a Spring data JPA auditing application. We will use the AuditorAware
interface to capture the auditing information. Database auditing is a mechanism to keep track and logs of events happening on the records present in a database like who did what and when.
1. Introduction
Before going further in this tutorial, we will look at the common terminology such as introduction to Spring Boot and Lombok.
1.1 Spring Boot
- Spring boot is a module that provides rapid application development feature to the spring framework including auto-configuration, standalone-code, and production-ready code
- It creates applications that are packaged as jar and are directly started using embedded servlet container (such as Tomcat, Jetty or, Undertow). Thus, no need to deploy the war files
- It simplifies the maven configuration by providing the starter template and helps to resolve the dependency conflicts. It automatically identifies the required dependencies and imports them into the application
- It helps in removing the boilerplate code, extra annotations, and XML configurations
- It provides powerful batch processing and manages the rest endpoints
- It provides an efficient JPA-starter library to effectively connect the application with the relational databases
- It offers a Microservice architecture and cloud configuration that manages all the application related configuration properties in a centralized manner
1.2 Lombok
- Lombok is nothing but a small library that reduces the amount of boilerplate Java code from the project
- Automatically generates the getters and setters for the object by using the Lombok annotations
- Hooks in via the Annotation processor API
- Raw source code is passed to Lombok for code generation before the Java Compiler continues. Thus, produces properly compiled Java code in conjunction with the Java Compiler
- Under the
target/classes
folder you can view the compiled class files - Can be used with Maven, Gradle IDE, etc.
1.2.1 Lombok features
Feature | Details |
---|---|
val | Local variables are declared as final |
var | Mutable local variables |
@Slf4J | Creates an SLF4J logger |
@Cleanup | Will call close() on the resource in the finally block |
@Getter | Creates getter methods for all properties |
@Setter | Creates setter for all non-final properties |
@EqualsAndHashCode |
|
@ToString |
|
@NoArgsConstructor |
|
@RequiredArgsContructor |
|
@AllArgsConstructor |
|
@Data |
|
@Builder |
|
@Value |
|
Let us go ahead with the tutorial implementation but before going any further I’m assuming that you’re aware of the Spring boot basics.
2. Spring Data JPA Auditing Example
2.1 Tools Used for Spring boot application and Project Structure
We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.
Let us start building the application!
3. Creating a Spring Boot application
Below are the steps involved in developing the application.
3.1 Maven Dependency
Here, we specify the dependency for the Spring boot (Web and JPA), H2 database, Java Faker (to generate the dummy data), and Lombok. The updated file will have the following code.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.2</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.springboot.jpa.auditing</groupId> <artifactId>SpringDataJpaAuditing</artifactId> <version>0.0.1-SNAPSHOT</version> <name>SpringDataJpaAuditing</name> <description>JPA auditing in spring boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.github.javafaker</groupId> <artifactId>javafaker</artifactId> <version>1.0.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
3.2 Application XML file
Create a new YML file at the location: SpringDataJpaAuditing/src/main/resources/
and add the following code to it. Here we will define the H2 database connection, database creation, and h2 console details. You’re free to change the application or the database details as per your wish. You can access the h2 console at the following URL – http://localhost:9800/h2-console
in the browser.
application.yml
server: port: 9800 spring: application: name: springboot-jpa-data-auditing datasource: driverClassName: org.h2.Driver password: '' url: jdbc:h2:mem:testdb username: sa h2: console: enabled: true path: /h2-console jpa: database-platform: org.hibernate.dialect.H2Dialect hibernate: ddl-auto: create-drop properties: hibernate: show_sql: true
3.3 Java Classes
Let us write the important java class(es) involved in this application. For brevity, we will skip the following classes –
Product.java
– Entity class that will be persisted in the database. The class also extends theAuditable
class which will be used for the auditing purposeProductRepository.java
– Repository interface that extends theJpaRepository
interface to perform the SQL operationsProductService.java
– Service class that interact with the DAO layer methodsDefaultProductsLoader.java
– Bootstrap class to populate dummy data to the h2 database once the application is started successfullyEntityNotFoundException.java
– Exception class for throwing the not found exception when the entity is not present in the database. The exception class is annotated with the HTTP 404 error response codeProductDto.java
– The mapper class will be used for creating the response structure and during the update operation in order to receive the request body from the userProductResponse.java
– The mapper class which will be used for creating the response structure at the service layer
3.3.1 Implementation/Main class
Add the following code to the main class to bootstrap the application from the main method. Always remember, the entry point of the spring boot application is the class containing @SpringBootApplication
annotation and the static main method.
SpringDataJpaAuditingApplication.java
package com.springboot.jpa.auditing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import lombok.extern.slf4j.Slf4j; //lombok annotation @Slf4j //spring annotation @SpringBootApplication public class SpringDataJpaAuditingApplication { public static void main(String[] args) { SpringApplication.run(SpringDataJpaAuditingApplication.class, args); log.info("Spring boot and jpa auditing application"); } }
3.3.2 Auditing Entity class
The idea of this class is to provide attributes and columns for the table auditing. To have the auditing feature in the application we need to create a class that includes the following Spring JPA annotations: @CreatedBy
, @CreatedDate
, @LastModifiedBy
, and @LastModifiedDate
. To enable the auditing feature for any entity class we will need to extend this class and the entity class will be inherited with all the auditing related attributes defined in this class.
Auditable.java
package com.springboot.jpa.auditing.audit; import lombok.Getter; import lombok.Setter; 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.util.Date; //lombok annotations @Getter @Setter //spring auditing annotations //annotation designates a class whose mapping information is applied to the //entities that inherit from it. A mapped superclass has no separate table defined //for it @MappedSuperclass //specifies the callback listener classes to be used for an entity or mapped //superclass @EntityListeners(AuditingEntityListener.class) public class Auditable<U> { //updatable flag helps to avoid the override of //column's value during the update operation @CreatedBy @Column(name = "created_by", updatable = false) private U createdBy; //updatable flag helps to avoid the override of //column's value during the update operation @CreatedDate @Column(name = "created_date", updatable = false) @Temporal(TemporalType.TIMESTAMP) private Date creationDate; @LastModifiedBy @Column(name = "last_modified_by") private U lastModifiedBy; @LastModifiedDate @Column(name = "last_modified_date") @Temporal(TemporalType.TIMESTAMP) private Date lastModifiedDate; }
3.3.3 Configuration class
To enable the auditing feature in the application we need to have the configuration class annotated with the @EnableJpaAuditing
annotation and also specify that it will be using the AuditorAware
instance. The configuration class will also contain the Faker
object for auto wiring purposes.
BeanConfig.java
package com.springboot.jpa.auditing.config; import com.github.javafaker.Faker; 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; import java.util.Locale; import java.util.Optional; //spring annotation @Configuration //spring jpa audit annotation //annotation enables the auditing in jpa via annotation configuration @EnableJpaAuditing(auditorAwareRef = "aware") public class BeanConfig { //helps to aware the application's current auditor. //this is some kind of user mostly. @Bean public AuditorAware<String> aware() { return () -> Optional.of("Administrator"); } @Bean public Faker faker() { return new Faker(Locale.ENGLISH); } }
3.3.4 Controller class
Add the following code to the controller class to specify the different endpoints to fetch the data from the database.
ProductController.java
package com.springboot.jpa.auditing.controller; import com.springboot.jpa.auditing.dto.ProductDto; import com.springboot.jpa.auditing.dto.ProductResponse; import com.springboot.jpa.auditing.entity.Product; import com.springboot.jpa.auditing.exception.EntityNotFoundException; import com.springboot.jpa.auditing.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import java.util.List; //spring web annotations @RestController @RequestMapping("/api") public class ProductController { @Autowired ProductService service; //get all products //URL - http://localhost:9800/api/products @GetMapping("/products") @ResponseStatus(code = HttpStatus.OK) public List<ProductResponse> getProducts() { return service.getAll(); } //get product by id //URL - http://localhost:9800/api/product-by-id?id=1 @GetMapping("/product-by-id") @ResponseStatus(code = HttpStatus.OK) public ProductResponse getProduct(@RequestParam(name = "id") final int id) throws EntityNotFoundException { final Product p = service.getProduct(id); return ProductResponse.from(p); } //update the product by id //URL - http://localhost:9800/api/product-by-id?id=1 //sample request body - /* { "productName":"Natraj Rubber", "material":"Rubber", "price":"9.21", "promotionCode":"IncrediblePrice1020" } */ @PutMapping("/product-by-id") @ResponseStatus(code = HttpStatus.NO_CONTENT) public void updateProduct(@RequestParam(name = "id") final int id, @RequestBody final ProductDto dto) throws EntityNotFoundException { service.updateProduct(id, dto); } }
4. Run the Application
To execute the application, right-click on the SpringDataJpaAuditingApplication.java
class, Run As -> Java Application
.
5. Project Demo
When the application is started, open the Postman tool to hit the application endpoints. You are free to choose any tool of your choice. You can hit the get all products endpoint to fetch the product details and can later use the other endpoints to get the product by id or update an existing product by id.
Application endpoints
-- HTTP GET endpoints -- //get all books http://localhost:9800/api/products //get product by id http://localhost:9800/api/product-by-id?id=1 -- HTTP PUT endpoint -- //update product by id //sample HTTP POST request /* { "productName":"Natraj Rubber", "material":"Rubber", "price":"9.21", "promotionCode":"IncrediblePrice1020" } */ http://localhost:9800/api/product-by-id?id=1
That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!
6. Summary
In this section, you learned,
- Spring boot, Database auditing, and Lombok introduction
- Steps to implement database auditing in a spring boot application
You can download the sample application as an Eclipse project in the Downloads section.
7. Download the Project
This was an example of a Spring data JPA auditing application.
You can download the full source code of this example here: Spring Data JPA Auditing Example