1) RestController란?
Spring MVC에서 제공하는 RestController
@RestController
-
Spring 4 에서 Rest API 또는 Web API를 개발하기 위해 등장한 어노테이션 합니다.
-
이전 버전의 @Controller와 @ResponseBody를 포함합니다.
MessageConvertor
-
자바 객체와 HTTP 요청 / 응답 바디를 변환하는 역할
-
@ResponseBody, @RequestBody
-
@EnableWebMvc 로 인한 기본 설정
-
WebMvcConfigurationSupport 를 사용하여 Spring MVC 구현
-
Default MessageConvertor 를 제공
-
링크 바로가기의 addDefaultHttpMessageConverters메소드 항목 참조
MessageConvertor 종류

JSON 응답하기
-
컨트롤러의 메소드에서는 JSON으로 변환될 객체를 반환합니다.
-
jackson라이브러리를 추가할 경우 객체를 JSON으로 변환하는 메시지 컨버터가 사용되도록 @EnableWebMvc에서 기본으로 설정되어 있습니다.
-
jackson라이브러리를 추가하지 않으면 JSON메시지로 변환할 수 없어 500오류가 발생합니다.
-
사용자가 임의의 메시지 컨버터(MessageConverter)를 사용하도록 하려면 WebMvcConfigurerAdapter의 configureMessageConverters메소드를 오버라이딩 하도록 합니다.
2) RestController를 이용하여 web api작성하기
Rest Controller 사용하려면 반드시 jackson 라이브러리 추가. -> @RestCotroller
guestbook05의 controller패키지의 GuestbookApiController.java
| package kr.or.connect.guestbook.controller; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| import javax.servlet.http.HttpServletRequest; | |
| import org.springframework.beans.factory.annotation.Autowired; | |
| import org.springframework.web.bind.annotation.DeleteMapping; | |
| import org.springframework.web.bind.annotation.GetMapping; | |
| import org.springframework.web.bind.annotation.PathVariable; | |
| import org.springframework.web.bind.annotation.PostMapping; | |
| import org.springframework.web.bind.annotation.RequestBody; | |
| import org.springframework.web.bind.annotation.RequestMapping; | |
| import org.springframework.web.bind.annotation.RequestParam; | |
| import org.springframework.web.bind.annotation.RestController; | |
| import kr.or.connect.guestbook.dto.Guestbook; | |
| import kr.or.connect.guestbook.service.GuestbookService; | |
| // RestController를 활용하여 Wep Api 작성. | |
| // Rest Api, 테스트하는 게 바로 확장 프로그램 (Talend API Tester) | |
| @RestController | |
| @RequestMapping(path="/guestbooks") | |
| public class GuestbookApiController { | |
| @Autowired // 서비스이용 | |
| GuestbookService guestbookService; | |
| @GetMapping // get 방식으로 요청이 들어오면 이 메서드 실행. path는 위에 적어서 생략 | |
| // 결과값으로 Map 객체를 반환하는데 application/json 요청이기 때문에 | |
| // DipatcherServlet은 jsonMessageConvert를 내부적으로 사용해서 해당 Map 객체를 json으로 변환해서 전송을 하게 됩니다. | |
| public Map<String, Object> list(@RequestParam(name="start", required=false, defaultValue="0") int start) { | |
| List<Guestbook> list = guestbookService.getGuestbooks(start); | |
| int count = guestbookService.getCount(); | |
| int pageCount = count / GuestbookService.LIMIT; | |
| if(count % GuestbookService.LIMIT > 0) | |
| pageCount++; | |
| List<Integer> pageStartList = new ArrayList<>(); | |
| for(int i = 0; i < pageCount; i++) { | |
| pageStartList.add(i * GuestbookService.LIMIT); | |
| } | |
| Map<String, Object> map = new HashMap<>(); | |
| map.put("list", list); | |
| map.put("count", count); | |
| map.put("pageStartList", pageStartList); | |
| return map; | |
| } | |
| @PostMapping | |
| // 클라이언트한테 응답이 갈 때는 json으로 바뀌어서 감. | |
| public Guestbook write(@RequestBody Guestbook guestbook, | |
| HttpServletRequest request) { | |
| String clientIp = request.getRemoteAddr(); | |
| // id가 입력된 guestbook이 반환된다. | |
| Guestbook resultGuestbook = guestbookService.addGuestbook(guestbook, clientIp); | |
| return resultGuestbook; | |
| } | |
| @DeleteMapping("/{id}") //PathVariable인거 알고 계시죠? | |
| public Map<String, String> delete(@PathVariable(name="id") Long id, | |
| HttpServletRequest request) { | |
| String clientIp = request.getRemoteAddr(); | |
| int deleteCount = guestbookService.deleteGuestbook(id, clientIp); | |
| return Collections.singletonMap("success", deleteCount > 0 ? "true" : "false"); | |
| } | |
| } |
3) Web API 테스트 코드 작성하기
test 폴더에서. junit으로 run
| package kr.or.connect.guestbook.controller; | |
| import kr.or.connect.guestbook.config.ApplicationConfig; | |
| import kr.or.connect.guestbook.config.WebMvcContextConfiguration; | |
| import kr.or.connect.guestbook.dto.Guestbook; | |
| import kr.or.connect.guestbook.service.GuestbookService; | |
| import org.junit.Before; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.mockito.InjectMocks; | |
| import org.mockito.Mock; | |
| import org.mockito.MockitoAnnotations; | |
| import org.springframework.http.MediaType; | |
| import org.springframework.test.context.ContextConfiguration; | |
| import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | |
| import org.springframework.test.context.web.WebAppConfiguration; | |
| import org.springframework.test.web.servlet.MockMvc; | |
| import org.springframework.test.web.servlet.RequestBuilder; | |
| import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | |
| import org.springframework.test.web.servlet.setup.MockMvcBuilders; | |
| import java.util.Arrays; | |
| import java.util.Date; | |
| import java.util.List; | |
| import static org.mockito.Mockito.verify; | |
| import static org.mockito.Mockito.when; | |
| import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; | |
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |
| @RunWith(SpringJUnit4ClassRunner.class) | |
| @WebAppConfiguration | |
| @ContextConfiguration(classes = {WebMvcContextConfiguration.class, ApplicationConfig.class }) | |
| public class GestubookApiControllerTest { | |
| @InjectMocks | |
| public GuestbookApiController guestbookApiController; | |
| // @InjectMocks어노테이션이 붙여서 선언된 guestbookApiController는 목객체인 GuestbookService를 사용하게 됩니다. | |
| // 스프링에 위해 주입된 객체를 사용하는 것이 아닌 Mockito 프레임워크에 위해 생성된 목객체가 주입되어 객체가 생성됩니다. | |
| @Mock //@Mock어노테이션을 붙여서 선언된 guestbookService는 mockito에 위해 목객체로 생성됩니다. 말그대로 가짜 객체가 됩니다. | |
| GuestbookService guestbookService; | |
| private MockMvc mockMvc; | |
| @Before //테스트 메소드가 실행되기 전에 @Before어노테이션이 붙은 메소드가 실행됩니다. | |
| public void createController() { | |
| MockitoAnnotations.initMocks(this); //현재 객체에서 @Mock이 붙은 필드를 목객체로 초기화시킵니다. | |
| mockMvc = MockMvcBuilders.standaloneSetup(guestbookApiController).build(); | |
| // MockMVC타입의 변수 mockMvc를 초기화 합니다. guestbookApiController를 테스트 하기 위한 | |
| // MockMvc객체를 생성합니다. | |
| } | |
| @Test | |
| public void getGuestbooks() throws Exception { | |
| Guestbook guestbook1 = new Guestbook(); | |
| guestbook1.setId(1L); | |
| guestbook1.setRegdate(new Date()); | |
| guestbook1.setContent("hello"); | |
| guestbook1.setName("kim"); | |
| List<Guestbook> list = Arrays.asList(guestbook1); | |
| when(guestbookService.getGuestbooks(0)).thenReturn(list); | |
| // List<Guestbook>타입의 변수 list를 초기화하고 해당 list에 방명록 한 건을 저장합니다. | |
| // when(guestbookService.getGuestbooks(0)).thenReturn(list); | |
| // 위의 문장은 아래와 같이 동작합니다. | |
| // when( 목객체.목객체메소드호출() ).threnReturn(목객체 메소드가 리턴 할 값) | |
| // guestbookService.getGuestbook(0) 이 호출되면 위에서 선언된 list객체가 리턴 되도록 설정합니다. | |
| RequestBuilder reqBuilder = MockMvcRequestBuilders.get("/guestbooks").contentType(MediaType.APPLICATION_JSON); | |
| // MockMvcRequestBuilders를 이용해 MockMvc에게 호출할 URL을 생성합니다. | |
| // get(“/guestbooks”) | |
| // GET 방식으로 /guestbooks 경로를 호출하라는 의미입니다. | |
| // contentType(MediaType.APPLICATION_JSON); | |
| // application/json 형식으로 api를 호출합니다. | |
| // 즉 2가지가 합치면 application/json형식으로 /guestbooks를 GET방식으로 호출한다는 것을 뜻합니다. | |
| // 이러한 URL정보를 가진 reqBuilder를 생성합니다 | |
| mockMvc.perform(reqBuilder).andExpect(status().isOk()).andDo(print()); | |
| // mockMvc.perform(reqBuilder) 는 reqBuilder에 해당하는 URL에 대한 요청을 보냈다는 것을 의미합니다. | |
| // andExpect(status().isOk()) 는 mockMvc에 위해 URL이 실행되고 상태코드값이 200이 나와야 한다는 것을 의미합니다. | |
| // andDo(print())는 처리 내용을 출력하게 됩니다. | |
| // 여기까지 실행되면 화면에 다음과 같은 결과가 출력되면서 테스트가 성공하게 됩니다. | |
| verify(guestbookService).getGuestbooks(0); | |
| // Guestbook 목객체의 getGuestbooks(0)메소드가 호출했다면 검증은 성공하게 됩니다. | |
| } | |
| // 아래의 코드는 방명록을 삭제하는 web api를 테스트하고 있습니다. | |
| @Test | |
| public void deleteGuestbook() throws Exception { | |
| Long id = 1L; | |
| when(guestbookService.deleteGuestbook(id, "127.0.0.1")).thenReturn(1); | |
| RequestBuilder reqBuilder = MockMvcRequestBuilders.delete("/guestbooks/" + id).contentType(MediaType.APPLICATION_JSON); | |
| // “/guestbooks/” + id 경로를 DELETE방식으로 호출하기 위한 경로 정보를 가지고 있는 reqBuilder객체를 생성합니다. | |
| mockMvc.perform(reqBuilder).andExpect(status().isOk()).andDo(print()); | |
| // reqBuilder에 해당하는 URL을 호출한 후, 상태 코드가 200일 경우 성공합니다. 그리고 결과를 출력하게 됩니다. | |
| verify(guestbookService).deleteGuestbook(id, "127.0.0.1"); | |
| // guestbookService 목객체의 deleteGuestbook(id, “127.0.0.1”)메소드가 Web API가 동작하면서 호출되었다면 성공하게 됩니다. | |
| } | |
| } |
'Spring > Boost Course Web' 카테고리의 다른 글
| 5.1 상태유지기술 - Cookie & Session (0) | 2020.11.19 |
|---|---|
| 4.5 Swagger (0) | 2020.11.19 |
| 4.3 WEB API (0) | 2020.11.19 |
| 4.2 Layered Architecture (0) | 2020.11.19 |
| 4.1 Spring MVC (0) | 2020.11.19 |
| 3.3 Spring JDBC (0) | 2020.11.19 |