@RestController
•
UI를 통해 제공하는 것이 아닌 백엔드에서 REST API를 통해 json(or XML)형태로 데이터만 전달하기 위해 @RestController를 사용해 컨트롤러 다시 정의
실습코드
결과
@Controller와 @RestController 차이
@Controller : 주로 View 반환할 때 사용
@RestController : 주로 데이터 반환 시 사용
@Controller
•
전통적인 스프링 MVC의 컨트롤러
•
주로 View를 반환하기 위해 사용
•
@ResponseBody 어노테이션을 활용해 데이터 반환도 가능
@RestController
•
@Controller에 @ResponseBody가 추가된 것
•
주로 Json 형태로 객체 데이터를 반환할 때 사용
•
ResponseEntity로 객체를 감싸서 반환
reference : https://mangkyu.tistory.com/49
API
Json형식으로 데이터를 어플리케이션끼리 주고 받으면서 서로 대화가 가능하게 하는 매커니즘!
•
Application Programming Interface로 컴퓨터나 소프트웨어를 서로 연결
•
Json형식으로 데이터를 리턴해주는 서버 프로그램
>> Json형식으로 데이터를 어플리케이션끼리 주고 받으면서 서로 대화가 가능하게 하는 매커니즘!
ex) 기상청의 소프트웨어 시스템에는 일일 기상 데이터 존재. 휴대폰의 날씨 앱은 API를 통해 이 시스템과 ‘대화’하여 휴대폰에 매일 최신 날씨 정보를 표시함.
reference : https://aws.amazon.com/ko/what-is/api/
Json
•
JavaScript Object Notation으로 "키-값 쌍"으로 이루어진 데이터 오브젝트를 표현하는 파일 포맷
◦
Example
위 데이터를 Json형식으로 표현하면, (GET /api/v1/hospitals/2321 호출)
{id:"", roadNameAddress:"", hospitalName:"",patientRoomCount:"", totalNumberOfBeds:"", businessTypeName:"",totalAreaSize:""}
Service
•
목표 : business_status_code에서 숫자로 표기된 값(13)을 매핑된 텍스트(영업중)로 변환하여 데이터 전달
•
문제점 : 해당 비즈니스 로직 어디로? Controller에? HospitalResponse에?
→ 레이어드 아키텍쳐에 맞게 비즈니스 계층인 Service에 구현
실습 코드
레이어드 아키텍쳐
•
어플리케이션 컴포넌트를 유사 관심사 기준으로 레이어로 묶어 수평적으로 구성한 구조
특징
•
각 레이어는 가장 가까운 하위 레이어의 의존성 주입받음
•
각 레이어는 관심사 따라 묶여 있고, 다른 레이어 역할 침범 X
◦
장점 : 코드 가독성, 기능 구현에 유리, 코드 확장성’
•
각 레이어가 독립적이면 단위테스트에 용이
Presentation계층 – Controller GET /api/v1/hospitals/{id}
비즈니스(Business) 계층 — Service
데이터 접근 계층— Dao(Repository)
이전 코드 문제점
@RestController
@RequestMapping("/api/v1/hospitals")
public class HospitalRestController {
private final HospitalRepository hospitalRepository;
Java
복사
•
레이어드 아키텍처에 맞게 설계 x
◦
Presentation 계층인 HospitalRestController 가 비즈니스 계층에게 의존성 갖는 것이 아닌 데이터 접근 계층인 HospitalRepository 를 의존하고 있음.
WebMvcTest
WebMvcTest와 Mock을 이용해 Controller를 테스트
문제점
1.
Contoller 테스트 시 Service에 의존성
→ Mock 객체 사용
2.
많은 Controller 테스팅 단계 수
1. SpringBoot 실행
b.
웹브라우저 or Api 호출 App
c.
/api/v1/hospitals/111
d.
눈으로 확인
→ @WebMvcTest 이용
어노테이션
@WebMvcTest(테스트 대상 클래스.class)
•
웹에서 사용되는 요청과 응답 테스트 수행
•
테스트 대상 클래스 선언안하면 @Controller, @RestController, @ControllerAdvice 등 컨트롤러 관련 빈 객체 모두 로드
@MockBean
•
가짜 객체 생성해서 주입
•
@MockBean이 선언된 객체는 실제 객체가 아니기 때문에 개발자가 given()메소드 통해 동작 정의해야함.
테스트 과정
@MockBean // HospitalService는 테스트를 위해 가짜 객체를 쓰겠다는 뜻
HospitalService hospitalService;
Java
복사
@MockBean을 통해 HospitalController가 의존하는 HospitalService 객체에 Mock객체를 주입한다.
HospitalResponse hospitalResponse = HospitalResponse.builder()
.id(2321)
.roadNameAddress("서울특별시 서초구 서초중앙로 230, 202호 (반포동, 동화반포프라자빌딩)")
.hospitalName("노소아청소년과의원")
.patientRoomCount(0)
.totalNumberOfBeds(0)
.businessTypeName("의원")
.totalAreaSize(0.0f)
.businessStatusName("영업중")
.build();
given(hospitalService.getHospital(2321))
.willReturn(hospitalResponse);
Java
복사
•
Builder 어노테이션 이용해 HospitalResponse 객체를 생성한다.
◦
필요한 파라미터만 넣고 빌드 가능
•
given() 메소드를 통해 Mock객체 동작 정의
◦
Mock객체인 hospitalService의 getHospital(2321) 호출
•
willReturn() 통해 어떤 결과 리턴할 지 정의
◦
hospitalService의 getHospital(2321)결과로 id가 2321인 HospitalResponse 객체 리턴
◦
Builder로 정의한 hospitalResponse 객체 넣기
int hospitalId = 2321;
String url = String.format("/api/v1/hospitals/%d", hospitalId);
mockMvc.perform(get(url))
.andExpect(status().isOk())
.andExpect(jsonPath("$.hospitalName").exists()) // $는 루트 $아래에 hospitalName이 있어야 함
.andExpect(jsonPath("$.hospitalName").value("노소아청소년과의원"))
.andDo(print()); // http request, response내역을 출력 해라
verify(hospitalService).getHospital(hospitalId);// getHospital()메소드의 호출이 있었는지 확인
Java
복사
•
perform()메소드를 통해 서버로 URL 요청하는 것처럼 테스트
◦
get(), post(), put(), delete()를 인자로 넣어 HTTP 메소드로 URL 정의 가능
◦
결과값 : ResultActions 객체
•
ResultActions의 andExpect()통해 결과값 검증
◦
MockMvcResultMatchers 클래스에 정의되어 있는 메서드 활용
▪
status() : HTTP 상태 코드 검증
▪
jsonPath() : jsonPath 표현 사용해 response body에 접근
•

•
andDo() : 요청과 응답 전체 내용 확인
◦
print() : 콘솔에 http request, response 내용 출력
•
verify() :지정된 메소드가 실행됐는지 검증