Study/Spring

[Spring] @ModelAttribute

개발개발개발 2021. 9. 8. 22:40

@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