spring-petclinic/README.md
2026-02-08 18:07:59 +05:30

153 lines
5.8 KiB
Markdown

Prerequisites
Java 17+
Docker (for PostgreSQL)
Maven
1. Start PostgreSQL
docker run --name petclinic-ff \
-e POSTGRES_DB=petclinic \
-e POSTGRES_USER=petclinic \
-e POSTGRES_PASSWORD=petclinic \
-p 5432:5432 \
-d postgres:15
2. Run Application
./mvnw spring-boot:run -Dspring.profiles.active=postgres
URLs:
App: http://localhost:8080
Flags API: http://localhost:8080/api/flags
H2 Console: http://localhost:8080/h2-console
Database: localhost:5432/petclinic (user: petclinic, pass: petclinic)
Feature Flags Implemented
Flag Key Controls Controller Method Strategy Examples
add-pet Add New Pet form PetController.initNewPetForm() Global OFF/ON, Percentage
add-visit Add Visit form VisitController.processNewVisit() Percentage rollout (50%)
owner-search Owner search OwnerController.processFindForm() Blacklist/Whitelist users
Behavior when OFF: Returns 403 Forbidden → redirects to /oups error page.
Feature Flag Strategies (Advanced)
Strategy Configuration Logic
GLOBAL {"enabled": true} Everyone ON/OFF
BLACKLIST {"users":["test@example.com"]} Blocks listed users
WHITELIST {"users":["admin@company.com"]} Only listed users
PERCENTAGE {"percentage":25} 25% of users randomly
Feature Flag Management API
GET /api/flags # List all flags
GET /api/flags/{key} # Get specific flag
POST /api/flags # Create flag
PUT /api/flags/{key} # Update flag
DELETE /api/flags/{key} # Delete flag
Example API Calls
1. Global OFF (blocks everyone):
curl -X POST http://localhost:8080/api/flags \
-H "Content-Type: application/json" \
-d '{
"flagKey": "add-pet",
"name": "Add New Pet",
"enabled": false,
"strategyType": "GLOBAL"
}'
2. Percentage Rollout (50% users):
curl -X POST http://localhost:8080/api/flags \
-H "Content-Type: application/json" \
-d '{
"flagKey": "add-visit",
"name": "Add Visit",
"enabled": true,
"strategyType": "PERCENTAGE",
"strategyValue": "{\"percentage\":50}"
}'
3. Blacklist specific user:
curl -X POST http://localhost:8080/api/flags \
-H "Content-Type: application/json" \
-d '{
"flagKey": "owner-search",
"name": "Owner Search",
"enabled": true,
"strategyType": "BLACKLIST",
"strategyValue": "{\"users\":[\"test@example.com\"]}"
}'
**Test with user email: Add ?email=test@example.com to flagged URLs.**
**Architecture Overview**
┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
│ PetClinic │◄──►│FeatureFlagService│◄──►│ PostgreSQL │
│ Controllers │ │ + Strategies │ │ feature_ │
│ │ │ │ │ flags table│
└─────────────────┘ └──────────────────┘ └─────────────┘
│ ▲
└──────────┬───────────┘
┌─────────────────┐
@FeatureFlag │ ← Custom Annotation + AOP
│ Aspect │
└─────────────────┘
**Key Implementation Features**
Custom-built (No FF4J/Togglz)
Database persistence (survives restarts)
4 Strategies: Global/Blacklist/Whitelist/Percentage
Custom Annotation @FeatureFlag("add-pet") + AOP
Helper function: featureFlagService.isFeatureEnabled(flagKey, userEmail)
Edge cases: Fail-open, JSON parsing errors, missing flags default ON
No authentication on flag API (per requirements)
**Code Locations**
src/main/java/org/springframework/samples/petclinic/model/
├── FeatureFlag.java # Entity
src/main/java/org/springframework/samples/petclinic/system/
├── FeatureFlag.java # @FeatureFlag annotation
src/main/java/org/springframework/samples/petclinic/service/
├── FeatureFlagService.java # Core logic + strategies
src/main/java/org/springframework/samples/petclinic/repository/
├── FeatureFlagRepository.java # JPA
src/main/java/org/springframework/samples/petclinic/controller/
├── FeatureFlagController.java # REST API
src/main/java/org/springframework/samples/petclinic/aop/
└── FeatureFlagAspect.java # AOP interceptor
Controllers with flags:
├── PetController.java # @FeatureFlag("add-pet")
├── VisitController.java # @FeatureFlag("add-visit")
└── OwnerController.java # @FeatureFlag("owner-search")
**Demo Script**
1. App running normally → All 3 features work
2. Create Global OFF flag → Add Pet → 403 Forbidden
3. Percentage flag → Add Visit works ~50% time (random)
4. Blacklist → Owner search blocked for test@example.com
5. Database → Flags persist after restart
6. CRUD → Create/Update/Delete via API
**Troubleshooting**
Issue Solution
AOP not working Add @EnableAspectJAutoProxy to PetClinicApplication.java
JSON parsing fails Check strategyValue format
Flags not persisting Verify Postgres connection
Package not found Use org.springframework.samples.petclinic.system
**Original Documentation**
For original PetClinic features, see Spring Petclinic.
🎥 Loom Video Walkthrough: [Insert Loom Link Here]
✨ Fully functional with advanced feature flag strategies, custom annotation, and production-ready code!