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 {
}
Last updated