분류 전체보기 (139) 썸네일형 리스트형 Spring의 @Configuration 스프링을 공부하다 보면 가장 처음 마주치는 어노테이션 중 하나가 @Configuration 입니다.처음엔 "설정 클래스인가 보다" 하고 넘어가기 쉬운데 이 어노테이션이 하는 일과 쓰는 이유를 정확히 이해하면 스프링 프레임워크에 대한 이해가 더 깊어질 수 있을 것 같아 글을 작성합니다. 이번 글에서는 @Configuration의 역할, @Component와의 차이점, 그리고 실제로 언제 왜 써야하는지를 예시와 함께 정리해보겠습니다.@Configuration의 정체@Configurationpublic class AppConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = objectMapper(); .. Kakao API를 사용하여 키워드로 장소 검색하기 1. 왜 Kakao API를 썼는가?오먹추 프로젝트의 목표는 사용자의 음식 선택을 도와주는 추천 기능을 만드는 것이었다.이때 가장 중요했던 건 장소 정보였다.예를 들어 사용자들이 '김밥', '떡볶이'처럼 투표한 메뉴를 기반으로 사용자 주변에 있는 관련 식당들을 알려줘야 했다. 그래서 생각났던 것이 Kakao Maps였는데 한국 기반 서비스 + 개발 문서가 깔끔 + 손쉬운 REST API를 제공 해서 선택을 하게 되었다.2. 연동을 위한 사전 준비개발자 등록 & 키 발급Kakao Devlopers 접속로그인 후 내 애플리케인션에서 애플리케이션 추가하기왼쪽 대시보드에 앱 설정 -> 앱 키에 들어가서 REST API 키 사용3. Kakao API 호출을 위한 Client 클래스일단 Kakao Maps의 키워드.. 복합 유니크 제약 조건의 필요성 1. 문제상황오먹추 프로젝트에서 "사용자가 하루에 한 번 특정 카테고리의 메뉴에만 투표할 수 있다"는 요구사항이 있었다.예를 들어 BREAKFAST 카테고리에서 투표는 1번만 진행 가능, 하지만 LUNCH 때는 투표를 다시 1회 가능.그래서 다음과 같은 제약을 의도했다한 유저는 하루에 한 번만 투표할 수 있어야 한다같은 날 같은 카테고리에 중복 투표가 불가능해야 한다.왜 이 제약 조건이 중요한가?예를 들어 오먹추에서 투표 결과를 집계할 때 user_id + category + vote_date가 중복되면 잘못된 순위 계산이나 추천 음식의 왜곡이 발생할 수 있다. 처음엔 이 제약을 서비스 로직에서만 체크했다.if (voteRepository.existsByUSerIdAndCategoryAndVoteDate.. Spring Security와 JWT로 로그인 구현하기 1. 왜 JWT와 Spring Security를 선택했는가?프로젝트에서 인증 기능이 필요했고, 다음 한 가지 조건이 있었다.프론트엔드 없이 백엔드 단독으로도 테스트 가능한 인증 방식이 필요했다.그래서 내가 선택한 방법은 Spring Security + JWT를 직접 구현하는 구조였다.세션을 서버에 저장하지 않아도 되니 구조가 단순해졌다. 2. 세션이나 쿠키를 사용하지 않은 이유는?이유1 : 백엔드 단독 실행 및 테스트의 편의성프론트 없이 Postman, Swagger 등에서 직접 요청을 보낼 수 있어야 했다.세션 기반 인증은 보통 쿠키 기반 요청을 전제로 하므로 브라우저 기반에서 테스트가 편하지만, Postman에서 매번 JSESSIONID를 수동 저장하거나 쿠키를 관리해야 함.이유2 : 서버가 상태를 .. 스프링 프로젝트에서 공통 응답 + 페이징 + 전역 예외처리 1. 통일된 응답 포맷 만들기 : ApiResponseAPI 마다 응답 형태가 다르면 프론트 개발자는 매번 if (response.data) {...}else if (response.content) {...}이런 식으로 응답을 파싱해야 한다. 그래서 프로젝트에서는 모든 응답을 하나의 포맷으로 통일하기로 했다.{ "status" : 200, "message" : "성공 메시지", "data" : {...}}해결 방법 : 제네릭 기반 응답 래퍼 만들기@AllArgsConstructorpublic class ApiResponse { private int status; private String message; private T data; public static ApiRe.. @Fetch(EAGER)와 fetch join 차이와 LAZY 로딩의 작동 방식 1. 즉시 로딩의 두 종료우선 즉시 로딩이란?A 엔티티를 로딩할 때, A와 연결된 연관 엔티티 B도 함께 가져오는 것을 의미한다. 즉시 로딩을 구현하는 방법은 JPA에서 2가지로 구분할 수 있다.방법설명예시제어 가능성EAGER어노테이션으로 고정된 즉시 로딩@ManyToOne(fetch = EAGER)매우 제한적fetch joinJPQL 쿼리로 지정된 즉시 로딩JOIN FETCH동적으로 선택 가능 2. EAGER는 고정, fetch join은 선택 가능EAGER는 선언한 시점부터 항상 즉시 로딩된다.즉 우리가 어떤 쿼리를 쓰든 상관없이 해당 연관 엔티티는 무조건 같이 가져오게 된다.@ManyToOne(fetch = FetchType.EAGER)private User user;위처럼 설정해두면 comment.. Spring AOP Proxy - SelfInvocation 문제 [Spring 애플리케이션이 실행되면서 AOP 프록시가 생성되고 동작하는 과정]1. AOP 적용 대상 클래스(OrderService)@Servicepublic class OrderService { public void processOrder() { System.out.println("Processing order..."); completeOrder(); } @Transactional public void completeOrder() { System.out.println("Order completed!"); printTransactionStatus("completeOrder"); } private void printT.. 결제 시나리오 3. 악의적 선점 - 데이터 정합성 문제(2) 문제 상황이전 트러블 슈팅을 통해 스케줄러가 조회한 후 결제 상태가 변경되었을 가능성을 고려하여 최신 상태를 다시 조회하는 로직을 추가함으로써 데이터 정합성 문제를 해결할 수 있었습니다.그러나 여전히 결제 승인 요청과 스케줄러가 동시에 실행되는 경우 아주 짧은 시간 간격으로 정합성이 깨질 가능성이 남아있었습니다.→ 여전히 발생할 수 있는 문제사용자가 9분 5x초에 결제 진행 → CONFIRMING 상태로 변경동일한 시점에 스케줄러 실행 → 기존 IN_PROGRESS 상태를 조회 후 취소 처리 시도스케줄러가 findById()로 최신 상태를 다시 조회했지만, 아주 미세한 타이밍 차이로 CONFIRMING 상태 변경이 반영되기 직전이면 여전히 취소 진행결제 승인 요청이 완료되었음에도, 결제 내역이 취소되는 .. 이전 1 2 3 4 ··· 18 다음