@ModelAttribute
Client가 전송하는 multipart/form-data 형태의 Http body와 Http 파라미터들을 Setter를 통해 객체에 1대 1 바인딩하는 역할이다. URI path, 요청 파라미터, 세션 등 다양한 곳에서 선언 가능하다. 바인딩 에러를 직접 다루고 싶은 경우 BindingResult 타입을 추가할 수 있으며, @Validate 어노테이션을 통해 매개변수에 대한 검증을 할 수 있다.
객체
먼저 Dante 객체를 선언하여 지역변수를 선언하고 Getter와 Setter를 작성한다. (여기서는 Getter, Setter는 생략)
public class Dante {
private String deadLift;
private String squat;
private String benchPress;
public Dante(String deadLift, String squat, String benchPress) {
this.deadLift = deadLift;
this.squat = squat;
this.benchPress = benchPress;
}
}
컨트롤러
Post 형식을 받으며, "/DDante" 경로를 매핑한다.
파라미터는 @ModelAttribute 어노테이션을 선언하며 "Dante" 객체를 받도록 설정하였다.
그리고 @ResponseBody 어노테이션을 통해 Body에 담아 return 한다.
@Controller
public class ControllerStudy {
@ResponseBody
@RequestMapping(method = RequestMethod.POST, path = "/DDante")
public Dante valueDante(@ModelAttribute("Dante") Dante dante ) {
System.out.println("Dead : " + dante.getDeadLift());
System.out.println("Squat : " + dante.getSquat());
System.out.print("Bench : " + dante.getBenchPress());
return dante;
}
}
컨트롤러 테스트
POST형식으로 param값을 세팅하여 보낸다.
@RunWith(SpringRunner.class)
@WebMvcTest
class ControllerTest {
@Autowired
MockMvc mockMvc;
@Test
void test5() throws Exception {
mockMvc.perform(post("/DDante")
.param("deadLift", "120")
.param("squat", "110")
.param("benchPress", "70")
)
.andDo(print())
.andExpect(status().isOk());
}
}
Request
내가 세팅한 파라미터가 담긴 것을 볼 수 있으며, 핸들러 메소드를 통해 valueDante에 매핑된 것을 볼 수 있다.
Response
내가 보낸 값 그대로 리턴한 받는 것을 볼 수 있다!
BindingResult
@Test
void test5() throws Exception {
mockMvc.perform(post("/DDante")
.param("deadLift", "120")
.param("squat", "110")
.param("benchPress", "70")
.param("conventional", "nolimit") // conventinal은 int형으로 선언 되어 있다.
)
.andDo(print())
.andExpect(status().isOk());
}
이번엔 바인딩이 실패되었을 때, 출력을 하도록 해보았다.
우선 Dante 객체에 int 형의 conventinal 지역변수를 선언하였고, post 형식을 보낼 때 conventional에 Stirng을 함께 담아 보냈다.
String 형은 int형으로 변형할 수 없기때문에 에러가 날 것이다.
@ResponseBody
@RequestMapping(method = RequestMethod.POST, path = "/DDante")
public Dante valueDante(@ModelAttribute("Dante") Dante dante, BindingResult bindingResult ) {
System.out.println("Dead : " + dante.getDeadLift());
System.out.println("Squat : " + dante.getSquat());
System.out.println("Bench : " + dante.getBenchPress());
if(bindingResult.hasErrors()) { //에러가 있을 시 처리
System.out.println("=======================");
System.out.print("Error");
bindingResult.getAllErrors().forEach(c -> {
System.out.println(c.toString());
});
}
return dante;
}
실행 결과 :
conventional 변수를 int형으로 변환할 수 없기 때문에 바인딩 에러가 발생하였다. 이 것을 통해 원하는 방식대로 에러를 처리할 수 있을 것이다. 예를 들면 다시 View 페이지로 이동하여 입력한 특정 파라미터가 잘못되었다던지.. 입 맛에 맞게 처리할 수 있다.
Dead : 120
Squat : 110
Bench : 70
=======================
ErrorField error in object 'Dante' on field 'conventinal': rejected value [nolimit];
codes [typeMismatch.Dante.conventinal,typeMismatch.conventinal,typeMismatch.int,typeMismatch];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable:
codes [Dante.conventinal,conventinal]; arguments []; default message [conventinal]];
default message
[Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'conventinal';
nested exception is java.lang.NumberFormatException: For input string: "nolimit"]
정리해보면,
@ModelAttribute는 클라이언트에서 전송하는 파라미터를 객체에 바인딩시켜준다. 그리고 setter를 통해 매핑한다.
여러곳에서 오는 데이터를 유연하게 하나의 객체로 받을 수 있다. 만약 바인딩할 수 없는 파라미터가 있으면 400 에러를 출력하게 되며, BindingResult를 통해 처리할 수 있다.
@validate는 다음에 제대로 정리해야겠다.
'Study > Spring' 카테고리의 다른 글
[Spring] RestTemplate (0) | 2021.09.23 |
---|---|
[Spring] Handler Method(ResponseEntity) (0) | 2021.09.12 |
[Spring] Spring IoC Container 그리고 Bean (0) | 2021.08.29 |
[Spring] Dispatcher Servlet (0) | 2021.08.24 |
[Spring] @RequestMapping (0) | 2021.08.19 |