@DateTimeFormat 

 

Spring에서 문자열 형태의 날짜/시간을 LocalDate, LocalDateTime, Date 등으로 변환할 때 사용하는 어노테이션

주로 Controller parameter, @ModelAttribute, Dto 등에 사용

 

 

 

GET /members?from=2025-07-01T00:00:00&to=2025-07-09T23:59:59

 

@GetMapping("/members")
public List<Member> getMembersByDateRange(
        @RequestParam("from")
        @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") LocalDateTime from,

        @RequestParam("to")
        @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") LocalDateTime to) {

    return memberService.getMembersBetween(from, to);
}

 

 

 

 

 

** 타입 ISO 기본 포맷 예시

LocalDate yyyy-MM-dd 2025-07-09
LocalTime HH:mm:ss 14:30:00
LocalDateTime yyyy-MM-dd'T'HH:mm:ss 2025-07-09T14:30:00

 

 

 

Dto에서의 활용

public class SearchRequest {

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate startDate;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate endDate;

    // getters/setters
}

 

 

변환 에러처리

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 날짜 파라미터 형식이 잘못된 경우 처리
    @ExceptionHandler({ MethodArgumentTypeMismatchException.class, BindException.class })
    public ResponseEntity<ErrorResponse> handleDateTimeFormatException(Exception ex) {
        return ResponseEntity
                .badRequest()
                .body(new ErrorResponse("INVALID_DATE_FORMAT", "날짜 형식이 잘못되었습니다. 예: yyyy-MM-dd 또는 yyyy-MM-dd'T'HH:mm:ss"));
    }

    // 기타 예외 처리
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
        return ResponseEntity
                .status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(new ErrorResponse("INTERNAL_ERROR", "서버 오류가 발생했습니다."));
    }
}

 

 

예외 클래스 발생 상황

MethodArgumentTypeMismatchException @RequestParam 변환 실패 (LocalDate, LocalDateTime 등)
BindException @ModelAttribute 또는 폼 바인딩 실패
HttpMessageNotReadableException @RequestBody 변환 실패 (JSON 날짜 오류 등)

 

 

 

 

@PathVariable을 이용한 경로 변수 처리

 

spring MVC에서 URL 경로에 포함된 값을 메서드의 파라미터로 바인딩할 때 사용하는 어노테이션

REST API 설계에서 자주 사용되며, 리소스의 식별자(ID, 이름 등) 를 전달할 때 적합

 

예시

@GetMapping("/members/{id}")
public Member getMemberById(@PathVariable("id") Long id) {
    return memberService.findById(id);
}

 

요청 예시

GET localhost:8080/members/123

 

위와 같이 members/ 뒤의 숫자를 통해 가변경로 처리 가능

 

 

 

 

Controller Exception 처리

Spring MVC에서 Exception을 처리하는 방식에는 크게 세 가지 방식 존재

범위 방식 특징 권장 여부
전역 처리 @RestControllerAdvice / @ControllerAdvice 모든 컨트롤러에서 공통 처리 표준방식
전역 저수준 HandlerExceptionResolver DispatcherServlet 수준 예외 가로채기 특수목적용
필터/서블릿 Filter, HttpServlet Spring 컨텍스트 외부에서 처리 보안/로깅 용도

 

 

 

@ExceptionHandler 

@RestController
@RequestMapping("/members")
public class MemberController {

    @GetMapping("/{id}")
    public Member get(@PathVariable Long id) {
        return memberService.findById(id); // 예외 가능성
    }

    @ExceptionHandler(MemberNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(MemberNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
    }
}

 

개별 컨트롤러에 에러 처리 메서드 선언

 

 

@RestControllerAdvice, @ControllerAdvice

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MemberNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleMemberNotFound(MemberNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(new ErrorResponse("MEMBER_NOT_FOUND", ex.getMessage()));
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<ErrorResponse> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
        return ResponseEntity.badRequest()
                .body(new ErrorResponse("INVALID_PARAMETER", "요청 파라미터 형식이 잘못되었습니다."));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneric(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(new ErrorResponse("INTERNAL_ERROR", "서버 내부 오류"));
    }
}

 

위처럼 @RestControllerAdvice 어노테이션을 사용한 클래스에서 

ExcptionHandler 메서드를 모아 전역으로 처리 가능

 

 

** RestControllerAdvice, ControllerAdvice 차이

 

RestController와 Controller의 차이와 같음

Response 의 형식에 대한 차이

 

 

항목 @ControllerAdvice @RestControllerAdvice
응답 처리 방식 View 이름 또는 Model 반환 JSON, XML 등 객체 직렬화 반환
@ResponseBody 포함 여부 ❌ 포함 안 됨 (수동 설정 필요) ✅ 자동 포함 (@ResponseBody 내장)
주 사용 대상 JSP, Thymeleaf 기반의 웹 MVC REST API, JSON 기반 서비스
반환 타입 ModelAndView, String, Model 등 POJO 객체 (ErrorResponse, Map 등)
도입 버전 Spring 3.2 이상 Spring 4.3 이상 (Spring Boot 1.4+)

 

 

쉽게 말해서 View를 반환하냐, json 응답 반환하냐 차이

대부분의 경우 이 방식 사용 권장

 

 

 

HandlerExceptionResolver

 

Spring MVC에서 제공하는 저수준 예외 처리 인터페이스

@ControllerAdvice나 @ExceptionHandler보다 먼저 실행되는 전역 예외 처리 수단

 

 

언제사용?

로깅 시스템 또는 알림 시스템과 연계 모든 예외를 공통 처리하거나 Slack/Email 전송
Spring이 처리하지 못하는 예외에 대한 대응 DispatcherServlet 수준에서 직접 처리
View 기반 프로젝트에서 특정 예외 → 특정 페이지 리턴 예: 404.html, 500.jsp 등 매핑 처리
Exception 흐름 완전 차단 (기존 핸들러 무시) 필터처럼 동작시킴

 

 

예시

@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {

        // 예외 로깅
        System.err.println("예외 발생: " + ex.getClass().getSimpleName());

        // 응답 상태 코드 설정
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

        // REST API의 경우 직접 JSON 응답 작성 (비권장 방식)
        // 또는 아래처럼 View를 지정
        ModelAndView mav = new ModelAndView("error/globalError");
        mav.addObject("errorMessage", ex.getMessage());

        return mav;
    }
}

 

+ Java config 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        resolvers.add(new CustomExceptionResolver());
    }
}

 

 

비교

항목 HandlerExceptionResolver  @RestControllerAdvice
동작 시점 DispatcherServlet 수준 HandlerAdapter 이후
예외 흐름 차단 가능 (더 이상 예외 던지지 않음) 예외는 전달되며 순서 중요
REST 응답 지원 비직관적 (직접 응답 작성 필요) 자동 JSON 직렬화
사용 목적 로깅, 비표준 처리 일반적인 예외 처리

 

 

Filter, HttpServlet 방식

Spring MVC 바깥의 계층에서 예외를 잡는 저수준 방식

 

목적  설명
Spring MVC 진입 전 예외 처리 예: 인증 필터, 로깅 필터, WAS 레벨 예외
Spring이 잡지 못하는 500 에러 대응 DispatcherServlet 밖에서 발생하는 예외 감지
커스텀 응답(JSON) 강제 처리 스프링이 처리하지 않는 응답 직접 구성
보안 필터 체인 / API Gateway 대응 인증, 권한 필터 등과 연계

 

 

예시

@Component
public class ExceptionHandlingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) res;

        try {
            chain.doFilter(req, res);
        } catch (Exception ex) {
            // 예외 로깅
            ex.printStackTrace();

            // 커스텀 JSON 응답
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.setContentType("application/json");
            response.getWriter().write("{\"error\": \"" + ex.getMessage() + "\"}");
        }
    }
}

 

  • DispatcherServlet 이전 단계에서 예외 처리 가능
  • JSON 응답 수동 처리 필요
  • SecurityFilterChain 앞뒤 어디든 배치 가능

 

 

 

 

Filter, SecurityFilter

클라이언트 요청
   ↓
[서블릿 필터 (Filter)]
   ↓
[Spring Security FilterChainProxy]
   ↓
[DispatcherServlet (Spring MVC)]
   ↓
@Controller 등

 

 

  • 일반 Filter는 Spring Security보다 먼저 실행됨
  • Spring Security는 자체 필터 체인을 갖고 있음 (FilterChainProxy로 래핑됨)

 

 

 

+ Recent posts