[온라인 화훼 경매](03) 카테고리를 구현해봅시다.
카테고리 조회 기능은 아래의 사진처럼 항목을 선택했을때 하위 항목을 전부 보여줘야합니다.
처음에는 JPA의 JPQL을 이용하여 구현하였습니다.
간단하게 선택한 식물의 id를 입력받아 하위의 모든 카테고리를 구현하는 방식을 택했습니다.
하지만 프론트 분들과 얘기하다보니 id값을 주고 받는것 보단 카테고리의 이름을 전달하는게 여러가지 이유로 좋겠다 생각하여 리팩토링 하였습니다. 자세한 내용은 코드로 설명하겠습니다.
변경 전
Service
public List<CategoryResponse> getCategories(Long parentId) {
return categoryRepository.findAllById(parentId)
.stream().map(CategoryResponse::new).collect(Collectors.toList());
}
private Category getCategoryEntity(Long categoryId) {
return categoryRepository.findById(categoryId)
.orElseThrow(() -> new EntityNotFoundException("존재하지 않는 카테고리 ID=" + categoryId));
}
처음 구현한 내용입니다. 위와 같이 부모의 id가 입력받은 id와 같은 값들을 가져와 response형식으로 변경해주었습니다.
Respository
@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {
@Query(value = "select category from Category category where category.parent.id = :id")
List<Category> findAllById(@Param("id") Long parentId);
}
조회 결과
{
"code": 200,
"status": "OK",
"message": "SUCCESS",
"data": [
{
"categoryId": 2,
"name": "빨강",
"level": 3
},
{
"categoryId": 3,
"name": "노랑",
"level": 3
},
{
"categoryId": 4,
"name": "파랑",
"level": 3
}
]
}
조회 결과입니다.
이처럼 카테고리 객체가 json형식의 list로 전달되었습니다.
프론트에서는 카테고리의 이름만 필요하기 때문에 카테고리의 이름만을 담은 list형식으로 전달하기로 하였습니다.
변경 후
Controller
@GetMapping("/type")
public ApiResponse<List<String>> getTypes(
@RequestParam(defaultValue = "절화") String code
) {
log.info("<카테고리 품목 조회> Controller");
List<String> types = categoryQueryService.getTypesForMember(code);
return ApiResponse.ok(types);
}
@GetMapping("/name")
public ApiResponse<List<String>> getNames(
@RequestParam(defaultValue = "절화") String code,
@RequestParam(defaultValue = "") String type
//날짜
) {
log.info("<카테고리 품종 조회> Controller");
List<String> names = categoryQueryService.getNamesForMember(code, type);
return ApiResponse.ok(names);
}
컨트롤러 입니다.
프론트로부터 카테고리의 이름을 입력받습니다. 이때 defaultValue를 이용하여 기본값을 설정해주었습니다.
Service
public List<String> getTypesForMember(String code) {
return categoryQueryRepository.getTypes(code);
}
public List<String> getNamesForMember(String code, String type) {
return categoryQueryRepository.getNames(code, type);
}
Repository
public List<String> getTypes(String codeName) {
QCategory code = new QCategory("code");
QCategory type = new QCategory("type");
return queryFactory
.select(type.name)
.from(type)
.join(type.parent, code)
.where(
type.active.isTrue(),
code.name.eq(codeName)
)
.orderBy(type.createdDate.asc())
.fetch();
}
Querydsl을 이용하여 부모카테고리와 join을 하였고 부모 카테고리의 이름과 입력받은 카테코리의 이름이 같은 값들을 가져왔습니다.
최하위 카테고리인 name은 이처럼 join을 두번 사용하여 조회하였습니다.
값은 String을 list형식으로 받았습니다.
Querydsl을 사용하면 확실히 직관적이고 수정이 용이한 코드가 된다고 생각합니다.
결과
{
"code" : 200,
"status" : "OK",
"message" : "SUCCESS",
"data" : [ "소재", "장미(스탠다드)" ]
}
깔끔하게 필요한 부분만을 가져오는것을 확인 할 수 있습니다.
요약
이번 글에서는 카테고리 조회, 리팩토링에 대해서 알아보았습니다.
다음 글에서는 캐시적용에 대해서 작성해보겠습니다!