인프런/스프링 MVC 1편

10)HandlerMethodArgument,RequestParam 처리 방법들

backend dev 2023. 1. 25.

요청매핑 - API예시

실제 데이터가 넘어가는 부분은 생략하고, URL매핑만

URL은 똑같은데 Http Method로 행위를 구별한다.

@RequestMapping("/mapping/users")
@RestController
public class MappingClassController {

    @GetMapping()
    public String user() {
        return "get users";
    }

    @PostMapping()
    public String addUser() {
        return "post user";
    }

    @GetMapping("/{userId}")
    public String findUser(@PathVariable String userId) {
        return "get userId =" +userId;
    }

    @PatchMapping("/{userId}")
    public String updateUser(@PathVariable String userId) {
        return "update user =" + userId;
    }
    @DeleteMapping("/{userId}")
    public String deleteUser(@PathVariable String userId) {
        return "delete user =" + userId;
    }
}

 


HTTP요청 - 기본, 헤더조회

어노테이션 기반의 스프링 컨트롤러는 다양한 파라미터를 지원한다.

이번 시간에는 HTTP 헤더 정보를 조회하는 방법을 알아보자.

 

 

파라미터 받아오기 테스트

@Slf4j
@RestController
public class RequestHeaderController {

    @RequestMapping("/headers")
    //어노테이션기반의 컨트롤러는 다양한 파라미터를 받아들일 수 있다(= 다양한 파라미터를 넣어줄 수 있다,스프링이 지원하는건!)
    public String headers(
        HttpServletRequest request,
        HttpServletResponse response, // 기본적인 서블릿reqeust,response 객체들은 기본으로 파라미터로 넣어줄수있고
        HttpMethod httpMethod, // 어떤 HttpMethod로 들어왔는지 객체로 받을 수 있고
        Locale locale, // 지역의 언어, 국가 등의 정보를 갖고 있는 객체도 받을 수 있고
        @RequestHeader MultiValueMap<String,String> headerMap,
        //헤더는 @RequestHeader라는 어노테이션과 함꼐 MultiValueMap이라는 Map으로 받을 수있다,헤더이므로 키값,밸류값 모두 String이다.(모든헤더가 다 담긴다)
        @RequestHeader("host")String host, //헤더를 하나만 받고싶을때 @ReqeustHeader("받고싶은헤더이름")으로 헤더를 받아올 수 있다.
        @CookieValue(value = "myCookie",required = false) String cookie
        //쿠키값도 @CookieValue로 받아올 수 있다, vale = "쿠키이름" , required = 필수인지여부 (기본값은 true이다)
    ) {
        log.info("request={}", request);
        log.info("response={}", response);
        log.info("httpMethod={}", httpMethod);
        log.info("locale={}", locale);
        log.info("headerMap={}", headerMap);
        log.info("header host={}", host);
        log.info("myCookie={}", cookie);
        return "ok";
    }
}

잘 받아와진걸 확인가능

locale은 가장 우선순위가 높은 locale로 받아와진다. (locale에 관련해서 더 공부,응용하고싶다면 localeResolver에 대해 공부할것)

@CookieValue(value = "myCookie", required = false,defaultValue = "hi") String cookie

이처럼 이 값이 없을때 가져오는 defaultValue도 설정가능하다.

없으면 null을 저장하기 때문이다.

쿼리 파라미터 하나의 키에 여러개값 테스트

@GetMapping("/head")
public String tt(@RequestParam("user") String user) {
    log.info("user = {}", user);
    return "ok";
}

@GetMapping("/head")
public String tt(@RequestParam("user") String[] user) {
    log.info("user = {}", Arrays.toString(user));
    return "ok";
}

String으로 받으면 a,b처럼 들어오고

String[]로 받으면 배열로 잘 들어온다.

MutiValueMap 테스트

@GetMapping("/head")
public String tt(@RequestParam MultiValueMap<String,String> map) {
    log.info("user = {}", map.get("user"));
    return "ok";
}

@RequestParam을 그냥 MultiValueMap에다 저장해버리면 된다. ( "user"이런거 안붙이고)

 

@Controller의 사용가능한 파라미터 목록

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

 

@Controller의 사용가능한 응답값 목록

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

 


Http요청파라미터 (쿼리 파라미터,HTML Form)

클라이언트에서 서버로 요청데이터를 보내는 방법은 단 3가지 뿐이다.

GET의 쿼리파라미터이던 , POST방식의 HTML Form전송이던

어차피 둘다 형식이 파라미터형식이므로 HttpServletRequest의 getParameter()로 파라미터를 조회할 수 있었다.

 

 

@Slf4j
@RestController
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")); //파리미터 형식은 String으로 들어오므로 파싱이 필요하다.
        log.info("username = {} , age = {}", username, age);
        response.getWriter().write("ok");
    }
}
파리미터 형식은 String으로 들어오므로 파싱이 필요하다.

response 객체에 ok값을 써줬으므로 ok가 보인다.

 

 

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head><body>
<form action="/request-param-v1" method="post">
  username: <input type="text" name="username" />
  age: <input type="text" name="age" />
  <button type="submit">전송</button>
</form>
</body>
</html>

서버주소 + html 위치를 적으면 잘 보인다. ( 실제경로는 프로젝트/resources/static/basic/hello-form.html이지만 리소스 기본경로는 /resources/static이므로 생략이 가능)

@Slf4j
@RestController
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")); //파리미터 형식은 String으로 들어오므로 파싱이 필요하다.
        log.info("username = {} , age = {}", username, age);
        response.getWriter().write("ok");
    }
}

여기까지가 HttpServeltRequest,Response로 데이터를 전달받고 응답받았던것을 복습하였다.


Http요청 파라미터 - @RequestParam

v2

@ResponseBody
//@Controller 어노테이션이 붙은 컨트롤러는 응답 String을 논리뷰이름으로 간주하여 처리하는데,
//그게아니라 응답메시지 바디에 값을 넣고싶다면 @ResponseBody를 사용한다.
@RequestMapping("/request-param-v2")
public String requestParamV2(
    @RequestParam("username")String memberName,
    @RequestParam("age") int memberAge) { //@RequestParam은 받으려는값으로 알아서 캐스팅이 된다.

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

}

 

v3

@ResponseBody
@RequestMapping("/request-param-v3")
public String requestParamV3(
    @RequestParam String username, //파라미터명과 변수명이 같을때, 파라미터명이 생략가능하다.
    @RequestParam int age) {

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

}

v4

@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age) {//파라미터명과 변수명이 같을때, 파라미터명과 @RequestParam어노테이션까지 생략가능하다.
    log.info("username = {} , age = {}", username, age);
    return "ok";
}

파라미터 필수 여부 requestParamRequired 

@ResponseBody
@RequestMapping("/request-param-v4")
public String requestParamV4(String username, int age) {//파라미터명과 변수명이 같을때, 파라미터명과 @RequestParam어노테이션까지 생략가능하다.
    log.info("username = {} , age = {}", username, age);
    return "ok";
}

@RequestParam(required = false) int age)

다음과 같이 age는 필수값이 아닐떄

http://localhost:8080/request-param-required?username=qwd 해당 url로 username만 보내면

age에 null이 저장되지않아 오류가 발생한다. (primitive에는 값이 무조건 들어가야한다. int니까 0이라도 들어가야함,

그러므로 defaultvalue라는것을 사용한다, 아니면 Integer를 사용하거나)

http://localhost:8080/request-param-required?username=qwd&age=   이런 url로 age에 빈값을 넣으려고하면

오류발생! , int에는 ""와같은 빈문자가 못들어가므로.

 

기본값 적용 ,requestParamDefault

@ResponseBody
@RequestMapping("/request-param-default")
public String requestParamDefault(
    @RequestParam(required = true,defaultValue = "guest") String username, //반드시 넣어야하는값으로 설정되어있는경우(기본값), 안들어왔을경우를 대비하여 defaultvalue설정
    @RequestParam(required = false,defaultValue = "-1") int age) { //primitive 타입에 빈문자나 null이 저장안되므로, 값이 안들어왔을경우를 대비하는 defaultvalue설정을 해준다.

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

}

기본값설정을 해줬으므로 값이 있든없든 상관없다. 그래서 required라는 설정이 필요가없다. 어차피 값은 들어갈거니까

값을 안넣어줘도 기본값을 설정해줬으므로 오류가발생하지않는다.

 

빈 문자를 넣으면 기본값으로 처리해준다.

 

 

파라미터를 Map으로 조회하기 - Map,MultiValueMap

@ResponseBody
 @RequestMapping("/request-param-map")
 public String requestParamDefault(
     @RequestParam Map<String,Object> paramMap) // 모든 요청 파라미터를 Map으로 받을 수 있다. String에는 파라미터명, Object에는 파라미터값을 저장
{
    log.info("username = {} , age = {}", paramMap.get("username"), paramMap.get("age"));
     return "ok";

 }

해당 파라미터명의 파라미터값이 하나가 확실하면 Map을 사용해도되지만,

그렇지않고 하나의 파라미터명에 2개이상의 파라미터값이 들어올 수 있다면 MultiValueMap을 사용한다.

MultiValueMap사용(하나의 파라미터명에 여러개의 파라미터값이 들어갈경우)

    @ResponseBody
    @RequestMapping("/request-param-Multimap")
    public String requestParamMultiValueMap(
        @RequestParam MultiValueMap<String,Object> paramMultiMap) //하나의 파라미터명에 여러개의 파라미터값이 들어갈가능성이 있다면 MultiValueMap을 사용한다.
    {
//        List<Object> username = paramMultiMap.get("username"); MultiValueMap은 값을 리스트형식으로 저장해둔다
        log.info("username = {} , age = {}", paramMultiMap.get("username"), paramMultiMap.get("age"));
        return "ok";
    }
}

댓글