2025-05-12 Spring Boot + Kotlin 기반 프로젝트
프로젝트 전환 및 기본 설정
1. Kotlin 기반 프로젝트
- 기존 Java 기반 코드에서 Kotlin으로 전환.
2. 디렉토리 구조 정리
/src/main/kotlin에 코어 비즈니스 로직 이전.
/java/org.example.expert → /kotlin/com.example.domain로 이전하며 패키지 통일.
3. 공통 설정 파일
application.yml 구성 완료.
.env 파일을 통해 외부 환경변수 분리.
SECRET_KEY, MYSQL_USERNAME 등 중요한 값들은 .env로 관리.
보안 / 인증 시스템 구축
1. JWT 유틸 클래스 구현 (JwtUtil.kt)
- HS256 알고리즘 기반 JWT 생성 및 파싱 구현.
- Claims 필드:
userId, email, userRole, nickname
- 만료 시간: 60분 설정.
@PostConstruct
fun init() {
val bytes = Base64.getDecoder().decode(secretKey)
key = Keys.hmacShaKeyFor(bytes)
}
2. JWT 필터 구현 (JwtAuthenticationFilter.kt)
OncePerRequestFilter 상속.
- 토큰 유효 시 사용자 인증 정보를
SecurityContextHolder에 등록.
3. Spring Security 설정 (SecurityConfig.kt)
/auth/**는 허용
/admin/**은 ADMIN Role만 허용
- 나머지는 모두 인증 필요
- Stateless 정책, Form Login / HTTP Basic 비활성화
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
사용자 기능
1. User 엔티티 변경
User.kt 클래스에 profileImage 필드 추가
fromAuthUser() 정적 팩토리 메서드 도입
changePassword, updateRole, setProfileImage 메서드 구현
2. UserController.kt / UserService.kt
- 비밀번호 변경 API (
/users, PUT)
- 사용자 정보 조회 (
/users/{userId})
- 닉네임 기반 조회 캐싱 적용 (
@Cacheable)
3. 예외 처리
InvalidRequestException, AuthException, ServerException 공통 처리
@RestControllerAdvice 기반 글로벌 예외 핸들러 작성
Todo 기능
1. Todo 엔티티 및 Repository
title, contents, weather, user 필드 포함
findAllByOrderByModifiedAtDesc() / searchTodos() 구현
2. TodoService.kt
saveTodo: 날씨 조회 후 저장
getTodos: 페이징 조회
searchTodos: 조건부 검색
getTodo: 단일 조회 + User join
searchTodosWithFilters: QueryDSL 기반 키워드, 닉네임, 날짜 필터링
3. TodoQueryRepositoryImpl
Projections.constructor를 사용한 커스텀 DTO 매핑
groupBy, leftJoin, where절 조합
- count 쿼리 분리하여 페이징 대응
Manager 기능
1. Manager 엔티티
@ManyToOne 연관관계로 User, Todo를 소유
@Id, @GeneratedValue 전략
2. ManagerService
saveManager: 일정 작성자와의 매칭 여부 검증
deleteManager: 생성자만 삭제 가능
getManagers: 일정별 매니저 목록 조회
3. 로깅 기능 추가
Log 엔티티: action, details, createdAt
LogService: @Transactional(REQUIRES_NEW)로 로그 분리 저장
- 예외가 발생해도 로그는 저장되도록
finally 블록 활용
contents, user, todo, Timestamped 상속
saveComment: Todo 존재 여부 확인 후 저장
getComments: TodoId로 Comment 전체 조회 (User Join 포함)
AWS / Redis 설정
1. S3 연동 (S3Service.kt)
updateFile() 메서드 구현
- 파일은 UUID 기반 이름으로 업로드
2. Redis 설정 (RedisConfig.kt)
RedisTemplate 및 RedisCacheManager 설정
- TTL: 10분
테스트 및 부가사항
@GetMapping("/health"): Health Check API 제공
AdminAccessLoggingAspect: AOP로 UserController.getUser() 접근 로그 출력
- 전체적으로
!!, ?, lateinit 등의 코틀린 nullable 처리 점검
@Valid, @RequestParam, @PageableDefault 등 다양한 Spring 어노테이션 적용
해결한 문제 목록
PasswordEncoder Bean 오류
- 의존성 누락 문제였으나,
Spring Boot Starter Security로 해결됨
JwtUtil 빈 주입 실패
SECRET_KEY 환경변수가 .env로만 존재할 때 인식 안됨
- 해결 방법:
.env -> OS 환경변수로 등록 or .yml에 직접 선언
LocalDateTime? → LocalDateTime 타입 불일치
- Repository 쿼리에서 nullable 타입이어서 타입 mismatch 오류 발생
todoRepository.searchTodos(pageable, weather, start ?: now(), end ?: now()) 식으로 대응
@Generated Q 클래스 import 오류
- Kotlin, Java 혼합 프로젝트에서 QueryDSL의
Q클래스 import 경로 꼬임 문제 발생
- 해결: QueryDSL 생성 경로를
kotlin에 통일 / querydslDir 명시