MVC 활용(23) : 핸들러 메소드 15부 - @RequestBody & HttpEntity

23. 핸들러 메소드 15부 - @RequestBody & HttpEntity

@RequestBody

  • 요청 본문(body)에 들어있는 데이터를 HttpMessageConveter를 통해 변환한 객체로 받아올 수 있다.
  • @Valid 또는 @Validated를 사용해서 값을 검증 할 수 있다.
  • BindingResult 아규먼트를 사용해 코드로 바인딩 또는 검증 에러를 확인할 수 있다.

HttpMessageConverter

  • 스프링 MVC 설정 (WebMvcConfigurer)에서 설정할 수 있다.
  • configureMessageConverters: 기본 메시지 컨버터 대체
  • extendMessageConverters: 메시지 컨버터에 추가
  • 기본 컨버터
    - WebMvcConfigurationSupport.addDefaultHttpMessageConverters

HttpEntity

  • @RequestBody와 비슷하지만 추가적으로 요청 헤더 정보를 사용할 수 있다.

@RestController     
@RequestMapping("/api/events")
public class EventApi {

    @PostMapping
    public Event createEvent(@RequestBody Event event){
        // save event
        return event;
    }
}

@RequestBody Event 타입으로 타입 컨버전을 하는게 메시지 컨버터이다. 메시지 컨버터는 아규먼트를 리졸빙할 때 핸들러 어댑터가 사용한다.

테스트 코드

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class EventApiTest {

    @Autowired
    ObjectMapper objectMapperr;

    @Autowired
    MockMvc mockMvc;

    @Test
    public void createEvent() throws Exception{
        Event event = new Event();
        event.setName("spring");
        event.setLimit(20);

        String json = objectMapperr.writeValueAsString(event);

        mockMvc.perform(post("/api/events")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(json)
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("name").value("spring"))
                .andExpect(jsonPath("limit").value(20));
    }
}

또한 @Valid를 붙여 @Valid @RequestBody Event event 라고 사용할 수도 있다. 그리고 BindingResult를 써서 BindingException을 받아올 수도 있다.

public class Event {

    private Integer id;

    @NotBlank
    private String name;

    @Min(0)
    private Integer limit;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getLimit() {
        return limit;
    }

    public void setLimit(Integer limit) {
        this.limit = limit;
    }
}
@RestController     
@RequestMapping("/api/events")
public class EventApi {

    @PostMapping
    public Event createEvent(@Valid @RequestBody Event event,
                             BindingResult bindingResult){
        // save event
        if(bindingResult.hasErrors()){
            bindingResult.getAllErrors().forEach(error -> {
               System.out.println(error);
            });
        }
        return event;
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class EventApiTest {

    @Autowired
    ObjectMapper objectMapperr;

    @Autowired
    MockMvc mockMvc;

    @Test
    public void createEvent() throws Exception{
        Event event = new Event();
        event.setName("spring");
        event.setLimit(-20);

        String json = objectMapperr.writeValueAsString(event);

        mockMvc.perform(post("/api/events")
                .contentType(MediaType.APPLICATION_JSON_UTF8)
                .content(json))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("name").value("spring"))
                .andExpect(jsonPath("limit").value(-20));
    }
}

HttpEntity를 써서 본문 정보를 꺼내올 수도 있다.

@RestController     
@RequestMapping("/api/events")
public class EventApi {

    @PostMapping
    public Event createEvent(HttpEntity<Event> request){
        // save event
        return request.getBody();
    }
}

RequestBody와 다른 점은 HttpEntity는 헤더 정보에도 접근할 수 있다는 것이다.

@RestController     
@RequestMapping("/api/events")
public class EventApi {

    @PostMapping
    public Event createEvent(HttpEntity<Event> request){
        // save event
        MediaType contentType = request.getHeaders().getContentType();
        System.out.println(contentType);
        return request.getBody();
    }
}

참고

좋은 웹페이지 즐겨찾기