spring 리마인드

Spring MVC의 예외처리 ExceptionHandler

LRWoo 2023. 10. 11. 18:11
728x90
반응형

 

@ExceptionHandler
어노테이션은 예외처리함수임을 명시한다
괄호안에는 어떤 타입의 예외가 발생했을 경우 처리하는 함수인지 명시한다.
이벤트 함수처럼, 특정 타입의 예외가 발생하면 해당 함수를 호출하여 실행한다. 

 

 

parseInt는 NumberFormatException을 throw하는 함수이다. 

그래서 정수로변환할 수 없는 문자열을 받을 경우 예외가 터진다. 

 

각각의 코드에서 예외가 발생할 수 있는 코드들이 분산되어있을 경우  일일이 예외처리를 해준다면 
코드의 가독성이 떨어지고 비슷한 코드들이 반복된다.  

SpringMVC에서는 똑같은 예외가 발생할 수 있는 코드들을 한데에 모아서 처리하게 된다. 

 

각각의 코드에 try-catch를 해주는 대신에 Controller에다가 어노테이션 처리를 해준다. 

서비스, 컴포넌트, DAO 등에서 발생하는 예외를 컨트롤러로 넘겨서 

컨트롤러에서 취합하여 특정 타입의 예외를 처리하는 함수를 별도로 처리한다. 

 

Controller

	@ExceptionHandler(NumberFormatException.class)
	public ModelAndView num1Exception(NumberFormatException e) {
		
		ModelAndView mav = new ModelAndView("number-exception");
		mav.addObject("msg", e.getMessage());
		
		return mav;
	}

 

number-excption. jsp 생성 

 

 

서버를 실행하면 예외가 터졌을 때 메세지를 ExceptionHandler가 처리하여 

모델엔드뷰가 number-exception.jsp로 반환하고 

number-exception.jsp에서 예외메세지를 띄운다. 

 

 

NullPointerException을 처리해보자

	public int getNum2() {
		String s1 = null;
		String s2 = "a";
//		return Integer.parseInt("300000000000");
		return s1.compareTo(s2);
	}

 

controller

	@ExceptionHandler(NullPointerException.class)
	public ModelAndView np2() {
		ModelAndView mav = new ModelAndView("number-exception");
		mav.addObject("msg", "알수없는 문제가 발생했습니다.");
		return mav;
	}

 

하지만 이렇게 controller에서 일일이 Handler처리를 해주면 

요청과 응답을 처리하는 Controller의 코드가 복잡해진다. 

 

ControllerAdvice: 스프링 빈으로 등록 필수 
예외처리함수가 모여있는 클래스에 지정한다.
범위를 별도로 지정하지 않으면, 프로젝트 전역에서 발생하는 예외를 처리한다.

 

새로운 패키지 생성 

root-context로 가서 component-scan을 추가해준다. 

 

Ex02Controller에서  배열의 범위를 초과하는 예외를 터트려보자 

 

@Controller
public class Ex02Controller {
	
	private int[] arr = {4,8,2,7,6};
	
	@GetMapping("/ex02")
	public ModelAndView ex02() {
		ModelAndView mav = new ModelAndView();
		mav.addObject("num1",arr[0]);
		mav.addObject("num2",arr[2]);
		mav.addObject("num3",arr[5]);	//ArrayIndexOutOfBoundsException
		return mav;
	}
	
}

 

exception패키지의 Ex02ControllerAdvice클래스에서 @ControllerAdvice어노테이션을 추가해준다. 

assignableTypes :
예외처리함수가 모여있는 클래스에 지정한다.
범위를 별도로 지정하지 않으면, 프로젝트 전역에서 발생하는 예외를 처리한다.
범위를 지정하는 방법
1) assignableTypes : 클래스 정보의 배열을 전달한다.
2) value :  특정 패키지를 문자열로 전달하여 내부의 컨트롤러에서 발생하는 예외를 처리하게된다.  
3) annotations : 단일 어노테이션클래스 정보를 전달한다.  

 

@ResponseBody는 따로 jsp를 만들지 않고 함수가 반환하는 내용 그자체가 응답으로 jsp 포워딩하지않는다. 

@ControllerAdvice(assignableTypes = {Ex02Controller.class})	
//					예외처리함수가 모여있는 클래스에 지정한다.
//					범위를 별도로 지정하지 않으면, 프로젝트 전역에서 발생하는 예외를 처리한다.
//					범위를 지정하는 방법
//					1) assignableTypes : 클래스 정보의 배열을 전달한다.
//					2) annotations : 단일 클래스 정보를 전달한다. 
//					3) 문자열 전달 : 특정 패키지 내부의 컨트롤러에서 발생하는 예외를 처리하게된다. 
public class Ex02ControllerAdvice {
	
	@ExceptionHandler(ArrayIndexOutOfBoundsException.class)
	@ResponseBody		//이 함수가 반환하는 내용 그자체가 응답이다. (그러니까 jsp포워딩 하지마라 )
	public String indexException(ArrayIndexOutOfBoundsException e ) {
		String html = "";
		html +="<!DOCTYPE html>";
		html +="<html>";
		html +="<head></head>";
		html +="<body>";
		html +="<script>";
		html +="	alert('" + e.getMessage() + "')\n";
		html +="	location.href = '/day10'";
		html +="</script>";
		html +="</html>";
		return html;
	}
}

 

ex02예외처리를 누르면 

만약 service에서 예외를 발생시키지않으면 

@Service
public class Ex02Service {

	private int[] arr = {4,8,2,7,6};
	public int getNum4() { /*	throws ArrayIndexOutOfBoundsException */						
		return arr[1];
	}

정상적으로 ex02.jsp가 뜬다. 

 

예외처리는 초반에 만들지 않는 것을 권장한다.  무슨 오류가 발생했는지 알 수 없어서

만드는 과정이 길어지고 복잡해진다.  

728x90
반응형