Spring Boot Demo
An interactive portfolio application demonstrating how I build a modern Spring Boot system from browser page to database. It replaces the original third-party API experiment with a self-contained demo: a Thymeleaf landing page, a live feature tour, secured REST APIs, JPA persistence, cache metrics, validation, error handling, and tested behaviour.
Live pages
| URL | Purpose |
|---|---|
/ |
Thymeleaf landing page based on my Spring portfolio content, with developer profile and contact details. |
/showcase |
Interactive jQuery AJAX tour. It calls the running controllers, shows JPA query results, creates a database record, reads a post twice, and displays live cache statistics. |
/api/posts |
Public paginated/searchable REST read API; POST, PUT, and DELETE require the EDITOR role. |
/api/showcase/cache |
Read-only Caffeine cache statistics for the feature tour. |
/actuator/health |
Public health check. |
Run it
Requires JDK 21+.
cd D:\app\springboot-jsonplaceholder-demo
./mvnw.cmd spring-boot:run
Open http://localhost:8080. The local profile uses an in-memory H2 database and automatically loads three sample posts for the feature tour.
The local editor account is intentionally a non-secret demo account:
username: demo-editor
password: changeit
The showcase form never pre-fills or stores credentials; it sends them only to the same local application for the authenticated request. Override them through APP_EDITOR_USERNAME and APP_EDITOR_PASSWORD.
What the feature tour proves
- Thymeleaf & MVC —
HomeControllerrenders/and/showcase; the index uses a server-side model for contact values. - jQuery AJAX & REST controllers — the browser calls
GET /api/posts,POST /api/posts,GET /api/posts/{id}, health, and cache-stat endpoints. Responses and errors are displayed directly in the page. - Spring Data JPA —
PostRepositoryprovides pagination and case-insensitive title search;PostServiceowns read/write transaction boundaries. - Caching — individual post reads use bounded Caffeine caching. The “Read twice” button produces real cache activity, then requests the cache-stat endpoint.
- Security — public portfolio pages and read APIs are open; data mutations require the
EDITORrole with BCrypt-backed, stateless HTTP Basic authentication. - Validation & error handling — request records validate input at the boundary and
ApiExceptionHandlerreturns consistent RFC-style problem documents. - Safe concurrent updates — the JPA
@Versionfield makes an outdated update return a conflict instead of silently overwriting a newer change. - Configuration management — typed cache and security settings live in application configuration. The
prodprofile uses PostgreSQL and requires database/editor environment variables with no committed production secrets.
Build and test
./mvnw.cmd test
./mvnw.cmd package
The integration test verifies the rendered Thymeleaf pages, unauthenticated versus editor-only API access, validation responses, search, and cache metrics.
Project layout
com.hoelee.demo
├── config typed cache and security configuration
├── post REST contract, JPA entity, repository, and service layer
├── support consistent API error mapping
└── web Thymeleaf pages, cache metrics, and local demo data
Each Java file has a compact learning note in the author/version comment format used by the larger reference application. The source uses 2024 timestamps in the requested evening window; the Git commits themselves retain their real creation times.
Production profile
SPRING_PROFILES_ACTIVE=prod selects PostgreSQL and requires:
APP_DB_URL
APP_DB_USERNAME
APP_DB_PASSWORD
APP_EDITOR_USERNAME
APP_EDITOR_PASSWORD
For production, use a managed secret store and add Flyway or Liquibase migrations before setting ddl-auto to validate.