안녕하세요 Not-Error 064 백엔드팀의 황윤준입니다.
이번 채식이들 쇼핑몰 프로젝트에서 카테고리 자기 자신이 parent이자 child인 방식을 활용하여 하위 카테고리 조회 시 상위 카테고리가 노출되며, 상위 카테고리에서도 하위 카테고리 조회가 가능한 방식을 구현하였습니다.
✅ 무한뎁스 카테고리 구현 방법을 활용하면
- 하나의 테이블로 전체 카테고리 관리가 가능합니다.
- 카테고리를 자유롭게 만들고 삭제할 수 있습니다.
- 카테고리 계층구조를 표현해 자기 자신이 포함된 상하위 카테고리를 조회하기 편합니다.
- 하나의 테이블에서 제작할 수 있기에 admin 페이지에서 운영자가 직접 카테고리를 추가 수정하는 api를 만들기에 적합합니다.
이번 카테고리 구현을 통해, 현시점에서 요구되는 개발요구사항을 넘어 카테고리의 목록과 구성을 자유롭게 확장하고 축소할 수 있는 확장성 있는 개발에 대해 많은 생각을 하게되었습니다
☑️ Table(Entity) 구현
▪️ Category(Enitity)
- 요구사항
- 무한하게 계층을 표현할 수 있는 무한뎁스 카테고리를 구현합니다.
- 카테고리를 depth에 따라 분류하고 조회할 수 있도록 구현합니다.
- 구현방법
- 하나의 테이블에서 구현해야 하기 위해 self-join 사용합니다.
- 자기참조를 이용해 parent와 child 관계를 이어줍니다.
- Spring data JPA를 활용해 연관관계를 설정합니다.
@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Long categoryId;
@Column
private String categoryName;
@ManyToOne (fetch = FetchType.LAZY) // 1.
@JoinColumn
@Nullable
//@JsonManagedReference
private Category parent; // 2.
/**
* 자식 카테고리, 하위 카테고리를 List 형태로 호출
*/
@OneToMany(mappedBy = "parent") // 3.
//@JsonBackReference
private List<Category> children = new ArrayList<>(); // 2.
/**
* 카테고리 깊이
*/
@Column
private Long depth;
😀 key points
@ManyToOne (fetch = FetchType.LAZY)
- JPA연관관계에서 ManyToOne, OneToOne은 fetchType.EAGER가 default이므로 LAZY 로 바꿔 줍니다. 지연 참조를 사용해줘야 n+1 문제를 방지할 수 있습니다.
parent, children
- 한 테이블 내에서 상하위 관계 표현을 위해 parent와 children을 설정해줍니다.
- children 칼럼에 mappedBy 속성을 활용해 parent를 연관관계의 owner로 설정해줍니다.
☑️ Repository Interface 구현
▪️ Category Repository
@Repositorpublic interface CategoryRepository extends JpaRepository<Category, Long> { //.1
List<Category> findByDepth(Long depth);
}
😀 key points
JpaRepository
- JPA기능을 활용하기 위해 JPARepository를 상속해줍니다.
findByDepth
- spring data jpa는 메소드 이름으로 검색 조건을 만들어 줍니다. 여기서 parameter에 값만 제대로 넣어주면 직관적으로 조회를 해줍니다.
- find + by + entity의 필드값
- 여기서는 depth 레벨을 이용해 조회를 합니다.
☑️ Response DTO 구현
▪️ Category Response DTO
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class CategoryResponseDto { // 1.
private Long categoryId;
private String categoryName;
private Long depth;
private List<CategoryResponseDto> children;
/**
*카테고리를 전달할 DTO를 정의한 정적 메서드
*/
public static CategoryResponseDto of(Category category){
return new CategoryResponseDto(
category.getCategoryId(),
category.getCategoryName(),
category.getDepth(),
category.getChildren().stream().map(CategoryResponseDto::of).collect(Collectors.toList())
);
}
}
😀 key points
- Entity는 절대 컨트롤러에 그냥 전달해주지 않습니다. DTO 클래스를 만들어서 필요한 요소만 전달해줍니다. 여기서는 모두 전달해줍니다.
☑️ Service 구현
▪️ Category Service
@Service
@Transactional
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService{
private final CategoryRepository categoryRepository; // 1.
@Override
public List<CategoryResponseDto> findCategoryList() {
List<CategoryResponseDto> results = categoryRepository.findByDepth(1L).stream().map(CategoryResponseDto::of).collect(Collectors.toList()); // 2.
return results;
}
}
😀 key points
- CategoryRepository를 주입해줍니다.
- CategoryRepository에서 조회한 결과를 CategoryResponseDto로 변환하여 List로 받아 컨트롤러에 전달해줍니다. 여기서는 스트림을 이용해 List 형태로 반환하였습니다.
☑️ Controller 구현
▪️ Category Controller
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/category")
public class CategoryController {
private final CategoryService categoryService; // 1.
/**
*카테고리 전체조회
*/
@GetMapping
public ResponseEntity getCategoryList() { // 2.
List <CategoryResponseDto> response = categoryService.findCategoryList();
return new ResponseEntity(
new SingleCategoryResponse(response),
HttpStatus.OK);
}
}
😀 key points
- CategoryService를 주입해줍니다.
- CategoryService에서 받은 리스트를 ResponseEntity로 감싸 Response로 반환해주면 depth가 있는 카테고리 메뉴가 구현됩니다. 최종으로는 이 로직을 제품 콘트롤러에 통합해주면 됩니다.
최종 결과물
최종적으로 위와같은 계층형 구조로 카테고리를 전달할 수 있습니다.
'[ BE ] 기술' 카테고리의 다른 글
[BE-기술] 채식 유형 계층형 검색 쿼리 만들기 (0) | 2022.10.10 |
---|---|
[BE-기술] Spring Data JPA와 QueryDSL (0) | 2022.10.08 |
[BE-기술] AWS EC2서버 개설과 RDS 연동 (1) | 2022.10.08 |
[BE-기술] 401(Unauthorized)과 403(Forbidden) (2) | 2022.10.08 |
[BE-기술] 채식쇼핑몰 '채식이들' 프로젝트 백엔드 개발 설계 후기 (0) | 2022.10.06 |