80 lines
4.0 KiB
Markdown
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`.
|