🧠 AI 브레인스토밍 플랫폼 개발 일지 - Day 3
📅 작업 일자
2025년 11월 26일 (Day 3)
🎯 오늘의 목표
- Service 계층 완성
- Service 테스트 코드 작성
- DTO 계층 설계 및 구현
✅ 완료 사항
1️⃣ Service 계층 구현
3개 도메인의 Service 계층을 완성했다.
UserService
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
// 사용자 저장 (OAuth 자동 가입 시 사용)
public User save(User user) {
return userRepository.save(user);
}
// 아이디로 사용자 찾기
public User findById(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new RuntimeException("아이디가 존재하지 않습니다."));
}
// 이메일로 사용자 찾기
public Optional<User> findByEmail(String email) {
return userRepository.findByEmail(email);
}
// 사용자 삭제
public void delete(Long userId) {
userRepository.deleteById(userId);
}
}
특징:
@RequiredArgsConstructor로 생성자 주입- Repository 계층에 위임하는 단순 CRUD
- 예외 처리 포함 (RuntimeException)
IdeaService
@Service
@RequiredArgsConstructor
public class IdeaService {
private final IdeaRepository ideaRepository;
public Idea save(Idea idea) { }
public Idea findById(Long ideaId) { }
public List<Idea> findByUserId(Long userId) { }
public void delete(Long ideaId) { }
public long countByUserId(Long userId) { }
}
InquiryService
@Service
@RequiredArgsConstructor
public class InquiryService {
private final InquiryRepository inquiryRepository;
public Inquiry save(Inquiry inquiry) { }
public Inquiry findById(Long inquiryId) { }
public List<Inquiry> findByUserId(Long userId) { }
public void delete(Long inquiryId) { }
}
2️⃣ Service 테스트 코드 작성
테스트 프레임워크:
- JUnit 5
- AssertJ (가독성 좋은 검증)
- Spring Boot Test
테스트 구조
@SpringBootTest
@Transactional // 테스트 후 자동 롤백
class UserServiceTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
@DisplayName("사용자 저장 테스트")
void save() {
// given
User user = new User(...);
// when
User savedUser = userService.save(user);
// then
assertThat(savedUser.getUserId()).isNotNull();
assertThat(savedUser.getEmail()).isEqualTo("test@example.com");
}
}
작성한 테스트:
- UserServiceTest (6개 테스트)
- save, findById, findByIdNotFound, findByEmail, findByEmailNotFound, delete
- IdeaServiceTest (5개 테스트)
- save, findById, findByUserId, delete, countByUserId
- InquiryServiceTest (4개 테스트)
- save, findById, findByUserId, delete
테스트 패턴:
// given-when-then 패턴 사용
// AssertJ로 가독성 높은 검증
assertThat(result).isNotNull();
assertThat(list).hasSize(2);
assertThat(list).extracting("title")
.containsExactlyInAnyOrder("title1", "title3");
3️⃣ DTO 계층 설계 및 구현
DTO가 필요한 이유:
- Entity 직접 노출 방지 (보안)
- API 스펙과 Entity 분리 (유지보수)
- 필요한 데이터만 전달 (성능)
Request DTO vs Response DTO
RequestDto: 클라이언트 → 서버
- 필요한 입력 데이터만 포함
toEntity()메서드로 Entity 변환
ResponseDto: 서버 → 클라이언트
- 반환할 데이터만 포함
from(Entity)정적 메서드로 Entity → DTO 변환
UserRequestDto
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class UserRequestDto {
private String email;
private String username;
private LoginProvider provider;
private String providerId;
public User toEntity() {
return new User(
null, // userId 자동생성
email,
username,
provider,
providerId,
MyRole.USER // 기본값 설정
);
}
}
UserResponseDto
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class UserResponseDto {
private Long userId;
private String email;
private String username;
private LoginProvider provider;
private LocalDateTime createdAt;
public static UserResponseDto from(User user) {
return new UserResponseDto(
user.getUserId(),
user.getEmail(),
user.getUsername(),
user.getProvider(),
user.getCreatedAt()
);
}
}
완성된 DTO:
- UserRequestDto / UserResponseDto
- IdeaRequestDto / IdeaResponseDto
- InquiryRequestDto / InquiryResponseDto
📊 프로젝트 현황
완료된 계층
✅ Entity (User, Idea, Inquiry)
✅ Repository (Spring Data JPA)
✅ Service (비즈니스 로직)
✅ Service Test (JUnit)
✅ DTO (Request/Response)디렉토리 구조
src/main/java/com/brainstorming/brainstorming_platform/
├── domain/
│ ├── user/
│ │ ├── entity/User.java
│ │ ├── repository/UserRepository.java
│ │ ├── service/UserService.java
│ │ └── dto/
│ │ ├── UserRequestDto.java
│ │ └── UserResponseDto.java
│ ├── idea/
│ │ ├── entity/Idea.java
│ │ ├── repository/IdeaRepository.java
│ │ ├── service/IdeaService.java
│ │ └── dto/
│ │ ├── IdeaRequestDto.java
│ │ └── IdeaResponseDto.java
│ └── inquiry/
│ ├── entity/Inquiry.java
│ ├── repository/InquiryRepository.java
│ ├── service/InquiryService.java
│ └── dto/
│ ├── InquiryRequestDto.java
│ └── InquiryResponseDto.java
└── global/
└── BaseEntity.java
src/test/java/
└── domain/
├── user/service/UserServiceTest.java
├── idea/service/IdeaServiceTest.java
└── inquiry/service/InquiryServiceTest.java💡 배운 점 & 트러블슈팅
1. JPA와 객체 참조
문제: save() 결과를 받지 않아도 원본 객체의 ID가 채워지는 이유?
Idea idea = new Idea(null, ...);
ideaService.save(idea);
// idea.getIdeaId()가 null이 아니다!
이유: JPA의 영속성 컨텍스트가 원본 객체에 ID를 자동으로 설정해주기 때문
2. DTO 필드 선택 기준
RequestDto에 포함하지 않는 것:
- 자동 생성 필드 (PK, createdAt, updatedAt)
- 서버에서 자동 설정하는 필드 (role, status)
ResponseDto에 포함하지 않는 것:
- 보안 정보 (providerId, password)
- 민감한 비즈니스 정보
3. AssertJ extracting 활용
List의 특정 필드만 검증:
assertThat(ideas)
.extracting("userId")
.containsOnly(1L);
assertThat(ideas)
.extracting("title")
.containsExactlyInAnyOrder("title1", "title3");
🎯 다음 단계 (Day 4)
우선순위 1
- Controller 작성 (REST API)
- Postman으로 API 테스트
- 예외 처리 개선
우선순위 2
- Controller 테스트 (MockMvc)
- Swagger 문서화
- Validation 추가 (@Valid)
우선순위 3
- Python FastAPI 연동
- OAuth2 로그인 구현
📚 참고 자료
- 김영한님 - 스프링 부트와 JPA 실무 완전 정복 로드맵
- Spring Boot 3.5.7 공식 문서
- AssertJ 공식 문서
🔗 GitHub
- Repository: brainstorming-platform
- Commit: Day 3 - Service, Test, DTO 완성
Day 3 완료! 수고하셨습니다! 🎉
'그래서 일단 프로젝트 > 개인프로젝트-IdeaMaker(클로드 작성본 md 모음)' 카테고리의 다른 글
| 기록 6 . 파이썬 모듈 JAVA 백엔드에 연결하기 .. (1) | 2025.12.01 |
|---|---|
| 기록 5 . 컨트롤러 계층 완성 및 테스트완료 (0) | 2025.11.27 |
| 기록 3 . Java Service 계층과 Repository 계층 작성 (0) | 2025.11.25 |
| 기록 2 . 엔티티 만들기 ERD까지. (0) | 2025.11.21 |
| 기록 1 . 기획 클로드 코드와 함께 Spring프로젝트 생성과 의존성생성 (0) | 2025.11.19 |