λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

Spring Boot와 μ˜ˆμ™Έ 처리 μ™„λ²½ κ°€μ΄λ“œ: κΈ€λ‘œλ²Œ μ˜ˆμ™Έ 처리 μ „λž΅κ³Ό μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€ κ΅¬ν˜„

mrmount 2024. 10. 21.

 

Spring Boot μ• ν”Œλ¦¬μΌ€μ΄μ…˜ κ°œλ°œμ—μ„œ μ€‘μš”ν•œ λΆ€λΆ„ 쀑 ν•˜λ‚˜λŠ” μ—λŸ¬ 처리(μ˜ˆμ™Έ 처리) μž…λ‹ˆλ‹€. μ μ ˆν•œ μ˜ˆμ™Έ 처리λ₯Ό 톡해 μ‚¬μš©μžμ—κ²Œ μœ μš©ν•œ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό 제곡 ν•˜κ³ , μ„œλΉ„μŠ€μ˜ μ•ˆμ •μ„±μ„ 높일 수 μžˆμŠ΅λ‹ˆλ‹€. 이번 ν¬μŠ€νŒ…μ—μ„œλŠ” @ControllerAdvice 와 @ExceptionHandler λ₯Ό ν™œμš©ν•œ μ˜ˆμ™Έ 처리 , κΈ€λ‘œλ²Œ μ˜ˆμ™Έ 처리 μ „λž΅ , 그리고 API 응닡에 μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό μ „λ‹¬ν•˜λŠ” 방법 을 μ•Œμ•„λ΄…λ‹ˆλ‹€.

 


 

 

λͺ©μ°¨

  1. Spring Boot μ˜ˆμ™Έ 처리의 κΈ°λ³Έ κ°œλ…
  2. @ControllerAdvice 와 @ExceptionHandler λ₯Ό ν™œμš©ν•œ μ˜ˆμ™Έ 처리
  3. κΈ€λ‘œλ²Œ μ˜ˆμ™Έ 처리 μ „λž΅
  4. API 응닡에 μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€ μ „λ‹¬ν•˜κΈ°
  5. μ—λŸ¬ 처리의 μ€‘μš”μ„±κ³Ό μ΅œμ‹  νŠΈλ Œλ“œ

 


 

1. Spring Boot μ˜ˆμ™Έ 처리의 κΈ°λ³Έ κ°œλ…

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹€ν–‰ 도쀑 예기치 μ•Šμ€ μ˜ˆμ™Έ(Exception) λ₯Ό λ§Œλ‚˜λ©΄, 이λ₯Ό 적절히 μ²˜λ¦¬ν•˜μ§€ μ•ŠμœΌλ©΄ μ„œλ²„κ°€ μ€‘λ‹¨λ˜κ±°λ‚˜ 잘λͺ»λœ 응닡을 λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. Spring BootλŠ” μŠ€ν”„λ§ μ‹œνλ¦¬ν‹° 와 ν•¨κ»˜ μ˜ˆμ™Έ 처리λ₯Ό μœ„ν•œ 도ꡬλ₯Ό μ œκ³΅ν•˜λ©°, λŒ€ν‘œμ μœΌλ‘œ @ControllerAdvice 와 @ExceptionHandler κ°€ μžˆμŠ΅λ‹ˆλ‹€.

μ˜ˆμ™Έ 처리의 ν•„μš”μ„±

  • μ‚¬μš©μž κ²½ν—˜ ν–₯상 : 직관적인 μ—λŸ¬ λ©”μ‹œμ§€ 제곡
  • μ„œλΉ„μŠ€ μ•ˆμ •μ„± 보μž₯ : μ—λŸ¬κ°€ λ°œμƒν•΄λ„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ€‘λ‹¨λ˜μ§€ μ•Šλ„λ‘ 보호
  • 디버깅 용이 : λ‘œκ·Έμ— μƒμ„Έν•œ μ—λŸ¬ 정보λ₯Ό κΈ°λ‘ν•˜μ—¬ 문제λ₯Ό λΉ λ₯΄κ²Œ ν•΄κ²°

 


 

2. @ControllerAdvice 와 @ExceptionHandler λ₯Ό ν™œμš©ν•œ μ˜ˆμ™Έ 처리

 

@ControllerAdvice λž€?

@ControllerAdvice λŠ” λͺ¨λ“  μ»¨νŠΈλ‘€λŸ¬μ—μ„œ λ°œμƒν•˜λŠ” μ˜ˆμ™Έλ₯Ό μ „μ—­μ μœΌλ‘œ 처리 ν•  수 μžˆλ„λ‘ λ„μ™€μ£ΌλŠ” μ• λ„ˆν…Œμ΄μ…˜μž…λ‹ˆλ‹€. 각 μ»¨νŠΈλ‘€λŸ¬μ—μ„œ κ°œλ³„μ μœΌλ‘œ μ˜ˆμ™Έ 처리λ₯Ό κ΅¬ν˜„ν•  ν•„μš” 없이, μ „μ—­ μ˜ˆμ™Έ 처리 클래슀 μ—μ„œ μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

예제 μ½”λ“œ: μ˜ˆμ™Έ 처리 κ΅¬ν˜„ν•˜κΈ°

 

UserNotFoundException.java (μ»€μŠ€ν…€ μ˜ˆμ™Έ)

package com.example.demo.exception;

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
}

 

GlobalExceptionHandler.java (κΈ€λ‘œλ²Œ μ˜ˆμ™Έ 처리)

package com.example.demo.handler;

import com.example.demo.exception.UserNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<Map<String, Object>> handleUserNotFoundException(UserNotFoundException ex) {
        Map<String, Object> response = new HashMap<>();
        response.put("timestamp", LocalDateTime.now());
        response.put("message", ex.getMessage());
        response.put("status", HttpStatus.NOT_FOUND.value());

        return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }
}

μ½”λ“œ μ„€λͺ…

  1. @ControllerAdvice : λͺ¨λ“  컨트둀러의 μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•˜λŠ” ν΄λž˜μŠ€μž„μ„ μ„ μ–Έν•©λ‹ˆλ‹€.
  2. @ExceptionHandler : νŠΉμ • μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•˜λŠ” λ©”μ„œλ“œμ— μ‚¬μš©ν•©λ‹ˆλ‹€.
  3. ResponseEntity : HTTP μƒνƒœ μ½”λ“œμ™€ ν•¨κ»˜ μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

 


 

3. κΈ€λ‘œλ²Œ μ˜ˆμ™Έ 처리 μ „λž΅

Spring Bootμ—μ„œλŠ” λͺ¨λ“  μ»¨νŠΈλ‘€λŸ¬μ—μ„œ λ°œμƒν•  수 μžˆλŠ” μ˜ˆμ™Έλ₯Ό κΈ€λ‘œλ²Œν•˜κ²Œ 처리 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ•Œ μ‚¬μš©λ˜λŠ” μ „λž΅μ€ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€:

μ˜ˆμ™Έ 처리 μ „λž΅ μ„€λͺ… μ˜ˆμ‹œ
κΈ€λ‘œλ²Œ μ˜ˆμ™Έ 처리 @ControllerAdvice 둜 λͺ¨λ“  μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•¨ λͺ¨λ“  컨트둀러의 μ˜ˆμ™Έλ₯Ό ν•˜λ‚˜μ˜ ν΄λž˜μŠ€μ—μ„œ 처리
νŠΉμ • μ˜ˆμ™Έ 처리 @ExceptionHandler 둜 νŠΉμ • μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•¨ UserNotFoundException 처리
HTTP μƒνƒœ μ½”λ“œ 맀핑 μ˜ˆμ™Έμ— λ§žλŠ” μƒνƒœ μ½”λ“œλ₯Ό λ°˜ν™˜ 404: λ¦¬μ†ŒμŠ€ μ—†μŒ
μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€ μ—λŸ¬ λ©”μ‹œμ§€μ— μ‚¬μš©μž μ •μ˜ 정보 μΆ”κ°€ μ‚¬μš©μž IDκ°€ μ—†λŠ” 경우 “μ‚¬μš©μž μ—†μŒ” λ©”μ‹œμ§€




 

4. API 응닡에 μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€ μ „λ‹¬ν•˜κΈ°

 

μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€ 포함 예제

μ•„λž˜λŠ” μ‚¬μš©μž 쑰회 APIμ—μ„œ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” μ‚¬μš©μž ID둜 μš”μ²­ν•  경우 μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•˜κ³ , μ»€μŠ€ν…€ λ©”μ‹œμ§€λ₯Ό μ‘λ‹΅μœΌλ‘œ λ³΄λ‚΄λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€.

 

UserController.java (μ‚¬μš©μž API 컨트둀러)

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.exception.UserNotFoundException;
import com.example.demo.repository.UserRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

@RestController
public class UserController {

    private final UserRepository userRepository;

    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping("/users/{id}")
    public User getUserById(@PathVariable Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new UserNotFoundException("μ‚¬μš©μžλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€. ID: " + id));
    }
}

μž…μΆœλ ₯ 예제

μš”μ²­ :
GET /users/999

응닡 :

{
    "timestamp": "2024-10-13T12:34:56.789",
    "message": "μ‚¬μš©μžλ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€. ID: 999",
    "status": 404
}

 


 

5. μ—λŸ¬ 처리의 μ€‘μš”μ„±κ³Ό μ΅œμ‹  νŠΈλ Œλ“œ

  • μ—λŸ¬ μ²˜λ¦¬λŠ” μ‚¬μš©μž κ²½ν—˜μ— 직결 λ©λ‹ˆλ‹€. μ μ ˆν•œ λ©”μ‹œμ§€λ₯Ό μ œκ³΅ν•˜μ§€ μ•ŠμœΌλ©΄ μ‚¬μš©μžλŠ” ν˜Όλž€μ„ λŠλ‚„ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • API 응닡 일관성 : λͺ¨λ“  μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό μΌκ΄€λœ ν˜•μ‹μœΌλ‘œ μ œκ³΅ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.
  • λ‘œκ·Έμ™€ λͺ¨λ‹ˆν„°λ§ : μ—λŸ¬λ₯Ό λ‘œκ·Έμ— κΈ°λ‘ν•˜κ³  λͺ¨λ‹ˆν„°λ§ 도ꡬ와 연동해 μ‹€μ‹œκ°„μœΌλ‘œ ν™•μΈν•˜λŠ” 것이 νŠΈλ Œλ“œμž…λ‹ˆλ‹€.
  • μ»€μŠ€ν…€ μ˜ˆμ™Έ 처리 와 ν•¨κ»˜ Spring Boot Actuator λ₯Ό μ‚¬μš©ν•΄ μ—λŸ¬ 정보λ₯Ό μ‹€μ‹œκ°„μœΌλ‘œ λͺ¨λ‹ˆν„°λ§ν•˜λŠ” 사둀도 λŠ˜μ–΄λ‚˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

 


 

κ΄€λ ¨ 링크


Spring 곡식 λ¬Έμ„œπŸ‘†

Spring Boot μ˜ˆμ™Έ 처리 κ°€μ΄λ“œπŸ‘†

Spring Boot Actuator둜 λͺ¨λ‹ˆν„°λ§ ν•˜κΈ°πŸ‘†

JUnit을 μ‚¬μš©ν•œ μ˜ˆμ™Έ 처리 ν…ŒμŠ€νŠΈπŸ‘†

ResponseEntity μ‚¬μš©λ²•πŸ‘†

HTTP μƒνƒœ μ½”λ“œ μ„€λͺ…πŸ‘†




FAQ

 

1. κΈ€λ‘œλ²Œ μ˜ˆμ™Έ μ²˜λ¦¬μ™€ κ°œλ³„ μ˜ˆμ™Έ 처리의 차이점은 λ¬΄μ—‡μΈκ°€μš”?

  • κΈ€λ‘œλ²Œ μ˜ˆμ™Έ μ²˜λ¦¬λŠ” λͺ¨λ“  컨트둀러의 μ˜ˆμ™Έ λ₯Ό ν•œ κ³³μ—μ„œ μ²˜λ¦¬ν•˜κ³ , κ°œλ³„ μ˜ˆμ™Έ μ²˜λ¦¬λŠ” νŠΉμ • μ»¨νŠΈλ‘€λŸ¬μ—μ„œλ§Œ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

2. API 응닡에 JSON ν˜•μ‹μœΌλ‘œ μ—λŸ¬λ₯Ό λ°˜ν™˜ν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•˜λ‚˜μš”?

  • ResponseEntity λ₯Ό μ‚¬μš©ν•΄ JSON ν˜•μ‹μ˜ μ»€μŠ€ν…€ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

3. @ExceptionHandler λ₯Ό μ—¬λŸ¬ 번 μ‚¬μš©ν•  수 μžˆλ‚˜μš”?

  • λ„€, ν•œ ν΄λž˜μŠ€μ—μ„œ μ—¬λŸ¬ μ’…λ₯˜μ˜ μ˜ˆμ™Έλ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ μ—¬λŸ¬ 개의 @ExceptionHandler λ©”μ„œλ“œ λ₯Ό μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

4. μ»€μŠ€ν…€ μ˜ˆμ™Έλ₯Ό μ–Έμ œ μ‚¬μš©ν•΄μ•Ό ν•˜λ‚˜μš”?

  • λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— λ§žλŠ” λͺ…ν™•ν•œ μ—λŸ¬ μ²˜λ¦¬κ°€ ν•„μš”ν•  λ•Œ μ»€μŠ€ν…€ μ˜ˆμ™Έλ₯Ό μ •μ˜ ν•΄ μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

5. Spring Bootμ—μ„œ λ°œμƒν•œ μ˜ˆμ™Έλ₯Ό λ‘œκ·Έμ— κΈ°λ‘ν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•˜λ‚˜μš”?

  • Logger λ₯Ό μ‚¬μš©ν•΄ μ˜ˆμ™Έ λ°œμƒ μ‹œ 둜그λ₯Ό 남기고, λͺ¨λ‹ˆν„°λ§ 도ꡬ와 연동해 μ‹€μ‹œκ°„μœΌλ‘œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

 


 

마무리

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” Spring Boot의 μ˜ˆμ™Έ 처리 μ „λž΅ 을 μƒμ„Ένžˆ μ‚΄νŽ΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€. κΈ€λ‘œλ²Œ μ˜ˆμ™Έ 처리 와 μ»€μŠ€ν…€ μ˜ˆμ™Έ λ©”μ‹œμ§€ λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ•ˆμ •μ„± κ³Ό μ‚¬μš©μž κ²½ν—˜ 을 κ°œμ„ ν•˜λŠ” μ€‘μš”ν•œ μš”μ†Œμž…λ‹ˆλ‹€. Spring Boot와 Spring Security λ₯Ό μ‚¬μš©ν•˜λŠ” κ²½μš°μ—λ„, λ‹€μ–‘ν•œ μ˜ˆμ™Έ 상황에 맞좘 μ •κ΅ν•œ μ˜ˆμ™Έ 처리 μ „λž΅ 은 ν•„μˆ˜μ μž…λ‹ˆλ‹€.

이제 μ—¬λŸ¬λΆ„μ˜ ν”„λ‘œμ νŠΈμ— κΈ€λ‘œλ²Œ μ˜ˆμ™Έ μ²˜λ¦¬μ™€ μ»€μŠ€ν…€ λ©”μ‹œμ§€ λ₯Ό λ„μž…ν•΄λ³΄μ„Έμš”. 이λ₯Ό 톡해 API μ‘λ‹΅μ˜ 일관성 을 μœ μ§€ν•˜κ³ , μ‚¬μš©μžκ°€ λͺ…ν™•ν•˜κ²Œ 이해할 수 μžˆλŠ” μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ μ ˆν•œ 둜그 관리와 λͺ¨λ‹ˆν„°λ§ 도 ν•¨κ»˜ λ„μž…ν•˜λ©΄ μ„œλΉ„μŠ€μ˜ μ•ˆμ •μ„±μ„ ν•œμΈ΅ 더 높일 수 μžˆμŠ΅λ‹ˆλ‹€.

λŒ“κΈ€