Spring Boot removes most configuration: an embedded server, auto-configured data source and one property file. REST controllers return JSON instead of views, which is how modern front ends consume the same student data.
Objectives
Do not copy. Read for understanding and the viva- Complete questions 29 to 32 of the manual: spring boot and rest controllers
- Prepare the deliverable before the lab and finish it during the session
- Be ready to explain every step in the viva
Questions Covered
Do not copy. Read for understanding and the viva| Question | Requirement | Status |
|---|---|---|
| Q29 | Create a Spring Boot application using Spring Initializer. Add the following… | Complete |
| Q30 | Configure Database settings through the property file in Spring Boot | Complete |
| Q31 | Create JPA Repositories for all entities used in the Student Admission lifecycle | Complete |
| Q32 | Create Rest Controller to fetch Student Information using JPA Repository; the response… | Complete |
Preparation
Do not copy. Read for understanding and the viva- Use Spring Initializr with the listed dependencies; the exact starter names are spring-boot-starter-web, spring-boot-starter-data-jpa, spring-boot-starter-thymeleaf, spring-boot-devtools, spring-boot-starter-actuator and the database driver.
- Database settings go in
application.properties: url, username, password,spring.jpa.hibernate.ddl-auto. - A
JpaRepository<Student, Long>interface needs no implementation; Spring generates it.
Sessions 7 to 10 build one project, admission-api. Each session adds files to it or replaces files from the session before. Every listing carries its path inside the project as a first-line comment. Nothing in these four sessions was executed here (no JDK, Maven or MySQL on this machine); every listing was checked by reading against the Spring Boot 3.3 and Spring Security 6 APIs.
Question 29
Problem Statement
Write in lab recordCreate a Spring Boot application using Spring Initializer. Add the following dependencies manually:
- Spring MVC
- Hibernate
- JPA
- Thymeleaf
- DevTool
- Actuator
- MySQL/MSSQL/Oracle/MongoDB (as per your choice) driver.
Solution
Write in lab recordSteps
- Open start.spring.io in a browser.
- Fill the left panel: Project
Maven, LanguageJava, Spring Boot3.3.4, Groupin.ignou, Artifactadmission-api, Nameadmission-api, Package namein.ignou.admission, PackagingJar, Java17. - Click
Add dependenciesand pick, one by one:Spring Web,Spring Data JPA,Thymeleaf,Spring Boot DevTools,Spring Boot Actuator,MySQL Driver. - Click
Generate; unzipadmission-api.zipinto your workspace. - Eclipse: File, Open Projects from File System, Directory, select the
admission-apifolder, Finish. Wait until Maven finishes downloading (bottom-right progress bar). - Open
pom.xmland compare with the listing below. If a dependency is missing, paste its block inside<dependencies>, save, then right-click the project, Maven, Update Project. - Run once: right-click the project, Run As, Spring Boot App (or
./mvnw spring-boot:runin a terminal).
Program
Lab record: every tab is one file of the answer. Write all of them.
<?xml version="1.0" encoding="UTF-8"?>
<!-- admission-api/pom.xml : generated by Spring Initializr, Spring Boot 3.3.4, Java 17 -->
<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>3.3.4</version>
<relativePath/>
</parent>
<groupId>in.ignou</groupId>
<artifactId>admission-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>admission-api</name>
<description>MCSL-222 Student Admission API (Sessions 7 to 10)</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- a. Spring MVC (embedded Tomcat, Jackson for JSON) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- b. Hibernate and c. JPA: one starter brings hibernate-core and Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- d. Thymeleaf view templates -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- e. DevTools: automatic restart on save -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- f. Actuator: /actuator/health, /actuator/metrics ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- g. MySQL driver -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</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>
</plugin>
</plugins>
</build>
</project>// src/main/java/in/ignou/admission/AdmissionApiApplication.java
package in.ignou.admission;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Entry point. @SpringBootApplication = @Configuration + @EnableAutoConfiguration
* + @ComponentScan of the package in.ignou.admission and everything below it.
*/
@SpringBootApplication
public class AdmissionApiApplication {
public static void main(String[] args) {
SpringApplication.run(AdmissionApiApplication.class, args);
}
}Output
Checked by reading, not executed. The first run stops before Tomcat starts because the data source is not configured yet; that is Question 30:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver classAfter Question 30 the same run ends with lines of this shape:
Tomcat initialized with port 8080 (http)
HikariPool-1 - Start completed.
Tomcat started on port 8080 (http) with context path '/'
Started AdmissionApiApplication in 4.1 seconds (process running for 4.6)Explanation
The seven items in the question map to six Maven artifacts. Spring MVC is spring-boot-starter-web (it also brings embedded Tomcat and Jackson). Hibernate and JPA arrive together in spring-boot-starter-data-jpa; Hibernate is the JPA implementation, so there is no separate starter. Thymeleaf, DevTools and Actuator are their own starters. The driver is mysql-connector-j with runtime scope because our code never imports a MySQL class; only JDBC needs it at run time. spring-boot-starter-parent fixes every version, so no <version> tag appears under the dependencies. @SpringBootApplication turns on auto-configuration and scans in.ignou.admission and its sub-packages for @Entity, @Repository, @Service and @Controller classes.
Question 30
Problem Statement
Write in lab recordConfigure Database settings through the property file in Spring Boot.
Solution
Write in lab recordSteps
- Start MySQL and create the schema:
mysql -u root -pthenCREATE DATABASE admission_db;. (ThecreateDatabaseIfNotExist=trueflag in the URL does the same job if the account may create schemas.) - Open
src/main/resources/application.properties(empty after Initializr) and paste the listing. - Change
spring.datasource.usernameandpasswordto your MySQL account. - Run the application; watch the console for
HikariPool-1 - Start completed.
Configuration
# src/main/resources/application.properties (Session 7, Q30)
spring.application.name=admission-api
server.port=8080
# --- MySQL connection ---
# create the schema first: CREATE DATABASE admission_db;
spring.datasource.url=jdbc:mysql://localhost:3306/admission_db?createDatabaseIfNotExist=true&serverTimezone=Asia/Kolkata
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# --- JPA / Hibernate ---
# update = create missing tables and columns from the @Entity classes, never drop
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
# --- seed data (src/main/resources/data.sql) ---
# run data.sql after Hibernate has created the tables, on a real (non-embedded) DB
spring.jpa.defer-datasource-initialization=true
spring.sql.init.mode=alwaysOutput
Checked by reading. Expected console lines on a successful start:
HikariPool-1 - Starting...
HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@5c3b1f2a
HikariPool-1 - Start completed.
HHH000412: Hibernate ORM core version 6.5.3.Final
HHH10001005: Database info:
Database JDBC URL [jdbc:mysql://localhost:3306/admission_db]
Database driver: com.mysql.cj.jdbc.Driver
Database version: 8.0.36A wrong password fails at the pool, not at the query:
HikariPool-1 - Exception during pool initialization.
java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)Explanation
| Property | Effect |
|---|---|
spring.datasource.url | JDBC URL; host, port, schema and flags. serverTimezone stops the “server time zone value is unrecognized” error. |
spring.datasource.username, password | MySQL account. Boot creates a HikariCP pool from these. |
spring.datasource.driver-class-name | Optional; Boot infers it from the URL. Kept so the driver name is visible in the record. |
spring.jpa.hibernate.ddl-auto=update | Hibernate compares entities with tables at start and issues CREATE TABLE or ALTER TABLE ADD as needed. It never drops columns. Use validate in production. |
spring.jpa.show-sql=true | Prints every SQL statement; useful evidence for the lab record. |
spring.jpa.defer-datasource-initialization=true | Runs data.sql after Hibernate has created the tables. Without it the inserts run first and fail. |
spring.sql.init.mode=always | Boot runs data.sql only for embedded databases by default; always enables it for MySQL. |
Question 31
Problem Statement
Write in lab recordCreate JPA Repositories for all entities used in the Student Admission lifecycle.
Solution
Write in lab recordSteps
- Create the package
in.ignou.admission.entityand addStudent,Programme,Course,Admissionand the enumAdmissionStatus. - Create the package
in.ignou.admission.repositoryand add one interface per entity extendingJpaRepository<Entity, Long>. - Run the application. With
ddl-auto=updateandshow-sql=truethe console prints thecreate tablestatements the first time. - Check in MySQL:
USE admission_db; SHOW TABLES;listsadmission,course,programme,student.
Program
The life cycle has four entities. A Student applies to a Programme; the application is an Admission whose status moves APPLIED, VERIFIED, APPROVED or REJECTED; a Programme owns Courses.
Lab record: every tab is one file of the answer. Write all of them.
// src/main/java/in/ignou/admission/entity/Student.java
package in.ignou.admission.entity;
import java.time.LocalDate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
/** Applicant. Maps to table `student` (Hibernate default: snake_case of the class name). */
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 80)
private String name;
@Column(nullable = false, unique = true, length = 120)
private String email;
@Column(length = 15)
private String phone;
@Column(length = 60)
private String city;
private LocalDate dateOfBirth;
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; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public LocalDate getDateOfBirth() { return dateOfBirth; }
public void setDateOfBirth(LocalDate dateOfBirth) { this.dateOfBirth = dateOfBirth; }
}// src/main/java/in/ignou/admission/entity/Programme.java
package in.ignou.admission.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
/** A degree programme such as MCA or BCA. Table `programme`. */
@Entity
public class Programme {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 10)
private String code;
@Column(nullable = false, length = 100)
private String name;
private int durationYears;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getDurationYears() { return durationYears; }
public void setDurationYears(int durationYears) { this.durationYears = durationYears; }
}// src/main/java/in/ignou/admission/entity/Course.java
package in.ignou.admission.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
/** One course inside a programme. Table `course`, FK column `programme_id`. */
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 10)
private String code;
@Column(nullable = false, length = 120)
private String title;
private int credits;
@ManyToOne(optional = false)
@JoinColumn(name = "programme_id")
private Programme programme;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public int getCredits() { return credits; }
public void setCredits(int credits) { this.credits = credits; }
public Programme getProgramme() { return programme; }
public void setProgramme(Programme programme) { this.programme = programme; }
}// src/main/java/in/ignou/admission/entity/AdmissionStatus.java
package in.ignou.admission.entity;
/** Life cycle of one application. Stored as a string column by @Enumerated(EnumType.STRING). */
public enum AdmissionStatus {
APPLIED, VERIFIED, APPROVED, REJECTED
}// src/main/java/in/ignou/admission/entity/Admission.java
package in.ignou.admission.entity;
import java.time.LocalDate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
/** A student applying to a programme. Table `admission`, FKs `student_id` and `programme_id`. */
@Entity
public class Admission {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "student_id")
private Student student;
@ManyToOne(optional = false)
@JoinColumn(name = "programme_id")
private Programme programme;
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 10)
private AdmissionStatus status = AdmissionStatus.APPLIED;
private LocalDate appliedOn = LocalDate.now();
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Student getStudent() { return student; }
public void setStudent(Student student) { this.student = student; }
public Programme getProgramme() { return programme; }
public void setProgramme(Programme programme) { this.programme = programme; }
public AdmissionStatus getStatus() { return status; }
public void setStatus(AdmissionStatus status) { this.status = status; }
public LocalDate getAppliedOn() { return appliedOn; }
public void setAppliedOn(LocalDate appliedOn) { this.appliedOn = appliedOn; }
}One repository per entity:
Lab record: every tab is one file of the answer. Write all of them.
// src/main/java/in/ignou/admission/repository/StudentRepository.java
package in.ignou.admission.repository;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import in.ignou.admission.entity.Student;
/** No implementation needed: Spring Data generates it at start-up from the method names. */
public interface StudentRepository extends JpaRepository<Student, Long> {
Optional<Student> findByEmail(String email);
List<Student> findByCityIgnoreCase(String city);
}// src/main/java/in/ignou/admission/repository/ProgrammeRepository.java
package in.ignou.admission.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import in.ignou.admission.entity.Programme;
public interface ProgrammeRepository extends JpaRepository<Programme, Long> {
Optional<Programme> findByCode(String code);
}// src/main/java/in/ignou/admission/repository/CourseRepository.java
package in.ignou.admission.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import in.ignou.admission.entity.Course;
public interface CourseRepository extends JpaRepository<Course, Long> {
/** Walks the association: course.programme.code = ?1 */
List<Course> findByProgrammeCode(String programmeCode);
}// src/main/java/in/ignou/admission/repository/AdmissionRepository.java
package in.ignou.admission.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import in.ignou.admission.entity.Admission;
import in.ignou.admission.entity.AdmissionStatus;
public interface AdmissionRepository extends JpaRepository<Admission, Long> {
List<Admission> findByStatus(AdmissionStatus status);
List<Admission> findByStudentId(Long studentId);
}Output
Checked by reading. Hibernate 6.5 with the MySQL dialect generates DDL of this shape on the first start (order may differ):
create table programme (
duration_years integer not null,
id bigint not null auto_increment,
code varchar(10) not null,
name varchar(100) not null,
primary key (id)
) engine=InnoDB;
alter table programme add constraint UK_programme_code unique (code);
create table student (
date_of_birth date,
id bigint not null auto_increment,
phone varchar(15),
city varchar(60),
name varchar(80) not null,
email varchar(120) not null,
primary key (id)
) engine=InnoDB;
alter table student add constraint UK_student_email unique (email);
create table course (
credits integer not null,
id bigint not null auto_increment,
programme_id bigint not null,
code varchar(10) not null,
title varchar(120) not null,
primary key (id)
) engine=InnoDB;
alter table course add constraint FK_course_programme foreign key (programme_id) references programme (id);
create table admission (
applied_on date,
id bigint not null auto_increment,
programme_id bigint not null,
student_id bigint not null,
status enum ('APPLIED','VERIFIED','APPROVED','REJECTED') not null,
primary key (id)
) engine=InnoDB;And the start-up log names the repositories it built:
Bootstrapping Spring Data JPA repositories in DEFAULT mode.
Finished Spring Data repository scanning in 41 ms. Found 4 JPA repository interfaces.Explanation
JpaRepository<T, ID> already declares save, findById, findAll, existsById, count, deleteById and paging variants. Spring Data creates a proxy class for each interface at start-up, so no implementation is written. Extra methods are derived from their names: findByCityIgnoreCase(String) becomes select s from Student s where upper(s.city) = upper(?1); findByProgrammeCode(String) walks the programme association and compares programme.code. A misspelt property name fails at start-up with No property 'citty' found for type 'Student', which is the check that the name is right.
Hibernate default naming converts dateOfBirth to date_of_birth and the class name Student to table student. The @ManyToOne fields become foreign-key columns named by @JoinColumn. @Enumerated(EnumType.STRING) stores APPROVED as text; without it Hibernate stores the ordinal 2, which breaks the moment someone reorders the enum.
Question 32
Problem Statement
Write in lab recordCreate Rest Controller to fetch Student Information using JPA Repository; the response should display in JSON format.
Solution
Write in lab recordSteps
- Create the package
in.ignou.admission.weband addStudentRestController. - Add
data.sqlundersrc/main/resourcesso the table has rows to fetch (the properties from Question 30 already enable it). - Restart the application. Handler mappings are logged only at DEBUG level, so the request test below is the real check.
- Run the curl commands in a terminal, or open
http://localhost:8080/api/studentsin a browser.
Program
Lab record: every tab is one file of the answer. Write all of them.
// src/main/java/in/ignou/admission/web/StudentRestController.java (Session 7, Q32: read only)
package in.ignou.admission.web;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import in.ignou.admission.entity.Student;
import in.ignou.admission.repository.StudentRepository;
/**
* @RestController = @Controller + @ResponseBody: every return value is written
* to the HTTP body as JSON by Jackson instead of being resolved as a view name.
*/
@RestController
@RequestMapping("/api/students")
public class StudentRestController {
private final StudentRepository students;
// one constructor: Spring injects the repository, no @Autowired needed
public StudentRestController(StudentRepository students) {
this.students = students;
}
/** GET /api/students or GET /api/students?city=Jaipur */
@GetMapping
public List<Student> all(@RequestParam(required = false) String city) {
return city == null ? students.findAll() : students.findByCityIgnoreCase(city);
}
/** GET /api/students/1 -> 200 with the student, or 404 with an empty body */
@GetMapping("/{id}")
public ResponseEntity<Student> one(@PathVariable Long id) {
return students.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}-- src/main/resources/data.sql : seed rows, runs at every start-up.
-- Explicit ids + INSERT IGNORE so a second start-up does not duplicate rows (MySQL syntax).
INSERT IGNORE INTO programme (id, code, name, duration_years) VALUES
(1, 'MCA', 'Master of Computer Applications', 2),
(2, 'BCA', 'Bachelor of Computer Applications', 3);
INSERT IGNORE INTO course (id, code, title, credits, programme_id) VALUES
(1, 'MCS-221', 'Data Warehousing and Data Mining', 4, 1),
(2, 'MCSL-222', 'Web Technologies Lab', 2, 1),
(3, 'BCS-011', 'Computer Basics and PC Software', 3, 2);
INSERT IGNORE INTO student (id, name, email, phone, city, date_of_birth) VALUES
(1, 'Asha Verma', 'asha@example.com', '9876543210', 'Jaipur', '2002-03-14'),
(2, 'Ravi Kumar', 'ravi@example.com', '9123456780', 'Patna', '2001-11-02');
INSERT IGNORE INTO admission (id, student_id, programme_id, status, applied_on) VALUES
(1, 1, 1, 'APPLIED', '2026-07-01'),
(2, 2, 1, 'APPROVED', '2026-06-20');Output
Checked by reading. Every endpoint with its curl command and expected response:
curl -s http://localhost:8080/api/students[{"id":1,"name":"Asha Verma","email":"asha@example.com","phone":"9876543210","city":"Jaipur","dateOfBirth":"2002-03-14"},
{"id":2,"name":"Ravi Kumar","email":"ravi@example.com","phone":"9123456780","city":"Patna","dateOfBirth":"2001-11-02"}]curl -s http://localhost:8080/api/students/1{"id":1,"name":"Asha Verma","email":"asha@example.com","phone":"9876543210","city":"Jaipur","dateOfBirth":"2002-03-14"}curl -s "http://localhost:8080/api/students?city=patna"[{"id":2,"name":"Ravi Kumar","email":"ravi@example.com","phone":"9123456780","city":"Patna","dateOfBirth":"2001-11-02"}]curl -i http://localhost:8080/api/students/99HTTP/1.1 404
Content-Length: 0The console shows the SQL Hibernate ran for the first call:
Hibernate: select s1_0.id,s1_0.city,s1_0.date_of_birth,s1_0.email,s1_0.name,s1_0.phone from student s1_0Explanation
@RestController is @Controller plus @ResponseBody: the returned List<Student> is not a view name, it is handed to Jackson, which walks the getters and writes JSON with Content-Type: application/json. LocalDate is written as 2002-03-14 because Boot registers the JavaTimeModule and turns off timestamp output. The constructor takes StudentRepository; with one constructor Spring injects it without @Autowired. ResponseEntity is used only where the status code varies: findById returns an Optional, map(ResponseEntity::ok) gives 200 with a body, orElse(notFound()) gives 404 with none. @RequestParam(required = false) lets the same method serve the full list and the filtered list.
Viva Questions
Do not copy. Read for understanding and the viva- Q: What does
@SpringBootApplicationcombine? A:@Configuration,@EnableAutoConfigurationand@ComponentScanon the package of the class. - Q: Why is there no
<version>under each dependency? A:spring-boot-starter-parentmanages versions through its dependencyManagement section, so all starters agree. - Q: What does
ddl-auto=updatedo and why not use it in production? A: It adds missing tables and columns from the entities at start-up. It never drops or renames, so the schema drifts; production usesvalidatewith migration scripts. - Q: How does Spring Data implement
findByCityIgnoreCasewithout code? A: It parses the method name into a JPQL query at start-up and generates a proxy that runs it. - Q: What is the difference between
@Controllerand@RestController? A:@RestControlleradds@ResponseBody, so return values are written to the response as JSON instead of resolved as view names. - Q: Why does
data.sqlneeddefer-datasource-initialization? A: Boot runs SQL scripts before JPA starts by default; deferring runs them after Hibernate created the tables. - Q: Why is
mysql-connector-jscopedruntime? A: Our code compiles against JDBC interfaces only; the driver is needed only when the application runs. - Q: What does
Optional.map(ResponseEntity::ok).orElse(notFound().build())return for a missing id? A: AResponseEntitywith status 404 and an empty body.
Common Mistakes
Do not copy. Read for understanding and the viva- Choosing Spring Boot 2.x on Initializr and then writing
jakarta.persistenceimports; 2.x usesjavax.persistenceand nothing compiles. - Placing entity or controller packages outside
in.ignou.admission; component scan never finds them and the endpoint returns 404 with no error in the log. - Forgetting
spring.sql.init.mode=always, sodata.sqlis silently skipped on MySQL and every GET returns[]. - Using
@EnumeratedwithoutEnumType.STRING, storing ordinals that break when the enum changes. - Adding a getter-less field to an entity and wondering why it is missing from the JSON; Jackson serialises getters.
- Running before MySQL is up. The pool fails with
Communications link failure, which students misread as a code error.
Session Summary
Write in lab record- Initializr settings and the
pom.xmlwith the six starters plus the MySQL driver application.propertieswith the datasource,ddl-auto=update,show-sqland thedata.sqlswitches- Entity classes
Student,Programme,Course,Admissionand theAdmissionStatusenum, with the generatedCREATE TABLEstatements - The four
JpaRepositoryinterfaces with their derived query methods StudentRestControllerwith the four curl calls and their JSON responses, including the 404 case