Files

80 lines
4.0 KiB
Markdown

# 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+.
```powershell
cd D:\app\springboot-jsonplaceholder-demo
./mvnw.cmd spring-boot:run
```
Open [http://localhost:8080](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:
```text
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
1. **Thymeleaf & MVC**`HomeController` renders `/` and `/showcase`; the index uses a server-side model for contact values.
2. **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.
3. **Spring Data JPA**`PostRepository` provides pagination and case-insensitive title search; `PostService` owns read/write transaction boundaries.
4. **Caching** — individual post reads use bounded Caffeine caching. The “Read twice” button produces real cache activity, then requests the cache-stat endpoint.
5. **Security** — public portfolio pages and read APIs are open; data mutations require the `EDITOR` role with BCrypt-backed, stateless HTTP Basic authentication.
6. **Validation & error handling** — request records validate input at the boundary and `ApiExceptionHandler` returns consistent RFC-style problem documents.
7. **Safe concurrent updates** — the JPA `@Version` field makes an outdated update return a conflict instead of silently overwriting a newer change.
8. **Configuration management** — typed cache and security settings live in application configuration. The `prod` profile uses PostgreSQL and requires database/editor environment variables with no committed production secrets.
## Build and test
```powershell
./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
```text
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:
```text
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`.