Spring Boot with MySQL

  • Last updated Apr 25, 2024

Spring Boot has gained significant popularity among developers due to its ability to simplify the development of Java-based applications, and MySQL remains one of the most widely used relational databases in the industry.

In this tutorial, you will learn how to build a Spring Boot application, establish a connection with a MySQL database, and create REST APIs for inserting, reading, updating, and deleting data from the MySQL database.


Follow these steps to complete this tutorial:

  1. Go to the Spring Initializr website at https://start.spring.io.
  2. Set up the project configuration:
    • Choose the project type (Maven or Gradle).
    • Set the language to Java.
    • Specify the Spring Boot version.
    • Enter a Group and Artifact name for your project. The group name is the id of the project. Artifact is the name of your project.
    • Add any necessary project metadata (description, package name, etc.).
    • Choose between packaging as a JAR (Java Archive) or a WAR (Web Application Archive) depends on how you plan to deploy your Spring Boot application. Choose JAR packaging if you want a standalone executable JAR file and WAR packaging if you intend to deploy your application to a Java EE application server or servlet container. When you package your Spring Boot application as a JAR using JAR packaging, it includes an embedded web server, such as Tomcat, by default. This means that you don't need to separately deploy your application to an external Tomcat server. Instead, you can run the JAR file directly, and the embedded Tomcat server will start and serve your application.
    • Select the Java version based on the compatibility requirements of your project. Consider the specific needs of your project, any compatibility requirements, and the Java version supported by your target deployment environment when making these choices.
  3. Add project dependencies:
    • Click on the "Add Dependencies" button.
    • Select the dependencies that your project requires (Spring Web, Spring Boot DevTools, MySQL Driver, Spring Data JPA, and Lombok).

    Refer to this image for example:



  4. Generate the project:
    • Click on the "Generate" button.
    • Spring Initializr will generate a zip file containing your Spring Boot project.
  5. Download and extract the generated project:
    • Download the zip file generated by Spring Initializr.
    • Extract the contents of the zip file to a directory on your local machine.
  6. Import the project into your IDE:
    • Open your preferred IDE (IntelliJ IDEA, Eclipse, or Spring Tool Suite).
    • Import the extracted project as a Maven or Gradle project, depending on the build system you chose in Spring Initializr.
  7. Add Configurations:
  8. Open the src/main/resources/application.properties file in your Eclipse editor and add the following configuration lines to the file:

    server.port= 8080
    
    #mysql database connection
    spring.datasource.url = jdbc:mysql://localhost:3306/test_buddy
    spring.datasource.username = root
    spring.datasource.password = Testing123
    spring.datasource.timeBetweenEvictionRunsMillis = 60000
    spring.datasource.maxIdle = 1
    
    #below properties will automatically creates and updates database schema
    spring.jpa.generate-ddl=true
    spring.jpa.hibernate.ddl-auto=update

    Here, server.port=8080 configuration line is used to specify the port number on which the server will listen for incoming requests. In this case, it sets the server port to 8080.

    spring.datasource.url: Specifies the URL for connecting to the MySQL database. In this example, it connects to a database named test_buddy on localhost at port 3306.

    spring.datasource.username and spring.datasource.password: Provide the credentials (username and password) for authenticating with the MySQL database.

    spring.datasource.timeBetweenEvictionRunsMillis: Sets the time interval (in milliseconds) between eviction runs for idle database connections.

    spring.datasource.maxIdle: Specifies the maximum number of idle connections in the connection pool.

    spring.jpa.generate-ddl=true: Instructs JPA to generate the necessary SQL scripts for creating database tables based on the entity classes.

    spring.jpa.hibernate.ddl-auto=update: Configures Hibernate (the JPA implementation) to automatically update the database schema when changes are detected in the entity classes.


  9. Implement your business logic by creating controllers, services, repositories, and other necessary components:
  10. Create a Student class that represents the student entity. This class can have properties such as id, firstName, lastName, email, etc., along with their getters and setters methods:

    package com.example.student.entity;
    
    import java.util.Date;
    import org.springframework.data.annotation.CreatedDate;
    import org.springframework.data.annotation.LastModifiedDate;
    import org.springframework.data.jpa.domain.support.AuditingEntityListener;
    import jakarta.persistence.Column;
    import jakarta.persistence.Entity;
    import jakarta.persistence.EntityListeners;
    import jakarta.persistence.GeneratedValue;
    import jakarta.persistence.GenerationType;
    import jakarta.persistence.Id;
    import jakarta.persistence.Table;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Builder
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @EntityListeners(AuditingEntityListener.class)
    @Entity
    @Table(name = "student")
    public class Student {
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       private Long id;
    
       @Column(name = "first_name")
       private String firstName;
    
       @Column(name = "last_name")
       private String lastName;
    
       @Column(name = "email")
       private String email;
    
       @Column(name = "mobile_number")
       private String mobileNumber;
    
       @Column(name = "date_of_birth")
       private Date dateOfBirth;
    
       @Column(name = "created_by")
       private String createdBy;
    
       @Column(name = "modified_by")
       private String modifiedBy;
    
       @CreatedDate
       @Column(name = "created")
       private Date created;
    
       @LastModifiedDate
       @Column(name = "modified")
       private Date modified;
    
    }

    Create a StudentRepository interface that represents a repository responsible for handling data access operations related to students:

    package com.example.student.repository;
    
    
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.repository.CrudRepository;
    import org.springframework.stereotype.Repository;
    import com.example.student.entity.Student;
    
    @Repository
    public interface StudentRepository extends CrudRepository<Student, Long> {
    
       public Page<Student> findAll(Pageable pageable);
    
    }

    Create a StudentRequest class as a Data Transfer Object (DTO) to represent the request payload for creating a student:

    package com.example.student.model;
    
    import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class StudentRequest {
    
      private Long studentId;
      private String firstName;
      private String lastName;
      private String email;
      private String mobileNumber;
      private String dateOfBirth;
    
    }

    StudentRequest should have properties such as firstName, lastName, email, etc., which correspond to the data you need to provide when creating a student. You can add more properties to the class as needed based on your specific requirements.


    Create a StudentResponse class as a Data Transfer Object (DTO) to represent the response for retrieving student information:

    package com.example.student.model;
    
    import java.util.Date;
    import lombok.Builder;
    import lombok.Data;
    
    @Builder
    @Data
    public class StudentResponse {
    
       private Long studentId;
       private String firstName;
       private String lastName;
       private String email;
       private String mobileNumber;
       private String dateOfBirth;
       private String createdBy;
       private String modifiedBy;
       private Date created;
       private Date modified;
    
    }

    In this example, the StudentResponse class represents the DTO for the response when retrieving student information. It includes properties such as firstName, lastName, email, studentId, etc., which correspond to the data you want to include in the response.


    Next, we will create classes to handle custom exceptions.  Custom exceptions allow you to create specific exception types for your application that can be thrown when certain exceptional situations occur.

    Let's start by creating a Java class named Error with three private fields: message, status, and timestamp. The use of Lombok @Data annotation will generate the getter and setter methods. This class represents data container that holds information related to an error:

    package com.example.exception.model;
    
    import lombok.Data;
    
    @Data
    public class Error {
       private String message;
       private int status;
       private Long timestamp;
    }

    Create a custom exception class named DataMissingException, which extends the RuntimeException class:

    package com.example.exception;
    
    public class DataMissingException extends RuntimeException {
       private static final long serialVersionUID = 1L;
    
       public DataMissingException(String message) {
          super(message);
       }
    
    }

    Extending RuntimeException indicates that DataMissingException is a subclass of the built-in RuntimeException class. It also means that our custom exception is an unchecked exception, meaning that it does not require explicit handling using try-catch blocks or declaring them in method signatures.


    Create a custom exception class named DataNotModifiedException, which extends the RuntimeException class:

    package com.example.exception;
    
    public class DataNotModifiedException extends RuntimeException {
       private static final long serialVersionUID = 1L;
    
       public DataNotModifiedException(String message) {
          super(message);
       }
    }

    Create a custom exception class named ResourceNotFoundException, which extends the RuntimeException class:

    package com.example.exception;
    
    public class ResourceNotFoundException extends RuntimeException {
       private static final long serialVersionUID = 1L;
    
       public ResourceNotFoundException(String message) {
          super(message);
       }
    }

    Create a custom exception class named InvalidDataException, which extends the RuntimeException class:

    package com.example.exception;
    
    public class InvalidDataException extends RuntimeException {
       private static final long serialVersionUID = 1L;
    
       public InvalidDataException(String message) {
          super(message);
       }
    }

    Create a Global Exception Handler class named GlobalExceptionHandlerController. The purpose of this class is to handle specific exceptions globally, providing consistent and customized error responses to clients when certain exceptions occur during the application's execution:

    package com.example.exception.controller;
    
    import java.util.Date;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import com.example.exception.DataMissingException;
    import com.example.exception.DataNotModifiedException;
    import com.example.exception.InvalidDataException;
    import com.example.exception.ResourceNotFoundException;
    import com.example.exception.model.Error;
    import jakarta.servlet.http.HttpServletRequest;
    
    @ControllerAdvice
    public class GlobalExceptionHandlerController {
    
      @ExceptionHandler(ResourceNotFoundException.class)
      public ResponseEntity<Object> resourceNotFound(ResourceNotFoundException ex,
          HttpServletRequest request) {
        Error error = new Error();
        error.setMessage(ex.getMessage());
        error.setTimestamp(new Date().getTime());
        error.setStatus(HttpStatus.NOT_FOUND.value());
        return new ResponseEntity<>(error, null, HttpStatus.NOT_FOUND);
      }
    
      @ExceptionHandler(InvalidDataException.class)
      public ResponseEntity<Object> invalidData(InvalidDataException ex, HttpServletRequest request) {
        Error error = new Error();
        error.setMessage(ex.getMessage());
        error.setTimestamp(new Date().getTime());
        error.setStatus(HttpStatus.BAD_REQUEST.value());
        return new ResponseEntity<>(error, null, HttpStatus.BAD_REQUEST);
      }
    
      @ExceptionHandler(DataMissingException.class)
      public ResponseEntity<Object> dataMissing(DataMissingException ex, HttpServletRequest request) {
        Error error = new Error();
        error.setMessage(ex.getMessage());
        error.setTimestamp(new Date().getTime());
        error.setStatus(HttpStatus.BAD_REQUEST.value());
        return new ResponseEntity<>(error, null, HttpStatus.BAD_REQUEST);
      }
    
      @ExceptionHandler(DataNotModifiedException.class)
      public ResponseEntity<Object> dataNotModified(DataNotModifiedException ex,
          HttpServletRequest request) {
        Error error = new Error();
        error.setMessage(ex.getMessage());
        error.setTimestamp(new Date().getTime());
        error.setStatus(HttpStatus.BAD_REQUEST.value());
        return new ResponseEntity<>(error, null, HttpStatus.BAD_REQUEST);
      }
    
    }

    Here, the class is annotated with @ControllerAdvice, which indicates that this class will provide advice (global exception handling) across all controllers. The methods within the class are annotated with @ExceptionHandler, which specifies that these methods will handle specific exceptions when they occur. In each method, a specific exception is caught (ResourceNotFoundException, MethodArgumentNotValidException, or DataMissingException). The method then creates an Error object, which is a custom model class that we earlier.

    The information from the caught exception is used to populate the Error object. In this example, the error message from the caught exception is set as the message in the Error object. The current timestamp is set using new Date().getTime(), and the appropriate HTTP status code is also set (e.g., HttpStatus.NOT_FOUND.value() for ResourceNotFoundException).

    Finally, a ResponseEntity is created, wrapping the Error object, and returned with the appropriate HTTP status code. This way, when one of these exceptions occurs, the framework will call the corresponding handler method to generate an error response with the necessary details.


    Next, create a utility class named CommonUtils. This class contains methods for converting dates to strings and strings to dates, as well as handling invalid data through a custom exception:

    package com.example.student.util;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import com.example.exception.InvalidDataException;
    
    public class CommonUtils {
    
      public static String convertDateToString(Date date) {
        if (date == null) {
          return "";
        }
        String pattern = "yyyy-MM-dd";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
      }
    
      public static Date convertStringToDate(String date) {
        if (date == null || date.isEmpty()) {
          return null;
        }
        String pattern = "yyyy-MM-dd";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        sdf.setLenient(false); // Disallow lenient parsing to ensure strict matching
    
        try {
          // Attempt to parse the date with the specified pattern
          return sdf.parse(date);
    
        } catch (ParseException e) {
          // If parsing fails, it means the date does not match the pattern,
          throw new InvalidDataException("dateOfBirth must be in yyyy-mm-dd format.");
        }
      }
    
    }

    Create a service interface that defines the contract for the StudentService. Create a new interface called StudentService:

    package com.example.student.service;
    
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import com.example.student.model.StudentRequest;
    import com.example.student.model.StudentResponse;
    
    public interface StudentService {
    
    	StudentResponse addStudent(StudentRequest studentRequest);
    
    	StudentResponse updateStudent(StudentRequest studentRequest);
    
    	void deleteStudent(Long studentId);
    
    	StudentResponse getStudentById(Long studentId);
    
    	Page<StudentResponse> getAllStudents(Pageable pageable);
    
    }

    Create an implementation class that implements the StudentService interface and handles the business logic. Let's create a class called StudentServiceImpl:

    package com.example.student.service.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageImpl;
    import org.springframework.data.domain.Pageable;
    import org.springframework.stereotype.Service;
    import com.example.exception.DataMissingException;
    import com.example.exception.DataNotModifiedException;
    import com.example.exception.ResourceNotFoundException;
    import com.example.student.entity.Student;
    import com.example.student.model.StudentRequest;
    import com.example.student.model.StudentResponse;
    import com.example.student.repository.StudentRepository;
    import com.example.student.service.StudentService;
    import com.example.student.util.CommonUtils;
    
    @Service
    public class StudentServiceImpl implements StudentService {
      private static final Logger LOGGER = LoggerFactory.getLogger(StudentServiceImpl.class);
    
      @Autowired
      private StudentRepository studentRepository;
    
      @Override
      public StudentResponse addStudent(StudentRequest studentRequest) {
        LOGGER.info("addStudent invoked...");
    
        if (studentRequest.getFirstName() == null || studentRequest.getFirstName().isEmpty()) {
          throw new DataMissingException("firstName is required.");
        }
        if (studentRequest.getLastName() == null || studentRequest.getLastName().isEmpty()) {
          throw new DataMissingException("lastName is required.");
        }
        if (studentRequest.getEmail() == null || studentRequest.getEmail().isEmpty()) {
          throw new DataMissingException("email is required.");
        }
    
        Student student = Student.builder().firstName(studentRequest.getFirstName())
            .lastName(studentRequest.getLastName()).email(studentRequest.getEmail())
            .mobileNumber(studentRequest.getMobileNumber())
            .dateOfBirth(CommonUtils.convertStringToDate(studentRequest.getDateOfBirth())).build();
    
        student = studentRepository.save(student);
    
        return StudentResponse.builder().studentId(student.getId())
            .firstName(student.getFirstName() != null ? student.getFirstName() : "")
            .lastName(student.getLastName() != null ? student.getLastName() : "")
            .email(student.getEmail() != null ? student.getEmail() : "")
            .mobileNumber(student.getMobileNumber())
            .dateOfBirth(CommonUtils.convertDateToString(student.getDateOfBirth()))
            .created(student.getCreated() != null ? student.getCreated() : null)
            .modified(student.getModified() != null ? student.getModified() : null)
            .createdBy(student.getCreatedBy() != null ? student.getCreatedBy() : "")
            .modifiedBy(student.getModifiedBy() != null ? student.getModifiedBy() : null).build();
      }
    
      @Override
      public StudentResponse updateStudent(StudentRequest studentRequest) {
        LOGGER.info("updateStudent invoked...");
    
        if (studentRequest.getStudentId() == null) {
          throw new IllegalArgumentException("studentId is required.");
        }
    
        Optional<Student> studentOpt = studentRepository.findById(studentRequest.getStudentId());
        if (!studentOpt.isPresent()) {
          throw new ResourceNotFoundException("student not found.");
        }
    
        Student existingStudent = studentOpt.get();
        boolean modified = false;
    
        if (studentRequest.getFirstName() != null && !studentRequest.getFirstName().contentEquals(
            existingStudent.getFirstName() != null ? existingStudent.getFirstName() : "")) {
          modified = true;
          existingStudent.setFirstName(studentRequest.getFirstName());
        }
        if (studentRequest.getLastName() != null && !studentRequest.getLastName().contentEquals(
            existingStudent.getLastName() != null ? existingStudent.getLastName() : "")) {
          modified = true;
          existingStudent.setLastName(studentRequest.getLastName());
        }
        if (studentRequest.getEmail() != null && !studentRequest.getEmail()
            .contentEquals(existingStudent.getEmail() != null ? existingStudent.getEmail() : "")) {
          modified = true;
          existingStudent.setEmail(studentRequest.getEmail());
        }
        if (studentRequest.getMobileNumber() != null && !studentRequest.getMobileNumber().contentEquals(
            existingStudent.getMobileNumber() != null ? existingStudent.getMobileNumber() : "")) {
          modified = true;
          existingStudent.setMobileNumber(studentRequest.getMobileNumber());
        }
        if (studentRequest.getDateOfBirth() != null && !studentRequest.getDateOfBirth().equals(
            existingStudent.getDateOfBirth() != null ? existingStudent.getDateOfBirth() : null)) {
          modified = true;
          existingStudent
              .setDateOfBirth(CommonUtils.convertStringToDate(studentRequest.getDateOfBirth()));
        }
    
        if (!modified) {
          throw new DataNotModifiedException("Data not modified because it is the same in the database.");
        }
    
        existingStudent = studentRepository.save(existingStudent);
    
        return StudentResponse.builder().studentId(existingStudent.getId())
            .firstName(existingStudent.getFirstName() != null ? existingStudent.getFirstName() : "")
            .lastName(existingStudent.getLastName() != null ? existingStudent.getLastName() : "")
            .email(existingStudent.getEmail() != null ? existingStudent.getEmail() : "")
            .mobileNumber(existingStudent.getMobileNumber())
            .dateOfBirth(CommonUtils.convertDateToString(existingStudent.getDateOfBirth()))
            .created(existingStudent.getCreated() != null ? existingStudent.getCreated() : null)
            .modified(existingStudent.getModified() != null ? existingStudent.getModified() : null)
            .createdBy(existingStudent.getCreatedBy() != null ? existingStudent.getCreatedBy() : "")
            .modifiedBy(
                existingStudent.getModifiedBy() != null ? existingStudent.getModifiedBy() : null)
            .build();
      }
    
      @Override
      public void deleteStudent(Long studentId) {
        LOGGER.info("deleteStudent invoked...");
        if (studentId == null) {
          throw new IllegalArgumentException("studentId is required.");
        }
        Optional<Student> studentOpt = studentRepository.findById(studentId);
        if (!studentOpt.isPresent()) {
          throw new ResourceNotFoundException("student not found.");
        }
        studentRepository.deleteById(studentId);
      }
    
      @Override
      public StudentResponse getStudentById(Long studentId) {
        LOGGER.info("getStudentById invoked...");
        if (studentId == null) {
          throw new IllegalArgumentException("studentId is required.");
        }
    
        Optional<Student> studentOpt = studentRepository.findById(studentId);
        if (!studentOpt.isPresent()) {
          throw new ResourceNotFoundException("student not found.");
        }
    
        Student existingStudent = studentOpt.get();
    
        return StudentResponse.builder().studentId(existingStudent.getId())
            .firstName(existingStudent.getFirstName() != null ? existingStudent.getFirstName() : "")
            .lastName(existingStudent.getLastName() != null ? existingStudent.getLastName() : "")
            .email(existingStudent.getEmail() != null ? existingStudent.getEmail() : "")
            .mobileNumber(existingStudent.getMobileNumber())
            .dateOfBirth(CommonUtils.convertDateToString(existingStudent.getDateOfBirth()))
            .created(existingStudent.getCreated() != null ? existingStudent.getCreated() : null)
            .modified(existingStudent.getModified() != null ? existingStudent.getModified() : null)
            .createdBy(existingStudent.getCreatedBy() != null ? existingStudent.getCreatedBy() : "")
            .modifiedBy(
                existingStudent.getModifiedBy() != null ? existingStudent.getModifiedBy() : null)
            .build();
      }
    
      @Override
      public Page<StudentResponse> getAllStudents(Pageable pageable) {
        LOGGER.info("getAllStudents invoked...");
        Page<Student> studentsPage = studentRepository.findAll(pageable);
    
        List<StudentResponse> studentsResponse = new ArrayList<>();
        Page<StudentResponse> studentsResponsePage = new PageImpl<>(studentsResponse, pageable, 0);
    
        if (studentsPage != null && !studentsPage.isEmpty()) {
    
          studentsPage.getContent().forEach(student -> {
    
            StudentResponse studentResponse = StudentResponse.builder().studentId(student.getId())
                .firstName(student.getFirstName() != null ? student.getFirstName() : "")
                .lastName(student.getLastName() != null ? student.getLastName() : "")
                .email(student.getEmail() != null ? student.getEmail() : "")
                .mobileNumber(student.getMobileNumber())
                .dateOfBirth(CommonUtils.convertDateToString(student.getDateOfBirth()))
                .created(student.getCreated() != null ? student.getCreated() : null)
                .modified(student.getModified() != null ? student.getModified() : null)
                .createdBy(student.getCreatedBy() != null ? student.getCreatedBy() : "")
                .modifiedBy(student.getModifiedBy() != null ? student.getModifiedBy() : null).build();
    
            studentsResponse.add(studentResponse);
          });
          studentsResponsePage =
              new PageImpl<>(studentsResponse, pageable, studentsPage.getTotalElements());
        }
        return studentsResponsePage;
      }
    
    }

    Create a controller class named StudentController. It will handle HTTP requests and interact with the StudentService:

    package com.example.student.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.web.PageableDefault;
    import org.springframework.data.web.SortDefault;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.DeleteMapping;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.PutMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import com.example.student.model.StudentRequest;
    import com.example.student.model.StudentResponse;
    import com.example.student.service.StudentService;
    
    @RequestMapping(path = "/students")
    @RestController
    public class StudentController {
    
    	@Autowired
    	private StudentService studentService;
    
    	@PostMapping(path = "/add")
    	public ResponseEntity<StudentResponse> addStudent(@RequestBody StudentRequest studentRequest) {
    		return ResponseEntity.ok(studentService.addStudent(studentRequest));
    	}
    
    	@PutMapping(path = "/update")
    	public ResponseEntity<StudentResponse> updateStudent(@RequestBody StudentRequest studentRequest) {
    		return ResponseEntity.ok(studentService.updateStudent(studentRequest));
    	}
    
    	@DeleteMapping(path = "/{studentId}/delete")
    	public void deleteStudent(@PathVariable(name = "studentId") Long studentId) {
    		studentService.deleteStudent(studentId);
    	}
    
    	@GetMapping(path = "/{studentId}")
    	public ResponseEntity<StudentResponse> getStudent(@PathVariable(name = "studentId") Long studentId) {
    		return ResponseEntity.ok(studentService.getStudentById(studentId));
    	}
    
    	@GetMapping(path = "/all")
    	public ResponseEntity<Page<StudentResponse>> getStudents(
    			@PageableDefault(page = 0, size = 30) @SortDefault.SortDefaults({
    					@SortDefault(sort = "modified", direction = Sort.Direction.DESC) }) Pageable pageable) {
    		
    		return ResponseEntity.ok(studentService.getAllStudents(pageable));
    	}
    
    }

    Annotate the main class with @EnableJpaAuditing annotation. It is used to enable auditing in JPA entities. Auditing allows automatic population of specific fields such as created and updated in JPA entities based on the current date and time. It is commonly used to keep track of when an entity was created or last modified. The main class should look like this:

    package com.example;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
    
    @EnableJpaAuditing
    @SpringBootApplication
    public class ExampleMysqlApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(ExampleMysqlApplication.class, args);
    	}
    
    }
    

  11. Run and Test your Application:
  12. Use your IDE's build tools (Maven or Gradle) to build your project and resolve dependencies. Once the build is successful, run the main class of your application. The Spring Boot application will start and deploy on an embedded web server (Tomcat) automatically. You should see logs indicating that the application has started.

    Use API testing tools (example: Postman) to test your application's endpoints and verify that your application is functioning as expected based on the implemented logic.

Congratulations! You have successfully created and run a Spring Boot project using Spring Initializr. You can continue developing your application by adding more features, configuring additional dependencies, and deploying it to various environments as needed.