Complete, runnable Spring Boot reference for Lab 6: Students CRUD REST API. Use this to teach from in class, demo to students, and as a yardstick when grading.
| Layer | Library |
|---|---|
| Language | Java 21 |
| Build | Maven (Spring Boot 3.3.4) |
| Web | Spring Web (Tomcat) |
| Persistence | Spring Data JPA + Hibernate |
| Database | PostgreSQL 16 (via Docker) |
| Validation | Jakarta Bean Validation (Hibernate Validator) |
| Docs | springdoc-openapi (Swagger UI) |
| Test | JUnit 5 + Spring Boot Test + MockMvc |
docker compose up -d # starts postgres:16-alpine on :5432
docker compose ps # confirm "healthy"
mvn spring-boot:run
The app boots on http://localhost:8080 and seeds 3 students on first run.
| What | URL |
|---|---|
| API root | http://localhost:8080/api/students |
| Swagger UI | http://localhost:8080/swagger-ui.html |
| OpenAPI JSON | http://localhost:8080/v3/api-docs |
# stop the app: Ctrl+C
docker compose down # stop Postgres
docker compose down -v # ...and erase its data
docker exec -it students-api-db psql -U studentsapi -d studentsdb
# inside psql:
\dt # list tables
SELECT * FROM students;
\q
Open requests.http in VS Code (REST Client extension). Each ### block sends one request.
Or with curl:
curl -s http://localhost:8080/api/students | jq
curl -s -X POST http://localhost:8080/api/students \
-H 'Content-Type: application/json' \
-d '{"name":"Test","email":"t@x.com","course":"BCS","year":2}' | jq
| Method | URL | Body | Success | Errors |
|---|---|---|---|---|
GET |
/api/students |
— | 200 | — |
GET |
/api/students?course=BCS |
— | 200 | — |
GET |
/api/students/{id} |
— | 200 | 404 |
POST |
/api/students |
StudentCreate |
201 | 400, 409 |
PUT |
/api/students/{id} |
StudentUpdate |
200 | 400, 404, 409 |
DELETE |
/api/students/{id} |
— | 204 | 404 |
src/main/java/tz/ac/suza/wt/studentsapi/
├── StudentsApiApplication.java # @SpringBootApplication entry point
├── config/
│ └── DataSeeder.java # seeds 3 demo students on startup
├── controller/
│ └── StudentController.java # HTTP layer (thin — no business logic)
├── dto/
│ ├── StudentCreateDto.java # incoming JSON for POST
│ ├── StudentUpdateDto.java # incoming JSON for PUT
│ └── StudentResponseDto.java # outgoing JSON to clients
├── entity/
│ └── Student.java # JPA @Entity → "students" table
├── exception/
│ ├── EmailAlreadyUsedException.java
│ ├── GlobalExceptionHandler.java # @RestControllerAdvice + ProblemDetail
│ └── StudentNotFoundException.java
├── repository/
│ └── StudentRepository.java # extends JpaRepository
└── service/
└── StudentService.java # business logic + transactions
docker-compose.yml # Postgres for local development
Override the datasource via environment variables — no code changes:
export SPRING_DATASOURCE_URL=jdbc:postgresql://prod.example.com:5432/studentsdb
export SPRING_DATASOURCE_USERNAME=appuser
export SPRING_DATASOURCE_PASSWORD=$(cat /run/secrets/db_password)
For production schema management, replace spring.jpa.hibernate.ddl-auto=update
with validate and add Flyway or Liquibase migrations.
See lab06_walkthrough.md — the step-by-step
lecturer guide that builds this same project from start.spring.io.