본문 바로가기

Project/Maturi

[MATURI] 상세 페이지, 좋아요 기능 상세설명

목차

  1. 상세 페이지의 게시글 데이터 상세설명
  2. 지도로 음식점 위치 확인하기
  3. 좋아요 기능 상세설명

1. 상세 페이지의 게시글 데이터 상세설명

메인 페이지에서 해당 게시글의 이미지 또는 내용을 클릭시 상세페이지로 들어갈 수 있습니다.

 

이 때 데이터를 가져올 때, DTO를 통해 값을 가져와서 메인페이지에서 사용하는 게시글 데이터, 상세페이지에서 사용되는 게시글 데이터를 동일하게 사용하여 재사용성을 높혔습니다.

상세 페이지와 메인 페이지에서 사용되는 게시글 출력 데이터 DTO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ArticleViewDTO {
  // 기본 article 정보
  private Long id;
  private String content;
  private List<String> image;
  private String date;//포매팅한 날짜

  // 글 작성자 정보
  private Long memberId;
  private String name;
  private String nickName;
  private String profileImg;

  //음식점 정보
  private String address;
  private String restaurantName;

  // 태그 리스트
  private List<String> tags;
  // 좋아요 관련
  private int like;
  private boolean isLiked;
  //댓글 갯수
  private int commentCount;
  //조회수
  private int views;
  //팔로잉 유저인지 확인하기위함
  private boolean isFollowingMember;

}
Service단에서 Article 데이터를 DB에서 받온 Entity를 DTO로 변환하는 메서드 
private ArticleViewDTO getArticleViewDTO(Article article, Long memberId) {
    if(article == null){
        return null;
    }

    List<TagValue> tagValues = tagValueRepository.findByArticleId(article.getId());
    ArrayList<String> tagName = new ArrayList<>();
    for(TagValue tagValue : tagValues){
        tagName.add("#" + tagValue.getTag().getName());
    }

    int likeNum = likeArticleRepository.countByArticleId(article.getId());
    Long articleMemberId = article.getMember().getId();
    boolean isFollowingMember = followQRepository.isFollowingMember(memberId, articleMemberId);
    log.info("isFollowingMember = {}",isFollowingMember);
    return ArticleViewDTO.builder()
            .id(article.getId())
            .content(article.getContent())
            .image(Arrays.asList(article.getImage().split(",")))
            .date(BaseTimeEntity.getFormatDate(article.getCreatedDate()))
            .memberId(article.getMember().getId())
            .name(article.getMember().getName())
            .nickName(article.getMember().getNickName())
            .profileImg(article.getMember().getProfileImg())
            .address(article.getRestaurant().getLocation().getAddress())
            .restaurantName(article.getRestaurant().getName())
            .tags(tagName)
            .like(likeNum)
            .isLiked(this.isLikedArticle(article.getId(), memberId))
            .commentCount(commentRepository.countByArticleId(article.getId()))
            .views(article.getViews())
            .isFollowingMember(isFollowingMember)
            .build();
}

Service단에서 DB에서 가져온 Entity를 메인페이지 및 상세페이지에 출력할 게시글 DTO로 변환하는 메서드입니다.

 

태그값과 좋아요 갯수는 article의 id값을 기준으로 DB에서 한번더 찾아오는 로직이 있습니다.

 

isLiked, isFollowingMember 값은 로그인한 회원이 해당 게시글을 클릭했는지, 팔로잉한 유저인지를 확인하는 로직이있습니다. isFollowingMember를 따로 받는 이유는 더보기 버튼이 팔로잉/팔로잉 취소 버튼중 어떤 버튼을 출력할지 처리하기 위해 받아온 데이터입니다.

더보기 버튼 클릭시

2. 지도로 음식점 위치 확인하기

지도로보기 클릭시 출력되는 팝업창

음식점 팝업창 html 소스코드
<th:block layout:fragment="restaurant-map">
    <div id="restaurantMapPopup">
        <div id="restaurantMapPopupContent">
            <div class="rMap" id="articleMap"
                 th:attr="data-lat=${restaurant.latitude}, data-long=${restaurant.longitude}"></div>
            <div id="popup-restaurant-info">
                <h4 class="restaurant-title" th:text="${restaurant.name}">음식점명</h4>
                <p class="restaurant-etc">
                    <span th:text="${restaurant.category}">카테고리</span>&nbsp;&nbsp;
                    <span th:text="${restaurant.oldAddress}">주소</span>
                </p>
            </div>
        </div>
        <div class="restaurant-map-popup-close-btn-wrap">
            <ion-icon class="popup-close-btn" onclick="restaurantMapPopupToggle()"
                      name="close-circle-outline"></ion-icon>
        </div>
    </div>
</th:block>

data 속성에 해당 음식점 위도(latitude), 경도(longitude)를 저장하여 이를 통해 카카오 Map API로 해당 음식점 위치를 요청하여 지도로 음식점의 위치를 확인할 수 있도록 코드를 작성하였습니다.

위도 경도 값을 기반으로 카카오 Map API에서 음식점 위치 값을 가져오는 javascript 소스 코드
const articleMap = document.getElementById("articleMap");
let a_latitude = articleMap.dataset.lat;
let a_longitude = articleMap.dataset.long;


var a_mapContainer = document.getElementById('articleMap'), // 지도를 표시할 div
  a_mapOption = {
    center: new kakao.maps.LatLng(a_latitude, a_longitude), // 지도의 중심좌표
    level: 3 // 지도의 확대 레벨
  };

var a_Map = new kakao.maps.Map(a_mapContainer, a_mapOption); // 지도 생성

// 마커가 표시될 위치
var a_markerPosition  = new kakao.maps.LatLng(a_latitude, a_longitude);

// 마커 생성
var a_Marker = new kakao.maps.Marker({
  position: a_markerPosition
});

// 마커가 지도 위에 표시되도록 설정
a_Marker.setMap(a_Map);

3. 좋아요 기능 상세설명

좋아요 버튼을 클릭하였을 시, 해당 유저가 이미 좋아요를 눌렀는지? 처음 좋아요를 눌렀는지 체크하여 처음 눌렀을 경우 좋아요 갯수가 증가하고, 하트가 빨간색으로 채워지도록 하고, 이미 좋아요를 눌렀을 경우 좋아요 갯수가 줄어들고, 하트가 채워지지 않도록 로직을 작성하였습니다.

좋아요를 이미 눌렀을 때 하트를 클릭시

Controller단의 좋아요 처리 소스 코드
@PostMapping("/{id}/like")
public ResponseEntity likeOrUnlike(@Login Long memberId,
                                 @PathVariable Long id) throws ParseException {

    int isLiked = // 좋아요 상태가 됨 -> 1
            articleService.likeOrUnlike(memberId, id)?
            1 : 0;
    int likeNum = articleService.likeNum(id);

    Map<String, Integer> result = new HashMap<>();
    result.put("isLiked", isLiked);
    result.put("likeNum", likeNum);

    return new ResponseEntity(result, HttpStatus.OK);
}

프론트 단에서 좋아요를 클릭했을 시 이미 눌렀는지, 처음 눌렀는지 구분하여 요청하지 않고, /articles/{id}/like 의 URL 과 POST method로 요청을 하고, 백단에서 좋아요를 눌렀는지 체크하여 데이터를 반환하도록 코드를 설계하였습니다.