Java EE 정리 38
19 Apr 2019
Reading time ~3 minutes
Java EE 정리 38 - Controller에서 예외처리, 응답시에 JSP가 아닌 다른 do를 다시 요청할 때
Controller에서 예외처리
-
요청을 처리하는 메소드에서 throws로 예외를 날림(예외 발생!)
- 예외처리하는 메소드위에 @ExceptionHandler 정의
- 한번에 하나의 예외만 처리한다
- 예외처리 메소드의 반환형은 반드시 ModelAndView
- 매개변수로 예외처리클래스명의 객체를 받는다
- 예외처리하는 메소드위에 @ExceptionHandler 정의
@ExceptionHandler(예외처리클래스명.class)
public ModelAndView 예외처리메소드명(예외처리클래스명 예외처리클래스객체명) {
// 예외가 발생하면 발생한 예외객체를 전달받아 사용
ModelAndView mav = new ModelAndView();
mav.setViewName("예외페이지 JSP명");
mav.addObject("msg", 예외처리클래스객체명.getMessage()); // 간단한 에러메시지
mav.addObject("exception", 예외처리클래스객체명.toString());
// 예외처리클래스 객체와 간단한 에러 메시지
return mav;
}
Controller에서 예외처리 예
<!-- main_menu.jsp -->
...
<li><a href="exception/exception.do">Controller에서 예외처리</a></li>
...
@Controller
public class ExceptionController {
@RequestMapping(value = "/exception/exception.do", method = GET)
public String exceptionForm() {
return "exception/exception_form";
}
@RequestMapping(value = "/exception/number_format.do", method = GET)
public String numberFormat(int age, Model model) {
// 입력받은 나이로 태어난 해 보여주기
model.addAttribute("birth", Calendar.getInstance().get(Calendar.YEAR) - age + 1);
return "exception/view_age";
}
...
<!-- exception/exception_form.jsp -->
...
<div>
<form action="number_format.do" method="get">
<label>나이</label>
<input type="text" name="age" class="inputBox"/>
<input type="submit" value="전송" class="btn"/>
</form>
<br/>
<form action="class_not_found.do" method="get">
<input type="submit" value="전송" class="btn"/>
</form>
</div>
...
<!-- exception/view_age.jsp -->
...
나이: ${ param.age }<br/>
태어난해: ${ requestScope.birth }<br/>
<a href="javascript:history.back()">뒤로</a>
...
-
ExceptionHandler로 예외처리하는 메소드는 ModelAndView를 반환한다
- ModelAndView에 이동할 예외처리 JSP명과 예외 메시지를 저장 후 반환
// ExceptionController
...
@ExceptionHandler(NumberFormatException.class)
public ModelAndView numberFormatProcess(NumberFormatException nfe) {
ModelAndView mav = new ModelAndView();
mav.setViewName("exception/error");
mav.addObject("msg", nfe.getMessage()); // 간단한 에러 메세지
mav.addObject("exception", nfe.toString()); // 예외처리 객체와 간단한 에러 메세지
return mav;
}
...
<!-- exception/error.jsp -->
...
<img src="http://localhost:8080/spring_mvc/common/images/err.png"/>
<br/>
문제가 발생했습니다.<br/>
간단한 메세지: ${ msg }<br/>
예외처리객체와 메세지: ${ requestScope.exception }
...
- 다른 예외처리 예, ClassNotFoundException
// ExceptionController
...
@RequestMapping(value = "/exception/class_not_found.do", method = GET)
public String classNotFound() throws ClassNotFoundException {
if (new Random().nextBoolean()) { // 랜덤하게 강제 예외발생
throw new ClassNotFoundException("클래스 없는 상황");
}
return "exception/view_class";
}
@ExceptionHandler(ClassNotFoundException.class)
public ModelAndView classNotFoundProcess(ClassNotFoundException cnfe) {
ModelAndView mav = new ModelAndView();
mav.setViewName("exception/error");
mav.addObject("msg", cnfe.getMessage());
mav.addObject("exception", cnfe.toString());
return mav;
}
}
응답시에 JSP가 아닌 다른 do를 다시 요청할 때
-
methodA에서 작업을 처리 후 methodB에 이동해서 나머지 작업을 처리해야 할 때
-
return에 JSP명이 아닌 요청을 처리하는 “~.do”가 나와야 한다.
- return에 forward를 붙이면 ViewResolver를 거치지 않고 정의된 URL을 직접 호출하게 된다.
-
return에 JSP명이 아닌 요청을 처리하는 “~.do”가 나와야 한다.
@RequestMapping("a.do")
public String methodA() {
// 작업...
// return "view명";
return "forward:b.do";
}
@RequestMapping("b.do")
public String methodB() {
// 나머지 작업 ...
return "view명";
}
<!-- main_menu.jsp -->
...
<li><a href="chain/chain_a.do">chain_a.do요청</a></li>
...
import static org.springframework.web.bind.annotation.RequestMethod.GET;
...
@Controller
public class ChainController {
@RequestMapping(value="/chain/chain_a.do",method=GET)
public String chainA() {
System.out.println("------------chain_A");
return "forward:/chain/chain_b.do";
}
@RequestMapping(value="/chain/chain_b.do",method=GET)
public String chainB() {
// 직접 호출될 수도 있고 A를 거쳐서 호출될 수도 있다.
System.out.println("------------chain_B");
return "chain/chain_b_result";
}
}
<!-- chain/chain_b_result.jsp -->
...
<strong>chain_b.do로 응답된 내용</strong><br/>
<a href="#" onclick="history.back()">뒤로</a>
...
- chainA에서 햄버거 정보를 추가하는 작업을 추가
@Controller
public class ChainController {
@RequestMapping(value="/chain/chain_a.do",method=GET)
public String chainA(Model model) {
String[] lunch = { "버거킹", "KFC", "맥날", "맘스터치", "롯데리아" };
model.addAttribute("lunch", lunch);
return "forward:/chain/chain_b.do";
}
@RequestMapping(value="/chain/chain_b.do",method=GET)
public String chainB() {
return "chain/chain_b_result";
}
}
<!-- chain/chain_b_result.jsp -->
...
<strong>chain_b.do로 응답된 내용</strong><br/>
<c:choose>
<c:when test="${ empty lunch }">
햄버거 목록을 받아오세요<br/>
(chain_a를 거쳐서 오세요.)<br/>
</c:when>
<c:otherwise>
좋아하는 햄버거 선택<br/>
<c:forEach var="menu" items="${ lunch }">
<input type="checkbox" name="menu" value="${ menu }"/>
<c:out value="${ menu }" escapeXml="false"/>
<!-- checkbox를 체크하고 value가 없이 전달하면 'on'이 넘어간다 -->
</c:forEach>
</c:otherwise>
</c:choose>
<br/>
<a href="#" onclick="history.back()">뒤로</a>
...