특정 예외가 발생한 요청을 처리하는 핸들러 정의
커스텀한 에러 만들기
public class EventException extends RuntimeException{
}
커스텀한 에러가 발생했을 때 특정한 메시지와 함께 뷰를 보여주고 싶다.
@Controller
@SessionAttributes("event")
public class EventController {
@ExceptionHandler
public String eventErrorHandler(EventException exception, Model model){
model.addAttribute("message", "event error");
return "error";
}
@InitBinder
public void initEventBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("id");
webDataBinder.addValidators(new EventValidator());
}
@ModelAttribute
public void categories(Model model){
model.addAttribute("categories", List.of("study", "seminar", "hobby", "social"));
}
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
throw new EventException();
// model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
// return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "/events/form-name";
}
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
Event newEvent = (Event) model.asMap().get("newEvent");
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(newEvent);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
에러 페이지
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Error Page</title>
</head>
<body>
<div th:if="${message}">
<h2 th:text="${message}"/>
</div>
</body>
</html>
또한 가장 구체적인 ExceptionHandler가 매핑된다.
@Controller
@SessionAttributes("event")
public class EventController {
@ExceptionHandler
public String eventErrorHandler(EventException exception, Model model){
model.addAttribute("message", "event error");
return "error";
}
@ExceptionHandler
public String runtimeExceptionHandler(RuntimeException exception, Model model){
model.addAttribute("message", "runtime error");
return "error";
}
@InitBinder
public void initEventBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("id");
webDataBinder.addValidators(new EventValidator());
}
@ModelAttribute
public void categories(Model model){
model.addAttribute("categories", List.of("study", "seminar", "hobby", "social"));
}
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
throw new EventException();
// model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
// return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "/events/form-name";
}
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
Event newEvent = (Event) model.asMap().get("newEvent");
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(newEvent);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
여러 에러를 같이 처리하고 싶은 경우 : 둘다 받을 수 있는 상위 타입으로 정의
@Controller
@SessionAttributes("event")
public class EventController {
@ExceptionHandler({EventException.class, RuntimeException.class})
public String eventErrorHandler(RuntimeException exception, Model model){
model.addAttribute("message", "runtime error");
return "error";
}
@InitBinder
public void initEventBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("id");
webDataBinder.addValidators(new EventValidator());
}
@ModelAttribute
public void categories(Model model){
model.addAttribute("categories", List.of("study", "seminar", "hobby", "social"));
}
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
throw new EventException();
// model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
// return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "/events/form-name";
}
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
Event newEvent = (Event) model.asMap().get("newEvent");
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(newEvent);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
Rest API의 경우 상태코드와 에러 메시지를 주기 위해 ResponseEntity를 주로 사용한다.
@RestController
@RequestMapping("/api/events")
public class EventApi {
@ExceptionHandler
public ResponseEntity errorHandler(){
return ResponseEntity.badRequest().body("cant't create event as ...");
}
@PostMapping
public ResponseEntity<Event> createEvent(@RequestBody @Valid Event event, BindingResult bindingResult){
// save event
if(bindingResult.hasErrors()){
bindingResult.getAllErrors().forEach(error -> {
System.out.println(error);
});
return ResponseEntity.badRequest().build();
}
return ResponseEntity.ok(event);
//return new ResponseEntity<Event>(event, HttpStatus.CREATED); 200이 아닌 201 Created 응답
return ResponseEntity.ok(event);
}
}
참고