Back-End/Spring

[Spring MVC][HTTP 요청] - 2. 요청 파라미터 - 쿼리 파라미터, HTML Form, @RequestParam, @ModelAttribute

얄루몬 2022. 3. 29. 20:05

💻본 포스팅은 '스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 김영한'님의 강의를 듣고 작성되었습니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com


[쿼리 파라미터와  HTML Form]

클라이언트에서 서버 요청 데이터를 전달할 때는 아래와 같이 3가지의 방법이 있다.

  • GET -쿼리 파라미터
    • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달해준다.
    • 예) 검색, 필터, 페이징 등에서 많이 사용하는 방식이다.
    • /url?username=hello&age=20
  • POST - HTML Form 
    • 메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20
    • 예) 회원가입, 상품 주문, HTML Form 에 사용하는 방식이다.
    • content-type:application/x-www-form-urlencoded
  • HTTP message body에 데이터를 직접 담아서 요청
    • HTTP API에서 주로 사용, JSON, XML, TEXT
    • 데이터 형식은 주로 JSON 사용
    • POST, PUT, PATCH

 

이때 GET 방식과 POST 방식은 둘 다 쿼리 파라미터 형식으로 전달하기 때문에 함께 알아보아도 무방하다. 

또한 이것들 간단히 요청 파라미터(request parameter)조회라고 한다.

[@RequestParam]

스프링이 제공하는 @RequestParam을 사용하면 요청 파라미터를 매우 편리하게 사용할 수 있다.

  • @RequestParam: 파라미터 이름으로 바인딩해주는 애노테이션이다.
  • @ResponseBody: View 조회를 무시하고, HTTP message body에 직접 해당 내용을 입력할 때 사용하는 애노테이션이다.
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@Slf4j
@Controller
public class RequestParamController {
    //기본 사용
    @RequestMapping("/request-param-v1")
    public void requestParamV1(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));
        log.info("username = {}, age={}",username,age);

        response.getWriter().write("ok");
    }

    // view 이름을 찾아 돌려주는 @Controller를 사용했기에 아래와 같은 애노테이션 사용
    //@ResponseBody를 사용해서 뷰를 넘기지 않고 String을 Body로 넘기는 방법
    @ResponseBody
    @RequestMapping("/request-param-v2")
    public String requestParamV2(
            @RequestParam("username") String memberName,
            @RequestParam("age") int memberAge) {
        log.info("username = {}, age = {}", memberName, memberAge);
        return "ok";
    }

    //V2에서 파라미터 이름과 변수 이름을 동일하게 맞춰 더욱 간략해진 코드
    @ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(
            @RequestParam String username,
            @RequestParam int age) {

        log.info("username = {}, age = {}", username, age);
        return "ok";
    }

    //파라미터 이름과 변수 이름이 같으면 파라미터 이름 생략 가능한 경우
    @ResponseBody
    @RequestMapping("/request-param-v4")
    public String requestParamV4(String username, int age) {
        log.info("username = {}, age = {}", username, age);
        return "ok";
    }

    //파라미터에 값이 있어야 하는지 없어야 하는지에 관한 required
    @ResponseBody
    @RequestMapping("/request-param-required")
    public String requestRequired(
            @RequestParam(required = true) String username,
            @RequestParam(required = false) Integer age) {
        //자바 내에서 int와 같은 기본타입엔 null값이 없기에 500 에러를 막기 위해 Integer을 사용해야 한다.
        log.info("username = {}, age = {}", username, age);
        return "ok";
    }

    //defaultValue 사용 -> required 필요 X 값이 있든 없든 값이 들어가기 때문이다.
    //또한 빈문자에도 설정한 값이 들어간다. (빈문자로 처리해줌)
    @ResponseBody
    @RequestMapping("/request-param-default")
    public String requestDefault(
            @RequestParam(defaultValue = "guest") String username,
            @RequestParam(defaultValue = "-1") int age) {
        log.info("username = {}, age = {}", username, age);
        return "ok";
    }

    //파라미터를 Map으로 조회하기 - requestParamMap
    @ResponseBody
    @RequestMapping("/request-param-map")
    public String requestMap(@RequestParam Map<String, Object> paramMap) {
        log.info("username = {}, age = {}", paramMap.get("username"), paramMap.get("age"));
        return "ok";
    }
  1. @RequestParam 없이 작성된 코드
  2. @RequestParam 사용 작성
  3. ver2 축약해서 작성
  4. 단순 타입을 사용한 것으로 RequestParam 생략 작성한 코드
  5. 파라미터의 필수 여부를 작성한 코드 (Required)
    • 이때 원시타입(int 등)을 사용하면 null값 예외 오류가 나기 때문에 객체타입(Long, Integer 등)을 사용해주어야 한다. 
  6. defaultValue 설정으로 값 입력이 없으면 설정해둔 기본값을 사용하기 위해 작성한 코드
    • 기본 값이 설정되어 있다면 required을 굳이 설정하지 않아도 모두 값이 들어있기 때문에 따로 required 여부를 설정하지 않아도 된다.
    • "" 빈문자 역시 설정한 값을 넣어 처리해주기 때문에 문제가 없다.
  7. 파라미터를 Map으로 조회 
    • Map보다는 MultiValueMap을 더 많이 사용한다. 그 이유는 하나의 키에 여러 키값이 있는 경우가 훨씬 많기 때문에 Map 사용보다는 MultiValueMap 사용이 적합하다. 

[@ModelAttribute]

실제 개발 시 요청 파라미터를 받아 필요한 객체를 만들고 그 객체에 값을 넣어주어야 한다. 그러나 이 작업은 매우 귀찮을 수가 있기 때문에 이 작업을 @ModelAttribute가 대신 작업 해준다.

  • 모델 객체를 생성해준다.
  • 생성한 모델 객체를 요청 파라미터 값을 자동으로 넣어준다.

[요청 파라미터를 바인딩 받을 객체]

package hello.springmvc.basic;
import lombok.Data;
@Data
public class HelloData {
    private String username;
    private int age;
}
  • @Data ?
    • @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor를 자동으로 적용시켜주는 애노테이션이다.

[@ModelAttribute 적용 전 요청 파라미터를 받아 필요한 객체를 넣어주는 코드]

// @ModelAttribute 사용
    /*@ModelAttribute 사용 없이 본래 코드
      요청 파라미터를 받아 필요한 객체를 생성해서 객체에 그 값을 넣어주는 작업
    * */
    @ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@RequestParam String username, @RequestParam int age){
        HelloData helloData = new HelloData();
        helloData.setUsername(username);
        helloData.setAge(age);

        log.info("username = {}, age = {}", helloData.getUsername(), helloData.getAge());
        return "ok";
    }

[@ModelAttribute를 적용한 버전 2가지]

package hello.springmvc.basic.request;


import hello.springmvc.basic.HelloData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@Slf4j
@Controller
public class RequestParamController {

    @ResponseBody
    @RequestMapping("/model-attribute-v1")
    public String modelAttributeV1(@ModelAttribute HelloData helloData){
        log.info("username = {}, age = {}", helloData.getUsername(), helloData.getAge());
        return "ok";
    }
    
    //@ModelAttribute생략 ver
    @ResponseBody
    @RequestMapping("/model-attribute-v2")
    public String modelAttributeV2(HelloData helloData){
        log.info("username = {}, age = {}", helloData.getUsername(), helloData.getAge());
        return "ok";
    }

    
}