티스토리 뷰
2) RestController를 이용하여 web api작성하기
web api 작성 실습
- 앞에서 작성했던 Guestbook 프로젝트에다가 웹 API를 추가하겠습니다.
- RestController 사용하려면 반드시 jackson 라이브러리 추가해야합니다. pom.xml을 확인하여 없다면 추가합니다.
- RestController를 사용해보기 위해서 일단은 controller 패키지에다가 RestController를 생성합니다. 클래스 이름은 GuestbookApiController.java으로 생성합니다. 생성하면 어노테이션을 @RestController라고 붙여줍니다.
- 그리고 해당 API 클래스 안에는 같은 매핑으로 여러 개를 수행하므로 이 클래스에 RequestMapping을 선언하면 클래스 안에 있는 것들을 다 공통으로 사용할 수가 있습니다. 그래서 RequestMapping에 "/" path를 지정해줍니다.
- 여기서도 서비스 인터페이스가 사용되니까 서비스를 선언하고 @Autowired를 붙여줍니다. GuestbookService 이용할 거니까 guestbookService, 이렇게 선언을 합니다.
- 첫 번째 메서드를 보면 @GetMapping 되어있는데 path는 따로 없습니다. 그 이유는 클래스에 RequestMapping이 붙어있기 때문입니다. path가 /guestbooks라고 시작을 하면서 Get 방식으로 요청이 들어오면 이 메서드를 실행할 겁니다. RequestMapping의 path URL로 요청이 들어오면서 Content-Type이 application/json, 그리고 Get 방식으로 요청이 들어오면 이 메서드가 실행됩니다. 그리고 이 메서드의 결과 값으로 Map 객체를 반환하고 있습니다.
- application/json 요청이기 때문에 DipatcherServlet은 jsonMessageConvert를 내부적으로 사용해서 리턴하는 해당 Map 객체를 json으로 변환해서 전송을 하게 됩니다.
- Post 방식의 요청은 @PostMapping 어노테이션이 붙어있는 write라는 메서드가 호출이 될 겁니다. 해당 결과는 Guestbook 객체로 반환하는데 이것도 json 메서드로 변환돼서 클라이언트한테는 갈 겁니다. 클라이언트한테 응답이 갈 때는 json으로 바뀌어서 간다는 것을 기억해야 합니다.
- 마지막으로 delete 메서드는 @DeleteMapping 어노테이션을 갖고 있습니다. @DeleteMapping은 path 정보가 있어요. /guestbooks/id 형식으로 URL이 올 때 메서드가 호출됩니다. 이런 id 정보를 PathVariable이라고 했던 거 기억하시죠? 메서드의 인자를 보면 @pathVaialbe이라는 어노테이션으로 값을 읽어들이고 있는 것을 볼 수 있습니다. 해당 메서드가 성공하면 Map 객체를 생성하는데 키값은 "success"로 주고 값은 true나 false가 리턴이 됩니다.
- 이렇게 작성한 Rest API가 잘 작동하는지 확인하기 위해서는 Rest API를 테스트하기 위한 클라이언트가 필요합니다. 이런 클라이언트는 다양한데 여기서는 크롬 브라우저의 Restlet Client라는 확장 프로그램을 사용하겠습니다. 크롬 웹스토어에서 Restlet Client를 찾아서 설치하면 쓸 수 있습니다.
- Restlet Client를 실행해서 보면 Add라는 버튼을 클릭해서 Request에다가 원하는 이름을 써주시면 됩니다. 테스트를 위해 name에 입력합니다. 예를 들면 "방명록 조회 api" 하고 넣어줍니다.
- 그리고 이제 실제 테스트해보기 위해서 메서드를 선택합니다. 원하는 메서드를 선택해서 들어갔을 때 제대로 동작이 되는지 확인합니다.
- 우선 GET 메서드를 선택할 거고요. 그다음에 HEADERS - add하고 name 부분에다가 Content-Type이라고 지정을 하고 value에는 application/json 이라고 지정합니다. 그리고 테스트할 URL을 넣어주는데 지금은 http://localhost:8080/guestbook/guestbooks 라고 넣습니다.
- 이렇게 설정을 하고 Send를 눌러서 실행해보면 하단의 Respone에 결과가 나오는 걸 볼 수 있습니다. 여기서는 list를 요청했기 때문에 이렇게 list가 보여집니다.
- 수행할 때 URL 뒤에 파라미터로 ?start=5 이렇게 설정하고 Send 하면 아까와 결과 값이 달라지는 것을 알 수 있습니다.
- 지금 여기에 나오는 데이터는 실제 데이터베이스의 guestbook을 select 했을 때 나오는 데이터와 같을 겁니다.
- GetMapping 하는 부분이 테스트가 되셨다면 다음은 PostMapping을 테스트해보겠습니다.
- PostMapping 할 때는 실제 입력할 guestbook의 정보를 넘겨야 합니다. 우선 메서드는 POST로 하고 URL은 같으니까 그냥 두고 Content-Type도 똑같겠죠. json 타입으로 올 거니까. 그리고 바디에다가 실제 입력할 값을 json 형태로 추가합니다. 그래야 테스트가 이루어집니다. name은 "강경미", content는 "잘되고계신가요?" 로 추가해보겠습니다.
- Send 해서 테스트를 해보니까 200이 나오면서 성공했다고 메시지가 나오고 있습니다. 실제 db에서 select 해보면 id가 10번인 "강경미"라는 데이터가 잘 들어가고 있는 것을 확인할 수가 있습니다.
- 이번에는 삭제를 테스트해보겠습니다. 4번 id를 삭제해겠습니다. 삭제는 DeleteMapping이므로 메서드를 DELETE로 바꾸시고 URL 뒤에다가 /4 를 붙여줍니다.
- Send 하면 success: "true"가 리턴되고 있는 것을 확인할 수 있습니다.
- 아래 화면이 해당 코드입니다. 이 부분이 잘 수행되고 넘어왔으면 실제 삭제가 됐으니까 deleteCount가 1이 넘어왔을 거고 0보다 크니까 true를 리턴해줬겠죠. 리턴한 true를 가지고 Map을 만들어서 응답을 하고 있으니까 응답 결과가 true로 나타난 겁니다.
- 이렇게 잘 응답되고 있는 것을 확인할 수 있습니다. mysql에서도 다시 select 해보면 4번 데이터가 삭제된 것까지 확인할 수 있습니다.
- 이렇게 Rest Controller를 이용해서 웹 API를 이용하는 실습까지 진행을 해보았습니다.
실습코드
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 @RequestMapping(path="/guestbooks") public class GuestbookApiController { @Autowired GuestbookService guestbookService;
@GetMapping 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 public Guestbook write(@RequestBody Guestbook guestbook, HttpServletRequest request) { String clientIp = request.getRemoteAddr(); // id가 입력된 guestbook이 반환된다. Guestbook resultGuestbook = guestbookService.addGuestbook(guestbook, clientIp); return resultGuestbook; }
@DeleteMapping("/{id}") 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"); } } |
생각해보기
- Web API에게 POST방식으로 값을 전달할 때 JSON메시지를 보냈고, 결과도 JSON메시지를 출력하도록 하였습니다. JSON메시지를 자바객체로 변환하고, 자바객체를 반대로 JSON메시지로 변화하는 부분들이 모두 자동으로 이뤄지고 있는 것을 알 수 있었습니다. 만약 서블릿을 이용해 개발한다면, 이 부분들을 어떻게 구현해야 할까요?
- 이를 통해 Spring MVC의 장점에 대해 생각해보세요.
참고 자료
[참고링크] Building a RESTful Web Service https://spring.io/guides/gs/rest-service/
[참고링크] Building REST services with Spring https://spring.io/guides/tutorials/bookmarks/
'부스트코스 웹 프로그래밍 > 3. 웹 앱 개발: 예약서비스 1' 카테고리의 다른 글
11. Controller - BE (1) (0) | 2019.08.07 |
---|---|
10. 레이어드 아키텍처(Layered Architecture) - BE (2) (0) | 2019.08.07 |
10. 레이어드 아키텍처(Layered Architecture) - BE (1) (0) | 2019.08.06 |
9. Spring MVC - BE (3) (0) | 2019.08.06 |
9. Spring MVC - BE (2) (0) | 2019.08.06 |