만약 도서 정보를 받는 간단한 페이지가 있다고 가정해보자.
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>도서 관리</title>
</head>
<body>
<%@include file="/WEB-INF/views/include/header.jsp" %>
<hr>
<h1>도서 등록</h1>
<form method="post" action="regist">
도서번호 <input type="text" name="isbn">
도서명 <input type="text" name="title">
저자 <input type="text" name="author">
<input type="submit" value="등록">
</form>
</body>
</html>
도서번호, 도서명 저자 모두 쓰지 않으면, 파라미터 입력값이 덜 들어왔다고 띄워주고 싶다.
그럼 일단 form에 적힌대로 컨트롤러에 post방식의 regist주소의 요청이 오면 기능할 수 있는 곳을 찾아준다.
=> @PostMapping("regist")
@PostMapping("regist")
public String doRegist(Book book, Model model) throws BindException {
if(book.getIsbn().equals("")||book.getTitle().equals("")||book.getAuthor().equals("")) {
throw new BindException();
}
model.addAttribute("book",book);
return "regist_result";
}
원래대로라면 값이 안들어왔다면 안들어온대로 regist_result페이지에 빈 값을 띄워줬겠지만, if문으로 BindException()을 날려 ExceptionController로 넘어갈 수 있게 했다. (남들은 안이래도 되던데... 왜 나만 안되는가?..)
import javax.swing.tree.DefaultTreeCellEditor.EditorContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class ExceptionController{
private static final Logger logger = LoggerFactory.getLogger(ExceptionController.class);
@ExceptionHandler(Exception.class)
public String handleException(Exception e, Model model) {
logger.error("예외 발생", e.getCause());
e.printStackTrace();
if(e instanceof java.net.BindException) {
model.addAttribute("msg","파라미터가 잘 등록되지 않았습니다.");
}
return "error/commonerr";
}
}
왜 이 페이지로 에러가 났을 때 넘어올 수 있냐면 @ControllerAdvice를 붙여줬기 때문이다. 이 어노테이션은 전역에서 발생할 수 있는 에러를 잡아주는 역할을 한다.
@ExceptionHandler같은 경우는 @ControllerAdvice가 적용된 Bean내에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능을 한다.
나는 @ExceptionHandler(Exception.class)를 써서 모든 예외를 잡았다. 저기에는 바로 BindException을 바로 써도 된다.
모든 예외를 잡아 메서드 안에 if로 java.net.BindException 에러가 나오면 들어오게 해 메세지를 model에 셋팅했다.
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>공용오류</title>
</head>
<body>
<!-- 코드작성 -->
<c:if test="${not empty msg}">
<h1>${msg}</h1>
</c:if>
<c:if test="${empty msg}">
<h1>서버 오류입니다.</h1>
</c:if>
</body>
</html>
그랬더니 아주 잘 뜬다. 원래는 if문에 BindException만 써줬을 땐 들어가지 않아서 msg에 담기는게 없어 "서버 오류입니다."만 떴는데, 에러 풀네임을 써주니 model 바구니에 잘 담겨서 메세지가 잘 뜬다.
+추가적으로 안 사실은 input 값에 number가 들어가는 요소가 있으면 그 요소를 입력하지 않았을 경우 정상적으로 BindException이 일어난다. 현재 위 예제는 number를 받는 input이 없기 때문에 잘 안넘어간 것 같다.