Using SLF4J in Spring Boot with CRUD Operations

Introduction

SLF4J (Simple Logging Facade for Java) serves as a simple facade or abstraction for various logging frameworks (e.g., java.util.logging, logback, log4j). It allows users to plug in their desired logging framework at deployment time. Spring Boot, by default, uses Logback as its logging framework and provides out-of-the-box support for SLF4J. In this tutorial, we will learn how to configure and use SLF4J for logging in a Spring Boot application, covering a complete CRUD setup with service, controller, and repository layers.

Prerequisites

  1. Java Development Kit (JDK) 17 or later
  2. Apache Maven installed
  3. An IDE like IntelliJ IDEA or Eclipse

Step 1: Create a Spring Boot Project

You can create a Spring Boot project using Spring Initializr or your IDE.

Using Spring Initializr

  1. Go to Spring Initializr.
  2. Select the following options:
    • Project: Maven Project
    • Language: Java
    • Spring Boot: 3.0.0 or later
    • Group: com.example
    • Artifact: slf4j-demo
    • Name: slf4j-demo
    • Package name: com.example.slf4jdemo
    • Packaging: Jar
    • Java: 17 or later
  3. Add the following dependencies:
    • Spring Web
    • Spring Data JPA
    • H2 Database
  4. Click "Generate" to download the project zip file.
  5. Extract the zip file and open the project in your IDE.

Step 2: Add SLF4J Dependency

By default, Spring Boot includes SLF4J and Logback. However, if you want to explicitly include SLF4J and exclude Logback, modify your pom.xml file as follows:

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Starter Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- H2 Database -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Exclude default logging framework (Logback) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
        <scope>provided</scope>
    </dependency>

    <!-- SLF4J API -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>

    <!-- SLF4J Simple Logger (for demonstration purposes) -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>2.0.0</version>
    </dependency>
</dependencies>

In this example, we use slf4j-simple for demonstration purposes. In a real-world application, you might use logback-classic or another logging implementation.

Step 3: Configure Application Properties

Add the following properties to src/main/resources/application.properties:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

Step 4: Create the Entity Class

Create a new Java class named User in the com.example.slf4jdemo package:

package com.example.slf4jdemo;

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

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Step 5: Create the Repository Interface

Create a new Java interface named UserRepository in the com.example.slf4jdemo package:

package com.example.slf4jdemo;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

Step 6: Create the Service Class

Create a new Java class named UserService in the com.example.slf4jdemo package:

package com.example.slf4jdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserService.class);

    @Autowired
    private UserRepository userRepository;

    public List<User> findAll() {
        logger.info("Fetching all users");
        return userRepository.findAll();
    }

    public Optional<User> findById(Long id) {
        logger.info("Fetching user with id: {}", id);
        return userRepository.findById(id);
    }

    public User save(User user) {
        logger.info("Saving user: {}", user);
        return userRepository.save(user);
    }

    public void deleteById(Long id) {
        logger.info("Deleting user with id: {}", id);
        userRepository.deleteById(id);
    }
}

Step 7: Create the Controller Class

Create a new Java class named UserController in the com.example.slf4jdemo package:

package com.example.slf4jdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> getAllUsers() {
        logger.info("GET /users - Fetching all users");
        return userService.findAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        logger.info("GET /users/{} - Fetching user by id", id);
        return userService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        logger.info("POST /users - Creating user: {}", user);
        return userService.save(user);
    }

    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        logger.info("PUT /users/{} - Updating user: {}", id, user);
        return userService.findById(id)
                .map(existingUser -> {
                    user.setId(existingUser.getId());
                    return ResponseEntity.ok(userService.save(user));
                })
                .orElse(ResponseEntity.notFound().build());
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        logger.info("DELETE /users/{} - Deleting user", id);
        return userService.findById(id)
                .map(user -> {
                    userService.deleteById(id);
                    return ResponseEntity.noContent().build();
                })
                .orElse(ResponseEntity.notFound().build());
    }
}

Step 8: Run the Application

Run your Spring Boot application by executing the main method in the Slf4jDemoApplication class:

package com.example.slf4jdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Slf4jDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(Slf4jDemoApplication.class, args);
    }
}

Step 9: Test the Logging

Using Postman or curl

Create User

  • Method: POST
  • URL: http://localhost:8080/users
  • Body:
    {
        "name": "Ramesh Fadatare",
        "email": "ramesh.fadatare@example.com"
    }
    

Get All Users

  • Method: GET
  • URL: http://localhost:8080/users

Get User by ID

  • Method: GET
  • URL: http://localhost:8080/users/{id}

Update User

  • Method: PUT
  • URL: http://localhost:8080/users/{id}
  • Body:
    {
        "name": "Ram Jadhav",
        "email": "ram.jadhav@example.com"
    }
    

Delete User

  • Method: DELETE
  • URL: http://localhost:8080/users/{id}

Check the Console Output

Check the console output for the log messages corresponding to each API call.

Conclusion

In this tutorial, we built a set of CRUD REST APIs using Spring Boot 3+ and integrated SLF4J for logging. We covered the entire process from setting up the environment, creating the necessary models, repository, service, and controller layers, to testing the APIs. 

By following these steps, you can effectively use SLF4J for logging in your Spring Boot applications and manage CRUD operations seamlessly. This knowledge can be extended to create more complex and feature-rich applications with robust logging.

Comments