이번 시간에는 사용자가 요청에 잘못된 값을 전달했을 때 처리하는 과정에 대해서 알아보도록 하겠습니다.
요청 데이터 에러 다루기
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는 다릅니다.)
xxxxxxxxxx
public 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 관련 코딩
xxxxxxxxxx
public 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
라는 문자열을 띄워줍니다.
xxxxxxxxxx
public void testPostEvent() throws Exception{
mockMvc.perform(post("/events")
.param("name", "jjy")
.param("age", "10"))
.andDo(print())
.andExpect(status().isOk());
}
/events
로 요청하는 테스트 코드를 작성합니다. form으로 넘어 오는 데이터는 param
을 이용하여 대체할 수 있습니다.
xxxxxxxxxx
public 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에러에 대한 메시지가 나타납니다.