Spring Boot Gradle Project CRUD Example

In this tutorial, we'll build a simple CRUD (Create, Read, Update, Delete) application using Spring Boot, Spring Data JPA, H2 and Gradle. 

Prerequisites

Ensure you have the following installed:

  • Java Development Kit (JDK) 21: Download JDK
  • Gradle: Follow the installation steps for your operating system.

Verify your installations by running the following commands in your terminal:

java -version
gradle -v

Step 1: Initialize the Project

Create a new Spring Boot project using Spring Initializr:

  1. Visit Spring Initializr.
  2. Select the following options:
    • Project: Gradle Project
    • Language: Java
    • Spring Boot: 3.2.0 (or the latest stable version)
    • Project Metadata: Fill in Group, Artifact, Name, Description, and Package Name.
    • Packaging: Jar
    • Java: 21
  3. Add dependencies:
    • Spring Web
    • Spring Boot DevTools
    • Spring Data JPA
    • H2 Database (for in-memory database)
  4. Click on "Generate" to download the project zip file.
  5. Extract the zip file to your desired directory.

Navigate to the project directory:

cd <your-project-directory>

Step 2: Configure build.gradle

Open the build.gradle file and ensure it is configured correctly with the latest Spring Boot and dependency versions.

Example build.gradle

plugins {
    id 'org.springframework.boot' version '3.2.0'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '21'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

Explanation

  • plugins: Specifies the Gradle plugins used in the project. We're using the Spring Boot plugin, the Spring dependency management plugin, and the Java plugin.
  • group and version: Define the group ID and version of the project.
  • sourceCompatibility: Sets the Java version compatibility.
  • repositories: Specifies where to fetch the project dependencies from. mavenCentral is the central repository for Maven.
  • dependencies: Lists the project dependencies, including Spring Boot, Spring Data JPA, H2 database, and Spring Boot testing libraries.

Step 3: Create the Product Entity

Create a new Java class named Product.java in the src/main/java/com/example directory.

Example Product.java

package com.example;

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

@Entity
public class Product {

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

    public Product() {
    }

    public Product(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    // 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 Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

Explanation

  • @Entity: Marks this class as a JPA entity.
  • @Id: Specifies the primary key of the entity.
  • @GeneratedValue: Indicates that the ID should be generated automatically.
  • Constructor: Includes a default constructor and a parameterized constructor.
  • Getters and Setters: Standard methods to access and modify the fields of the entity.

Step 4: Create the Repository Layer

Create a new Java interface named ProductRepository.java in the src/main/java/com/example directory.

Example ProductRepository.java

package com.example;

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

public interface ProductRepository extends JpaRepository<Product, Long> {
}

Explanation

  • JpaRepository: This interface extends JpaRepository, providing CRUD operations for the Product entity. The generic parameters specify the entity type (Product) and the type of its primary key (Long).

Step 5: Create the Service Layer

Create a new Java class named ProductService.java in the src/main/java/com/example directory.

Example ProductService.java

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class ProductService {

    private final ProductRepository productRepository;

    @Autowired
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public List<Product> findAll() {
        return productRepository.findAll();
    }

    public Optional<Product> findById(Long id) {
        return productRepository.findById(id);
    }

    public Product save(Product product) {
        return productRepository.save(product);
    }

    public void deleteById(Long id) {
        productRepository.deleteById(id);
    }
}

Explanation

  • @Service: Marks this class as a service layer component.
  • ProductService: Provides methods to interact with the ProductRepository for CRUD operations.
  • Autowired: Injects the ProductRepository dependency.

Step 6: Create the Controller Layer

Create a new Java class named ProductController.java in the src/main/java/com/example directory.

Example ProductController.java

package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/products")
public class ProductController {

    private final ProductService productService;

    @Autowired
    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping
    public List<Product> getAllProducts() {
        return productService.findAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity<Product> getProductById(@PathVariable Long id) {
        Optional<Product> product = productService.findById(id);
        return product.map(ResponseEntity::ok)
                      .orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).build());
    }

    @PostMapping
    public ResponseEntity<Product> createProduct(@RequestBody Product product) {
        Product savedProduct = productService.save(product);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedProduct);
    }

    @PutMapping("/{id}")
    public ResponseEntity<Product> updateProduct(@PathVariable Long id, @RequestBody Product product) {
        Optional<Product> existingProduct = productService.findById(id);
        if (existingProduct.isPresent()) {
            product.setId(id);
            Product updatedProduct = productService.save(product);
            return ResponseEntity.ok(updatedProduct);
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
        productService.deleteById(id);
        return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
    }
}

Explanation

  • @RestController: Marks this class as a RESTful web service controller.
  • @RequestMapping: Maps HTTP requests to handler methods of the controller.
  • @GetMapping: Handles GET requests for retrieving products.
  • @PostMapping: Handles POST requests for creating a new product.
  • @PutMapping: Handles PUT requests for updating an existing product.
  • @DeleteMapping: Handles DELETE requests for deleting a product.

Step 7: Configure Application Properties

Open the src/main/resources/application.properties file and configure the H2 database settings.

Example application.properties

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

Explanation

  • spring.datasource.url: URL for the H2 in-memory database.
  • spring.datasource.driverClassName: Driver class name for the H2 database.
  • spring.datasource.username: Username for the database connection.
  • spring.datasource.password: Password for the database connection.
  • spring.jpa.database-platform: Dialect for the H2 database.
  • spring.h2.console.enabled: Enables the H2 database console for debugging.

Step 8: Run the Application

Run the Spring Boot application using Gradle.

./gradlew bootRun

Step 9: Running the Application

To package the application as a JAR and run it, execute the following command:

./gradlew build
java -jar build/libs/<your-application-name>.jar

Replace <your-application-name> with the actual name of your JAR file.

Explanation

  • ./gradlew bootRun: Runs the Spring Boot application using the Gradle wrapper.
  • ./gradlew build: Builds the Spring Boot application and packages it as a JAR file.
  • java -jar: Runs the packaged JAR file.

Testing the API

Use Postman to test the CRUD operations. Here are some example requests:

  • Create a Product (POST request to /api/products):

    {
      "name": "Product1",
      "price": 100.0
    }
    
  • Get All Products (GET request to /api/products)

  • Get a Product by ID (GET request to /api/products/{id})

  • Update a Product (PUT request to /api/products/{id}):

    {
      "name": "Updated Product",
      "price": 150.0
    }
    
  • Delete a Product (DELETE request to /api/products/{id})

Conclusion

In this tutorial, we have learned how to create a simple CRUD application using Spring Boot and Gradle. We covered the creation of the Product entity, repository, service, and controller layers. We also configured the H2 in-memory database and tested the application using Postman.

Comments