Skip to content

Commit 9853f62

Browse files
feat: add AWS S3 integration for product image management
* feat: add AWS S3 integration for product image management * fix few things * fix test
1 parent 47c4929 commit 9853f62

File tree

15 files changed

+1480
-61
lines changed

15 files changed

+1480
-61
lines changed

.cursor/commands/datajpatest-context.md

Whitespace-only changes.

README.md

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
# Product Image Management with AWS S3
2+
3+
This Spring Boot application provides a complete product management system with image upload and download capabilities using Amazon S3 for storage.
4+
5+
## Features
6+
7+
- **Product Management**: Create, read, update, and delete products
8+
- **Image Upload**: Upload product images to Amazon S3
9+
- **Image Download**: Download and display product images from S3
10+
- **Web Interface**: Simple HTML interface for testing functionality
11+
- **REST API**: Complete REST API for product and image management
12+
13+
## Prerequisites
14+
15+
- Java 21+
16+
- Maven 3.6+
17+
- PostgreSQL database
18+
- AWS Account with S3 access
19+
- AWS CLI configured (optional, for local development)
20+
21+
## Setup Instructions
22+
23+
### 1. Quick Local Setup (Recommended)
24+
25+
For local development and testing, we use MinIO (S3-compatible storage) and PostgreSQL via Docker:
26+
27+
```bash
28+
# Run the setup script
29+
./setup-local.sh
30+
31+
# Or manually start services
32+
docker compose -f docker-compose-db-only.yml up -d
33+
```
34+
35+
This will start:
36+
- **PostgreSQL** on port 5333
37+
- **MinIO** (S3-compatible) on port 9000 (API) and 9001 (Console)
38+
- **MinIO bucket initialization** (creates `product-images` bucket)
39+
40+
### 2. Manual Database Setup
41+
42+
**Option A: Use Docker (Recommended)**
43+
```bash
44+
docker compose -f docker-compose-db-only.yml up -d
45+
```
46+
47+
**Option B: Local PostgreSQL**
48+
- Install PostgreSQL
49+
- Create a database named `jfs`
50+
- Update `application.properties` with your database credentials
51+
52+
### 3. Local Development Configuration
53+
54+
The application is pre-configured for local development with MinIO:
55+
56+
```properties
57+
# Database Configuration
58+
spring.datasource.url=jdbc:postgresql://localhost:5333/jfs
59+
spring.datasource.username=amigoscode
60+
spring.datasource.password=password
61+
62+
# AWS S3 Configuration (MinIO for local development)
63+
aws.region=us-east-1
64+
aws.s3.bucket=product-images
65+
aws.s3.endpoint-override=http://localhost:9000
66+
aws.s3.path-style-enabled=true
67+
aws.access-key-id=minioadmin
68+
aws.secret-access-key=minioadmin123
69+
```
70+
71+
### 4. Production AWS S3 Configuration
72+
73+
For production deployment with real AWS S3:
74+
75+
#### Create S3 Bucket
76+
1. Log into AWS Console
77+
2. Go to S3 service
78+
3. Create a new bucket (e.g., `your-product-images-bucket`)
79+
4. Note the bucket name for configuration
80+
81+
#### Configure AWS Credentials
82+
83+
**Option A: AWS CLI (Recommended for local development)**
84+
```bash
85+
aws configure
86+
```
87+
88+
**Option B: Environment Variables**
89+
```bash
90+
export AWS_ACCESS_KEY_ID=your_access_key
91+
export AWS_SECRET_ACCESS_KEY=your_secret_key
92+
export AWS_DEFAULT_REGION=us-east-1
93+
```
94+
95+
**Option C: IAM Roles (for EC2/ECS deployment)**
96+
- Attach appropriate IAM role with S3 permissions
97+
98+
#### Update Application Properties for Production
99+
100+
```properties
101+
# AWS S3 Configuration (Production)
102+
aws.region=us-east-1
103+
aws.s3.bucket=your-product-images-bucket
104+
aws.s3.endpoint-override=
105+
aws.s3.path-style-enabled=false
106+
aws.access-key-id=${AWS_ACCESS_KEY_ID}
107+
aws.secret-access-key=${AWS_SECRET_ACCESS_KEY}
108+
```
109+
110+
### 5. Required S3 Permissions
111+
112+
Your AWS credentials need the following S3 permissions:
113+
114+
```json
115+
{
116+
"Version": "2012-10-17",
117+
"Statement": [
118+
{
119+
"Effect": "Allow",
120+
"Action": [
121+
"s3:GetObject",
122+
"s3:PutObject",
123+
"s3:DeleteObject",
124+
"s3:HeadObject"
125+
],
126+
"Resource": "arn:aws:s3:::your-product-images-bucket/*"
127+
},
128+
{
129+
"Effect": "Allow",
130+
"Action": [
131+
"s3:ListBucket"
132+
],
133+
"Resource": "arn:aws:s3:::your-product-images-bucket"
134+
}
135+
]
136+
}
137+
```
138+
139+
## Running the Application
140+
141+
### 1. Start Local Services
142+
```bash
143+
# Quick setup (recommended)
144+
./setup-local.sh
145+
146+
# Or manually
147+
docker compose -f docker-compose-db-only.yml up -d
148+
```
149+
150+
### 2. Build the Application
151+
```bash
152+
mvn clean package
153+
```
154+
155+
### 3. Run the Application
156+
```bash
157+
mvn spring-boot:run
158+
```
159+
160+
Or run the JAR file:
161+
```bash
162+
java -jar target/product-service.jar
163+
```
164+
165+
### 4. Access the Application
166+
- **Web Interface**: http://localhost:8080
167+
- **API Base URL**: http://localhost:8080/api/v1/products
168+
- **MinIO Console**: http://localhost:9001 (minioadmin/minioadmin123)
169+
170+
## API Endpoints
171+
172+
### Product Management
173+
- `GET /api/v1/products` - Get all products
174+
- `GET /api/v1/products/{id}` - Get product by ID
175+
- `POST /api/v1/products` - Create new product (JSON)
176+
- `POST /api/v1/products` - Create new product with image (multipart/form-data)
177+
- `PUT /api/v1/products/{id}` - Update product
178+
- `DELETE /api/v1/products/{id}` - Delete product
179+
180+
### Image Management
181+
- `POST /api/v1/products/{id}/image` - Upload product image
182+
- `GET /api/v1/products/{id}/image` - Download product image
183+
184+
## Usage Examples
185+
186+
### Create a Product with Image
187+
188+
**Using the Web Interface:**
189+
1. Open http://localhost:8080
190+
2. Fill in the product form
191+
3. Select an image file
192+
4. Click "Create Product"
193+
194+
**Using cURL (Single Request - Recommended):**
195+
```bash
196+
# Create product with image in single request
197+
curl -X POST http://localhost:8080/api/v1/products \
198+
-F "name=Sample Product" \
199+
-F "description=A sample product description" \
200+
-F "price=29.99" \
201+
-F "stockLevel=100" \
202+
-F "image=@/path/to/image.jpg"
203+
```
204+
205+
**Using cURL (Separate Requests):**
206+
```bash
207+
# Create product first
208+
curl -X POST http://localhost:8080/api/v1/products \
209+
-H "Content-Type: application/json" \
210+
-d '{
211+
"name": "Sample Product",
212+
"description": "A sample product description",
213+
"price": 29.99,
214+
"stockLevel": 100
215+
}'
216+
217+
# Upload image (replace {product-id} with actual ID)
218+
curl -X POST http://localhost:8080/api/v1/products/{product-id}/image \
219+
-F "file=@/path/to/image.jpg"
220+
```
221+
222+
### Download Product Image
223+
```bash
224+
curl -O http://localhost:8080/api/v1/products/{product-id}/image
225+
```
226+
227+
## Project Structure
228+
229+
```
230+
src/
231+
├── main/
232+
│ ├── java/com/amigoscode/
233+
│ │ ├── config/
234+
│ │ │ └── AwsS3Config.java # AWS S3 configuration
235+
│ │ ├── product/
236+
│ │ │ ├── Product.java # Product entity
237+
│ │ │ ├── ProductController.java # REST controller
238+
│ │ │ ├── ProductService.java # Business logic
239+
│ │ │ ├── ProductImageService.java # Image handling service
240+
│ │ │ └── ProductRepository.java # Data access
241+
│ │ └── storage/
242+
│ │ └── S3StorageService.java # S3 operations
243+
│ └── resources/
244+
│ ├── static/
245+
│ │ └── index.html # Web interface
246+
│ └── application.properties # Configuration
247+
```
248+
249+
## Docker Deployment
250+
251+
### Build Docker Image
252+
```bash
253+
mvn jib:build
254+
```
255+
256+
### Run with Docker Compose
257+
```bash
258+
docker compose up -d
259+
```
260+
261+
## Testing
262+
263+
### Unit Tests
264+
```bash
265+
mvn test
266+
```
267+
268+
### Integration Tests
269+
```bash
270+
mvn verify
271+
```
272+
273+
## Troubleshooting
274+
275+
### Common Issues
276+
277+
1. **MinIO Connection Issues (Local Development)**
278+
- Ensure MinIO is running: `docker ps | grep minio`
279+
- Check MinIO logs: `docker logs jfs-minio-local`
280+
- Verify MinIO is accessible: `curl http://localhost:9000/minio/health/live`
281+
- Access MinIO console at http://localhost:9001
282+
283+
2. **AWS Credentials Not Found (Production)**
284+
- Ensure AWS credentials are properly configured
285+
- Check environment variables or AWS CLI configuration
286+
287+
3. **S3 Bucket Access Denied**
288+
- Verify bucket name in configuration
289+
- Check IAM permissions for S3 access
290+
- For MinIO: ensure bucket exists and is public
291+
292+
4. **Database Connection Issues**
293+
- Ensure PostgreSQL is running: `docker ps | grep postgres`
294+
- Check database logs: `docker logs jfs-postgres-local`
295+
- Verify database credentials in application.properties
296+
297+
5. **Image Upload Fails**
298+
- Check file size limits
299+
- Verify image file format is supported
300+
- Ensure S3/MinIO bucket exists and is accessible
301+
- Check MinIO bucket policy: should be public for downloads
302+
303+
### Logs
304+
Check application logs for detailed error messages:
305+
```bash
306+
tail -f logs/application.log
307+
```
308+
309+
## Security Considerations
310+
311+
- Use IAM roles instead of access keys when possible
312+
- Implement proper CORS configuration for production
313+
- Add authentication and authorization as needed
314+
- Consider using S3 pre-signed URLs for direct uploads
315+
- Implement file type validation and size limits
316+
317+
## Contributing
318+
319+
1. Fork the repository
320+
2. Create a feature branch
321+
3. Make your changes
322+
4. Add tests
323+
5. Submit a pull request
324+
325+
## License
326+
327+
This project is licensed under the MIT License.

docker-compose-db-only.yml

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,47 @@ services:
1414
networks:
1515
- amigos
1616

17+
minio:
18+
container_name: jfs-minio-local
19+
image: minio/minio:latest
20+
command: server /data --console-address ":9001"
21+
environment:
22+
MINIO_ROOT_USER: minioadmin
23+
MINIO_ROOT_PASSWORD: minioadmin123
24+
ports:
25+
- "9000:9000" # API port
26+
- "9001:9001" # Console port
27+
restart: unless-stopped
28+
volumes:
29+
- minio-data:/data
30+
networks:
31+
- amigos
32+
healthcheck:
33+
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
34+
interval: 30s
35+
timeout: 20s
36+
retries: 3
37+
38+
minio-init:
39+
container_name: jfs-minio-init
40+
image: minio/mc:latest
41+
depends_on:
42+
minio:
43+
condition: service_healthy
44+
entrypoint: >
45+
/bin/sh -c "
46+
/usr/bin/mc alias set myminio http://minio:9000 minioadmin minioadmin123;
47+
/usr/bin/mc mb myminio/product-images --ignore-existing;
48+
/usr/bin/mc policy set public myminio/product-images;
49+
exit 0;
50+
"
51+
networks:
52+
- amigos
53+
1754
networks:
1855
amigos:
1956
driver: bridge
2057

2158
volumes:
22-
db-local:
59+
db-local:
60+
minio-data:

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ services:
99
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/jfs
1010
SPRING_DATASOURCE_USERNAME: amigoscode
1111
SPRING_DATASOURCE_PASSWORD: password
12+
SPRING_PROFILES_ACTIVE: aws
1213
ports:
1314
- "8090:8080"
1415
networks:

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@
8686
<artifactId>spring-boot-starter-webflux</artifactId>
8787
<scope>test</scope>
8888
</dependency>
89+
<dependency>
90+
<groupId>software.amazon.awssdk</groupId>
91+
<artifactId>s3</artifactId>
92+
<version>2.21.29</version>
93+
</dependency>
8994
</dependencies>
9095

9196
<build>

0 commit comments

Comments
 (0)