📆 src
├ 📁 components // 재사용 가능한 UI contribute
├ 📁 pages // 라우트와 매핑되는 주요 페이지
├ 📁 routes // React Router 설정
├ 📁 services // API 통신 및 외부 서비스
└ 🗾 App.jsx // 루트 contribute
React Router를 사용한 SPA(Single Page Application) 라우트입니다.
| 건데 | 설명 |
|---|---|
/ → /login |
접근 시 로그인 페이지로 redirection |
/home |
메인 홈 페이지 |
/books |
전체 도서 목록 |
/books/:id |
특정 도서 상세 |
/create |
도서 생성 |
/edit/:id |
도서 편집 |
/my |
사용자가 등록한 도서 |
/ai-cover |
AI 커버 이미지 생성 페이지 |
📌 Navigate를 사용하여 /로 접근 시 /login으로 redirection 처리
OpenAI의 DALL·E 모델을 사용해 텍스트 프롬프트로 커버 이미지를 생성합니다.
export async function generateImageFromPrompt(apiKey, prompt, model, quality, style, size)
| 파라미터 | 설명 |
|---|---|
apiKey |
OpenAI API 키 |
prompt |
이미지 생성 프론프트 |
model |
사용 모델 (dall-e-3, dall-e-2) |
quality |
standard or hd (dall-e-3 전용) |
style |
vivid or natural (dall-e-3 전용) |
size |
이미지 크기 (기본: 1024x1024) |
dall-e-3과dall-e-2의 API 스텝 차이를 반영하여 옵션 동적 설정- 응답 데이터가 없거나 오류 시 예외 처리
- 유효하지 않은 사이즈 요청 시 기본값으로 자동 변경
const url = await generateImageFromPrompt(
OPENAI_API_KEY,
'A fantasy-style magical book cover with dragons and castles'
);
📆 사용자
└── [로그인]
└── /home → /create
└── [프론프트 입력 + generateImageFromPrompt 호출]
└── OpenAI API 호출
└── 이미지 URL 반환
└── 커버 이미지 미리보기 및 저장
- 이미지 응답 오류 시
throw new Error(...)로 예외 발생 → 프롬프트에서 Toast Notification 등 처리 필요 - API Key는
.env등을 통해 보안 관리 권장
- 프론프트 추천 기능 추가 (장르 기반 자동 제안)
- 사용자 생성 이미지 저장 이력 조회 기능
- 생성 이미지 수정 옵션 (re-roll, 업스케일 등)
| 기술 | 설명 |
|---|---|
React |
UI 프레임워크 |
React Router DOM |
SPA 라우트 관리 |
fetch API |
이미지 생성용 OpenAI API 요청 |
OpenAI DALL·E |
텍스트-이미지 생성 모델 |
Spring MVC 설정 클래스.
주요 역할:
- CORS 설정을 통해 **React 프론트엔드(포트 3000)**에서의 요청 허용
📌 허용 도메인: <http://localhost:3000>
📌 허용 메서드: GET, POST, PUT, PATCH, DELETE, OPTIONS
📌 allowCredentials: true
/api/books 경로로 도서 관련 API 제공.
| HTTP | URL | 기능 |
|---|---|---|
| POST | /api/books |
도서 등록 |
| GET | /api/books |
전체 도서 목록 조회 |
| GET | /api/books/{id} |
특정 도서 상세 조회 |
| PUT | /api/books/{id} |
도서 정보 수정 |
| DELETE | /api/books/{id} |
도서 삭제 |
기타 특징:
@CrossOrigin으로 CORS 허용 (localhost:3000)BookService에 실제 로직 위임
/api/users 경로로 사용자 관련 API 제공.
| HTTP | URL | 기능 |
|---|---|---|
| POST | /api/users |
사용자 등록 |
| GET | /api/users |
전체 사용자 조회 |
| POST | /api/users/login |
사용자 로그인 (이메일/비밀번호 기반) |
기타 특징:
LoginFailedException예외 발생 시 401 응답 처리UserService를 통해 사용자 로직 처리- 응답 시
UserResponseDto,UserLoginResponseDto사용
✅ DTO 설명 (Data Transfer Object)
도서 및 사용자 관련 데이터를 요청하거나 응답할 때 사용하는 객체입니다. Controller ↔ Service ↔ Entity 간 데이터 전달에 사용됩니다.
-
UserRequestDto사용자 등록 요청에 사용.
필드:
username,email,password -
UserResponseDto사용자 정보 응답에 사용.
필드:
userId,username,email -
UserLoginResponseDto로그인 응답 시 사용.
필드:
token(JWT 등),user(UserResponseDto)
-
BookRequestDto도서 등록/수정 요청에 사용.
필드:
title,description,coverImageUrl,userId -
BookResponseDto도서 정보 응답에 사용.
필드:
id,title,description,coverImageUrl,createdAt,updatedAt,userId,username
-
ErrorResponse에러 응답 포맷.
필드:
code(HTTP 상태 코드),status(error등),message(에러 메시지)
- 역할: 도서 관련 비즈니스 로직 처리
- 주요 메서드:
createBook(BookRequestDto dto): 도서 등록 (userId를 받아Users와 연관 지음)getAllBooks(): 모든 도서 조회getBook(Long id): 단일 도서 상세 조회updateBook(Long id, BookRequestDto dto): 도서 수정deleteBook(Long id): 도서 삭제
- 특징:
BookRepository와UserRepository를 활용- DTO ↔ Entity 변환
Users와Book간의 연관 관계 매핑 사용
- 역할: 사용자 관련 비즈니스 로직 처리
- 주요 메서드:
createUser(UserRequestDto dto): 사용자 회원가입getAllUsers(): 전체 사용자 목록 조회login(UserRequestDto dto): 사용자 로그인 (단순 로그인 로직 / JWT 미포함)
- 특징:
- 사용자 인증 처리 (실패 시
LoginFailedException발생) - 사용자 정보 응답 시
UserResponseDto사용
- 사용자 인증 처리 (실패 시
@ManyToOne→Users(도서를 작성한 사용자)- 필드:
title,description,coverImageUrl,createdAt,updatedAt
@OneToMany(mappedBy = "user")→List<Book>- 필드:
username,email,password,book(도서 목록)
📦 Controller
└── BookController
└── BookService
├── BookRepository
└── UserRepository (userId → Users 조회)
📦 Controller
└── UserController
└── UserService
└── UserRepository
Spring Data JPA를 활용하여 데이터베이스 접근을 추상화한 Repository 계층입니다. 복잡한 SQL 작성 없이 메서드 네이밍만으로 쿼리를 자동 생성할 수 있습니다.
- 도서 정보를 관리하는 JPA Repository
JpaRepository<Book, Long>상속 → 기본적인 CRUD 제공
public interface BookRepository extends JpaRepository<Book, Long> {
// 필요시 커스텀 쿼리 추가 가능
}- 사용자 정보를 관리하는 JPA Repository
- 이메일 기반 조회 기능을 위한 커스텀 메서드 추가
public interface UserRepository extends JpaRepository<Users, Long> {
Optional<Users> findByEmail(String email);
}📌 기능 요약
| 메서드 | 설명 |
|---|---|
findByEmail(String email) |
사용자의 이메일을 기반으로 Optional로 조회 |
| 기본 제공 메서드 | findById, findAll, save, deleteById 등 |
- 비즈니스 로직과 DB 로직 분리
- SQL 작성 없이 빠른 개발 가능
- 필요시
@Query또는 Querydsl로 확장 가능
비즈니스 로직을 처리하는 핵심 계층입니다. DTO를 통해 컨트롤러와의 데이터 흐름을 관리하고, DB 접근은 Repository를 통해 수행합니다.
📘 책 CRUD + 유저 연동
| 메서드 | 설명 |
|---|---|
createBook(BookRequestDto dto) |
책 생성 (제목, 설명, 이미지 URL, 유저 ID 필요) |
getAllBooks() |
전체 책 목록 조회 |
getBook(Long id) |
ID로 책 조회 |
updateBook(Long id, BookRequestDto dto) |
책 정보 수정 |
deleteBook(Long id) |
책 삭제 |
🔧 주요 특징:
BookRequestDto→ 엔티티 → 저장 →BookResponseDto변환- 책 저장 시 유저 존재 여부 확인
LocalDateTime.now()으로createdAt,updatedAt자동 설정- 예외 처리:
BookCreateException: 입력 값 유효성 실패BookNotFoundException: 해당 ID의 책이 없는 경우
👤 유저 조회 + 로그인 (회원가입 없음)
| 메서드 | 설명 |
|---|---|
getAllUsers() |
전체 유저 목록 조회 |
getUser(Long userId) |
ID로 유저 조회 |
deleteUser(Long userId) |
유저 삭제 |
login(UserRequestDto dto) |
이메일 & 패스워드 기반 로그인, 임시 토큰 발급 |
🔐 로그인 상세:
- 이메일로 유저 조회 (
findByEmail) - 비밀번호 일치 여부 확인
- 성공 시
UserLoginResponseDto반환 (토큰 + 유저 정보) - 실패 시
LoginFailedException예외 발생
로그인은 사전에 DB에 저장된 유저 정보만을 기반으로 작동합니다.
- DTO ↔ Entity 명확 분리
- 예외 처리로 사용자 경험 개선
- 추후 확장 용이 (예: JWT 토큰 발급, 회원가입 추가 가능)
spring:
datasource:
url: jdbc:h2:file:~/librarytestdb
driver-class-name: org.h2.Driver
username: sa
password: 1234
jpa:
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate:
format_sql: true
defer-datasource-initialization: true
h2:
console:
enabled: true
path: /h2-console
sql:
init:
mode: always
server:
port: 8081
- H2 DB: 파일 모드 (
~/librarytestdb) - 웹 콘솔 URL: http://localhost:8081/h2-console
- 접속 정보:
- JDBC URL:
jdbc:h2:file:~/librarytestdb - 사용자명:
sa - 비밀번호:
1234
- JDBC URL:
- JPA ddl-auto:
create→ 서버 실행 시 매번 테이블 새로 생성 - 서버 포트:
8081
⚠️ 회원가입 페이지는 제공하지 않으며,H2 DB에 미리 등록된 유저 정보로만 로그인이 가능합니다.
- 로그인 테스트를 위해
resources/data.sql에 사용자 정보와 책 데이터를 사전 삽입해야 합니다. - 직접 H2 콘솔에서 삽입해도 가능하지만, 초기화 자동화를 위해
data.sql사용을 권장합니다.
-- 유저 데이터 삽입
INSERT INTO users (user_id, username, email, password) VALUES
(1, 'testuser', '[email protected]', 'password123'),
(2, 'anotheruser', '[email protected]', 'password456');
-- 도서 데이터 삽입
INSERT INTO book (title, description, cover_image_url, created_at, updated_at, user_id) VALUES
('Spring Boot in Action', 'Spring Boot 설명서', '<https://example.com/spring.jpg>', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1),
('JPA with Hibernate', 'JPA를 활용한 ORM 설명서', '<https://example.com/jpa.jpg>', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1),
('React for Beginners', '프론트엔드 입문서', '<https://example.com/react.jpg>', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 2);
users테이블의user_id는 직접 지정book테이블의id는 auto-increment라 생략- 각 도서의
user_id는 등록된 사용자와 연관
본 프로젝트는 예외 상황을 명확히 분리하고, 사용자에게 의미 있는 응답을 제공하기 위해 커스텀 예외 클래스와 **전역 예외 처리기(GlobalExceptionHandler)**를 사용합니다.
| 예외 클래스명 | 설명 |
|---|---|
BookNotFoundException |
요청한 도서를 찾을 수 없을 때 발생 (404) |
BookCreateException |
도서 생성 중 오류가 발생했을 때 |
CoverNotFoundException |
도서 표지 이미지가 존재하지 않을 때 |
CoverGenerateException |
도서 표지 생성 중 오류가 발생했을 때 |
LoginFailedException |
로그인 정보가 일치하지 않을 때 (401) |
UserNotFoundException |
특정 사용자를 찾을 수 없을 때 발생 (404) |
public class LoginFailedException extends RuntimeException {
public LoginFailedException(String message) {
super(message);
}
}@RestControllerAdvice를 통해 모든 컨트롤러에서 발생하는 예외를 일괄 처리합니다.
| 예외 타입 | HTTP 상태코드 | 응답 메시지 예시 |
|---|---|---|
BookNotFoundException, UserNotFoundException |
404 Not Found |
해당 리소스가 존재하지 않습니다: [message] |
LoginFailedException |
401 Unauthorized |
로그인 실패: [message] (직접 핸들링 가능) |
IllegalArgumentException |
400 Bad Request |
잘못된 요청입니다: [message] |
| 그 외 모든 예외 | 500 Internal Server Error |
서버 내부 오류가 발생했습니다. |
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body("해당 사용자가 존재하지 않습니다: " + ex.getMessage());
}🔸 Note: LoginFailedException은 UserController 내부에서 try-catch로 처리되어 있으며, 추후 전역 예외 처리기로 이동시킬 수 있습니다.
- 예외별 메시지 및 상태코드 명확하게 관리
- 코드 중복 제거 및 유지보수 용이
- 사용자 중심의 응답 제공으로 UX 향상