일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 백준
- BFS
- Spring
- DFS
- Java8
- programmers
- LEVEL2
- 네트워크
- 백트래킹
- lambda
- 프로젝트
- TDD
- 알고리즘
- OS
- 스프링
- algorithm
- 그래프
- java
- 자료구조
- 모던자바
- baekjoon
- 자바
- back-end
- kotlin
- 코틀린
- backtracking
- 프로그래머스
- Brute-force
- 운영체제
- DP
- Today
- Total
요깨비's LAB
[Spring Boot, Back-End] 5. 가게 상세 구현 본문
1. 가게 상세
- GET방식 /restaurants/{id}
- {
"id":2019,
"name":"식당",
"address":"골목"
}
형태의 JSON값 반환
2. Code 구현
I. 컨트롤러 단 구현
1. RestaurantControllerTest 작성
@RunWith(SpringRunner.class)
@WebMvcTest(RestaurantController.class) // Restaurant 컨트롤러를 테스트하겠다는 어노테이션
public class RestaurantControllerTest {
@Autowired
private MockMvc mvc;
// 이전 내용
@Test
public void list() throws Exception {
...
}
@Test
public void detail() throws Exception {
mvc.perform(get("/restaurants/1004"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("\"id\":1004")))
.andExpect(content().string(containsString("\"name\":\"Mcdonald\"")))
.andExpect(content().string(containsString("\"address\":\"Seoul\"")));
}
}
자, 당연히 detail을 위한 컨트롤러가 없으니까 에러가 나겠죠? 이제 실제 컨트롤러 단을 작성할게요.
2. RestaurantController 작성
@RestController
public class RestaurantController {
// 이전 챕터 내용
@GetMapping("/restaurants")
public List<Restaurant> list() {
List<Restaurant> restaurants = new ArrayList<>();
restaurants.add(new Restaurant(1004L,"Mcdonald","Seoul"));
restaurants.add(new Restaurant(2020L,"Cyber Food","Seoul"));
return restaurants;
}
@GetMapping("/restaurants/{id}")
public Restaurant detail(@PathVariable("id") Long id) {
List<Restaurant> restaurants = new ArrayList<>();
restaurants.add(new Restaurant(1004L,"Mcdonald","Seoul"));
restaurants.add(new Restaurant(2020L,"Cyber Food","Seoul"));
// 모던 자바의 기능인 Stream API 사용
Restaurant restaurant = restaurants.stream()
.filter(r -> r.getId().equals(id))
.findFirst()
.orElse(null);
return restaurant;
}
}
이제 테스트 코드가 정상 작동하게 됩니다. 그런데, detail과 list 코드를 보면
List<Restaurant> restaurants = new ArrayList<>();
restaurants.add(new Restaurant(1004L,"Mcdonald","Seoul"));
restaurants.add(new Restaurant(2020L,"Cyber Food","Seoul"));
이 코드가 중복되어 사용이 되고 있습니다. 이 부분을 하나로 묶어서 컨트롤러와 상관없는 곳에 두어서 유지 보수하기 좋게
리펙토링을 해야겠습니다. 해당 데이터들을 어딘가에 저장해 두고 이것들을 필요할때마다 불러오면 좋겠죠? 이제부터
Repository 영역을 개발하겠습니다.
II. Repository 단 구현
1. Repository 클래스 구현(RestaurantRepository)
데이터를 저장하고 비지니스 로직 처리 기능을 구현할 Repository 클래스를 구현하겠습니다.
public class RestaurantRepository {
// 현재는 리스트를 이용해서 기능을 구현했지만 데이터베이스를 활용하여 효과적으로 관리할 것.
private List<Restaurant> restaurants = new ArrayList<>();
public RestaurantRepository() {
restaurants.add(new Restaurant(1004L, "Mcdonald", "Seoul"));
restaurants.add(new Restaurant(2020L, "Cyber Food", "Seoul"));
}
public List<Restaurant> findAll() {
return restaurants;
}
public Restaurant findById(Long id) {
return restaurants.stream().filter(r -> r.getId().equals(id)).findFirst().orElse(null);
}
}
구현 후에 Controller에 중복되어 존재하던 리스트 관련 코드를 삭제해줍니다.
List<Restaurant> restaurants = new ArrayList<>();
restaurants.add(new Restaurant(1004L,"Mcdonald","Seoul"));
restaurants.add(new Restaurant(2020L,"Cyber Food","Seoul"));
그 후에 아래의 컨트롤러 코드를 보겠습니다. 자세한 설명은 코드와 함께 보아야 이해가 쉬우므로, 주석으로 대체하였습니다.
@RestController
public class RestaurantController {
private RestaurantRepository repository = new RestaurantRepository();
@GetMapping("/restaurants/{id}")
public Restaurant detail(@PathVariable("id") Long id) {
// 레스토랑들을 가져와서 id값을 이용해서 특정 레스토랑을 찾고 있는데 이것은 컨트롤러의 역할이 아니다.
// Repository의 findById()라는 메소드로 책임을 위임
// Restaurant restaurant = restaurants.stream().filter(r -> r.getId().equals(id)).findFirst().orElse(null);
Restaurant restaurant = repository.findById(id);
return restaurant;
}
}
코드 구현을 완료 후에 테스트를 실행하면 정상적으로 작동하는 것을 확인할 수 있습니다.
이럿듯, 중복된 코드를 하나의 통합 코드로 따로 분리하여 코드 수정 해야할 때 하나만 수정할 수 있도록 바꾸고, 가독성을
높여 유지 보수성을 높이고, 사용자와 내부에 있는 비즈니스 로직/도메인 모델들 사이의 징검다리 역할만 수행하도록
개발하고, 실제 로직을 수행하는 코드는 비즈니스 로직/도메인 모델에 분리함으로써 책임 분산이 확실하고, 확장성 있는
코드를 개발할 수 있습니다. 현재 Repository는 리스트를 이용하여 기능을 구현하였지만, 추후에 데이터베이스에 연동하여
좀 더 효율적이고 뛰어난 기능으로 바꾸도록 하겠습니다.
'웹 개발 > 스프링 부트 프로젝트(레스토랑 예약)' 카테고리의 다른 글
[Spring Boot, Back-End] 번외. Mock(가짜) 객체 (0) | 2020.01.16 |
---|---|
[Spring Boot, Back-End] 번외. 의존성 주입 (0) | 2020.01.07 |
[Spring Boot, Back-End] 4. 가게 목록 구현 (0) | 2019.12.30 |
[Spring Boot, Back-End] 3. Test Driven Development (0) | 2019.12.30 |
[Spring Boot, Back-End] 2. 프로젝트 시작 (0) | 2019.12.30 |