์ฐ์ํํ ํฌ์ฝ์ค - ์คํ๊ณผ์ ๋ฐฑ์๋ API ์๋ฒ
๊ฐ์์ค ์์ฝ ๋ฐ ๊ด๋ฆฌ๋ฅผ ์ํ RESTful API ์๋ฒ์ ๋๋ค.
Spring Boot ๊ธฐ๋ฐ์ ๊ฐ์์ค ๊ด๋ฆฌ ์์คํ ๋ฐฑ์๋ API ์๋ฒ์ ๋๋ค. ํ์๊ณผ ๊ต์ง์์ ๊ฐ์์ค ์์ฝ, ๊ด๋ฆฌ์์ ๊ฐ์ด๋๋ผ์ธ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ถ๊ฐ๋ก ๊ณ ์ฅ ์ ๊ณ ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
- ๊ฐ์์ค ์์ฝ ๋ฑ๋ก
- ์์ฝ ์กฐํ (๋ชฉ๋ก/์์ธ)
- ์์ฝ ์์ ๋ฐ ์ทจ์
- ๋น๋ฐ๋ฒํธ ๊ธฐ๋ฐ ์์ฝ ๋ณดํธ
- ๊ฐ์์ค๋ณ ์ฌ์ฉ ๊ฐ์ด๋๋ผ์ธ ๋ฑ๋ก
- ๊ฐ์ด๋๋ผ์ธ ์กฐํ
- ํ์ผ ์ฒจ๋ถ (AWS S3 ์ฐ๋)
- ๊ฐ์์ค ๋ชฉ๋ก ์กฐํ
- ์ด๊ธฐ ๊ฐ์์ค ๋ฐ์ดํฐ ์๋ ์ค์
- JWT ๊ธฐ๋ฐ ๊ด๋ฆฌ์ ์ธ์ฆ
- ์ด๊ธฐ ๊ด๋ฆฌ์ ๊ณ์ ์๋ ์์ฑ
- ๊ฐ์์ค ๊ณ ์ฅ ์ ๊ณ
- ๊ฐ์์ค ๊ณ ์ฅ ์ ๊ณ ๋ชฉ๋ก ์กฐํ
- ๊ณ ์ฅ ์๋ฆฌ ์๋ฃ ์ฒ๋ฆฌ
- Spring Boot 3.x - ์ ํ๋ฆฌ์ผ์ด์ ํ๋ ์์ํฌ
- Spring Data JPA - ORM
- Spring Security - ์ธ์ฆ/์ธ๊ฐ
- Spring Web - RESTful API
- MySQL 8.0 - ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค
- Docker Compose - ์ปจํ ์ด๋ ์ค์ผ์คํธ๋ ์ด์
- AWS S3 - ํ์ผ ์คํ ๋ฆฌ์ง (์ด๋ฏธ์ง/๋ฌธ์)
- Spring Cloud AWS - AWS SDK ํตํฉ
- JWT (JSON Web Token) - ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ
- BCrypt - ๋น๋ฐ๋ฒํธ ์ํธํ
- Gradle (์ถ์ )
- Java 17+
- Docker & Docker Compose
- AWS ๊ณ์ (S3 ์ฌ์ฉ)
git clone [repository-url]
cd classroom-manager-backenddocker-compose up -dsrc/main/resources/application-local.yml ํ์ผ ์์ฑ:
# AWS S3 ์ค์
spring:
cloud:
aws:
s3:
bucket: {bucket ์ด๋ฆ}
credentials:
access-key: {access key}
secret-key: {secret-key}
# ๊ด๋ฆฌ์ ๊ณ์
admin:
super:
id: super_admin
password: super_admin
# JWT
jwt:
secret-key: {secret key}
# Frontend URL
front:
url: http://localhost:5173application-local.ymlํ์ผ์ ์ ๋ Git์ ์ปค๋ฐํ์ง ๋ง์ธ์.gitignore์ ์ถ๊ฐ๋์ด ์๋์ง ํ์ธํ์ธ์- ์ด์ ํ๊ฒฝ์์๋ ํ๊ฒฝ ๋ณ์ ๋๋ AWS Secrets Manager ์ฌ์ฉ ๊ถ์ฅ
# ๋ฏผ๊ฐํ ์ค์ ํ์ผ (๋ฐ๋์ ํฌํจ!)
application-local.yml
application-dev.yml
application-prod.yml
# ๊ธฐํ
.env
*.log
target/
build/# Gradle ์ฌ์ฉ ์
./gradlew bootRun --args='--spring.profiles.active=local'
# Maven ์ฌ์ฉ ์
./mvnw spring-boot:run -Dspring-boot.run.profiles=localIntelliJ IDEA์์ ์คํ:
- Run โ Edit Configurations
- Active profiles์
local์ ๋ ฅ - Apply โ OK
- ์คํ ๋ฒํผ ํด๋ฆญ
์๋ฒ๊ฐ http://localhost:8080์์ ์คํ๋ฉ๋๋ค.
src/main/resources/
โโโ application.yml # ๊ณตํต ์ค์ (Git์ ์ปค๋ฐ)
โโโ application-local.yml # ๋ก์ปฌ ๊ฐ๋ฐ (Git ์ ์ธ)
โโโ application-dev.yml # ๊ฐ๋ฐ ์๋ฒ (Git ์ ์ธ)
โโโ application-prod.yml # ์ด์ ์๋ฒ (Git ์ ์ธ)
spring:
application:
name: manager
datasource:
url: jdbc:mysql://localhost:3306/classroom_db?useSSL=false&allowPublicKeyRetrieval=true
username: classroom_user
password: classroom_user
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
open-in-view: false
hibernate:
ddl-auto: create # ์ด์: validate
properties:
hibernate:
format_sql: true
show-sql: true
cloud:
aws:
s3:
bucket: ${AWS_S3_BUCKET:default-bucket}
region:
static: "ap-northeast-2"
credentials:
access-key: ${AWS_ACCESS_KEY}
secret-key: ${AWS_SECRET_KEY}
admin:
super:
id: ${ADMIN_ID:super_admin}
password: ${ADMIN_PASSWORD:super_admin}
name: "์ ์ฒด ๊ด๋ฆฌ์"
contact: "010-0000-0000"
class:
code:
- "5413"
- "5414"
- "5527"
- "5507"
- "5508"
- "627-A"
- "627-B"
jwt:
access-token-expiration-day: 10
secret-key: ${JWT_SECRET_KEY}
front:
url: ${FRONT_URL:http://localhost:5173}# ๋ก์ปฌ ๊ฐ๋ฐ
./gradlew bootRun --args='--spring.profiles.active=local'
# ๊ฐ๋ฐ ์๋ฒ
./gradlew bootRun --args='--spring.profiles.active=dev'
# ์ด์ ์๋ฒ
java -jar build/libs/app.jar --spring.profiles.active=prod# Gradle ์ฌ์ฉ ์
./gradlew bootRun
# ๋๋ IDE์์ ์ง์ ์คํ์๋ฒ๊ฐ http://localhost:8080์์ ์คํ๋ฉ๋๋ค.
http://localhost:8080/api
# ์์ฝ ๋ชฉ๋ก ์กฐํ
GET /api/reservations/{roomCode}?yearMonth={yearMonth}
# ์์ฝ ์์ธ ์กฐํ
GET /api/reservations/detail/{reservationId}
# ์์ฝ ๋ฑ๋ก
POST /api/reservations
Content-Type: application/json
{
"memberId": "2021001",
"contact": "010-1234-5678",
"role": "STUDENT",
"roomCode": "5413",
"title": "์คํฐ๋",
"purpose": "์๊ณ ๋ฆฌ์ฆ ์คํฐ๋",
"startDate": "2024-01-15T09:00",
"endDate": "2024-01-15T11:00",
"password": "1234"
}
# ์์ฝ ์์
PUT /api/reservations/{reservationId}
Content-Type: application/json
{
"memberId": "2021001",
"contact": "010-1234-5678",
"role": "STUDENT",
"roomCode": "5413",
"title": "์คํฐ๋",
"purpose": "์๊ณ ๋ฆฌ์ฆ ์คํฐ๋",
"startDate": "2024-01-15T09:00",
"endDate": "2024-01-15T11:00",
"password": "1234"
}
# ์์ฝ ์ทจ์
DELETE /api/reservations/{reservationId}
Content-Type: application/json
{
"password":"1234"
}# ๊ฐ์ด๋๋ผ์ธ ๋ชฉ๋ก ์กฐํ
GET /api/guidelines
# ๊ฐ์ด๋๋ผ์ธ ์์ธ ์กฐํ
GET /api/guidelines/{guideLineId}
# ๊ฐ์ด๋๋ผ์ธ ๋ฑ๋ก (๊ด๋ฆฌ์)
POST /api/guidelines
Authorization: Bearer {jwt-token}
Content-Type: multipart/form-data
{
"guideLine": {
"roomCode": "5413",
"content": "๊ฐ์์ค ์ฌ์ฉ ๊ฐ์ด๋๋ผ์ธ"
},
"files": [ํ์ผ1, ํ์ผ2, ...]
}# ๊ฐ์์ค ๋ชฉ๋ก ์กฐํ
GET /api/classrooms# ๊ด๋ฆฌ์ ๋ก๊ทธ์ธ
POST /api/admins/login
Content-Type: application/json
{
"adminId": "super_admin",
"password": "super_admin"
}
# ์๋ต
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
}docker-compose.yml:
version: '3.8'
services:
mysql-db:
image: mysql:8.0
container_name: classroom-manager-db-container
restart: always
environment:
MYSQL_ROOT_PASSWORD: admin
MYSQL_DATABASE: "classroom_db"
MYSQL_USER: "classroom_user"
MYSQL_PASSWORD: "classroom_user"
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --default-time-zone=Asia/Seoul
volumes:
mysql-data:Host: localhost
Port: 3306
Database: classroom_db
Username: classroom_user
Password: classroom_user
์ ํ๋ฆฌ์ผ์ด์ ์์ ์ ์๋์ผ๋ก ์์ฑ๋๋ ๋ฐ์ดํฐ:
ID: super_admin
Password: super_admin
Role: SUPER_ADMIN
- 5413
- 5414
- 5527
- 5507
- 5508
- 627-A
- 627-B
erDiagram
MEMBER {
string member_id PK
string contact
string role
string name
}
ADMIN {
string admin_id PK
string name
string contact
string role
string authorization
string active
string password
}
CLASSROOM {
bigint room_id PK
string roomNumber UK
}
REPORT {
bigint report_id PK
string member_id FK
bigint room_id FK
datetime date
string item
string contact
string content
string status
}
RESERVATION {
bigint reservation_id PK
string member_id FK
bigint room_id FK
string purpose
datetime start_time
datetime end_time
}
GUIDELINE {
bigint guideline_id PK
bigint room_id FK
string content
}
FILE {
bigint file_id PK
string file_type
string file_url
string original_filename
bigint related_id
string related_type "REPORT, GUIDELINE, RESERVATION"
}
MEMBER ||--o{ REPORT : "report"
MEMBER ||--o{ RESERVATION : "reserve"
CLASSROOM ||--o{ RESERVATION : "has"
CLASSROOM ||--o{ REPORT : "is_related_to"
ADMIN ||--o{ GUIDELINE :"creates"
CLASSROOM ||--o{ GUIDELINE : "is_related_to"
REPORT ||..o{ FILE : "has"
RESERVATION ||..o{ FILE : "has"
GUIDELINE ||..o{ FILE : "has"
erDiagram
MEMBER {
string member_id PK
string contact
Role role "STUDENT, STAFF"
string name
}
ADMIN {
string admin_id PK
string name
string contact
string password
Role role "STUDENT, STAFF"
Authorization authorization "SUPER_ADMIN, ADMIN, EDITOR, VIEWER"
Active active "ACTIVE, INACTIVE"
}
CLASSROOM {
bigint room_id PK
string room_code UK
}
REPORT {
bigint report_id PK
string member_id FK
bigint room_id FK
datetime date
Item item "PROJECTOR, PC, SPEAKER, MICROPHONE"
string contact
string content
Status status "PENDING, COMPLETED"
}
RESERVATION {
bigint reservation_id PK
string member_id FK
bigint room_id FK
string purpose
datetime start_time
datetime end_time
}
GUIDELINE {
bigint guideline_id PK
bigint room_id FK
string admin_id FK
string content
}
FILE {
bigint file_id PK
string file_url
string file_type
string original_filename
bigint related_id
string related_type "REPORT, GUIDELINE, RESERVATION"
}
MEMBER ||--o{ REPORT : "report"
MEMBER ||--o{ RESERVATION : "reserve"
CLASSROOM ||--o{ RESERVATION : "has"
CLASSROOM ||--o{ REPORT : "is_related_to"
ADMIN ||--o{ GUIDELINE :"creates"
CLASSROOM ||--o{ GUIDELINE : "is_related_to"
dependencies {
// Spring Boot
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
// Database
runtimeOnly 'com.mysql:mysql-connector-j'
// AWS
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}# ์ปจํ
์ด๋ ์์
docker-compose up -d
# ์ปจํ
์ด๋ ์ค์ง
docker-compose down
# ๋ก๊ทธ ํ์ธ
docker-compose logs -f mysql-db
# MySQL ์ ์
docker exec -it classroom-manager-db-container mysql -u classroom_user -p# ์ปจํ
์ด๋ ๋ฐ ๋ณผ๋ฅจ ์ญ์ (๋ฐ์ดํฐ ์์ ์ญ์ )
docker-compose down -v
# ์ฌ์์
docker-compose up -d# ๋ก๊ทธ์ธ
curl -X POST http://localhost:8080/api/admins/login \
-H "Content-Type: application/json" \
-d '{"memberId":"super_admin","password":"super_admin"}'
# ์๋ต์์ ํ ํฐ ๋ณต์ฌ ํ ์ฌ์ฉ
curl -X GET http://localhost:8080/api/admins/something \
-H "Authorization: Bearer {your-token}"โ ๏ธ application.yml์ ์๋ AWS ํค์ JWT secret์ ์ ๋ Git์ ์ปค๋ฐํ์ง ๋ง์ธ์- ํ๊ฒฝ ๋ณ์ ๋๋
.envํ์ผ ์ฌ์ฉ ๊ถ์ฅ .gitignore์ ๋ค์ ์ถ๊ฐ:.env application-local.yml application-prod.yml
- ๊ฐ๋ฐ:
spring.jpa.hibernate.ddl-auto: create - ์ด์:
spring.jpa.hibernate.ddl-auto: validate๋๋none
- ํ๋ก ํธ์๋ URL์
front.url์ ์ ํํ ์ค์ - ์ด์ ํ๊ฒฝ์์๋ ๋๋ฉ์ธ ํ์ดํธ๋ฆฌ์คํธ ๊ด๋ฆฌ
Woowa-Tech-Course - ์คํ๊ณผ์