728x90
반응형

Dev. 59

[Spring] QueryDSL Projection 방식 비교

개요QueryDSL로 검색 API를 구현하면서 엔티티가 아닌 검색 전용 DTO로 결과를 조회해야 했다.DTO 매핑방식으로 두가지 선택지가 있다는 것을 알게되었다Projections.constructor()@QueryProjection두 방식은 결과는 같아 보이지만,안전성 · 유지보수성 · 오류 발견 시점에서 큰 차이가 있었다. Projections.constructor 방식.select(Projections.constructor( TodoSearchResponse.class, todo.title, manager.id.countDistinct(), comment.id.countDistinct()))특징DTO에 QueryDSL 의존성 X생성자만 있으면 바로 사용 가능설정이 간단단점 생성..

Dev./Spring 2025.12.17

[Spring] Spring Security + JWT로 로그인 기능 구현

전체적인 흐름 클라이언트가 /auth/login 으로 이메일/비밀번호 전송서버에서 사용자 검증 후 JWT 발급이후 요청들은 Authorization: Bearer token헤더에 JWT를 담아서 호출커스텀 JwtAuthFilter가 토큰을 검증하고 userId를 꺼냄@AuthUser 파라미터로 컨트롤러에 userId를 바로 주입→ 컨트롤러/서비스는 JWT 구조를 모른 채 로그인된 사용자 ID만 다룸설계JwtUtil - JWT 생성 및 검증역할토큰 생성토큰 검증Claims / subject 추출설계 기준subject에는 userId를 넣음 (주 식별자)claim으로 email 정도만 추가validate()는 예외 캐치로 단순 처리@Componentpublic class JwtUtil { @Value(..

Dev./Spring 2025.12.09

[Spring] Transactional 사용시 자가호출(Self-Invocation)이슈

문제다음과 같은 코드에서,한 메서드 안에서 다른 @Transactional 메서드를 호출하면나는 REQUIRES_NEW가 적용되어 별도 트랜잭션이 만들어질 것이라고 기대했다.그러나 실제 동작은 전혀 달랐다.@Service@Slf4j@RequiredArgsConstructorpublic class OrderService { private final StockService stockService; private final PaymentService paymentService; private final PaymentRepository paymentRepository; private final OrderRecordService orderRecordService; @Transaction..

Dev./Spring 2025.12.08

[Spring]왜 Security 의존성을 추가하면 API 호출시 401이 뜰까

기존에 잘 돌아가던 demo 프로젝트에 Security 의존성을 추가하니 모든 API 호출시 401에러가 떴다. 왜 의존성 추가 하나만으로 잘 돌아가던 서버가 에러를 뱉는걸까?Security의 기본 보안 정책 자동 활성화Spring Security는 의존성 추가만으로도 다음 설정을 자동 적용 모든 요청은 인증 필요인증되지 않은 요청은 → 401 UnauthorizedForm 로그인 페이지가 자동 생성됨기본 사용자 계정이 자동 생성됨 (username=user, password=콘솔에 출력)즉 security가 추가되며 모든 요청을 가로막은 것이다.Security를 추가한 후의 동작 흐름왜 401일까?Spring Security가 요청을 Controller로 보내기 전에 차단하기 때문 , 컨트롤러에 도달하..

Dev./Spring 2025.12.06

[Spring] AOP 정리

AOP란AOP (Aspect Oriented Programming) 는 여러 곳에 반복되는 공통 관심사를 비즈니스 로직과 분리해서 한 곳에서 관리하기 위한 프로그래밍 기법AOP가 왜 필요할까?예를들어 기획자가 개발자님 성능 측정을 위해 모든 메서드에 시작 시간과 종료 시간을 남기는 기능 추가해주세요라고 요청을 했을 때public void save() { log.info("start"); // 비즈니스 로직 log.info("end");}다음과 같은 코드가 모든 서비스 메서드마다 중복되면 로깅, 트랜잭션, 권한 체크 코드가 모든 메서드에 흩어짐수정하려면 전체 코드를 다 건드려야 함비즈니스 로직이 더러워짐AOP 도입 후에는 시간 측정은 AOP가 알아서 처리한다.AOP는 어디에 적용되는걸까?..

Dev./Spring 2025.12.03

[Spring] Interceptor 정리

Interceptor란Spring MVC에서 컨트롤러(Controller) 호출 전·후에 요청을 가로채서 공통 로직을 수행하는 도구JWT 기반 인증이 끝난 후, 인증된 사용자 정보(SecurityContext)를 활용해자원 소유자 검증역할 기반 접근 제어API 사용 제한등의 부가 검증 수행Spring MVC 요청 흐름[사용자 요청] ↓[JwtFilter] ↓[SecurityContextHolder에 인증 저장] ↓[Interceptor] ↓[인증 사용자 검증] ↓[Controller]Interceptor가 왜 필요할까?예를 들어 컨트롤러 마다 다음과 같은 코드가 반복된다면if (!isLogin(request)) { throw new UnauthorizedException(..

Dev./Spring 2025.12.02

[Git] merge 진행 과정

merge를 이해하기Git에서 협업 할 때 내가 가장 중요하다고 생각하는 것은내 작업 브랜치는 어떤 dev를 기준으로 만들어졌는가?이다. dev는 공용 개발 브랜치이며 모든 feature 브랜치는 dev의 특정 시점에서 분기된다. 문제는 dev는 계속 변한다는 것인데 본질을 이해하고 넘어가면 실수할 일이 줄어든다.그래서 merge의 본질은 내 브랜치를 최신 dev 기준으로 다시 맞추는 과정이라고 생각한다.merge의 기준점은 항상 devdev를 항상 최신으로 만든 뒤작업 브랜치에 dev를 mergefetch와 pull의 역할git fetch형상 확인용, 정보 동기화용git fetch origin원격 저장소의 최신 상태를 복사만 해옴origin/dev가 업데이트됨내 로컬 브랜치에는 아무 변화 없음 git ..

Dev./Git 2025.11.30

[Spring] interface의 default 메서드를 언제 써야 할까

default 메서드란설계 확장을 위한 도구Java 8 이전에는 인터페이스에 추상 메서드만 선언할 수 있었다. 문제는 인터페이스를 이미 여러 구현체가 구현하고 있는 상황에서 메서드 하나를 추가하면 모든 구현체가 깨짐이문제를 해결하기 위해 default 메서드가 나왔다public interface Repository { Optional findById(Long id); default T getOrNull(Long id) { return findById(id).orElse(null); }} 인터페이스에 기본 구현을 제공기존 구현체를 깨지 않고 기능 추가 가능무엇을 담당하는 메서드일까?모든 구현체에서 동일하게 동작해야 하는 공통 행위구현체마다 바뀌면 안되는 로직맥락을 몰라도 실행 ..

Dev./Spring 2025.11.29

[Git] git switch와 checkout 차이

습관적으로 checkout을 사용하다 커밋이 꼬이는 일이 생겨 두가지의 차이를 정리해보려고 한다.한줄 요약git checkout은 브랜치 이동 + 파일 변경 + 커밋 되돌리기까지 모든 걸 하는 올드한 만능 명령어이고, git switch는 브랜치 이동만 전담하게 분리된 최신 명령어이다.왜 git switch가 만들어졌을까?git checkout은 너무 많은 기능을 한 명령어에 몰아넣어서 실수가 잦았음git checkout dev # 브랜치 이동git checkout main.txt # 파일 상태 되돌리기같은 checkout 기능이지만 의미가 완전히 다름git switch브랜치 이동 전용 명령어이다.브랜치 이동git switch dev새 브랜치 생성 + 이동git switch -c feature/..

Dev./Git 2025.11.26

[Error] Docker MySQL 세팅 시 3306 포트 오류 해결방법

왜 3306 포트 오류가 나올까?도커 MySQL과 로컬 MySQL이 둘 다 3306 포트를 사용하려고 해서 충돌하기 때문이다.도커는 포트를 실제 OS에서 공유함. 즉, “가상환경”이라도 포트는 절대 가상화되지 않는다대표 오류 메세지Ports are not available: listen tcp 0.0.0.0:3306: bind: address already in use3306 이미 누가 쓰고 있어서 도커가 못 씀해결 방법 1. 3306 점유 프로세스 확인lsof -i :3306문제가 있는 경우mysqld 1234 ...com.docke 5678 ...mysqld (로컬 MySQL) 포트 때문에 충돌이 난다.2. 로컬 MySQL 중지brew services stop mysql 맥은 macOS의 기능 ..

Dev./Error. 2025.11.25
728x90
반응형