Java 11에서 17, Maven에서 Gradle, Spring Boot 2.7에서 3.4까지 마이그레이션
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 5. 14. 11:03Java 11에서 17, Maven에서 Gradle, Spring Boot 2.7에서 3.4까지 마이그레이션

InkBridge 프로젝트를 리팩토링하던 중, 스프링 배치를 적용해야 할 시점이 왔었다.그래서 스프링 배치 공부를 5버전으로 했는데 스프링 부트 3 이상에서만 이 버전을 지원한다는 것을 알았다.원래는 전반적인 리팩토링을 끝낸 뒤 마이그레이션을 진행하려고 했지만, 배치를 5버전으로 공부한 김에 지금 계획했던 마이그레이션을 하기로 했다. 마이그레이션 대상은 다음과 같다.Java 11 -> Java 17Maven -> GradleSpring Boot 2.7 -> Spring Boot 3.4현재 스프링 부트의 가장 최신 버전인 3.4 버전으로 마이그레이션 하기로 했고, 그에 따라 자바 버전도 17이상으로 올려야 했다.그리고 기존 빌드 도구는 Maven이었는데 이 팀 프로젝트를 진행한 이후로는 Gradle만 사용..

카테고리 구조 리팩토링: N+1 문제 해결과 계층 구조 설계 개선
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 4. 23. 16:33카테고리 구조 리팩토링: N+1 문제 해결과 계층 구조 설계 개선

기존에 구현한 카테고리 로직에서는 N+1 문제, 재귀적 구조의 한계, 조회 효율성 저하 같은 문제점들이 있었다.그래서 이번 글에서는 카테고리 리팩토링 과정을 담아보도록 하겠다.1. 기존 구조의 문제점1.1 인접 리스트 모델(Adjacency List Model)기존 구조는 인접 리스트 모델로, Category 엔티티 내에 자기 자신을 참조하는 CategoryParent, CategoryChildren 필드를 통해 재귀적으로 자기 자신을 참조했다.1.2 N+1 문제 발생readAllCategory() 메서드에서 부모 카테고리를 조회한 뒤, 각 카테고리의 자식들을 DTO로 변환하는 과정에서 지연 로딩으로 인해 매번 추가 쿼리가 발생했다. 여기서는 @BatchSize설정으로도 최적화할 수 없다.그 이유는 Hi..

이미지 업로드와 DB 저장에 대한 고민과 해결과정
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 4. 11. 15:25이미지 업로드와 DB 저장에 대한 고민과 해결과정

책 정보나 작가 정보, 리뷰 등을 등록할 때, 이미지 파일을 함께 저장해야 한다.이미지 파일은 DB와는 다른 IO 작업이라서 어떻게 로직을 구성할지가 중요했다.간단하게 생각하면 "이미지 업로드 → DB 저장" 또는 "DB 저장 → 이미지 업로드" 중 하나를 선택하면 될거라고 생각할 수도 있지만, 트랜잭션 처리, 예외 상황, 서버 부하 등 여러 요소를 함께 고려해야한다. 그래서 이 글에서는 내가 고민한 부분들과 해결 과정을 공유해보겠다.1. 사진 업로드와 DB 저장의 순서에 대한 고민1.1 하나의 요청 안에서 사진 업로드 → DB 저장이 방식은 파일을 먼저 업로드한 뒤, 그 결과로 받은 URL 혹은 파일식별자를 DB에 저장하는 구조다.장점이미지 업로드를 실패하면 DB 작업을 진행할 필요가 없어서 트랜잭션 ..

요청 DTO에서 ConstraintValidator로 Enum 검증하기
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 4. 6. 14:07요청 DTO에서 ConstraintValidator로 Enum 검증하기

요청 DTO에서 ConstraintValidator로 Enum 검증하기클라이언트에서 데이터를 넘겨줄 때 @NotBlank, @NotEmpty 등으로 대부분의 유효성 검사를 할 수 있다.하지만 나의 경우에는 Enum에 바인딩 될 수 있는 값인지 검증을 해야했다. 그래서 이번 글에서는 ConstraintValidator를 활용해 Enum에서 지원하는 값인지 검증하는 방법을 공유해보겠다.1. 첫 번째 시도 : 바인딩 이후 도메인 변환 시점에서 Enum 검증처음에는 요청으로 들어온 문자열이 유효한 Enum 값인지 검증할 때, 아래와 같이 도메인 변환 로직 안에서 직접 처리했었다. 예시 Request 클래스DomainStatus.class 응답   이렇게 처리하면 올바르게 예외 처리를 할 수 있다.하지만 이 방식..

주소 도메인 테이블 구조 리팩토링으로 성능·동시성 문제 해결
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 3. 28. 14:18주소 도메인 테이블 구조 리팩토링으로 성능·동시성 문제 해결

주소 도메인의 구조에 문제점이 있다고 판단하여 리팩토링을 진행했다.이 글에서는 ERD와 코드 구조를 개선하고, 어떤 문제를 어떻게 해결했는지 전반적인 리팩토링 과정을 작성해보겠다.1. 리팩토링 내용2개로 나뉘어 있던 테이블 -> 단일 테이블기존 코드 구조 개선 및 기능 추가주소 최대 10개 제한 로직 추가(기존 요구사항에 있던 내용)기본 배송지 설정 로직 추가(개인적인 추가)동시성 문제 해결계층 단위로 나뉘어진 패키지 구조 -> 도메인 기반 패키지 구조추후 모듈 분리를 고려한 구조로 설계2. 기존 ERD 구조 기존 주소 도메인은 general_address, member_address 두 테이블로 분리되어 있었다.아마 아파트 등의 공통 주소를 공유하는 사용자를 고려한 정규화로 추정된다.하지만 이 구조에 ..

Object Storage 업로드 방식과 이미지 조회 방식 변경
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 3. 13. 12:00Object Storage 업로드 방식과 이미지 조회 방식 변경

1. 기존 방식: RestTemplate으로 업로드1.1 RestTemplate을 이용한 업로드의 문제점기존 InkBridge는 NHN Cloud Object Storage를 사용하여 이미지를 업로드하고 있었고,업로드 방식은 RestTemplate을 이용하여 직접 API 요청을 보내는 방식이었다. 이 방식의 문제점은 다음과 같다.직접 API 호출 필요 → RestTemplate을 사용하여 직접 API를 호출해야 하므로 신경써야할 부분이 많아진다.인증 처리 번거로움 → X-Auth-Token을 수동으로 발급 받아야 하고 토큰 갱신 로직이 필요하다.대용량 파일 확장성 부족 → 현재는 책 사진, 리뷰 사진 등의 작은 이미지만 처리하는데 나중에 동영상 등 대용량 파일을 업로드할 경우 코드의 변화가 클 수 있다...

설정파일 암호화 로직 리팩토링으로 의존성 분리와 API 호출 최적화하기
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 3. 7. 21:15설정파일 암호화 로직 리팩토링으로 의존성 분리와 API 호출 최적화하기

데이터베이스 접속 정보나 클라우드 관련 키가 퍼블릭한 공간에 노출되면 보안이 취약해진다.특히 클라우드 키가 노출되면 요금 폭탄을 맞을 수도 있다. 따라서 키들을 Github나 DockerHub에 업로드하는 것은 위험하다.이 문제를 해결하는 가장 단순한 방법은 properties/yml 파일을 퍼블릭 공간에 업로드하지 않거나 환경 변수로 처리하는 것이다.하지만 이 프로젝트에서는 NHN Cloud에서 제공하는 Key Manager를 이용하여 설정 키들을 암호화하는 방식을 이용했다.그래서 이 방식을 최대한 살려서 리팩토링을 진행하였다.Key Manager에 대한 설명은 프로젝트를 진행할 때 기록해둔 자료로 대신하겠다.1. 기존 방식KeyConfig.classKeyStore메서드로 복호화를 진행하는 코드이며, ..

DBCP2에서 HikariCP로 전환 과정
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 3. 4. 23:02DBCP2에서 HikariCP로 전환 과정

NHN Academy에서 진행했던 InkBridge 프로젝트는 DBCP2를 커넥션 풀로 사용하고 있다. 그러나 현재 스프링부트의 기본 커넥션 풀은 HikariCP를 채택하고 있다.이 부분에 의문이 들어서 두 커넥션풀에 대해서 공부해보고 나서 HikariCP로 전환하기로 결정하였다.이 글에서는 그 과정에 대해서 설명해보겠다.1. DBCP2DBCP는 Apache Commons 프로젝트에서 제공하는 커넥션 풀이다. DBCP는 오랜 기간 동안 사용되었으며, 많은 레거시 시스템에서 사용되고 있다.2002년에 DBCP1이 출시되었지만 1.x버전대에서는 성능이 부족하고 멀티스레드 환경에서 동기화 이슈가 종종 발생했다고 한다.DBCP2는 DBCP1의 후속 버전으로 2014년에 출시되어 성능 개선 및 버그 수정이 이루어..

Logback 설정 실수로 인해 로그가 출력되지 않은 문제 해결 과정
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 2. 27. 10:37Logback 설정 실수로 인해 로그가 출력되지 않은 문제 해결 과정

1. 문제상황1년전에 진행했던 팀프로젝트를 개선하기 위해서 Git에서 클론 후 인텔리제이에서 실행했다.그런데 아래와 같은 메시지가 출력되면서 애플리케이션이 즉시 종료되는 문제가 발생했다.실제로는 즉시 종료된 것이 아니라 즉시 종료된 것처럼 보이는 것이었다. 차근차근 설명해보겠다.2. 원인 분석 과정2.1 Process finished with exit code 1의 의미Process finished with exit code 1는 Spring Boot 애플리케이션이 내부적인 문제로 인해 비정상 종료되었다는 것을 의미한다.정상적으로 실행된다면 exit code 0으로 끝나야 한다.2.2  어떠한 로그도 출력되지 않음스프링 로고를 제외한 어떠한 로그도 출력되지 않는다는 점에서 Logback 설정을 의심했다...

Maven 프로젝트에서 Lombok이 인식되지 않는 문제 해결
프로젝트/온라인 서점 프로젝트 + 리팩토링2025. 2. 25. 13:54Maven 프로젝트에서 Lombok이 인식되지 않는 문제 해결

1. 문제 상황과거에 진행했던 Maven 기반의 팀 프로젝트를 다시 리팩토링하기 위해 클론을 받아왔다.하지만 프로젝트를 컴파일하는 과정에서 Lombok을 인식하지 못하는 문제가 발생했다.1.1  문제 분석이 프로젝트는 Maven 기반으로 작성되었으며, 당시 정상적으로 작동하던 프로젝트였다.하지만 현재 환경에서 빌드하자 Lombok이 정상적으로 적용되지 않는 문제가 발생했다.이 프로젝트 이후에 나는 Gradle만 사용했는데 Gradle에서는 annotationProcessor 설정을 추가하여 Lombok을 사용한다.그래서 Maven에서도 유사한 설정이 필요할 것으로 생각했다.2. 해결 방법pom.xml에 maven-compiler-plugin에 대한 Lombok 설정 추가Maven의 maven-compil..

image