Home

0

레스토랑 예약 사이트 만들기 8 - 가게목록 필터링

@Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class Region { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name;} @Repositorypublic interface RegionRepository extends JpaRepository<Region,Long> {} @Service@RequiredArgsConstructorpublic class RegionService { private final RegionRepository regionRepository; public List<Region> getRegions() { return regionRepository.findAll(); }} @Service@RequiredArgsConstructorpublic class RegionService { private final RegionRepository regionRepository; public List<Region> getRegions() { return regionRepository.findAll(); }} class RegionServiceTest { private RegionService regionService; @Mock private RegionRepository regionRepository; @BeforeEach public void setUp(){ MockitoAnnotations.openMocks(this ); regionService = new RegionService(regionRepository); } @Test public void 지역정보들을_가져온다() { List<Region> mockRegions = new ArrayList<>(); mockRegions.add(Region.builder() .name("Seoul") .build()); given(regionRepository.findAll()).willReturn(mockRegions); List<Region> regions = regionService.getRegions(); Region region = regions.get(0); assertThat(region.getName()).isEqualTo("Seoul"); }} @RestController@RequiredArgsConstructorpublic class RegionController { private final RegionService regionService; @GetMapping("/regions") public List<Region> list(){ List<Region> regions = regionService.getRegions(); return regions; }} @WebMvcTest(RegionController.class)class RegionControllerTest { @Autowired private MockMvc mockMvc; @MockBean private RegionService regionService; @Test public void 지역목록들을_가져온다() throws Exception { List<Region> regions = new ArrayList<>(); regions.add(Region.builder().name("Seoul").build()); given(regionService.getRegions()).willReturn(regions); mockMvc.perform(get("/regions")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Seoul"))); }} 카테고리 만들기@Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; public String name;}

0

레스토랑 예약 사이트 만들기 7 - 멀티모듈

dependencies { implementation project(':eatgo-common') implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test'} jar { enabled = true}bootJar { enabled = false} @Testpublic void 레스토랑에_해당되는_메뉴들을_반환한다() { List<MenuItem> mockMenuItems = new ArrayList<>(); mockMenuItems.add(MenuItem.builder() .name("Kimchi") .build()); given(menuItemRepository.findAllByRestaurantId(1004L)).willReturn(mockMenuItems); List<MenuItem> menuItems = menuItemService.getMenuItems(1004L); MenuItem menuItem = menuItems.get(0); assertThat(menuItem.getName()).isEqualTo("Kimchi");} public List<MenuItem> getMenuItems(Long restaurantId) { return menuItemRepository.findAllByRestaurantId(restaurantId);} 리뷰 정보 가져오기@GetMapping("/reviews")public List<Review> list(){ List<Review> reviews = reivewService.getReviews(); return reviews;} @Testpublic void 레스토랑에_해당되는_리뷰들을_가져온다() throws Exception { List<Review> mockReviews = new ArrayList<>(); mockReviews.add(Review.builder() .description("Cool!") .build()); given(reviewService.getReviews()).willReturn(mockReviews); mockMvc.perform(get("/reviews")) .andExpect(status().isOk()) .andExpect(content().string(containsString("Cool!")));} public List<Review> getReviews() { return reviewRepository.findAll();} @Testpublic void 리뷰들을_가져온다(){ List<Review> mockReviews = new ArrayList<>(); mockReviews.add(Review.builder() .description("Cool!") .build()); given(reviewRepository.findAll()).willReturn(mockReviews); List<Review> reviews = reviewService.getReviews(); Review review = reviews.get(0); assertThat(review.getDescription()).isEqualTo("Cool!");}

0

레스토랑 예약 사이트 만들기 6 - 리뷰 기능

새로운 리뷰 생성 오청을 처리하기 위한 control@RestController@RequiredArgsConstructorpublic class ReviewController { private final ReviewService reivewService; @PostMapping("/restaurants/{restaurantId}/reviews") public ResponseEntity<?> create( @PathVariable Long restaurantId, @Valid @RequestBody Review resource ) throws URISyntaxException { Review review = reivewService.addReview(restaurantId, resource); String url = "/restaurants/" + restaurantId + "/reviews/" + review.getId(); return ResponseEntity.created(new URI (url)).body("{}"); }} @WebMvcTest(ReviewController.class)class ReviewControllerTest { @Autowired private MockMvc mockMvc; @MockBean private ReviewService reviewService; @Test public void 리뷰를_생성한다() throws Exception { given(reviewService.addReview(eq(1L), any())).willReturn( Review.builder() .id(1004L) .name("JOKER") .score(3) .description("Mat-it-da") .build()); mockMvc.perform(post("/restaurants/1/reviews") .contentType(MediaType.APPLICATION_JSON) .content("{\"name\":\"JOKER\", \"score\":3,\"description\" : \"Mat-it-da\"}")) .andExpect(status().isCreated()) .andExpect(header().string("location", "/restaurants/1/reviews/1004")); verify(reviewService).addReview(eq(1L), any()); }} Review 도메인 객체를 생성@Entity@Builder@NoArgsConstructor@AllArgsConstructor@Getter@Setterpublic class Review { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull private Long restaurantId; @NotEmpty private String name; @NotNull private Integer score; @NotEmpty private String description;} Review를 저장하기 위한 Repository 생성@Repositorypublic interface ReviewRepository extends JpaRepository<Review, Long> { List<Review> findAllByRestaurantId(Long restaurantId);} Review Service 클래스를 생성한다.@Service@RequiredArgsConstructorpublic class ReviewService { private final ReviewRepository reviewRepository; public Review addReview(Long restaurantId, Review review) { review.setRestaurantId(restaurantId); reviewRepository.save(review); return review; }}

0

레스토랑 예약 사이트 만들기 5 - 메뉴 관리

메뉴를 추가하는 요청을 처리하기 위한 control@RestController@RequiredArgsConstructorpublic class MenuItemController { private final MenuItemService menuItemService; @PatchMapping("/restaurants/{restaurantId}/menuitems") public String buikUpdate(){ List<MenuItem> menuItems = new ArrayList<>(); menuItemService.bulkUpdate(menuItems); return ""; }} @WebMvcTest(MenuItemController.class)class MenuItemControllerTest { @Autowired private MockMvc mockMvc; @MockBean private MenuItemService menuItemService; @Test public void bulkUpdate() throws Exception { ResultActions resultActions = mockMvc.perform(patch("/restaurants/1/menuitems") .contentType(MediaType.APPLICATION_JSON) .content("[]")); resultActions .andExpect(status().isOk()); verify(menuItemService).bulkUpdate(any()); }} @Service@RequiredArgsConstructorpublic class MenuItemService { private final MenuItemRepository menuItemRepository; public void bulkUpdate(Long restaurantId, List<MenuItem> menuItems) { for(MenuItem menuItem : menuItems){ menuItem.setRestaurantId(restaurantId); menuItemRepository.save(menuItem); } }} class MenuItemServiceTest { private MenuItemService menuItemService; @Mock private MenuItemRepository menuItemRepository; @BeforeEach public void setUp(){ MockitoAnnotations.initMocks(this); menuItemService = new MenuItemService(menuItemRepository); } @Test public void bulkUpdate() { List<MenuItem> menuItems = new ArrayList<>(); menuItems.add(MenuItem.builder() .name("Kimchi") .build()); menuItems.add(MenuItem.builder() .name("Gukbob") .build()); menuItemService.bulkUpdate(1L, menuItems); verify(menuItemRepository, times(2)).save(any());; }} 메뉴 삭제 요청@Builder@Entity@Setter@Getter@NoArgsConstructor@AllArgsConstructorpublic class MenuItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long restaurantId; private String name; @Transient private boolean destroy; public MenuItem(String name){ this.name = name; }} @Service@RequiredArgsConstructorpublic class MenuItemService { private final MenuItemRepository menuItemRepository; public void bulkUpdate(Long restaurantId, List<MenuItem> menuItems) { for(MenuItem menuItem : menuItems){ updateOrDeleteMenuItems(restaurantId, menuItem); } } private void updateOrDeleteMenuItems(Long restaurantId, MenuItem menuItem) { if(menuItem.isDestroy()){ menuItemRepository.deleteById(menuItem.getId()); }else { menuItem.setRestaurantId(restaurantId); menuItemRepository.save(menuItem); } }} @Testpublic void 메뉴를_삭제한다() { List<MenuItem> menuItems = new ArrayList<>(); menuItems.add(MenuItem.builder() .name("Kimchi") .build()); menuItems.add(MenuItem.builder() .name("Gukbob") .build()); menuItems.add(MenuItem.builder() .id(1004L) .destroy(true) .build()); menuItemService.bulkUpdate(1L, menuItems); verify(menuItemRepository, times(2)).save(any()); verify(menuItemRepository, times(1)).deleteById(eq(1004L));}

0

레스토랑 예약 사이트 만들기 4 - 예외 처리

없는 페이지 요청에 대한 예외처리@Testpublic void 없는_페이지에대한_예외처리를_한다() throws Exception{ given(restaurantService.getRestaurant(404L)).willThrow(new RestaurantNotFoundException(404L)); ResultActions resultActions = mockMvc.perform(get("/restaurants/404")); resultActions .andExpect(status().isNotFound()) .andExpect(content().string("{}"));} public class RestaurantNotFoundException extends RuntimeException{ public RestaurantNotFoundException(Long id) { super("Could not find Restaurant" + id ); }} @ControllerAdvicepublic class RestaurantErrorAdvice { @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(RestaurantNotFoundException.class) public String handleNotFound(){ return "{}"; }} Service 계층에서의 예외처리@Testpublic void 없는_레스토랑을_가져온다() { assertThatThrownBy(() -> { Restaurant restaurant = restaurantService.getRestaurant(404L); }).isInstanceOf(RestaurantNotFoundException.class);// Restaurant restaurant = restaurantService.getRestaurant(404L);} public Restaurant getRestaurant(Long id) { Optional<Restaurant> optional = restaurantRepository.findById(id); if (optional.isPresent()) { List<MenuItem> menuItems = menuItemRepository.findAllByRestaurantId(id); Restaurant restaurant = new Restaurant(); restaurant.setMenuItems(menuItems); return restaurant; }else{ throw new RestaurantNotFoundException(id); }}

0

레스토랑 예약 사이트 만들기 3

<!DOCTYPE html><html lang="ko"><head> <meta charset="UTF-8"> <title>Title</title></head><body><div id="app">Hello, world!</div><script src="./src/index.js"></script></body></html> (async () => { const url = "http://localhost:8080/restaurants"; const response = await fetch(url); const restaurants = await response.json(); console.log(restaurants); const element = document.getElementById('app'); element.innerHTML = JSON.stringify(restaurants);})(); (async () => { const url = "http://localhost:8080/restaurants"; const response = await fetch(url); const restaurants = await response.json(); console.log(restaurants); const element = document.getElementById('app'); element.innerHTML = ` ${restaurants[0].id} ${restaurants[0].name} `})(); (async () => { const url = "http://localhost:8080/restaurants"; const response = await fetch(url); const restaurants = await response.json(); console.log(restaurants); const element = document.getElementById('app'); element.innerHTML = ` ${restaurants.map(restaurant => ` <p> ${restaurant.id} ${restaurant.name} ${restaurant.address} </p> `).join('')} `;})();

0

레스토랑 예약 사이트 만들기 2 - 메뉴 정보 추가(관리자)

레스토랑에 메뉴정보를 담기@Entity@Getter@Setter@NoArgsConstructor@AllArgsConstructor@Builderpublic class Restaurant { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull private Long categoryId; @NotEmpty private String name; @NotEmpty private String address; @Transient @JsonInclude(JsonInclude.Include.NON_NULL) private List<MenuItem> menuItems; public void addMenuItem(MenuItem menuItem){ menuItems.add(menuItem); } public void setMenuItems(List<MenuItem> menuItems){ this.menuItems = new ArrayList<>(menuItems); } public String getInformation(){ return name + " in " + address; }} 메뉴에 대한 정보를 담고있는 MenuItem 클래스@Builder@Entity@Setter@Getter@NoArgsConstructor@AllArgsConstructorpublic class MenuItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Long restaurantId; private String name; @Transient @JsonInclude(JsonInclude.Include.NON_DEFAULT) private boolean destroy; public MenuItem(String name){ this.name = name; }} 레스토랑에서 메뉴정보 가져오기public interface MenuItemRepository extends JpaRepository<MenuItem, Long> { List<MenuItem> findAllByRestaurantId(Long restaurantId);} 레스토랑에 메뉴등록 요청 보내기추가하고자 하는 데이터는 Http Body에 넣어서 보낸다.

0

레스토랑 예약 사이트 1 - 레스토랑 관리(사용자) 레스토랑 정보 가져오기

사용자 페이지사용자의 경우 레스토랑을 관리하지 않으므로 레스토랑 정보를 추가하거나 수정할필요는 없고 조회하는 기능만 있으면 된다. 모든 Restaurant정보 가져오기 특정 Restaurant정보 가져오기 Request Parameter를 통한 레스토랑 조회 control요청시 RequestParameter를 통해 원하는 지역, 카테고리를 통해 해당 조건을 만족하는 레스토랑 정보를 모두 가져올 수 있도록 한다. 특정 Restaurant 정보를 가져오는 함수들은 관리자에서 만들었던 내용과 같으므로 생각한다. @CrossOrigin@RestController@RequiredArgsConstructorpublic class RestaurantController { private final RestaurantService restaurantService; @GetMapping("/restaurants") public List<Restaurant> list(@RequestParam("region") String region, @RequestParam("category") Long category) { List<Restaurant> restaurants = restaurantService.getRestaurants(region, category); return restaurants; } @GetMapping("/restaurants/{id}") public Restaurant detail(@PathVariable Long id) throws Exception { Restaurant restaurant = restaurantService.getRestaurant(id); return restaurant; }} Request Parameter를 통한 레스토랑 조회 테스트 코드 작성@Testpublic void RequestParameter를_이용한_list를_확인한다() throws Exception { List<Restaurant> restaurants = new ArrayList<>(); restaurants.add(Restaurant.builder() .id(1004L) .categoryId(1L) .name("JOKER House") .address("Seoul") .build()); given(restaurantService.getRestaurants("Seoul", 1L)).willReturn(restaurants); ResultActions resultActions = mockMvc.perform(get("/restaurants?region=Seoul&category=1")); resultActions .andExpect(status().isOk()) .andExpect(content().string(containsString("\"id\":1004"))) .andExpect(content().string(containsString("\"name\":\"JOKER House\""))) .andDo(print());}

0

레스토랑 예약 사이트 1 - 레스토랑 관리(관리자) 레스토랑 정보 업데이트

4. 레스토랑 정보 업데이트레스토랑 업데이트 하기 위한 control 추가레스토랑 정보를 업데이트 하기 위해서는 업데이트 하고자 하는 레스토랑을 가지고 와야 한다. /restaurants경로뒤에 레스토랑 id를 붙여 요청이 들어오면 id를 이용해 레스토랑을 찾고 request body에 들어있는 정보로 레스토랑을 업데이트 한다. 업데이트 요청을 처리하기 위해 Http 메소드 중에서 patch메소드를 이용할 것이다. @PatchMapping("/restaurants/{id}")public String update(@PathVariable("id") Long id, @RequestBody Restaurant restaurant) throws Exception { restaurantService.updateRestaurant(id, restaurant.getName(), restaurant.getAddress()); return "{}";} 업데이트 요청에 대한 테스트 코드 작성@Testpublic void 레스토랑정보_업데이트() throws Exception { String JOKER = "JOKER Bar"; String Busan = "Busan"; Restaurant restaurant = Restaurant.builder() .categoryId(1L) .name(JOKER) .address(Busan) .build(); String content = objectMapper.writeValueAsString(restaurant); ResultActions resultActions = mockMvc.perform(patch("/restaurants/1004") .contentType(MediaType.APPLICATION_JSON) .content(content)); resultActions .andExpect(status().isOk()) .andDo(print()); verify(restaurantService).updateRestaurant(1004L, JOKER, Busan);} 레스토랑 업데이트를 하기 위한 Service 메소드먼저 id를 갖고 저장돼 있는 해당 레스토랑을 가져온 후 전달 받은 name값과 address값으로 업데이트 한다. 만약 해당 레스토랑이 없을 경우 RestaurantNotFoundException예외를 일으키도록 한다.

0

레스토랑 예약 사이트 1 - 레스토랑 관리(관리자) 레스토랑 생성

3. 레스토랑 추가하기레스토랑 생성 요청을 처리하기 위한 control 추가Http 메소드들 중에서 post메소드를 사용해 새로운 레스토랑을 추가하는 요청을 처리할 것이고, /restaurnt경로로 요청이 들어올 경우 request body에 들어가 있는 데이터를 가져와 새로운 레스토랑을 생성한다. @PostMapping("/restaurants")public ResponseEntity<?> create(@RequestBody Restaurant resource) throws URISyntaxException { String name = resource.getName(); String address = resource.getAddress(); Restaurant restaurant = Restaurant.builder() .name(name) .address(address) .build(); restaurantService.addRestaurant(restaurant); URI location = new URI("/restaurants/" + restaurant.getId()); return ResponseEntity.created(location).body("{}");} 요청에 대한 레스토랑 생성 테스트 코드 작성POJO를 JSON형태로 변환하기 위해 Jackson라이브러리의 ObjectMapper를 사용할 것이다.ObjectMapper를 통해 Restaurant객체를 JSON String 형태로 변환해 request body에 넣어 /restaurants경로로 post요청을 한다. @Autowiredprivate ObjectMapper objectMapper;@Testpublic void 새로운_레스토랑_저장하기() throws Exception { String BobZip = "BobZip"; String Seoul = "Seoul"; Restaurant restaurant = Restaurant.builder() .categoryId(1L) .name(BobZip) .address(Seoul) .build(); // POJO를 JSON형태로 변환해준다. String content = objectMapper.writeValueAsString(restaurant); ResultActions resultActions = mockMvc.perform(post("/restaurants") .content(content) .contentType(MediaType.APPLICATION_JSON)); resultActions .andExpect(status().isCreated()) .andDo(print());} 새로운 레스토랑을 생성하는 요청을 한 후 레스토랑의 정보를 가져오는 요청을 해 해당 정보가 제대로 생성 됐는지 확인한다. @Testpublic void 새로운_레스토랑_저장_및_조회하기() throws Exception { String BobZip = "BobZip"; String Seoul = "Seoul"; Restaurant restaurant = Restaurant.builder() .categoryId(1L) .name(BobZip) .address(Seoul) .build(); String content = objectMapper.writeValueAsString(restaurant); ResultActions postResultActions = mockMvc.perform(post("/restaurants") .content(content) .contentType(MediaType.APPLICATION_JSON)); postResultActions .andExpect(status().isCreated()) .andDo(print()); List<Restaurant> restaurants = new ArrayList<>(); restaurants.add(restaurant); given(restaurantService.getRestaurants()).willReturn(restaurants); ResultActions getResultActions = mockMvc.perform(get("/restaurants")); getResultActions .andExpect(status().isOk()) .andExpect(jsonPath("$[0].name").value(BobZip)) .andExpect(jsonPath("$[0].address").value(Seoul)) .andDo(print());}