backend
  • README
  • DOCS
    • Java Docs
    • Servlet Docs
    • JSP Docs
    • DB & SQL Docs
    • Spring Boot Docs
    • Spring Security Docs
    • AWS Docs
  • 설치하기
    • Intellij 설정
  • 자바
    • 01 Java란?
    • 02 자바 시작하기
    • 03 자료형과 연산자
    • 04 제어문
    • 05 메소드
    • 06 클래스 기초
      • Static 보충자료
      • 패키지 보충자료
    • 07 객체지향 프로그래밍
    • 08 클래스 더 알아보기
      • 열거형 ENUM 보충자료
    • 09 클래스와 자료형
      • 다형성 보충자료
      • 제네릭 보충자료
    • 10 컬렉션 프레임워크
      • 컬렉션 프레임워크 보충자료
    • 11 람다식과 함수형 프로그래밍
      • 람다식 보충자료
    • 12 오류 대비하기
      • 오류 보충자료
    • 13 멀티태스킹
      • 멀티태스킹 보충자료
    • 교재보충
      • java.lang
  • 스프링
    • 서블릿, JSP
      • 05 Servlet(서블릿)
        • 서블릿 보충자료
        • 서블릿 추가코드
        • XML, YAML, JSON
      • 06 JSP(자바 서버 페이지)
        • JSP 보충자료
      • 07 JSTL(JSP 스탠다드 태그 라이브러리)
        • JSTL 보충자료
      • 08 Cookie(쿠키), Session(세션)
      • 09 서블릿,필터,리스너
        • 서블릿,필터,리스너 보충자료
      • 11 도서관리 프로젝트 실습
    • Spring Boot
      • 01 스프링 등장 배경, 객체지향
        • 스프링 등장 배경, 객체지향 보충자료
      • 02 IOC(제어의 역전), DI(의존성 주입)
        • IOC 보충자료
        • DI 보충자료
      • 03 스프링 구조
        • 스프링 구조 보충설명
      • 04 테스트코드 실습
      • 05 스프링 빈 설정
        • 스프링 빈 설정 보충자료
      • 06 싱글톤
        • 싱글톤 보충 자료
      • 07 스프링 빈 자동설정
        • 스프링 빈 자동설정 보충자료
      • 08 빈 생명주기
        • 빈 생명주기 보충자료
      • 09 빈 스코프
        • 빈 스코프 보충자료
      • 10 스프링 MVC
        • 스프링 MVC 보충자료
        • 데이터베이스 연동에 필요한 부분
      • 11 Validation(검증)
        • Validation(검증) 보충자료
      • 12 Bean Validation(빈검증)
        • Bean Validation(빈검증) 보충자료
      • 13 예외처리
        • 예외처리 보충자료
      • 14 타입변환
      • 15 JDBC(Java Database Connectivity)
      • 16 커넥션풀
      • 17 트랜잭션
        • 트랜잭션 보충자료
      • 18 JDBC 템플릿 활용
      • 19 MyBatis
      • 20 JPA(Java Persistence API)
      • 22 게시판 프로젝트 실습
    • Spring Security
      • 보안(Security)
      • Spring Security
      • 2. Spring Security 알아보기
        • 보안 위협 실제 사례와 방어 전략
      • 3. Spring Security 기본 동작 흐름
      • 4. Spring Security로 인증 권한 추가하기
        • Spring Security의 인증 및 인가
      • 5. Spring Security에서 세션 관리하기
        • 세션(Session)과 쿠키(Cookie) 비교, 토큰(Token)과의 관계
        • 해싱 및 해싱알고리즘
        • base64
      • 6. Spring Security 악용 보호
        • SameSite
      • 7. Spring Security로 인가 권한 추가하기
      • 8. Bcrypt(비크립트) 암호화
      • OAuth2 적용하기
  • 네트워크
    • HTTP
    • OSI 7계층
  • DB&SQL
    • 01 Database(데이터베이스)와 SQL 개요
    • 02 관계형 모델
    • 03 집합
    • 04 JOIN 연산
    • 05 MySQL
      • 세이브포인트
      • DBeaver, Mysql 오토커밋 설정 관련
    • 06 SQL 기초
      • 예시데이터 쿼리문
    • 07 SQL 실습
      • 실습 스키마
    • 08 Join 활용
      • 실습스키마
    • 09 SQL 활용
      • 실습스키마
    • 10 정규화
      • 실습 스키마
    • 데이터타입
    • 예시 프로젝트 스키마 구성
  • AWS
    • SSL 연결하기
    • 보충설명
Powered by GitBook
On this page
  1. 스프링
  2. Spring Boot

13 예외처리

p230 - src/main/java/mvc/error/controller/ErrorController

@Slf4j
@Controller
@RequestMapping("/error")
public class ErrorController {

    @GetMapping("/test")
    public void getTestError(HttpServletResponse resp) throws IOException {
        resp.sendError(400, "에러 발생");
    }

    @GetMapping("/404")
    public String get400Error(){
        return "error/404";
    }

    // 404 에러 처리 - JSON 응답
    @GetMapping(value = "/404", produces = "application/json")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> get404ErrorJson() {
        Map<String, Object> errorDetails = new HashMap<>();
        errorDetails.put("status", 404);
        errorDetails.put("error", "Not Found");
        errorDetails.put("message", "Page not found");
        errorDetails.put("path", "/error/404");
        return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
    }


    @GetMapping("/500")
    public String get500Error() {
        return "error/500";
    }

    // 500 에러 처리 - JSON 응답
    @GetMapping(value = "/500", produces = "application/json")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> get500ErrorJson() {
        Map<String, Object> errorDetails = new HashMap<>();
        errorDetails.put("status", 500);
        errorDetails.put("error", "Internal Server Error");
        errorDetails.put("message", "An unexpected error occurred");
        errorDetails.put("path", "/error/500");
        return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
    }


    @GetMapping("/runtime")
    public void runtimeException() {
        throw new RuntimeException("runtime exception 발생");
    }

    // Runtime Exception 처리 - JSON 응답
    @GetMapping(value = "/runtime", produces = "application/json")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> runtimeExceptionJson() {
        Map<String, Object> errorDetails = new HashMap<>();
        errorDetails.put("status", 500);
        errorDetails.put("error", "Internal Server Error");
        errorDetails.put("message", "Runtime exception 발생");
        errorDetails.put("path", "/error/runtime");
        return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @GetMapping(value = "/illegal")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> IllegalExceptionHtml() {
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "타입 에러", new IllegalArgumentException());
    }

    @GetMapping(value = "/illegal", produces = "application/json")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> IllegalExceptionJson() {
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "타입 에러", new IllegalArgumentException());
    }

}

p232 - src/main/java/mvc/error/CustomWebServerFactoryCustomizer

@Component
public class CustomWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {

    @Override
    public void customize(ConfigurableWebServerFactory factory) {
        // 404 에러 페이지 등록
        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"));
        // 500 에러 페이지 등록
        factory.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
    }

}

p233 - src/main/resources/templates/error/4xx.html, 404.html, 500.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>400 - Bad Request</title>
</head>
<body>
<h1>400 - Bad Request</h1>

<!-- 오류 정보를 출력 -->
<p><strong>Timestamp:</strong> <span th:text="${timestamp}">2024-10-02T10:15:30</span></p>
<p><strong>Status:</strong> <span th:text="${status}">400</span></p>
<p><strong>Error:</strong> <span th:text="${error}">Bad Request</span></p>
<p><strong>Exception:</strong> <span th:text="${exception}">org.springframework.web.bind.MissingServletRequestParameterException</span></p>
<p><strong>Message:</strong> <span th:text="${message}">Required String parameter 'param' is not present</span></p>
<p><strong>Path:</strong> <span th:text="${path}">/requested/path</span></p>

<!-- 커스텀 에러 메시지 -->
<p th:text="${errorMessage}">요청하신 페이지를 찾을 수 없습니다.</p>

</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>404 - Bad Request</title>
</head>
<body>
<h1>404 - Bad Request</h1>

<!-- 오류 정보를 출력 -->
<p><strong>Timestamp:</strong> <span th:text="${timestamp}">2024-10-02T10:15:30</span></p>
<p><strong>Status:</strong> <span th:text="${status}">400</span></p>
<p><strong>Error:</strong> <span th:text="${error}">Bad Request</span></p>
<p><strong>Exception:</strong> <span th:text="${exception}">org.springframework.web.bind.MissingServletRequestParameterException</span></p>
<p><strong>Message:</strong> <span th:text="${message}">Required String parameter 'param' is not present</span></p>
<p><strong>Path:</strong> <span th:text="${path}">/requested/path</span></p>

<!-- 커스텀 에러 메시지 -->
<p th:text="${errorMessage}">요청하신 페이지를 찾을 수 없습니다.</p>

</body>
</html>
<!DOCTYPE html>
<html>
<head>
  <title>500 - Internal Server Error</title>
</head>
<body>
<h1>500 - Internal Server Error</h1>
<p th:text="${errorMessage}">서버에 오류가 발생했습니다. 잠시 후 다시 시도해주세요.</p>
</body>
</html>

p234 - src/main/java/mvc/error/ExceptionHandlingFilter

@WebFilter("/*") // 모든 요청에 대해 이 필터를 적용합니다.
public class ExceptionHandlingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 필터 초기화 (필요한 경우)
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        try {
            // 다음 필터 또는 서블릿으로 요청 전달
            chain.doFilter(request, response);
        } catch (Exception e) {
            // 예외 발생 시 500 에러 페이지로 포워딩
            handleException(e, httpRequest, httpResponse);
        }

        // 404 오류를 감지하여 처리
        if (httpResponse.getStatus() == HttpServletResponse.SC_NOT_FOUND) {
            httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND, "페이지를 찾을 수 없습니다.");
        }
    }

    @Override
    public void destroy() {
        // 필터 종료 작업 (필요한 경우)
    }

    // 예외를 처리하는 메서드
    private void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 로그 작성 (선택적)
        e.printStackTrace();

        // 500 에러 페이지로 포워딩
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "서버 내부 오류가 발생했습니다.");
    }
}

p238, 240 - src/main/java/mvc/error/LoggingIntercetor

@Slf4j
@Component
public class LoggingInterceptor implements HandlerInterceptor {

    // 요청이 컨트롤러에 전달되기 전에 호출
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 요청별로 고유한 요청 UUID 생성
        String requestUUID = UUID.randomUUID().toString();

        // 요청 객체에 UUID를 저장
        request.setAttribute("requestUUID", requestUUID);

        log.info("preHandle 요청이 컨트롤러에 전달되기 전에 호출 [{}]: {} {}", requestUUID, request.getMethod(), request.getRequestURI());
        return true;
    }

    // 컨트롤러 실행 후, 뷰 렌더링 전에 호출
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        String requestUUID = (String) request.getAttribute("requestUUID");
        log.info("postHandle 컨트롤러 실행 후, 뷰 렌더링 전에 호출 [RequestUUID: {}]", requestUUID);
    }

    // 요청 완료 후 (뷰 렌더링 완료 후) 호출
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        String requestUUID = (String) request.getAttribute("requestUUID");
        log.info("afterCompletion 요청 완료 후 (뷰 렌더링 완료 후) 호출 [RequestUUID: {}]", requestUUID);
        if (ex != null) {
            log.info("afterCompletion 예외 발생 [RequestUUID: {}]: {}", requestUUID, ex.getMessage());
        }
    }
}

p239 , 241- src/main/java/mvc/error/WebConfig

@Configuration
public class WebConfig implements WebMvcConfigurer {
    private final LoggingInterceptor loggingInterceptor;

    @Autowired
    public WebConfig(LoggingInterceptor loggingInterceptor) {
        this.loggingInterceptor = loggingInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 모든 요청에 대해 인터셉터 적용
        registry.addInterceptor(loggingInterceptor)
                .addPathPatterns("/**") // 특정 경로에만 적용하려면 "/api/**" 등으로 변경 가능
                .excludePathPatterns("/static/**", "/css/**", "/js/**", "/public/**", "/error");  // 특정 경로는 제외
    }
}

p243 - src/resources/templates/error/404.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>404 - Bad Request</title>
</head>
<body>
<h1>404 - Bad Request</h1>

<!-- 오류 정보를 출력 -->
<p><strong>Timestamp:</strong> <span th:text="${timestamp}">2024-10-02T10:15:30</span></p>
<p><strong>Status:</strong> <span th:text="${status}">400</span></p>
<p><strong>Error:</strong> <span th:text="${error}">Bad Request</span></p>
<p><strong>Exception:</strong> <span th:text="${exception}">org.springframework.web.bind.MissingServletRequestParameterException</span></p>
<p><strong>Message:</strong> <span th:text="${message}">Required String parameter 'param' is not present</span></p>
<p><strong>Path:</strong> <span th:text="${path}">/requested/path</span></p>

<!-- 커스텀 에러 메시지 -->
<p th:text="${errorMessage}">요청하신 페이지를 찾을 수 없습니다.</p>

</body>
</html>

p246 - src/main/java/mvc/error/GlobalExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body("잘못된 요청입니다: " + ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGenericException(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("서버에서 오류가 발생했습니다: " + ex.getMessage());
    }
}

p247 - src/main/java/mvc/error/PackageSpecificExceptionHandler, SpecificControllerExceptionHandler

@ControllerAdvice("mvc.error.controller")
public class PackageSpecificExceptionHandler {

}
@ControllerAdvice(assignableTypes = {ErrorController.class})
public class SpecificControllerExceptionHandler {

}

PreviousBean Validation(빈검증) 보충자료Next예외처리 보충자료

Last updated 6 months ago