이번 시간에는 사용자가 요청에 잘못된 값을 전달했을 때 처리하는 과정에 대해서 알아보도록 하겠습니다.
요청 데이터 에러 다루기
1. 시나리오
- 사용자는 form 페이지를 작성한다.
- 사용자의 form 요청 데이터에 에러가 있다.(age에 문자열을 입력하는 등의)
- 다시 form 페이지로 이동되면서 발생한 error를 메시지로 보여준다.
- 에러가 없으면 list.html로 이동하게 된다.
2. 요청 데이터 에러 다루기 예제
에러상황을 처리하는 방법은 예제를 통해 알아보는것이 가장 빠를것 같아 예제로 바로 넘어가도록 하겠습니다. 사실 이전 포스팅(https://galid1.tistory.com/559)에서 에러를 다루는 방법을 다 알아보았기 때문에 따로 설명을 드리지 않아도 될 것 같습니다.
2.1 form.html 관련 코딩
우선 사용자가 맨처음 보게될 form.html 페이지에 대한 코딩을 합니다.
x
public class Event { private String name; (0) private Integer age; public void setName(String name) { this.name = name; } public String getName(){return this.name;} public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }}예제에서 사용될 DTO 클래스입니다. Name은 blank이면 안되며, Age의 경우 0과 같거나 커야합니다.(Null 과 Blank는 다릅니다.)
xxxxxxxxxxpublic class HelloController { ("/form") public String getForm(){ return "/events/form"; }}사용자가 /form으로 요청시 form.html을 전달해주는 Handler를 작성합니다.
xxxxxxxxxx<form action="#" th:action="@{/events}" method="post"> <input type="text" name="name"/> <input type="text" name="age"/> <input type="submit" value="Create" /></form>view Template로는 Thymeleaf를 사용할 것입니다. form.html을 위와 같이 작성합니다. form을 submit할 시에는 /events로 요청을 보내게 됩니다.
x
public void testGetForm() throws Exception{ mockMvc.perform(get("/form")) .andDo(print()) .andExpect(status().isOk());}form.html을 요청하는 test코드를 작성합니다. 성공입니다.
2.2 list.html 관련 코딩
xxxxxxxxxxpublic class HelloController { ("/form") public String getForm(){ return "/events/form"; } ("/events") public String getEvents( Event event, BindingResult bindingResult){ return (bindingResult.hasErrors() ? "/events/form" : "/events/list"); }}사용자가 form을 전송할 때 요청을 처리할 /events에 대한 Handler를 작성합니다. 간단히 사용자의 요청에 Error가 존재한다면 다시 form.html으로 이동하며, Error가 존재하지 않는다면 list.html로 이동합니다.
@Validated
사용자가 보낸 요청 데이터가 Event에 맵핑되며 에러가 존재하는지 검사하여 BindingResult에 에러를 담습니다.
@ModelAttribute
사용자의 요청에 담긴 데이터를 Event객체에 맵핑합니다.
BindingResult
사용자의 요청 에러값을 담고 있습니다.
xxxxxxxxxx<body> LIST</body>위와 같이 list.html을 작성합니다. 간단히 LIST라는 문자열을 띄워줍니다.
xxxxxxxxxxpublic void testPostEvent() throws Exception{ mockMvc.perform(post("/events") .param("name", "jjy") .param("age", "10")) .andDo(print()) .andExpect(status().isOk());}/events 로 요청하는 테스트 코드를 작성합니다. form으로 넘어 오는 데이터는 param을 이용하여 대체할 수 있습니다.
xxxxxxxxxxpublic void testPostEvent() throws Exception{ mockMvc.perform(post("/events") .param("name", "jjy") .param("age", "-10")) .andDo(print()) .andExpect(status().isOk()) .andExpect(model().hasErrors());}age에 -10을 보내어 일부러 ERROR를 만들어보겠습니다. 이때는 andExpect()에 model().hasErros()를 통해 결과 값에 ERROR가 존재하도록 할 수 있습니다.
2.3 어플리케이션 구동 후 테스트
form 으로 먼저 접근합니다. 그 후 값을 입력한 뒤 create버튼을 클릭합니다.
list.html이 나타납니다.
이번에는 age에 문자열을 담아 error를 발생시켜 보겠습니다.
다시 form.html이 나타나는것을 볼 수 있습니다.
3. Thymeleaf에서 요청데이터 에러 출력예제
앞선 예제에 추가적으로 만약 사용자가 보낸 data에 에러가 있을때 error를 template에 나타내는 코드를 추가해보겠습니다.
("/form")public String getForm(Model model){ Event event = new Event(); model.addAttribute("event", event); return "/events/form";}getForm() 핸들러에 model 매개변수를 추가하고 Event객체를 생성하여 담아줍니다.
<form action="#" th:action="@{/events}" method="post" th:object="${event}"> <p th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Incorrect date</p> <p th:if="${#fields.hasErrors('age')}" th:errors="*{age}">Incorrect date</p> <input type="text" name="name"/> <input type="text" name="age" /> <input type="submit" value="Create" /></form>form.html의 코드를 위와 같이 수정합니다. 간단히 해석하면, form을 통해 사용자의 요청이 /events로 전달되면, 해당 핸들러에서 검증을 통해 에러가 있을때에는 다시 /form으로 이동하게 되는데 이때 각각의 필드에 맵핑된 에러를 보여주게 됩니다.
age의 값을 -1로 지정하여 에러를 발생시킵니다.
위와 같이 에러메시지가 타나납니다.
이번에는 age에는 올바른 값을 입력하고 name을 비워둡니다.
blank에러에 대한 메시지가 나타납니다.