프로그래밍 공부/Spring

[Spring] Controller에서 데이터 받기

대체로 Spring으로 애플리케이션을 구성한다면, Controller에서 값을 받아서 비즈니스 로직을 처리하도록 넘기게 된다. 이때, 이러한 Method Parameter를 어떻게 받는지에 대해서 이야기해보고자 한다. 

 

어찌보면 간단한 개념을 왜 정리하지? 싶을 수도 있으나, 공식 문서를 보게되면 굉장히 많은 Method Argument를 제공하고 있다는 것을 볼 수 있다. 그렇기에, 일단 지금 쓰는 것을 제대로 소화하고, 그 이유를 이해한 뒤에 추가적으로 다른 개념들을 이해하면 더 좋을 것 같아서 정리해본다. 

 

 

@RequestParam

@Controller
@RequestMapping("/pets")
public class EditPetForm {
    // ...

    @GetMapping
    public String getCatInfo(@RequestParam("catName") String catName, Model model) { 
        Cat cat = this.clinic.getCat(catName);
        model.addAttribute("cat", cat);
        return "catInfo";
    }

    // ...
}

위의 예시는 catName을 가지고 cat을 가져오도록 @Request Param을 설정한 경우이다.

 

@RequestParam에서는 아래와 같은 세 타입의 옵션을 추가할 수 있다. (위의 예시는 name이 추가된 형태) 아래에 나와있듯이 기본 required 값이 true이기 때문에 만약 해당 값이 안들어가있다면 400에러가 바로 발생하게 된다.

이름 타입 설명
name, value (Alias for name) String 파라미터 이름
required bollean 해당 파라미터의 필수 여부 (기본값 = true)
defaultValue String 해당 파라미터 기본값

 

 

@RequestBody

@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
    // ...
}

파라미터를 객체로 받게 되며, 이는 MessageConverter를 통해서 자바의 객체로 변환된다.

이로 인해서 Request가 가지는 특징은 다음과 같다.

 

1. POST요청과 함께 사용되어야한다.

 : MessageConverter는 HTTP 요청의 Body내용을 자바의 객체로 변환시킨다. GET방식의 메서드는 애초에 Body가 존재하지 않기때문에 에러를 발생시킨다.

 

2. JSON 데이터받을 때 주로 사용

 : JSON이나 XML과 같은 데이터를 MessageConverter를 이용해서 자바의 객체로 변환한다. 

 

3. Setter가 없어도 된다.

 : @ModelAttribute는 자바의 객체로 1:1 매핑이기에 Setter가 필수지만 @RequestBody는 MessageConverter를 통한 자바의 객체로 변환이기때문에 Setter가 없어도 괜찮다.

  • 다만 직렬화를 위해 기본 생성자는 필수다.
  • 또한 데이터 바인딩을 위한 필드명을 알아내기 위해 getter나 setter 중 1가지는 정의되어 있어야 한다.

 

 

여담을 조금 적자면 나는 스프링을 처음 공부할때 일단 뭔지도 모르고 쓰다보니 GET 메서드에서 해당 어노테이션을 썼다가 한동안 헤멘적이 있었다.

 

 

@ModelAttribute

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
    // ...
}

@RequestParam과 비슷한데, 차이점은 1:1로 하나씩 파라미터를 받을 때는 @RequestBody, 여러 파라미터들을 받아서 자바의 객체로 매핑하는 경우는 @ModelAttribute 라고 한다. 또한, @RequestBody와는 달리 Setter가 필수적으로 요구된다고 한다.

 

공식문서에 따르면, 위의 Pet 인스턴스의 경우 다음 방법중 하나로 소싱된다고 한다. 

  • @ModelAttribute메서드 에 의해 추가되었을 수 있는 모델에서 검색
  • 모델 특성이 @SessionAttributes 주석에 나열된 경우 HTTP 세션에서 검색
  • 모델 속성 이름이 경로 변수 또는 요청 매개변수와 같은 요청 값의 이름과 일치 하는 곳을 검색
  • 기본 생성자로 인스턴스화
  • 서블릿 요청 매개변수와 일치하는 인수를 사용하여 "기본 생성자"를 통해 인스턴스화

 

개인적으로 ModelAttribute는 거의 사용해본 적이 없던터라, @RequestBody와 @ModelAttribute를 비교한 좋은 테코블 포스팅도 함께 공유한다. 링크

 

 

 

어노테이션이 없으면?

어노테이션이 없어도 값을 받을 수 있다. 다만, 이 경우에는 변수명과 동일한 파라미터 값만을 받을 수 있으며, String과 Long 타입은 @RequestParam으로 취급하지만 그 이외에는 @ModelAttribute로 취급하게 된다.

@PostMapping("/getWithdoutAnnotation");
public void getWithdoutAnnotation(String id, UserVO user){
    log.info("get parameter" + id);
    log.info("get parameter" + user.getId());
}

 

 

 

참고자료

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-methods

https://doing7.tistory.com/10