관리 메뉴

bright jazz music

blog02: POST로 데이터 전송(x-www-form-urlencoded, Json) 본문

Projects/blog

blog02: POST로 데이터 전송(x-www-form-urlencoded, Json)

bright jazz music 2022. 12. 12. 09:50
//http method
//GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD, TRACE, CONNECT 총 9개

 

데이터를 보내는 테스트를 해보자.

MockMvc는 기본적으로 contentType을 application/json 형식으로 보낸다.

contentType은 http request 메시지의 바디에 들어가는 데이터 형식을 헤더에 명시해주는 항목이다.

즉, 보내는 자원의 형식을 명시하기 위해 헤더에 실리는 정보 이다. 이 값은 표준 mime-type중의 하나이다

 

application/x-www-form-urlencoded

그러나 여기서는 우선 과거의 방식인 application/x-www-form-urlencoded로 보내보자.

//PostControllerTest.java


@WebMvcTest
class PostControllerTest {
    @Autowired
    private MockMvc mockMvc; ////Could not autowire. No beans of 'MockMvc' type found.

    @Test
    @DisplayName("/posts 요청시 hello world를 출력한다")
    void test() throws Exception {
        //expected

        //기본적으로 Content-Type을 application/json으로 보냄. 예전에는 application/x-www-form-urlencoded를 썼다.
        mockMvc.perform(post("/posts")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED) //application/x-www-form-urlencoded 사용하기
                        .param("title", "글 제목입니다.") //map 형태로 헤더에 넣어서 보낸다
                        .param("content", "글 내용입니다") // 그러나 key:value 방식은 도메인 데이터를 명확히 표현하는 데 한계가 있다. 예를 들어 뎁스가 하나 더 들어간다고 생각해 보자.
                )
                .andExpect(status().isOk()) //http response 가 200인지
                .andExpect(content().string("hello world")) // 내용이 hello world인지
                .andDo(print()); //요청에 대한 전반적인 요약을 출력해준다.

    }

}

 

VO역할을 할 클래스를 생성한다.

//PostCreate.java

package com.endofma.blog.request;
public class PostCreate {
    public String title;
    public String content;

    public void setTitle(String title) {
        this.title = title;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "PostCreate{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

 

받는 쪽은 이렇게 받아보자.

 

//PostController.java

@Slf4j
@RestController
public class PostController {

    @PostMapping("/posts")
//    public String post(@RequestParam String title, @RequestParam String content){ //각각 받기
//    public String post(@RequestParam Map<String, String> params){ //map으로 받기
    public String post(@ModelAttribute PostCreate params) { //데이터 형태에 맞는 클래스, 즉 VO로 받기
    
    	log.info("params={}", params.toString());
        return "hello world";
    }
}

 

 

결과 출력

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.6)

2022-12-12 10:26:09.057  INFO 15068 --- [    Test worker] c.e.blog.controller.PostControllerTest   : Starting PostControllerTest using Java 11.0.12 on DESKTOP-Q7HBM41 with PID 15068 (started by user in D:\personal\work\blog)
2022-12-12 10:26:09.059  INFO 15068 --- [    Test worker] c.e.blog.controller.PostControllerTest   : No active profile set, falling back to 1 default profile: "default"
2022-12-12 10:26:10.667  INFO 15068 --- [    Test worker] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
2022-12-12 10:26:10.667  INFO 15068 --- [    Test worker] o.s.t.web.servlet.TestDispatcherServlet  : Initializing Servlet ''
2022-12-12 10:26:10.670  INFO 15068 --- [    Test worker] o.s.t.web.servlet.TestDispatcherServlet  : Completed initialization in 3 ms
2022-12-12 10:26:10.721  INFO 15068 --- [    Test worker] c.e.blog.controller.PostControllerTest   : Started PostControllerTest in 2.273 seconds (JVM running for 4.824)
2022-12-12 10:26:11.360  INFO 15068 --- [    Test worker] c.e.blog.controller.PostController       : params=PostCreate{title='글 제목입니다.', content='글 내용입니다'}

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /posts
       Parameters = {title=[글 제목입니다.], content=[글 내용입니다]}
          Headers = [Content-Type:"application/x-www-form-urlencoded;charset=UTF-8"]
             Body = null
    Session Attrs = {}

Handler:
             Type = com.endofma.blog.controller.PostController
           Method = com.endofma.blog.controller.PostController#post(PostCreate)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"11"]
     Content type = text/plain;charset=UTF-8
             Body = hello world
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
BUILD SUCCESSFUL in 10s
4 actionable tasks: 3 executed, 1 up-to-date
AM 10:26:11: Execution finished ':test --tests "com.endofma.blog.controller.PostControllerTest.test"'.

 

그러나 application/x-www-form-urlencoded 형식은 데이터를 키 맵 형태로 나열해야 하기 때문에 온전히 데이터를 표현하기 어렵다. 구분하기도 어렵다. json 형식의 경우 아래와 같이 데이터 표현이 가능하다.

json으로 데이터 표현

 

 

 

application/json으로 보내기

 

//PostControllerTest.java

@WebMvcTest
class PostControllerTest {
    @Autowired
    private MockMvc mockMvc; ////Could not autowire. No beans of 'MockMvc' type found.

    @Test
    @DisplayName("/posts 요청시 hello world를 출력한다")
    void test() throws Exception {
        //expected

        //기본적으로 Content-Type을 application/json으로 보냄. 예전에는 application/x-www-form-urlencoded를 썼다.
        mockMvc.perform(post("/posts")
//                      .contentType(MediaType.APPLICATION_JSON) //미디어 타입을 변경해 주었다.
                        .content("{\"title\": \"제목입니다.\", \"content\": \"내용입니다.\"}") //json 형태로 값 넣어주기
                )
                .andExpect(status().isOk()) //http response 가 200인지
                .andExpect(content().string("hello world")) // 내용이 hello world인지
                .andDo(print()); //요청에 대한 전반적인 요약을 출력해준다.

    }

}

 

 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.6)

2022-12-12 11:16:52.921  INFO 19892 --- [    Test worker] c.e.blog.controller.PostControllerTest   : Starting PostControllerTest using Java 11.0.12 on DESKTOP-Q7HBM41 with PID 19892 (started by user in D:\personal\work\blog)
2022-12-12 11:16:52.925  INFO 19892 --- [    Test worker] c.e.blog.controller.PostControllerTest   : No active profile set, falling back to 1 default profile: "default"
2022-12-12 11:16:54.642  INFO 19892 --- [    Test worker] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
2022-12-12 11:16:54.642  INFO 19892 --- [    Test worker] o.s.t.web.servlet.TestDispatcherServlet  : Initializing Servlet ''
2022-12-12 11:16:54.645  INFO 19892 --- [    Test worker] o.s.t.web.servlet.TestDispatcherServlet  : Completed initialization in 3 ms
2022-12-12 11:16:54.689  INFO 19892 --- [    Test worker] c.e.blog.controller.PostControllerTest   : Started PostControllerTest in 2.352 seconds (JVM running for 4.807)
2022-12-12 11:16:55.279  INFO 19892 --- [    Test worker] c.e.blog.controller.PostController       : params=PostCreate{title='null', content='null'}

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /posts
       Parameters = {}
          Headers = [Content-Length:"60"]
             Body = {"title": "제목입니다.", "content": "내용입니다."}
    Session Attrs = {}

Handler:
             Type = com.endofma.blog.controller.PostController
           Method = com.endofma.blog.controller.PostController#post(PostCreate)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"11"]
     Content type = text/plain;charset=UTF-8
             Body = hello world
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
BUILD SUCCESSFUL in 8s
4 actionable tasks: 3 executed, 1 up-to-date
AM 11:16:55: Execution finished ':test --tests "com.endofma.blog.controller.PostControllerTest.test"'.

 

 

 

출력 내용에서 요청이 전달되는 것을 확인할 수 있다.

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /posts
       Parameters = {}
          Headers = [Content-Length:"60"]
             Body = {"title": "제목입니다.", "content": "내용입니다."}
    Session Attrs = {}

 

 

문제는 아래와 같이 VO에 값이 담아지지 않는다는 것이다.

2022-12-12 11:16:55.279  INFO 19892 --- [    Test worker] c.e.blog.controller.PostController       : params=PostCreate{title='null', content='null'}

 

 

이는 우리가 아래와 같이 @ModelAttribute로 데이터를 받았기 때문이다.

  public String post(@ModelAttribute PostCreate params) {...}

 

@RequestBody로 받아야 한다.

//PostController.java

@Slf4j
@RestController
public class PostController {

    @PostMapping("/posts")
    public String post(@RequestBody PostCreate params) { //데이터 형태에 맞는 클래스, 즉 VO로 받기
        log.info("params={}", params.toString());
        return "hello world";
    }

}

 

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.6)

2022-12-12 11:30:33.394  INFO 5520 --- [    Test worker] c.e.blog.controller.PostControllerTest   : Starting PostControllerTest using Java 11.0.12 on DESKTOP-Q7HBM41 with PID 5520 (started by user in D:\personal\work\blog)
2022-12-12 11:30:33.398  INFO 5520 --- [    Test worker] c.e.blog.controller.PostControllerTest   : No active profile set, falling back to 1 default profile: "default"
2022-12-12 11:30:35.232  INFO 5520 --- [    Test worker] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
2022-12-12 11:30:35.233  INFO 5520 --- [    Test worker] o.s.t.web.servlet.TestDispatcherServlet  : Initializing Servlet ''
2022-12-12 11:30:35.235  INFO 5520 --- [    Test worker] o.s.t.web.servlet.TestDispatcherServlet  : Completed initialization in 2 ms
2022-12-12 11:30:35.278  INFO 5520 --- [    Test worker] c.e.blog.controller.PostControllerTest   : Started PostControllerTest in 2.53 seconds (JVM running for 5.149)
2022-12-12 11:30:35.953  INFO 5520 --- [    Test worker] c.e.blog.controller.PostController       : params=PostCreate{title='제목입니다.', content='내용입니다.'}

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /posts
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"60"]
             Body = {"title": "제목입니다.", "content": "내용입니다."}
    Session Attrs = {}

Handler:
             Type = com.endofma.blog.controller.PostController
           Method = com.endofma.blog.controller.PostController#post(PostCreate)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"11"]
     Content type = text/plain;charset=UTF-8
             Body = hello world
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
BUILD SUCCESSFUL in 8s
4 actionable tasks: 2 executed, 2 up-to-date
AM 11:30:36: Execution finished ':test --tests "com.endofma.blog.controller.PostControllerTest.test"'.

 

 

아래와 같이 PostCreate 객체에 바인딩 된 값이 출력되는 것을 확인할 수 있다.

2022-12-12 11:30:35.953  INFO 5520 --- [    Test worker] c.e.blog.controller.PostController       : params=PostCreate{title='제목입니다.', content='내용입니다.'}

 

 

 

Comments