mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2026-02-12 09:11:12 +00:00
153 lines
5.8 KiB
Markdown
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!
|