관리 메뉴

거니의 velog

231208_SPRING 2 (13-1) 본문

대덕인재개발원_웹기반 애플리케이션

231208_SPRING 2 (13-1)

Unlimited00 2023. 12. 8. 08:07

package kr.or.ddit.controller.exception;

public class ExceptionController {

	/*
	 * [ 16장 : 예외처리 ]
	 * 
	 * 		1. 예외처리
	 * 
	 * 			일반적으로 프로그램이 처리되는 동안 특정한 문제가 일어났을 때, 처리를 중단하고 다른 처리를 하는 것을 예외처리라고 한다.
	 * 			웹 컨테이너는 기본적으로 예외처리를 하여 기본 에러 페이지를 표시해준다.
	 * 			하지만, 페이지에 애플리케이션 서버의 내부 정보가 일반 사용자들에게 노출되어 프레임워크의 보안 취약점을 노린 공격을 
	 * 			받을 수 있다. 이런 점을 고려하여 최대한 사용자가 직접 예외를 처리하여 사용자가 정의한 에러 페이지를 표시하게 해야 한다.
	 * 
	 * 			1-1) 예외 종류
	 * 			- 스프링 프레임워크 예외
	 * 			- 사용자 정의 예외
	 * 			- 의존 라이브러리에서 발생한 예외
	 * 			- 시스템 예외
	 * 
	 * 			1-2) 이번 장에서 가상한 예외 상황
	 * 			- A. 수정 화면 생성하고 뷰 파일에서 예외 발생
	 * 			- B. 삭제 할 때, 매핑 파일에서 예외 발생
	 * 			- C. 존재 하지 않는 게시물을 조회할 때, 사용자가 정의한 예외 발생
	 * 			- D. 존재 하지 않는 페이지 URL 요청 시 예외 발생
	 * 
	 * 			1-3) 예외처리 불가 기준
	 * 			- 사용자가 정의한 예외 처리기를 거치지 않는 예외로 프레임워크에서 이러한 예외를 처리한 기본적인 내용은 아래와 같다.
	 * 				> Http Status 400 - Bad Request
	 * 
	 * 		2. 예외상황
	 * 
	 * 			2-1) 예외 발생 상황
	 * 
	 * 				- 수정 화면 생성하고 뷰 파일에서 예외 발생
	 * 					> Http Status 500
	 * 					> [예외 상황 만들 위치]
	 * 						views/crud/register.jsp <form:title path="title2" />로 수정
	 * 
	 * 				- 삭제 할 때 매핑 파일에서 예외 발생
	 * 					> Http Status 500
	 * 					> [예외 상황 만들 위치]
	 * 						sqlmap/boardMapper_SQL.xml id가 delete인 삭제 기능을 가진 태그에서
	 * 						board_no를 board_no2로 수정
	 * 
	 * 				- 존재하지 않는 게시물을 조회할 때 사용자가 정의한 예외 발생
	 * 					> Http Status 500
	 * 					> [예외 상황 만들 위치]
	 * 						kr.or.ddit.service.impl.BoardServiceImpl read() 수정
	 * 						new BoardRecordNotFoundException 예외 발생
	 * 
	 * 				- 존재하지 않는 페이지 URL 요청 시 예외 발생
	 * 					> Http Status 404
	 * 					> [요청 URL]
	 * 						/crud/board/retry
	 * 
	 * 		3. 상태 코드 사용한 에러 페이지 설정
	 * 
	 * 			- 웹 컨테이너 설정 파일(web.xml)의 <error-code> 요소에 상태 코드를 설정하고 <location> 요소에 이동 대상
	 * 				페이지를 지정한다.
	 * 
	 * 				[예외 처리 방법]
	 * 				- 웹 컨테이너 설정(web.xml)
	 * 				<error-page></error-page> 400 코드 설정
	 * 				<error-page></error-page> 404 코드 설정
	 * 				<error-page></error-page> 500 코드 설정
	 * 
	 * 				> 수정 화면 생성할 때 뷰 파일에서 예외 발생
	 * 				> 삭제 할 때 매핑 파일에서 예외 발생
	 * 				> 존재하지 않는 게시물을 조회할 때 사용자가 정의한 예외 발생
	 * 				> 존재하지 않는 페이지 URL 요청 시 예외 발생
	 * 
	 * 				- 처리할 수 있는 예외
	 * 
	 * 				- 처리할 수 없는 예외
	 * 
	 * 		4. 예외 타입 사용한 에러 페이지 설정
	 * 
	 * 			- 웹 컨테이너 설정 파일(web.xml)의 <exception-type> 요소에 예외 타입을 설정하고 <location> 요소에 이동 대상 페이지를
	 * 				지정한다.
	 * 
	 * 				[예외 처리 방법]
	 * 				- 웹 컨테이너 설정(web.xml)
	 * 					> <error-page><exception-type></exception-type>...</error-page>
	 * 
	 * 				- 처리할 수 있는 예외
	 *
	 *				- 처리할 수 없는 예외
	 *
	 *		5. 기본 에러 페이지 설정
	 *
	 *			- 웹 컨테이너 설정 파일(web.xml)의 <location> 요소만 지정해 <error-page> 요소를 정의한다.
	 *
	 *			[예외 처리 방법]
	 *			- 웹 컨테이너 설정(web.xml)
	 *				> <error-page></error-page>
	 *				> 기본 이동 대상의 설정
	 *				> 에러 페이지를 jsp 파일 절대 경로로 설정
	 *				> Controller에서 선언한 URL 매핑 정보로도 설정 가능
	 *				> 서블릿 3.1 이상에서 지원
	 *
	 *			- 처리할 수 있는 예외
	 *				> 수정 화면 생성할 때 뷰 파일에서 예외 발생
	 * 				> 삭제 할 때 매핑 파일에서 예외 발생
	 * 				> 존재하지 않는 게시물을 조회할 때 사용자가 정의한 예외 발생
	 * 				> 존재하지 않는 페이지 URL 요청 시 예외 발생
	 *
	 *			- 처리할 수 없는 예외
	 *
	 *		6. 예외 처리 어노테이션
	 *
	 *			- @ExceptionHandle과 @ControllerAdvice를 이용하여 처리한다.
	 *
	 *				[예외 처리 방법]
	 *				- @ControllerAdvice 어노테이션은 스프링 컨트롤러에서 발생하는 예외를 처리하는 핸들러 클래스임을 명시한다.
	 *				- @ExceptionHandle 어노테이션은 괄호 안에 설정한 예외 타입을 해당 메소드가 처리한다는 것을 의미한다.
	 *
	 *				예외 처리 핸들러 생성
	 *				> kr.or.ddit.controller.exception.CommonExceptionHandler 클래스 생성
	 *
	 *				- 처리할 수 있는 예외
	 * 				> 삭제 할 때 매핑 파일에서 예외 발생
	 * 				> 존재하지 않는 게시물을 조회할 때 사용자가 정의한 예외 발생
	 *
	 *				- 처리할 수 없는 예외
	 *				> 수정 화면 생성할 때 뷰 파일에서 예외 발생
	 *					> ServletException을 상속받는 JasperException 에러 발생이므로 Exception 처리를 타지 않음
	 * 				> 존재하지 않는 페이지 URL 요청 시 예외 발생
	 * 					> 404 종류에 해당하는 에러기 때문에 예외를 타지 않음
	 * 
	 * 		7. 예외 정보 출력
	 * 
	 * 			- 예외에 대한 내용을 Model 객체를 이용해서 전달하여 뷰 화면에서 출력이 가능하다.
	 * 
	 * 				[예외 처리 방법]
	 * 				- CommonExceptionHandler 클래스에서 에러 정보를 페이지로 던져 준다.
	 * 
	 * 				- 처리할 수 있는 예외
	 * 				> 삭제 할 때 매핑 파일에서 예외 발생
	 * 				> 존재하지 않는 게시물을 조회할 때 사용자가 정의한 예외 발생
	 *
	 *				- 처리할 수 없는 예외
	 *				> 수정 화면 생성할 때 뷰 파일에서 예외 발생
	 *					> ServletException을 상속받는 JasperException 에러 발생이므로 Exception 처리를 타지 않음
	 * 				> 존재하지 않는 페이지 URL 요청 시 예외 발생
	 * 					> 404 종류에 해당하는 에러기 때문에 예외를 타지 않음
	 * 
	 * 		8. 404 에러 페이지 처리
	 * 
	 * 			- web.xml 설정을 통해서 처리할 수 있다.
	 * 
	 * 				[예외 처리 방법]
	 * 				- 웹 컨테이너 설정
	 * 					> 404 에러를 처리할 수 있도록 DispatcherServlet의 throwExceptionIfNoHandlerFound
	 * 						속성을 true로 설정
	 * 
	 * 				- 처리할 수 있는 예외
	 * 					> 존재하지 않는 페이지 URL 요청 시 예외 발생
	 * 
	 * 		9. 입력값 검증 예외 처리
	 * 
	 * 			- @Validated 어노테이션을 사용하면 Bean Validation의 유효성 검증 메커니즘을 이용할 수 있다.
	 * 
	 * 				[예외 처리 방법]
	 * 				- 입력값 검증 기능의 활성화와 BindingResult 정의
	 * 					> 입력값 검증 대상인 자바빈즈 메소드 매개변수에 @Validated 어노테이션을 지정하고 바로 다음에 BindingResult를 정의한다.
	 * 					> BindingResult에는 요청 데이터의 바인딩 에러와 검사 에러 정보가 저장된다.
	 * 
	 * 			- 스프링 form 태그를 이용한 입력값 검증
	 * 				<form:form> 클라이언트에서 열고 서버와 데이터를 주고 받는 순환 체계를 생성할 때 필수로 들어가는 값이 modelAttribute.
	 * 				이 안에 member에 해당하는 자바 객체 타입으로 순환 체계를 연결하겠다고 설정했다면, 이것과 서버의 연결 조건은? Model model이라는 데이터 전달자를 선언해야 함
	 * 				그런 상태에서 디폴트로 여러 값들을 세팅하고 자동으로 매핑 됨. @Validated 어노테이션을 지정
	 * 				중첩된 자바빈즈 클래스를 정의하고 @Valid를 지정.
	 * 				여기서 발생한 에러를 BindingResult가 잡아준다.
	 * 				<form:errors /> 이게 오류를 출력해 줌.
	 * 				
	 */
	
}

[web.xml]

	<!-- 3. 상태 코드를 사용한 이동 대상 페이지 설정 시작 -->
	<error-page>
		<error-code>400</error-code>
		<location>/WEB-INF/views/error/errorCommon400.jsp</location>
	</error-page>
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/error/errorCommon404.jsp</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/error/errorCommon500.jsp</location>
	</error-page>
	<!-- 3. 상태 코드를 사용한 이동 대상 페이지 설정 끝 -->

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>COMMON ERROR 400</title>
	</head>
	<body>
		<h2>errorCommon400 Error Page...!</h2>
	</body>
</html>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>COMMON ERROR 404</title>
	</head>
	<body>
		<h2>errorCommon404 Error Page...!</h2>
	</body>
</html>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>COMMON ERROR 500</title>
	</head>
	<body>
		<h2>errorCommon500 Error Page...!</h2>
	</body>
</html>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>CRUD REGISTER</title>
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
	</head>
	<body>
		<h2>REGISTER</h2>
		<form:form modelAttribute="registerForm" action="/crud/board/register" method="post">
		
			<c:if test="${status eq 'u' }">
				<input type="hidden" name="boardNo" value="${board.boardNo }" />
			</c:if>
			
			<table border="1">
				<tr>
					<td>제목</td>
					<td>
						<form:input path="title2" />
						<%-- <input type="text" id="title" name="title" value="${board.title }" /> --%>
					</td>
				</tr>
				<tr>
					<td>작성자</td>
					<td><input type="text" id="writer" name="writer" value="${board.writer }" /></td>
				</tr>
				<tr>
					<td>내용</td>
					<td>
						<textarea rows="10" cols="40" name="content" id="content" wrap="soft">${board.content }</textarea>
					</td>
				</tr>
			</table>
			<div>
				<c:set value="등록" var="btnText" />
				<c:if test="${status eq 'u' }">
					<c:set value="수정" var="btnText" />
				</c:if>
				<button type="button" id="registerBtn">${btnText }</button>
				<c:if test="${status eq 'u' }">
					<button type="button" id="cancelBtn">취소</button>
				</c:if>
				<c:if test="${status ne 'u' }">
					<button type="button" id="listBtn">목록</button>
				</c:if>
			</div>
		</form:form>
	</body>
	<script type="text/javascript">
		$(function(){
			
			var registerForm = $("#registerForm"); // form element
			var registerBtn = $("#registerBtn"); // 등록 버튼 element
			var listBtn = $("#listBtn"); // 목록 버튼 element
			var cancelBtn = $("#cancelBtn"); // 취소 버튼 element
			
			registerBtn.on("click", function(){
				var title = $("#title").val();
				var writer = $("#writer").val();
				var content = $("#content").val();
				
				if(!title) {
					alert("제목을 입력해 주세요!");
					return false;
				}
				
				if(!writer) {
					alert("작성자를 입력해 주세요!");
					return false;
				}
				
				if(!content) {
					alert("내용을 입력해 주세요!");
					return false;
				}
				
				// 수정일 때 수정 경로로 변경한다.
				if($(this).text() == "수정") {
					registerForm.attr("action", "/crud/board/modify");
				}
				
				registerForm.submit();
			});
			
			listBtn.on("click", function(){
				location.href = "/crud/board/list";
			});
			
			cancelBtn.on("click", function(){
				location.href = "/crud/board/read?boardNo=${board.boardNo}";
			});
			
		});
	</script>
</html>

	<delete id="delete" parameterType="int">
		delete from board where board_no2 = #{boardNo}
	</delete>

	@Override
	public Board read(int boardNo) throws Exception {
		
//		return mapper.read(boardNo);
		
		Board board = mapper.read(boardNo);
		
		if(board == null) {
			throw new BoardRecordNotFoundException("Not Found boardNo = " + boardNo);
		}
		
		return board;
		
	}

package kr.or.ddit.controller.crud;

// 사용자 정의 에러 출력 컨트롤러
public class BoardRecordNotFoundException extends Exception {

	public BoardRecordNotFoundException(String msg) {
		// 부모인 Exception으로 사용자가 정의한 메시지를 전달한다.
		super(msg);
	}
	
}
package kr.or.ddit.service;

import java.io.IOException;
import java.util.List;

import kr.or.ddit.vo.Board;

public interface IBoardService {

	public void register(Board board) throws IOException;
	public List<Board> list();
	public Board read(int boardNo) throws Exception;
	public void modify(Board board);
	public void remove(int boardNo);
	public List<Board> search(Board board);

}
package kr.or.ddit.controller.crud;

import java.io.IOException;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import kr.or.ddit.service.IBoardService;
import kr.or.ddit.vo.Board;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/crud/board")
public class CrudBoardController {

	@Inject
	private IBoardService service;
	
	@PostConstruct
	public void init() {
		log.info("aopProxy 상태(interface 기반) : {}", AopUtils.isAopProxy(service));
		log.info("aopProxy 상태(클래스 상속 기반) : {}", AopUtils.isCglibProxy(service));
	}
	
	@RequestMapping(value = "/register", method = RequestMethod.GET)
	public String crudRegisterForm() {
		log.info("crudRegisterForm() 실행...!");
		
		return "crud/register";
	}
	
	@RequestMapping(value = "/register", method = RequestMethod.POST)
	public String crudRegister(Board board, Model model) throws IOException {
		log.info("crudRegister() 실행...!");
		
		service.register(board);
		// 게시글을 입력 후 최근 게시글 번호가 담겨있다(boardNo)
		log.info("게시글 등록 후 만들어진 최신 게시글 번호 : " + board.getBoardNo());
		
		model.addAttribute("msg", "등록이 완료되었습니다!");
		return "crud/success";
	}
	
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String crudList(Model model) {
		log.info("crudList() 실행...!");
		List<Board> boardList = service.list();
		model.addAttribute("boardList", boardList);
		return "crud/list";
	}
	
	@RequestMapping(value = "/read", method = RequestMethod.GET)
	public String crudRead(int boardNo, Model model) throws Exception {
		log.info("crudRead() 실행...!");
		Board board = service.read(boardNo);
		model.addAttribute("board", board);
		return "crud/read";
	}
	
	@RequestMapping(value = "/modify", method = RequestMethod.GET)
	public String crudModifyForm(int boardNo, Model model) throws Exception {
		log.info("crudModifyForm() 실행...!");
		Board board = service.read(boardNo);
		model.addAttribute("board", board);
		model.addAttribute("status", "u"); // '수정을 진행합니다' 라는 flag
		return "crud/register";
	}
	
	@RequestMapping(value = "/modify", method = RequestMethod.POST)
	public String crudModify(Board board, Model model) {
		log.info("crudModify() 실행...!");
		service.modify(board);
		model.addAttribute("msg", "수정이 완료되었습니다.");
		return "crud/success";
	}
	
	@RequestMapping(value = "/remove", method = RequestMethod.POST)
	public String crudDelete(int boardNo, Model model) {
		log.info("crudDelete() 실행...!");
		service.remove(boardNo);
		model.addAttribute("msg", "삭제가 완료되었습니다.");
		return "crud/success";
	}
	
	@RequestMapping(value = "/search", method = RequestMethod.POST)
	public String crudSearch(String title, Model model) {
		log.info("crudSearch() 실행...!");
		Board board = new Board();
		board.setTitle(title);
		
		List<Board> boardList = service.search(board);
		model.addAttribute("boardList", boardList);
		model.addAttribute("board", board);
		return "crud/list";
	}
	
}

(1) 수정 예외

- http://localhost/crud/board/modify?boardNo=17

(2) 삭제 예외

- http://localhost/crud/board/read?boardNo=16

(3) 존재하지 않는 게시글 번호 예외

- http://localhost/crud/board/read?boardNo=1611

(4) 요청 URL이 없을 때 예외

- http://localhost/crud/board/123124


[web.xml]

	<!-- 3. 상태 코드를 사용한 이동 대상 페이지 설정 시작 -->
	<!-- <error-page>
		<error-code>400</error-code>
		<location>/WEB-INF/views/error/errorCommon400.jsp</location>
	</error-page>
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/error/errorCommon404.jsp</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/error/errorCommon500.jsp</location>
	</error-page> -->
	<!-- 3. 상태 코드를 사용한 이동 대상 페이지 설정 끝 -->

	<!-- 4. 예외 타입을 사용한 이동 대상 페이지 설정 시작 -->
	<error-page>
		<exception-type>java.lang.Exception</exception-type>
		<location>/WEB-INF/views/error/errorCommon.jsp</location>
	</error-page>
	<!-- 4. 예외 타입을 사용한 이동 대상 페이지 설정 끝 -->

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>COMMON ERROR</title>
	</head>
	<body>
		<h2>ERROR!</h2>
	</body>
</html>

- http://localhost/crud/board/modify?boardNo=17

- http://localhost/crud/board/remove

- http://localhost/crud/board/read?boardNo=123124

- http://localhost/crud/board/124123

404 에러만 제외되고 나머지는 예외 처리 되었다.


[web.xml]

	<!-- 3. 상태 코드를 사용한 이동 대상 페이지 설정 시작 -->
	<!-- <error-page>
		<error-code>400</error-code>
		<location>/WEB-INF/views/error/errorCommon400.jsp</location>
	</error-page>
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/error/errorCommon404.jsp</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/error/errorCommon500.jsp</location>
	</error-page> -->
	<!-- 3. 상태 코드를 사용한 이동 대상 페이지 설정 끝 -->

	<!-- 4. 예외 타입을 사용한 이동 대상 페이지 설정 시작 -->
	<!-- <error-page>
		<exception-type>java.lang.Exception</exception-type>
		<location>/WEB-INF/views/error/errorCommon.jsp</location>
	</error-page> -->
	<!-- 4. 예외 타입을 사용한 이동 대상 페이지 설정 끝 -->
	
	<!-- 5. 기본 에러 페이지 설정 시작 -->
	<error-page>
		<location>/WEB-INF/views/error/errorCommon.jsp</location>
	</error-page>
	<!-- 5. 기본 에러 페이지 설정 끝 -->

- http://localhost/crud/board/modify?boardNo=17

- http://localhost/crud/board/remove

- http://localhost/crud/board/read?boardNo=123124

- http://localhost/crud/board/123124123


[web.xml]

	<!-- <error-page>
		<error-code>400</error-code>
		<location>/WEB-INF/views/error/errorCommon400.jsp</location>
	</error-page>
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/error/errorCommon404.jsp</location>
	</error-page>
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/error/errorCommon500.jsp</location>
	</error-page> -->
	<!-- 3. 상태 코드를 사용한 이동 대상 페이지 설정 끝 -->

	<!-- 4. 예외 타입을 사용한 이동 대상 페이지 설정 시작 -->
	<!-- <error-page>
		<exception-type>java.lang.Exception</exception-type>
		<location>/WEB-INF/views/error/errorCommon.jsp</location>
	</error-page> -->
	<!-- 4. 예외 타입을 사용한 이동 대상 페이지 설정 끝 -->
	
	<!-- 5. 기본 에러 페이지 설정 시작 -->
	<!-- <error-page>
		<location>/WEB-INF/views/error/errorCommon.jsp</location>
	</error-page> -->
	<!-- 5. 기본 에러 페이지 설정 끝 -->

package kr.or.ddit.controller.exception;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

// @ControllerAdvice 어노테이션은 스프링 컨트롤러에서 발생하는 예외를 처리하는 핸들러 클래스임을 명시한다.
@ControllerAdvice
public class CommonExceptionHandler {

	// @ExceptionHandler 어노테이션은 괄호 안에 설정한 예외 타입을 해당 메소드가 처리한다는 것을 의미한다.
	@ExceptionHandler(Exception.class)
	public String Handle(Exception e, Model model) {
		model.addAttribute("exception", e);
		return "error/errorCommon";
	}
	
}

<%@ 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>COMMON ERROR</title>
	</head>
	<body>
		<h2>ERROR!</h2>
		<h4>${exception.message }</h4>
		
		<ul>
			<c:forEach items="${exception.stackTrace }" var="stack">
				<li>${stack.toString() }</li>
			</c:forEach>
		</ul>
	</body>
</html>

- http://localhost/crud/board/modify?boardNo=17

예외 처리 안 됨

- http://localhost/crud/board/remove

- http://localhost/crud/board/read?boardNo=124123

- http://localhost/crud/board/1243142

예외 처리 안 됨

	 *		6. 예외 처리 어노테이션
	 *
	 *			- @ExceptionHandle과 @ControllerAdvice를 이용하여 처리한다.
	 *
	 *				[예외 처리 방법]
	 *				- @ControllerAdvice 어노테이션은 스프링 컨트롤러에서 발생하는 예외를 처리하는 핸들러 클래스임을 명시한다.
	 *				- @ExceptionHandle 어노테이션은 괄호 안에 설정한 예외 타입을 해당 메소드가 처리한다는 것을 의미한다.
	 *
	 *				예외 처리 핸들러 생성
	 *				> kr.or.ddit.controller.exception.CommonExceptionHandler 클래스 생성
	 *
	 *				- 처리할 수 있는 예외
	 * 				> 삭제 할 때 매핑 파일에서 예외 발생
	 * 				> 존재하지 않는 게시물을 조회할 때 사용자가 정의한 예외 발생
	 *
	 *				- 처리할 수 없는 예외
	 *				> 수정 화면 생성할 때 뷰 파일에서 예외 발생
	 *					> ServletException을 상속받는 JasperException 에러 발생이므로 Exception 처리를 타지 않음
	 * 				> 존재하지 않는 페이지 URL 요청 시 예외 발생
	 * 					> 404 종류에 해당하는 에러기 때문에 예외를 타지 않음

[web.xml]

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		
		<init-param>
			<param-name>throwExceptionIfNoHandlerFound</param-name>
			<param-value>true</param-value>
		</init-param>
		
		<load-on-startup>1</load-on-startup>
package kr.or.ddit.controller.exception;

import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

// @ControllerAdvice 어노테이션은 스프링 컨트롤러에서 발생하는 예외를 처리하는 핸들러 클래스임을 명시한다.
@ControllerAdvice
public class CommonExceptionHandler {

	// @ExceptionHandler 어노테이션은 괄호 안에 설정한 예외 타입을 해당 메소드가 처리한다는 것을 의미한다.
	@ExceptionHandler(Exception.class)
	public String Handle(Exception e, Model model) {
		model.addAttribute("exception", e);
		return "error/errorCommon";
	}
	
	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseStatus(value = HttpStatus.NOT_FOUND)
	public String handle404(Exception e) {
		return "error/custom404";
	}
	
}

<%@ 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>CUSTOM 404</title>
	</head>
	<body>
		<h2>해당 URL은 존재하지 않습니다!</h2>
	</body>
</html>

- http://localhost/crud/board/1243142