미리 DB에 서울특별시의 식당정보를 저장해 둘 거지만 새로 추가할 경우 사용예정
- 데이터베이스에서 입력된 문자열과 일치하는 식당 정보를 가져온다.
- name.substring(i, i+2)를 통해 입력된 식당 이름에서 i부터 i+2까지의 두 글자를 추출한다.
- restaurantRepository.findByName(sub)을 통해 데이터베이스에서 이 두 글자를 포함하는 모든 식당을 찾아온다.
- 이렇게 찾아온 식당 목록이 비어있지 않으면, 즉 최소 두 글자 이상이 연속된 문자가 같은 다른 식당이 존재하는 경우는 이 목록을 반환
이렇게 다른 이름으로 검색을 시도하는 이유는, 종종 사용자들이 실수로 식당 이름을 잘못 기억하거나, 조금 다르게 입력할 수 있기 때문입니다. 예를 들어, "김밥"을 찾고자 할 때, "김밥"이라는 이름으로 등록된 식당이 없을 수도 있습니다. 그러나 "김밥천국", "김밥나라" 등과 같이, 최소 두 글자 이상이 연속된 문자가 같은 다른 식당들은 존재할 수 있습니다. 따라서 이러한 식당들을 찾아서 결과로 제공해주는 것입니다.
이 서비스 로직에선 자바 정규식 Regex(Regular Expression)을 사용하였다.
정규식을 이용하면 많은 양의 텍스트 파일 중에서 원하는 데이터를 손쉽게 뽑아낼 수 있고, 입력된 데이터가 형식에 맞는지 체크할 수도 있다.
내가 사용한 정규식
- (?i) = 대소문자 구분x
- .* = 모든문자
- \b = 문자의 경계
예를들어 서초구 양재동으로 입력될 경우 공백을 확인하고 배열에 담고
앞 글자인 서초구가 포함된 주소를 찾고 그 중에서 양재동을 포함하는 주소만 리스트로 가져올 수 있게 만들었다.
//통합 검색
public List<Restaurant> searchByNameAndAddress(String keyword) {
if (keyword.length() < 2) {
throw new IllegalArgumentException("최소 두 글자 이상 입력해 주세요.");
}
List<Restaurant> restaurants = restaurantRepository.SearchByNameAndAddress(keyword);
if (restaurants.isEmpty()) {
restaurants = restaurantRepository.searchByKeywordContaining(keyword);
}
return restaurants;
}
@Test
public void 식당생성() throws Exception {
//given
Restaurant restaurant = Restaurant.builder()
.name("김밥천국")
.address_name("강남구")
.lat(123.123)
.lng(456.456)
.build();
em.persist(restaurant);
//when
Long restaurantId = restaurantService.createRestaurant(restaurant);
Restaurant findRestaurant = restaurantRepository.findOne(restaurantId);
//then
assertThat(findRestaurant.getId()).isEqualTo(restaurantId);
}
- 식당객체를 하나 생성해 주고 값을 담아 저장
- DB에 아이디가 일치하는 식당을 가져옴
- 입력받은 식당과 일치하는지 확인
@Test
public void 식당이름으로조회() throws Exception {
//given
Restaurant restaurant1 = Restaurant.builder()
.name("김밥 천국 강남점")
.address_name("강남구")
.lat(123.123)
.lng(456.456)
.build();
Restaurant restaurant2 = Restaurant.builder()
.name("김밥 천국 중구점")
.address_name("중구")
.lat(123.456)
.lng(456.123)
.build();
em.persist(restaurant1);
em.persist(restaurant2);
String inputName1 = "김밥천국";
String inputName2 = "김밥";
String inputName3 = "김";
//when
List<Restaurant> restaurants1 = restaurantService.findByRestaurantName(inputName1);
List<Restaurant> restaurants2 = restaurantService.findByRestaurantName(inputName2);
//then
assertThat(restaurants1.size()).isEqualTo(2);
assertThat(restaurants2.size()).isEqualTo(2);
assertThrows(IllegalArgumentException.class, () -> {
restaurantService.findByRestaurantName(inputName3);
});
}
같은 이름의 식당 2개를 설정한 후 3가지 경우
1. 완전일치
2. 한 단어만 일치
3. 예외문구
를 입력받았을때 값이 잘 들어가는지 예외가 잘 발생하는지 코드를 만듦
@Test
public void 주소로식당조회() throws Exception {
//given
Restaurant restaurant1 = Restaurant.builder()
.name("마루심")
.address_name("서초구 반포동 54-10")
.lat(123.123)
.lng(456.456)
.build();
Restaurant restaurant2 = Restaurant.builder()
.name("메종조")
.address_name("서초구 서초동 1476-10")
.lat(123.456)
.lng(456.123)
.build();
Restaurant restaurant3 = Restaurant.builder()
.name("서관면옥")
.address_name("서초구 서초동 1675-5")
.lat(123.456)
.lng(456.123)
.build();
em.persist(restaurant1);
em.persist(restaurant2);
em.persist(restaurant3);
String inputName1 = "서초구";
String inputName2 = "서";
String inputName3 = "반포동";
//when
List<Restaurant> address1 = restaurantService.findByAddressName(inputName1);
List<Restaurant> address3 = restaurantService.findByAddressName(inputName3);
//then
assertThat(address1.size()).isEqualTo(3);
assertThrows(IllegalArgumentException.class, () -> {
restaurantService.findByAddressName(inputName2);
});
assertThat(address3.size()).isEqualTo(1);
}
- 구를 입력했을때 입력받은 구를 포함한 식당 모두 조회
- 한 글자 입력시 예외발생
- 동을 입력받았을때 입력받은 동을 포함하는 식당 모두 조회
@Test
public void 식당상세조회() throws Exception {
//given
Restaurant restaurant = Restaurant.builder()
.name("마루심")
.address_name("서초구 반포동 54-10")
.lat(123.123)
.lng(456.456)
.reviews(new ArrayList<>())
.build();
em.persist(restaurant);
Review review1 = Review.builder()
.title("Good")
.likeCount(18)
.build();
Review review2 = Review.builder()
.title("fuck")
.likeCount(3)
.build();
Review review3 = Review.builder()
.title("soso")
.likeCount(4)
.build();
Review review4 = Review.builder()
.title("bad")
.likeCount(1)
.build();
restaurant.addReview(review1);
restaurant.addReview(review2);
restaurant.addReview(review3);
restaurant.addReview(review4);
em.persist(restaurant);
em.persist(review1);
em.persist(review2);
em.persist(review3);
em.persist(review4);
em.flush();
//when
Restaurant detail = restaurantService.detailRestaurant(restaurant.getId());
//then
List<Review> top3Reviews = detail.getReviews();
assertThat(detail.getReviews().size()).isEqualTo(3);
assertThat(top3Reviews).containsExactly(review1, review3, review2);
}
저장된 식당아이디와 조회하려는 식당의 아이디가 같으면 식당정보 리턴
@Test
public void 통합검색() throws Exception {
//given
Restaurant restaurant1 = Restaurant.builder()
.name("미분당")
.address_name("서울특별시 강남구 역삼동 148-1")
.lat(123.123)
.lng(456.456)
.build();
Restaurant restaurant2 = Restaurant.builder()
.name("미소야(역삼점)")
.address_name("서울특별시 강남구 논현동 527-96")
.lat(123.456)
.lng(456.123)
.build();
em.persist(restaurant1);
em.persist(restaurant2);
String inputName1 = "미소야";
String inputName2 = "서울";
String inputName3 = "미";
//when
List<Restaurant> restaurants1 = restaurantService.searchByNameAndAddress(inputName1);
List<Restaurant> restaurants2 = restaurantService.searchByNameAndAddress(inputName2);
assertThat(restaurants1.size()).isEqualTo(1);
assertThat(restaurants2.size()).isEqualTo(2);
assertThrows(IllegalArgumentException.class, () -> {
restaurantService.findByRestaurantName(inputName3);
});
}
기존 식당이름으로 검색과 주소로 검색을 나눴었는데 나눌 필요성과 사용성을 고려하여 통합검색 하나로 수정.