Project/커뮤니티 게시판

[커뮤니티 게시판] 게시판 기능 관련 정리

SN.Flower 2023. 8. 19.

💡   게시글 CRUD 기능은 어떻게 구현했나요?

Create: dto로 받은 게시글 데이터를 유효성 검사를 한 후 문제가 없다면 modelMapper를 사용해서 게시글 엔티티로 매핑해주고 JpaRepository를 상속받는 Repository에서 save() 함수를 호출해서 게시글을 생성하고 작성자와 작성일을 추가했습니다.

Read: 게시글 상세 조회는 dto를 통해 게시글 상세 정보와 좋아요 데이터를 가져온 후 모델에 추가하고 뷰에 전달했습니다.

게시글 전체 조회는 Querydsl과 BooleanExpression을 사용해서 사용자가 선택한 게시판과 게시글 카테고리에 해당하는 게시글들의 데이터와 개수를 찾아 최신 게시글이 먼저 보이도록 고유 id를 기준으로 오름차순 정렬을 했습니다.

이 때, 회원 엔티티는 ManyToOne이므로 기본 fetchType이 Eager인데, 즉시로딩은 예측이 어렵고, 조인할 때 어떤 SQL이 사용되는지 추적하기가 어려우므로 Lazy 지연 로딩으로 바꿨습니다.

작성자 그리고 Pageable 인터페이스를 활용해서 페이징 관련 설정을 하고 Page 인터페이스를 활용해서 페이지 사이즈, 번호, 전체 엔티티 개수등을 받아 모델에 추가하고 뷰에 전달했습니다.

Update: dto로 받은 게시글 데이터를 유효성 검사를 한 후 문제가 없다면 modelMapper를 사용해서 게시글 엔티티로 매핑해주었습니다.

이 때, 매핑할 게시글 엔티티를 Service에서 JpaRepository를 상속받는 Repository를 통해 받아오므로 게시글 엔티티는 영속 상태입니다. 그래서 따로 save()를 통해 merge하지 않았습니다.

Delete: 삭제할 게시글 엔티티를 Service에서 JpaRepository를 상속받는 Repository를 통해 받아온 후 delete() 함수를 통해 삭제했습니다.

바로 delete를 통해 삭제하지않는 이유는 게시글 삭제 전에 삭제할 게시글 데이터를 사용자에게 보여주는 화면이 있고 이 때 삭제할 데이터의 작성자 여부도 확인하는 로직이 있습니다. 이 부분은 post 요청을 통해 삭제할 때도 적용되기 때문에 코드가 겹칠 것이라 생각되어 게시글 엔티티를 가져오고 삭제하도록 했습니다.

 

💡   조회수 기능은 어떻게 구현했나요?

게시글 상세조회를 할 때 Service에서 Repository를 거쳐 게시글 엔티티에 있는 조회수 필드값을 1 증가시키는 함수를 호출해서 조회수 기능을 구현했습니다.

 

💡   카테고리별 분류 기능은 어떻게 구현했나요?

게시판, 게시글별 카테고리 필드를 게시글 엔티티에 추가했습니다. 그리고 게시글을 작성할 때 두 가지 카테고리를 게시판 카테고리는 작성하는 게시판에 맞게하고, 게시글 카테고리는 회원이 설정하는 카테고리로 저장되도록 했습니다.

 

💡   추천 기능은 어떻게 구현했나요?

게시글에 어떤 회원이 추천을 했는지 알아야 중복 추천을 막고 추천과 추천 취소 기능을 구현할 수 있어서 추천 엔티티를 추가했습니다.

추천 엔티티는 회원, 게시글 엔티티와 1대다 관계이고 고유 id를 가지고 있습니다.

추천 버튼을 누르면 추천 dto에 회원, 게시글 엔티티 정보를 넣어준 후 querydsl을 사용해서 dto로 받은 회원과 게시글에 맞는 추천 엔티티가 존재하는지 확인합니다.

그리고 존재한다면 게시글의 추천 수를 1 감소시키고 JpaRepository를 상속받는 Repository를 통해 삭제합니다.

존재하지 않는다면 게시글의 추천 수를 1 증가시키고 JpaRepository를 상속받는 Repository를 통해 저장합니다.

 

💡   검색 조건별 검색 목록 조회 기능은 어떻게 구현했나요?

@RequestParam 어노테이션을 통해서 검색 조건과 키워드 데이터를 컨트롤러에서 받으면 Service에서 게시글을 조회하는 함수를 호출합니다.

해당 함수에서 검색 키워드가 존재한다면 검색 조건과 키워드를 포함해서 조회하는 Repository의 함수를 호출하도록 합니다.

그 후 Querydsl과 BooleanExpression을 사용해서 검색 조건과 키워드에 맞는 게시글들의 데이터와 개수를 조회합니다.

리고 Pageable 인터페이스를 활용해서 페이징 관련 설정을 하고 Page 인터페이스를 활용해서 페이지 사이즈, 번호, 전체 엔티티 개수등을 받아 모델에 추가하고 뷰에 전달했습니다.

 

💡   페이징 기능은 어떻게 구현했나요?

우선 페이징 기본 설정은 SpringDataJpa에서 해주지만, 최대 페이지 사이즈나 첫 페이지 값을 1로 바꾸는 설정을 하기위해서 WebMvcConfigurer을 상속받는 WebConfig 클래스를 생성했습니다. 그리고 ArgumentResolver를 추가하는 함수를 오버라이딩해서 기본 설정에서 추가적으로 원하는 페이징 설정을 했습니다.

게시글 Repository는 JpaRepository를 상속받고 JpaRepository는 PagingAndSortingRepository를 상속받으므로 페이징 기능을 제공하는 Pageable 인터페이스와 Page 타입을 사용할 수 있습니다.

Querydsl을 사용해서 Pegeable에서 offset과 pagesize 받아 게시글 데이터를 받고, 데이터 개수를 구하는 count 쿼리를 통해 pageImpl로 변환해서 Page타입으로 리턴했습니다.

리턴받은 페이징 결과 데이터에서 필요한 값들을 모델에 추가해서 뷰에 전달하여 페이징된 게시글 목록 화면을 구현했습니다.

 

💡   N+1 문제는 어떻게 해결했나요?

게시글 목록이나 댓글 목록을 불러올 때 회원, 게시글 정보를 추가적으로 불러올 필요가 있다면 지연 로딩과 fetch join을 통해서 한번에 데이터를 가져오는 쿼리를 만들어서 해결했을 것입니다.

하지만 저는 해당 엔티티 전체를 select 하지않고 left join을 통해 원하는 데이터 몇가지만 가지고 와서 추가적인 조회 쿼리가 발생하지는 않아서 해당 방법을 사용하지는 않았습니다.

댓글