๋์ ๋ณดํ ๊ด๋ฆฌ ์์คํ ์ Spring Boot ๊ธฐ๋ฐ ๋ฐฑ์๋ API ์๋ฒ์ ๋๋ค. ๋์ ๋ณดํ ๋ณดํ๋ฃ ๊ณ์ฐ, ๋ ์จ ์ ๋ณด ์ ๊ณต, AI ์ฑํ ์๋ด, OAuth2 ์์ ๋ก๊ทธ์ธ ๋ฑ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ํ๋ก์ ํธ ๊ฐ์
- ์ฃผ์ ๊ธฐ๋ฅ
- ๊ธฐ์ ์คํ
- ํ๋ก์ ํธ ๊ตฌ์กฐ
- API ๋ฌธ์
- ์ค์น ๋ฐ ์คํ
- ํ๊ฒฝ ์ค์
- ๋ฐฐํฌ
- ๊ฐ๋ฐ ๊ฐ์ด๋
๋์ ์ธ๊ณผ ๋์ ๋ณดํ ์ ๊ณต์๋ฅผ ์ํ ์ข ํฉ ๋์ ๋ณดํ ๊ด๋ฆฌ ์์คํ ์ ๋๋ค.
- ๋์ ๋ณดํ ๋ณดํ๋ฃ ๊ณ์ฐ: 67๊ฐ์ง ์๋ฌผ์ ๋ํ 4๊ฐ์ง ๋ณด์ฅ ์ ํ๋ณ ๋ณดํ๋ฃ ๊ณ์ฐ
- ์ค์๊ฐ ๋ ์จ ์ ๋ณด: OpenWeatherMap API๋ฅผ ํตํ ๋ ์จ ์๋ณด ์ ๊ณต
- AI ์๋ด ์๋น์ค: RAG ๊ธฐ๋ฐ ๋์ ๋ณดํ ๊ด๋ จ ์ง์์๋ต
- ๋ณดํ์ํ ๊ด๋ฆฌ: ์๋ฌผ๋ณ ๋ณดํ์ํ ์ ๋ณด ๋ฐ PDF ๋ฌธ์ ๊ด๋ฆฌ
- ์ฌ์ฉ์ ์ธ์ฆ: OAuth2 ๊ธฐ๋ฐ ์์ ๋ก๊ทธ์ธ
์ง์ ๋ณด์ฅ ์ ํ:
โข ์ํ๊ฐ์๋ณด์ฅ (HARVEST_REDUCTION)
โข ์์ฐ๋น๋ณด์ฅ (PRODUCTION_COST)
โข ์์์์ค ์์ฐ๋น๋ณด์ฅ (FACILITY_PRODUCTION_COST)
โข ์ํด๋ณด์ฅ (LOSS)
์ง์ ์๋ฌผ๊ตฐ:
โข ๋ฐญ์๋ฌผ (FIELD_CROPS)
โข ๊ณผ์์๋ฌผ (FRUIT_CROPS)
โข ์์์์ค (HORTICULTURAL_FACILITY)
โข ๋ฒผ๋งฅ๋ฅ (PADDY_CEREALS)
โข ๋ฒ์ฏ๋ฅ (MUSHROOMS)
- OAuth2 ์์ ๋ก๊ทธ์ธ (Google, Kakao, Naver ๋ฑ)
- JWT ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ
- Spring Security ์ ์ฉ
- WebSocket ๊ธฐ๋ฐ ์ค์๊ฐ ์ฑํ
- ๋ํ ์ปจํ ์คํธ ๊ด๋ฆฌ (์ฌ๋ผ์ด๋ฉ ์๋์ฐ ๋ฐฉ์)
- ๋น๋๊ธฐ ๋ฉ์์ง ์ฒ๋ฆฌ๋ก ์์ ๋ณด์ฅ
- ๋ํ ์์ฝ ๋ฐ ์บ์ฑ
- OpenWeatherMap API ์ฐ๋
- ์์ธ ์ง์ญ ์ค์๊ฐ ๋ ์จ
- ์ค๋/๋ด์ผ ์๋ณด ์ ๋ณด
- Framework: Spring Boot 3.5.0
- Language: Java 17
- Database: MySQL (Production), H2 (Test)
- Security: Spring Security + OAuth2 + JWT
- Build Tool: Gradle
- Web: Spring Web, Spring WebFlux
- Data: Spring Data JPA
- Security: Spring Security, OAuth2 Client, JWT
- Validation: Spring Validation
- Utils: Lombok
- Test: JUnit 5, Spring Boot Test
- Containerization: Docker
- Reverse Proxy: Nginx
- External APIs: OpenWeatherMap, FastAPI (AI Chat)
src/main/java/com/aivle/agriculture/
โโโ domain/
โ โโโ auth/ # ์ฌ์ฉ์ ์ธ์ฆ (OAuth2, JWT)
โ โโโ calculate/ # ๋ณดํ๋ฃ ๊ณ์ฐ ๋ก์ง
โ โโโ chat/ # AI ์ฑํ
์์คํ
โ โโโ detail/ # ๋ณดํ์ํ ์ธ๋ถ์ ๋ณด
โ โโโ mainpage/ # ๋ฉ์ธํ์ด์ง (๋ ์จ, ๋ณดํ์ ๋ณด)
โ โโโ test/ # ๊ฐ๋ฐ/ํ
์คํธ ์ ํธ๋ฆฌํฐ
โโโ global/
โ โโโ base/ # ๊ธฐ๋ณธ ์ํฐํฐ ํด๋์ค
โ โโโ config/ # ์ค์ ํด๋์ค๋ค
โ โโโ exception/ # ์์ธ ์ฒ๋ฆฌ
โ โโโ response/ # API ์๋ต ํ์คํ
โ โโโ security/ # ๋ณด์ ์ค์ (JWT, OAuth2)
โโโ AgricultureApplication.java
๊ฐ ๋๋ฉ์ธ์ ๋ค์๊ณผ ๊ฐ์ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ฆ ๋๋ค:
controller/ # REST API ์๋ํฌ์ธํธ
service/ # ๋น์ฆ๋์ค ๋ก์ง
repository/ # ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต
entity/ # JPA ์ํฐํฐ
dto/ # ๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด
GET /api/auth/login/{provider} # OAuth2 ๋ก๊ทธ์ธ ์์
GET /api/auth/success # ๋ก๊ทธ์ธ ์ฑ๊ณต ์ฝ๋ฐฑ
GET /api/auth/failure # ๋ก๊ทธ์ธ ์คํจ ํ์ด์งPOST /api/calc
Content-Type: application/json
{
"coverageType": "HARVEST_REDUCTION",
"cropType": "SWEET_POTATO",
"insuredAmount": 1000000,
"damageRate": 30.0,
"selfBurdenRate": 20.0,
"area": 1000
}POST /api/chat
Content-Type: application/json
{
"conversationId": "uuid-string",
"question": "๋ฒผ ๋์
๋ณดํ์ ๋ํด ์๋ ค์ฃผ์ธ์"
}// ์ฐ๊ฒฐ
const socket = new SockJS('/ws');
const stompClient = Stomp.over(socket);
// ๋ฉ์์ง ์ ์ก
stompClient.send('/app/chat.send', {}, JSON.stringify(message));
// ์๋ต ๊ตฌ๋
stompClient.subscribe('/queue/response', callback);GET /api/insurance/{cropType} # ์๋ฌผ๋ณ ๋ณดํ์ํ ์ ๋ณดGET /api/main # ๋ ์จ ์ ๋ณด + ๋ณดํ ์ ๋ณด- Java 17+
- MySQL 8.0+
- Gradle 7.0+
# ์ ์ฅ์ ํด๋ก
git clone <repository-url>
cd agriculture-backend
# ์์กด์ฑ ์ค์น ๋ฐ ๋น๋
./gradlew build
# ์ ํ๋ฆฌ์ผ์ด์
์คํ
./gradlew bootRun# Docker ์ด๋ฏธ์ง ๋น๋
docker build -t agriculture-backend .
# ์ปจํ
์ด๋ ์คํ
docker run -p 8080:8080 agriculture-backend# ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์
SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/agriculture
SPRING_DATASOURCE_USERNAME=username
SPRING_DATASOURCE_PASSWORD=password
# OAuth2 ์ค์
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENT_ID=your-google-client-id
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENT_SECRET=your-google-client-secret
# JWT ์ค์
JWT_SECRET_KEY=your-jwt-secret-key
JWT_EXPIRATION_TIME=86400000
# ์ธ๋ถ API ์ค์
OPENWEATHER_API_KEY=your-openweather-api-key
FASTAPI_BASE_URL=http://your-fastapi-server
# CORS ์ค์
URL_FRONTEND=http://localhost:3000
URL_TEMP=http://localhost:3001
URL_TEMP2=http://localhost:3002
URL_TEMP3=http://localhost:3003- CORS: ํ๋ก ํธ์๋ URL์ ๋ํ CORS ํ์ฉ
- Rate Limiting: Nginx๋ฅผ ํตํ ์์ฒญ ์๋ ์ ํ (IP๋น ์ด๋น 10๊ฑด)
- Connection Limiting: ๋์ ์ฐ๊ฒฐ ์ ํ (IP๋น 10๊ฐ)
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- mysql
mysql:
image: mysql:8.0
environment:
MYSQL_DATABASE: agriculture
MYSQL_ROOT_PASSWORD: password
ports:
- "3306:3306"
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx:/etc/nginx/conf.d
depends_on:
- app- ํ๊ฒฝ๋ณ์ ์ค์ ํ์ธ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ง์ด๊ทธ๋ ์ด์
- SSL ์ธ์ฆ์ ์ค์
- ๋ก๊ทธ ์์ง ์ค์
- ๋ชจ๋ํฐ๋ง ์ค์
- ๋ฐฑ์ ์ ๋ต ์๋ฆฝ
- ํจํค์ง ๊ตฌ์กฐ: ๋๋ฉ์ธ ์ค์ฌ ์ค๊ณ (Domain-Driven Design)
- ๋ค์ด๋ฐ: ํ๊ธ ์ฃผ์๊ณผ ์๋ฌธ ๋ณ์๋ช ๋ณํ
- API Response:
ResponseFactory๋ฅผ ํตํ ํ์คํ๋ ์๋ต ํ์ - ์์ธ ์ฒ๋ฆฌ: ์ ์ญ ์์ธ ์ฒ๋ฆฌ๊ธฐ ์ ์ฉ
domain/{domain-name}ํจํค์ง ์์ฑ- Controller, Service, Repository, Entity, DTO ํด๋์ค ์์ฑ
- ํ์์ Config ํด๋์ค์ ์ค์ ์ถ๊ฐ
- ํ ์คํธ ์ฝ๋ ์์ฑ
calculatorํจํค์ง์ ์ ๊ณ์ฐ๊ธฐ ํด๋์ค ์์ฑCalculator์ธํฐํ์ด์ค ๊ตฌํCalculateService์ ๊ณ์ฐ๊ธฐ ๋ฑ๋ก- ํด๋น ๋ณด์ฅ ์ ํ์
CoverageTypeenum์ ์ถ๊ฐ
ConversationContextManager: ๋ํ ์ปจํ ์คํธ ๊ด๋ฆฌ ๋ก์งChatWebSocketHandler: WebSocket ๋ฉ์์ง ์ฒ๋ฆฌ- ์ฃผ์์ฌํญ: ๋ฉ์์ง ์์ ๋ณด์ฅ์ ์ํด CompletableFuture ์ฒด์ด๋ ์ฌ์ฉ
- ๋ํ ์ปจํ ์คํธ: Spring Cache๋ฅผ ํตํ conversation ์บ์ฑ
- ์ฌ๋ผ์ด๋ฉ ์๋์ฐ: ์ต๊ทผ 10๊ฐ ๋ฉ์์ง๋ง ๋ฉ๋ชจ๋ฆฌ์ ์ ์ง
- ์์ฝ ์์คํ : 20๊ฐ ์ด์ ๋ฉ์์ง ์ ์ด์ ๋ํ ์์ฝ
- ์ธ๋ฑ์ฑ:
conversationId์ ๋ํ ์ธ๋ฑ์ค ์ค์ - ํ์ด์ง: ๋ํ ์ด๋ ฅ ์กฐํ ์ PageRequest ์ฌ์ฉ
- ์ง์ฐ ๋ก๋ธ:
@ManyToOne(fetch = FetchType.LAZY)์ ์ฉ