Spring 주니어 코딩 면접
새 면접Q. Spring Boot에서 간단한 회원가입 API를 만들 때, User 엔티티와 UserController, UserService의 기본 구조를 어떻게 작성하시겠습니까? 각 계층의 역할과 어노테이션을 설명해주세요.
User 엔티티는 @Entity와 @Table로 정의하고 id, username, email 등의 필드를 @Column으로 매핑합니다. UserController는 @RestController를 사용하여 HTTP 요청을 받고, @PostMapping으로 회원가입 엔드포인트를 정의합니다. UserService는 @Service로 비즈니스 로직을 담당하며, UserRepository를 주입받아 데이터베이스 작업을 수행합니다. Controller는 요청/응답 처리, Service는 비즈니스 로직, Repository는 데이터 접근을 담당하는 계층 분리가 핵심입니다.
- • @Entity로 엔티티 정의, @RestController로 API 엔드포인트 생성
- • @Service로 비즈니스 로직 분리, 생성자 주입으로 의존성 관리
- • Controller-Service-Repository 계층 구조 유지
- • @PostMapping으로 POST 요청 처리, @RequestBody로 DTO 바인딩
회원가입 시 비밀번호를 어떻게 안전하게 저장하시겠습니까? PasswordEncoder의 사용 방법을 설명해주세요.
Q. JpaRepository에서 특정 조건으로 데이터를 조회하는 메서드를 작성할 때, 메서드 이름 규칙(Query Method)과 @Query 어노테이션을 사용하는 방법의 차이점과 각각의 장단점을 설명해주세요.
메서드 이름 규칙은 findByUsernameAndEmail처럼 메서드 이름만으로 쿼리가 자동 생성되어 간단한 조회에 적합하지만, 복잡한 조건이나 조인이 필요한 경우 메서드 이름이 길어지는 단점이 있습니다. @Query 어노테이션은 JPQL이나 네이티브 SQL을 직접 작성하여 복잡한 쿼리를 명확하게 표현할 수 있지만, 문자열로 작성되어 컴파일 타임에 오류를 발견하기 어렵습니다. 실무에서는 간단한 조회는 메서드 이름 규칙을, 복잡한 조건은 @Query를 사용하는 것이 일반적입니다.
- • 메서드 이름 규칙: findBy, existsBy, countBy 등 키워드로 자동 쿼리 생성
- • @Query: JPQL 또는 네이티브 SQL 직접 작성 가능
- • 메서드 이름 규칙은 간단하지만 복잡한 조건에서 가독성 저하
- • @Query는 유연하지만 문자열 기반이라 타입 안정성 낮음
QueryDSL을 사용하면 어떤 장점이 있으며, 언제 도입을 고려해야 할까요?
Q. Controller에서 비즈니스 로직을 직접 작성하고 Repository를 바로 호출하는 코드를 발견했습니다. 이런 코드의 문제점과 올바른 리팩토링 방향을 설명해주세요.
Controller에 비즈니스 로직이 있으면 테스트가 어렵고, 코드 재사용이 불가능하며, 단일 책임 원칙을 위반합니다. Controller는 HTTP 요청/응답 처리만 담당하고, 비즈니스 로직은 Service 계층으로 분리해야 합니다. 리팩토링 시 Service 클래스를 생성하여 비즈니스 로직을 옮기고, @Transactional을 Service 메서드에 적용하며, Controller는 Service를 주입받아 호출만 하도록 변경합니다. 이렇게 하면 각 계층의 책임이 명확해지고 유지보수성이 향상됩니다.
- • Controller는 요청/응답 처리만, Service는 비즈니스 로직만 담당
- • 계층 분리로 테스트 용이성과 코드 재사용성 향상
- • @Transactional은 Service 계층에 적용
- • 단일 책임 원칙(SRP) 준수
Service 계층에서도 너무 많은 책임을 가진 클래스가 생길 수 있습니다. 이를 어떻게 분리하시겠습니까?
Q. Spring에서 비즈니스 로직 수행 중 발생하는 예외를 처리할 때, 커스텀 예외를 만들어 처리하는 방법과 그 장점을 설명해주세요. RuntimeException과 Checked Exception 중 어떤 것을 상속받아야 하나요?
커스텀 예외는 RuntimeException을 상속받아 만드는 것이 권장됩니다. Checked Exception은 메서드 시그니처에 throws를 명시해야 하고 호출하는 모든 곳에서 try-catch나 throws를 강제하여 코드가 복잡해집니다. UserNotFoundException, DuplicateEmailException 같은 명확한 이름의 커스텀 예외를 만들면 예외 상황을 명확히 표현할 수 있고, @ControllerAdvice의 @ExceptionHandler에서 예외 타입별로 다른 HTTP 응답을 반환할 수 있습니다. 예외 클래스에 에러 코드와 메시지를 포함시켜 일관된 에러 응답 구조를 만들 수 있습니다.
- • RuntimeException 상속으로 Unchecked Exception 생성 권장
- • 명확한 예외 이름으로 예외 상황 표현력 향상
- • @ExceptionHandler로 예외 타입별 HTTP 응답 제어
- • 에러 코드와 메시지를 포함한 일관된 에러 응답 구조
GlobalExceptionHandler에서 예외를 처리할 때, 클라이언트에게 어떤 정보를 포함해야 하고, 어떤 정보는 숨겨야 할까요?
Q. 사용자 입력 데이터의 유효성을 검증하는 코드를 Service 계층에서 if문으로 작성하고 있습니다. Spring Validation을 활용하여 이를 개선하는 방법을 설명해주세요.
DTO 클래스의 필드에 @NotNull, @Size, @Email, @Pattern 같은 검증 어노테이션을 선언하고, Controller 메서드의 파라미터에 @Valid를 붙이면 자동으로 검증이 수행됩니다. 검증 실패 시 MethodArgumentNotValidException이 발생하며, BindingResult를 파라미터로 추가하면 예외 없이 에러 정보를 받을 수 있습니다. Service 계층의 if문을 제거하고 선언적 검증으로 변경하면 코드가 간결해지고, 검증 로직이 DTO에 명확히 표현되어 가독성이 향상됩니다. 커스텀 검증이 필요한 경우 @AssertTrue나 커스텀 어노테이션을 만들 수 있습니다.
- • DTO 필드에 @NotNull, @Size, @Email 등 검증 어노테이션 선언
- • Controller 파라미터에 @Valid로 자동 검증 수행
- • BindingResult로 검증 에러 정보 접근
- • 선언적 검증으로 코드 간결화 및 가독성 향상
그룹 검증(Validation Groups)은 무엇이며, 생성과 수정 API에서 다른 검증 규칙을 적용하려면 어떻게 해야 하나요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!