@ModelAttribute
@Controller
public class SampleController {
@GetMapping("/events/form")
public String eventsForm(Model model) {
Event newEvent = new Event();
newEvent.setLimit(50);
model.addAttribute("event", newEvent);
return "events/form";
}
@PostMapping("/events")
@ResponseBody
public Event createEvent(@ModelAttribute Event event){
return event;
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void eventForm() throws Exception{
mockMvc.perform(get("/events/form"))
.andDo(print())
.andExpect(view().name("/events/form"))
.andExpect(model().attributeExists("event"));
}
@Test
public void createEvent() throws Exception{
mockMvc.perform(post("/events)
.param("name", "spring")
.param("limit", "20"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value(spring));
}
}
또는 요청 파라미터 말고도 URI 패턴도 복합 타입 객체로 받아올 수 있다.
@Controller
public class SampleController {
@GetMapping("/events/form")
public String eventsForm(Model model) {
Event newEvent = new Event();
newEvent.setLimit(50);
model.addAttribute("event", newEvent);
return "events/form";
}
@PostMapping("/events/name/{name}")
@ResponseBody
public Event createEvent(@ModelAttribute Event event){
return event;
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void eventForm() throws Exception{
mockMvc.perform(get("/events/form"))
.andDo(print())
.andExpect(view().name("/events/form"))
.andExpect(model().attributeExists("event"));
}
@Test
public void createEvent() throws Exception{
mockMvc.perform(post("/events/name/spring")
.param("limit", "20"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value(spring));
}
}
그런데 만약에 limit 파라미터에 Integer가 아닌 String 값을 채운다고 가정해보자.
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void eventForm() throws Exception{
mockMvc.perform(get("/events/form"))
.andDo(print())
.andExpect(view().name("/events/form"))
.andExpect(model().attributeExists("event"));
}
@Test
public void createEvent() throws Exception{
mockMvc.perform(post("/events/name/spring")
.param("limit", "abc"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value(spring));
}
}
이 경우에는 BindException이 발생한다.
값을 바인딩 할 수 없는 경우에는?
바인딩 에러를 직접 다루고 싶은 경우
BindingResult를 추가하면 일단 바인딩은 된다. 하지만 BindingResult 안에 에러가 들어있다.
@Controller
public class SampleController {
@GetMapping("/events/form")
public String eventsForm(Model model) {
Event newEvent = new Event();
newEvent.setLimit(50);
model.addAttribute("event", newEvent);
return "events/form";
}
@PostMapping("/events/name/{name}")
@ResponseBody
public Event createEvent(@ModelAttribute Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
System.out.println("======================");
bindingResult.getAllErrors().forEach(c -> {
System.out.println(c.toString());
});
}
return event;
}
}
바인딩 이후에 검증 작업을 추가로 하고 싶은 경우
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void eventForm() throws Exception{
mockMvc.perform(get("/events/form"))
.andDo(print())
.andExpect(view().name("/events/form"))
.andExpect(model().attributeExists("event"));
}
@Test
public void createEvent() throws Exception{
mockMvc.perform(post("/events/name/spring")
.param("limit", "-10"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value(spring));
}
}
public class Event {
private Integer id;
private String name;
@Min(0)
private Integer limit;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
}
@Controller
public class SampleController {
@GetMapping("/events/form")
public String eventsForm(Model model) {
Event newEvent = new Event();
newEvent.setLimit(50);
model.addAttribute("event", newEvent);
return "events/form";
}
@PostMapping("/events/name/{name}")
@ResponseBody
public Event createEvent(@Valid @ModelAttribute Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
System.out.println("======================");
bindingResult.getAllErrors().forEach(c -> {
System.out.println(c.toString());
});
}
return event;
}
}
바인딩 이후 Validation 작업 수행 -> 여기서도 에러가 발생하면 BindingResult에 담아준다.
BindingResult를 추가하면 일단 바인딩은 된다. 하지만 BindingResult 안에 에러가 들어있다.
참고