국비교육(22-23)

56일차(2)/Spring(18) : 예외 클래스, Exception Controller

서리/Seori 2022. 12. 26. 21:25

56일차(2)/Spring(18) : 예외 클래스, Exception Controller

 

- Spring 프로젝트로 돌아와서, 예외 상황시의 control 방법 추가히기

 

 

com.sy.spring04.exception 패키지 생성

ExceptionController 클래스 생성

package com.sy.spring04.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
/*
 * Spring MVC가 동작중에 특정 type의 예외가 발생하면 해당 예외를 여기서 처리할 수 있다.
 */

@ControllerAdvice
public class ExceptionController {
	//spring Framework가 동작하는 중에 NotDeleteException type의
	//예외가 발생하면 호출되는 메소드
	@ExceptionHandler(NotDeleteException.class)
	public ModelAndView notDelete(NotDeleteException nde) {//메소드의 인자로 예외객체가 전달된다.
		ModelAndView mView=new ModelAndView();
		//exception이라는 키값으로 예외 객체를 담고
		mView.addObject("exception", nde);
		//view page(/WEB-INF/views/error/info.jsp) 로 forward 이동해서 예외정보 응답하기
		mView.setViewName("error/info");
		return mView;
	}
}

 

@ControllerAdvice 어노테이션 붙여주기!

 

 

NotDeleteException 생성

package com.sy.spring04.exception;
/*
 * 예외 클래스를 만드는 방법
 * 
 * 1. RuntimeException 클래스를 상속받아서 만든다.
 * 2. String type 을 전달받는 생성자를 정의한 다음 생성자에 전달되는 문자열을 
 *    부모 생성자에 전달하는 코드를 작성한다.
 * - 이 클래스로 생성된 객체는 getMessage() 라는 메소드를 가지고 있는데
 *   해당 메소드는 생성자에 전달받았던 예외 메세지를 리턴해준다.
 *   
 * ex)
 * NotDeleteException nde=new NotDeleteException("oh! no");
 * String msg=nde.getMessage(); // "oh! no"
 * 
 * - 어디에선가 이 예외를 발생시키고 싶으면 throw 예약어를 활용하면 된다.
 * 
 * ex) throw new NotDeleteException("남의 파일 지우기 없기");
 */
public class NotDeleteException extends RuntimeException{

	//생성자
	public NotDeleteException(String message) {
		super(message);
	}
}

 

[ 예외 클래스를 만드는 방법 ]
1. RuntimeException 클래스를 상속받아서 만든다.
2. String type 을 전달받는 생성자를 정의한 다음, 생성자에 전달되는 문자열을 부모 생성자에 전달하는 코드를 작성한다.
- 이 클래스로 생성된 객체는 getMessage() 라는 메소드를 가지고 있는데, 해당 메소드는 생성자에 전달받았던 예외 메세지를 리턴해준다.

 

ex)
NotDeleteException nde=new NotDeleteException("oh! no");
String msg=nde.getMessage(); // "oh! no"
- 어디에선가 이 예외를 발생시키고 싶으면 throw 예약어를 활용하면 된다.
ex) throw new NotDeleteException("남의 파일 지우기 없기");

 

- 예외 클래스를 하나 정의해놓고, 예외클래스를 실행하고 싶을 때 throw로 작성해놓으면

 개발자가 의도한 custom 예외가 발생하게 된다.

 


 

 

FileService - deleteFile 메소드

@Override
public void deleteFile(int num, HttpServletRequest request) {

    //삭제할 파일의 정보를 얻어오기
    FileDto dto=dao.getData(num);

    //글 작성자와 로그인된 아이디가 일치하는지 확인해서 일치하면 삭제하고, 일치하지 않으면 예외를 발생시키기
    String id=(String)request.getSession().getAttribute("id");
    if(!dto.getWriter().equals(id)) {
        //예외를 발생시키면 해당 예외를 처리하는 곳으로 실행의 흐름이 넘어간다.
        throw new NotDeleteException("남의 파일 지우기 없기!");
    }

    //파일 시스템에서 삭제(upload 폴더에서 해당파일을 삭제)
    String saveFileName=dto.getSaveFileName();
    String path=request.getServletContext().getRealPath("/resources/upload")
            +File.separator+saveFileName;
    //경로를 사용해서 파일객체를 생성해서
    new File(path).delete();
    //DB에서 파일 정보 삭제
    dao.delete(num);		
}

 

- 무조건 삭제하는 것이 아니고, 메소드 실행 전 본인 확인을 거친다.

- 글 작성자와 로그인된 아이디가 일치하는지 확인해서 일치하면 삭제하고, 일치하지 않으면 예외를 발생시키기!

- 에러발생시 에러 정보에 대한 응답을 해주어야 한다.

 

- 이렇게 중간에 exception 처리를 위한 코드를 넣어준다.

 

- throw 문으로 들어가서 예외가 실행되면 아래 구문은 실행되지 않는다.

 실행의 흐름이 넘어간다!!

 

- 이렇게 작성하면?

 

- 이렇게 의도적으로 500번 오류를 발생시켜 응답해줄 수 있다.

 

- 아래 나온 내용은 tomcat에서 응답해준 것인데, 다른방식으로 처리하고 싶으면

 개발자가 예외 컨트롤러에서 직접 컨트롤 할 수 있다.

 

 

- @ExceptionHandler 사용. NotDeleteException 클래스를 가져온다.

- 메소드의 인자로 예외 객체가 전달된다.

- 에러정보를 출력하려면 error/info 페이지를 만들어야 한다.

 

info.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/views/error/info.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
	<div class="container">
		<h1>Oops!</h1>
		<p class="alert alert-danger">
			<%--
				예외 컨트롤러에서				
				ModelAndView mView=new ModelAndView();		
				mView.addObject("exception", nde);
				exception이라는 키값으로 예외객체를 담았기때문에
				예외메시지는
				${exception.message} (는 ${exception.getMessage}를 대신한다.)
				로 출력할 수 있다.
			 --%>
			<strong>${exception.message}</strong>
			<a href="${pageContext.request.contextPath}/">인덱스로 돌아가기</a>
		</p>
	</div>
</body>
</html>

 

- ModelAndView로 담아주었기 때문에, EL로 출력할 수 있다.

 

- 본인이 아닌 삭제 요청에 대해서 예외 컨트롤러가 잘 동작한다.

 

- 파일간의 연관성을 보면, 위와 같이 예외객체를 담은 메세지를 호출하는 구조인 것을 알 수 있다.

 

- 생성자로 전달된것이 뷰페이지에서 활용된다.

- Service에서 throw 하면 예외 컨트롤러가 동작한다!

- 그러면 controller가 수행되고, 아래 구문이 실행된다

 

- notDelete 메소드가 실행되면서 예외객체를 mView에 담아서 응답하면

  뷰페이지로 포워드 이동해서 클라이언트에게 응답한다.

 

- 요청에 실패하면 예외 클래스를 만들어놓고, 실패 상황 발생시 throw하면 된다.

- 예외컨트롤러에 세부적인 내용(처리, 응답)을 적어둔다.