Spring 5

[Spring] 기존 Todo API 리팩터링 - Boot 4 마이그레이션부터 QueryDSL 검색까지

요약기존 Todo API를 Spring Boot 4.1.1 환경으로 옮기면서 단순히 의존성 버전만 올리는 데서 끝내지 않았다. JWT 인증 정보의 전달 방식, 매니저 등록 실패 시 남겨야 하는 로그의 트랜잭션 경계, 조회 API의 N+1과 집계 검색까지 함께 정리했다.이 글에서 다루는 범위는 다음과 같다.Java 17·Spring Boot 4.1.1·Gradle Wrapper 8.14.3 기반 실행 환경 정비HttpServletRequest attribute 기반 JWT 전달 구조를 Spring Security 표준 구조로 전환관리자 역할 변경 접근 로그와 담당자 등록 요청 로그의 목적 분리Todo 생성과 담당자 자동 등록, 요청 로그의 독립 트랜잭션 처리JPQL fetch join·@EntityGrap..

Spring 2026.09.04

[Spring Security] JWT 인증 성공 로그가 있는데 관리자 API가 401이었던 이유

배경Spring Security로 JWT 인증·인가 구조를 전환한 뒤, USER 권한 토큰으로 관리자 API를 호출했다.기대한 결과는 403 Forbidden이었다.인증 성공하지만 ADMIN 권한 없음→ 403 Forbidden그런데 실제 응답은 401 Unauthorized였다. 더 혼란스러웠던 점은 애플리케이션 로그에 JWT 인증 성공까지 남았다는 것이다.JwtFilter 진입 - uri=/admin/users/1JWT 인증 성공 - userId=1, role=USER이 글은 “토큰 검증은 성공했는데 왜 최종 응답은 401이었는가”를 추적하며, JWT 필터와 Spring Security 인가 정책의 책임을 다시 나눈 기록이다.먼저 구분할 것: 401과 403은 실패 지점이 다르다관리자 API의 응답은..

Spring 2026.09.04

[Spring] GlobalExceptionHandler와 AOP 로깅 - 응답과 실패 기록의 책임 나누기

팀 프로젝트에서 AOP와 로깅 작업을 맡았다. 처음에는 Controller의 반복 로그를 AOP로 묶고, 예외는BusinessException으로 던져 GlobalExceptionHandler에서 공통 응답으로 바꾸면 충분하다고 생각했다.하지만 결제·환불 흐름에 업무 로그를 추가하는 중, 두가지 의문이 생겼다.이 실패를 클라이언트에 어떤 HTTP 응답으로 돌려줄 것인가?이 실패를 개발자가 나중에 어떤 정보로 추적할 것인가?둘은 관련 있지만 같은 책임은 아니다. 이 글에서는 커머스 결제 시스템에 적용한GlobalExceptionHandler, Controller AOP, 결제·환불 업무 로그를 기준으로 응답과 기록의 책임을나눈 과정을 정리한다.GlobalExceptionHandler는 오류 응답을 통일한다..

Spring 2026.08.25

[Spring] 엔티티와 DTO는 왜 타입이 달라도 되는가

배경"엔티티 필드와 DTO 필드는 이름과 타입이 같아야 한다"고 배웠던 것 같은데, 실제 실습 코드를 보면 그렇지 않았다.// 엔티티@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@ManyToOne(fetch = FetchType.LAZY)private User user;// 응답 DTOpublic class PostDto { private long Id; private String username; // user 객체가 아니라 username 문자열}이름도 다르고(user → username), 타입도 다르다(Long → long, 객체 참조 → 문자열). 그런데도 이 코드는 실제로 잘 동작한다. 왜 그런지, 그리..

Spring 2026.07.28

[Spring Data JPA] 동적 쿼리 처리 — JPQL과 Specification

배경선택적 검색 조건, 쿼리 메서드로 다 만들 수 있을까? 검색 API를 만들다 보면 조건이 하나만 오는 경우도 있고, 여러 개가 조합되어 오는 경우도 있고, 아예 아무 조건 없이 전체 목록을 요청하는 경우도 있다. 예를 들어 고객 검색에서 이름(keyword)과 상태(status)가 각각 있을 수도, 없을 수도 있는 구조라면 이 조합을 어떻게 처리할지가 선택해야한다.문제: 조건 조합이 지수적으로 늘어난다가장 단순한 방법은 Spring Data JPA가 제공하는 쿼리 메서드다. findByNameAndStatus, findByName, findByStatus, findAll 처럼 조건 조합마다 메서드를 하나씩 만드는 방식이다. 문제는 조건이 늘어날수록 필요한 메서드 수가 2ⁿ으로 늘어난다는 것이다. 조건..

Spring 2026.07.22