대용량프로젝트에 들어가기 앞서 기본적인 검색기능과 crud 기능을 구현하기 위해 기초작업을 하였다
queryDSL을 활용한적이 많이 없어서 적극적으로 해보겠다고 하여 작업에 들어갔는데 생각보다 어려웠다
먼저 검색을 요청받기위한 controller를 작성했다
@GetMapping("/v1/search")
fun searchHotel(
@RequestParam(name = "name") name:String,
@RequestParam(value = "page") page: Int,
@RequestParam(value = "size")size: Int
):ResponseEntity<Page<HotelResponse>>
{
return ResponseEntity
.status(HttpStatus.OK)
.body(hotelService.searchHotelPageList(name,page,size))
}
}
처음에는 강의내용 대로 pageable을 인자값으로 받았는데 좀 다른 방식으로 해보고 싶어서 @RequestParam으로 받아보았다
기존의 레포지토리와 커스텀레포지토리 구현체를 작성해보았는데
interface HotelRepository: JpaRepository<HotelEntity, Long>,CustomHotelRepository {
}
//HotelRepository
interface CustomHotelRepository {
fun searchByHotelNamePageList(name: String,page:Int,size:Int):Page<HotelEntity>
}
//CustomRepository
@Repository
class HotelRepositoryImpl:CustomHotelRepository, QueryDslSupport() {
private val hotel = QHotelEntity.hotelEntity
override fun searchByHotelNamePageList(name: String,page:Int,size:Int): Page<HotelEntity> {
val result = queryFactory.selectFrom(hotel)
.where(hotel.name.contains(name))
.offset(page.toLong())
.limit(size.toLong())
.orderBy(hotel.name.asc())//이름순 정렬 할꺼 요구사항에 따라 변화
.fetch()
return PageImpl(result)
}
}
//구현체
인자값으로 name을 받아서 호텔테이블의 name(행)안에서 문자열이 포함되어있는 열을 찾고 page를 구분하기위한
.offset과 한 페이지당 들어갈 사이즈를 .limit으로 받아서 이름 내림차순으로 정렬했다
crud를 가볍게 만들고 캐시와 동시성제어에 힘을 주려고 일단은 이렇게 만들었지만 설정할 비즈니스 요구사항들을 좀 더 많이 챙겼다면 아마 코드가 바뀌었지 않을까 싶다 처음 만든거 치곤 잘한거일지도 ? PageImpl은 아직 잘모르겠어서 조금 더 공부를 해봐야겠음 !
ServiceImpl 부분
@Service
class HotelServiceImpl(
private val hotelRepository: HotelRepository,
private val historyService: HistoryService
): HotelService {
//호텔검색 페이징 적용
@Transactional
// 검색이지만 검색과 동시에 히스토리에 저장하기 때문에 history서비스와 같이 @Trnasactional을 붙여줌
override fun searchHotelPageList(name: String, page: Int,size:Int): Page<HotelResponse> {
historyService.saveKeyword(name)// 호텔을 검색하면 히스토리테이블에 기록을 남긴다
return hotelRepository.searchByHotelNamePageList(name,page,size).map { it.toResponse() }
}
}
인기검색어를 위해 historyService에 접근해서 검색단어를 저장하는 로직을 짜서 같이 넣어줬다
팀원과 생각이 조금 달랐는데 history는 그저 저장만 하는곳이라 생각해서 호텔서비스구현체에서 작업을 하신분도 있었다
나는 생각이 조금 다르게 생각한 부분이 강의내용이나 튜터님들이 객체를 다른데에서 조작을 한다는게 조금 객체지향적이지 않다 라고 말을 많이 들어서 인지 history를 저장만 하더라도 저장은 그쪽 서비스에서 해야된다고 생각했다
HistoryServiceImpl
@Transactional
override fun saveKeyword(name: String) {
var findKeyword = historyRepository.findByKeyWord(name)
if (findKeyword != null){
findKeyword.searchNumber++
historyRepository.save(findKeyword)
}else{
findKeyword = HistoryEntity(
keyWord = name,
searchNumber = 1
)
historyRepository.save(findKeyword)
}
}
키워드에 접근해서 값이 있다면 조회수를 올려주고 / 값이 없다면 저장하면서 조회수를 1로 지정해준다
인기 검색어를 조회하기 위해 !
인기검색어 요약
//Controller
@GetMapping("/v1")
fun searchTrend(
):ResponseEntity<List<HistoryResponse>>
{
return ResponseEntity
.status(HttpStatus.OK)
.body(historyService.trendKeyword())
}
//RepositortImpl
override fun searchTrend():List<HistoryEntity> {
return queryFactory.selectFrom(history)
.orderBy(history.searchNumber.desc(),history.id.desc())//조회수가 동일할경우 일단 id값 오름차순으로 가장 최근의 트렌드니께
.limit(5)
.fetch()
}
//ServiceImpl
override fun trendKeyword(): List<HistoryResponse> {
return historyRepository.searchTrend().map { it.toResponse() }
}
간단하게 조회만 하면 조회수 오름차순으로 정렬하고 조회수가 같다면 id값을 오름차순으로 정렬했다 트렌드니까 최근에 만들어진 id가 더 최신트렌드라고 생각해보았음
v1은 이제 다 만들었고 v2를 위해 캐시 공부를 하여 효율을 올려보도록 하자
'TIL' 카테고리의 다른 글
24_02_21 TIL redis-cache 적용 (0) | 2024.02.21 |
---|---|
24_02_16TIL Cach (1) | 2024.02.16 |
24_02_13 TIL (0) | 2024.02.13 |
24_02_08 TIL (0) | 2024.02.08 |
24_02_06 TIL (1) | 2024.02.06 |