오늘은 Servlet 컨트롤러를 RestController로 변경하면서 RestController를 사용하는 이유와 Rest API를 구축하는 과정에 대해 기록해보고자 한다.
아래 이미지는 Servlet 컨트롤러를 사용해 API를 구현해놓은 것이다.
Servlet을 사용하면 request와 response 값을 다루기 정말 쉬워지지만 하나의 기능당 하나의 클래스가 필요해 쓸데없이 많은 클래스를 생성해야한다.
기능당 하나의 서블렛이 생성된 모습이다. 이렇게 되면 프로그램의 용량이 쓸데없이 커지게 되며,
대규모 프로젝트라면 어떤 클래스가 어떤 기능인지 알 수도 없다.
나는 이러한 문제점을 해결하기 위해 @RestController를 채택했다.
Spring MVC Controller인 @Controller 가 아닌 @RestController를 사용하는 이유는 이러하다.
현재 개발중인 서버는 SSR(Server Side Rendering)을 거쳐 만들어진 View를 반환하는 서버가 아니라
클라이언트가 요청한 리소스를 제공하는 RestAPI 서버이다.
(완벽한 Rest는 못지켜서 사실상 HTTP API 서버긴하다..)
RestController는 Spring MVC Controller인 @Controller 애노테이션에 @ResponseBody 가 추가된 것으로
서버->클라이언트로 Response시에 자바 객체를 Json형태의 데이터로 반환하는데에 사용된다.
현재 DB에서 데이터를 가져와 비즈니스 로직을 거친 뒤에 안드로이드에 전달해주어야하는 상황이므로
@RestController 사용이 적합하다고 생각됐다.
컨트롤러 변경
ParkDataAddrSearchServlet.java
@WebServlet(name = "parkDataAddrSearchServlet", urlPatterns = "/lots/address")
public class ParkDataAddrSearchServlet extends HttpServlet {
ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private ParkServiceImpl parkingService;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String addr = request.getParameter("addr");
String latitude = request.getParameter("latitude");
String longitude = request.getParameter("longitude");
List<Park> parkList = parkingService.searchAddr(addr, latitude, longitude);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
List<String> parkJsonList = new ArrayList<>();
//objectMapper 로 'park(자바객체형태)' -> 'Json 형태'-> 'Json 구문의 String 형태' 순으로 변환하여 String 변수에 저장
//그리고 String List 인 parkJsonList 에 값 저장
for (Park park : parkList) {
String parkJson = objectMapper.writeValueAsString(park);
parkJsonList.add(parkJson);
}
//저장한 parkJsonList 를 클라이언트에게 전달
out.print(parkJsonList);
out.flush();
}
}
기존 컨트롤러 코드는 완전히 기초에 대해서 공부하고 있던 차라서
일반적인 컨트롤러가 아니라 서블렛을 extends해서 작성되어 있었다.
서블렛 사용 방식은 하나의 API 당 하나의 서블렛 클래스를 생성해야해서 클래스가 너무 많았기 때문에
ParkDataAddrSearchServlet 클래스 하나를 중심으로 설명하겠다.
parkService에서 searchAddr을 사용한 결과를 출력해주는 것이 끝인데 이렇게나 길다.
헤더에 UTF-8 , application/json 등도 추가해주어야하고 jackson 라이브러리를 통해 json형태로 변환시켜 리턴해주어야한다.
너무 복잡하고 귀찮지 않은가.
RestController를 사용하면 이렇게 긴 코드도 아주 짧게 변경할 수 있다.
LotsController.java
@RestController //주용도는 Json 형태로 객체 데이터를 반환하는 것이며, Spring boot를 API 서버로 활용할 때 사용.
@RequestMapping("/lots")
public class LotsController {
private ParkServiceImpl parkService;
@Autowired
public LotsController(ParkServiceImpl parkService) {
this.parkService = parkService;
}
@GetMapping("address")
public List<Park> ParkDataAddrSearch(@RequestParam("addr") String addr, @RequestParam("latitude") String latitude, @RequestParam("longitude") String longitude) {
return parkService.searchAddr(addr, latitude, longitude);
}
어이없게도 Servlet으로 구현했을 때 길었던 것이 이렇게 정리된다. 이게 @RestController의 힘이다.
LotsController.java
@RestController //주용도는 Json 형태로 객체 데이터를 반환하는 것이며, Spring boot를 API 서버로 활용할 때 사용.
public class LotsController {
private ParkServiceImpl parkService;
public LotsController(ParkServiceImpl parkService) {
this.parkService = parkService;
}
@PostMapping("/lots")
public void ParkDataSave() {
parkService.saveData();
}
@GetMapping("/lots/address")
public List<Park> ParkDataAddrSearch(@RequestParam(value = "addr") String addr, @RequestParam(value = "latitude") String latitude, @RequestParam(value = "longitude") String longitude) {
return parkService.searchByAddr(addr, latitude, longitude);
}
@GetMapping("/lots/location")
public List<Park> ParkDataLocationSearch(@RequestParam(value = "latitude") String latitude, @RequestParam(value = "longitude") String longitude) {
return parkService.searchByLotLoc(latitude, longitude);
}
@GetMapping("/lots/tel")
public List<Park> ParkDataTelSearch(@RequestParam(value = "num") String num) {
return parkService.searchByTel(num);
}
}
또한 RestController 를 사용해 여러 서블렛 클래스로 분리되어 있던 API 들을 하나의 클래스로 합칠 수 있었다.
다시 말하지만 @RestController는 @Controller와 @ResponseBody가 합쳐진 것이기 때문에 내부의 메서드를 알아서 @ResponseBody 처리해준다.
오늘은 이렇게 Servlet 컨트롤러를 RestController로 변경하는 과정을 보여드렸습니다.
Servlet컨트롤러를 사용하시는 분들은 특별한 이유가 없다면 이렇게 하나의 컨트롤러로 사용하시는게 관리하기 더 편할 것 같습니다!
이제 2021년도 얼마 남지 않았는데 다들 남은 올해 아깝지않게 빡공합시다! 감사합니다:)
'BackEnd > Spring' 카테고리의 다른 글
[SpringBoot] JPA 외래키 제약 조건 해제(with. SQLIntegrityConstraintViolationException) (3) | 2021.12.31 |
---|---|
[SpringBoot] 스프링 파일 사이즈 제한 오류 - FileSizeLimitExceededException (2) | 2021.12.30 |
[SpringBoot] @EnableScheduling - 스프링 스케쥴러로 Cron 작업 돌리기 (0) | 2021.12.22 |
[SpringBoot] 스프링부트 / 인텔리제이 서버 포트 변경하기! (1) | 2021.12.15 |
[SpringBoot] JPA 카멜케이스 컬럼명 적용법 (3) | 2021.12.08 |