Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.myteam.server.global.util.redis.CommonCountDto;
import org.myteam.server.global.util.redis.ServiceType;
import org.myteam.server.global.util.redis.service.RedisCountService;
import org.myteam.server.global.util.redis.service.RedisService;
import org.myteam.server.home.dto.HotBoardDto;
import org.myteam.server.home.dto.NewBoardDto;
import org.myteam.server.report.domain.DomainType;
Expand All @@ -57,6 +58,7 @@ public class BoardQueryRepository {
private final JPAQueryFactory queryFactory;
private final RedisBoardRankingReader rankingReader;
private final RedisCountService redisCountService;
private final RedisService redisService;

/**
* 게시글 목록 조회
Expand Down Expand Up @@ -488,6 +490,33 @@ public List<HotBoardDto> getHotBoardList() {

return hotBoardList;
}
public List<HotBoardDto> zSetGetHotBoardList(){
List<Long> boardId=redisService.getBoardRecommendRankPerDay();
List<HotBoardDto> hotBoardList = queryFactory
.select(Projections.fields(HotBoardDto.class,
board.boardType,
board.categoryType,
board.id,
board.title,
board.id.in(boardId).as("isHot"),
board.id.in(getNewBoardIdList()).as("isNew"),
new CaseBuilder()
.when(board.thumbnail.isNotEmpty()).then(true)
.otherwise(false)
.as("isImage")
))
.from(board)
.where(board.id.in(boardId))
.fetch();
Map<Long, Integer> orderMap = IntStream.range(0, boardId.size())
.boxed()
.collect(Collectors.toMap(boardId::get, i -> i));
hotBoardList.sort(Comparator.comparingInt(dto -> orderMap.getOrDefault(dto.getId(), Integer.MAX_VALUE)));
// 순위 부여
AtomicInteger rankCounter = new AtomicInteger(1);
hotBoardList.forEach(dto -> dto.setRank(rankCounter.getAndIncrement()));
return hotBoardList;
}

public Long findPreviousBoardId(Long boardId, Category boardType, CategoryType categoryType) {
return queryFactory
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.myteam.server.comment.controller;

import static org.myteam.server.comment.dto.response.CommentResponse.*;
import static org.myteam.server.global.web.response.ResponseStatus.SUCCESS;

import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -14,6 +15,7 @@
import org.myteam.server.comment.dto.request.CommentRequest.CommentDeleteRequest;
import org.myteam.server.comment.dto.request.CommentRequest.CommentListRequest;
import org.myteam.server.comment.dto.request.CommentRequest.CommentSaveRequest;
import org.myteam.server.comment.dto.response.CommentResponse;
import org.myteam.server.comment.dto.response.CommentResponse.BestCommentSaveListResponse;
import org.myteam.server.comment.dto.response.CommentResponse.CommentSaveListResponse;
import org.myteam.server.comment.dto.response.CommentResponse.CommentSaveResponse;
Expand All @@ -33,6 +35,8 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/comments")
@RequiredArgsConstructor
Expand Down Expand Up @@ -169,4 +173,19 @@ public ResponseEntity<ResponseDto<BestCommentSaveListResponse>> getBestComments(
bestComments
));
}
@Operation(summary = "최신 댓글 조회", description = "최신 댓글들을 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "최신 댓글 목록 조회 성공"),
@ApiResponse(responseCode = "404", description = "게시글이 존재하지 않음", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/latest")
public ResponseEntity<ResponseDto<List<LatestCommentListResponse>>> getLatestComments() {
List<LatestCommentListResponse>
latestCommentListResponse=commentReadService.getLatestComments();
return ResponseEntity.ok(new ResponseDto<>(
SUCCESS.name(),
"베스트 댓글 목록 조회 성공",
latestCommentListResponse
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.myteam.server.comment.domain.Comment;
import org.myteam.server.comment.domain.CommentType;
import org.myteam.server.global.page.response.PageCustomResponse;
import org.myteam.server.util.ClientUtils;

Expand Down Expand Up @@ -122,4 +125,12 @@ public static BestCommentSaveListResponse createResponse(
.build();
}
}

@AllArgsConstructor
public static class LatestCommentListResponse{
private Long commentId;
@Schema(description = "최신댓글이 어떤 게시글에 대한 댓글인지를 보여줍니다.")
private CommentType commentType;
private String content;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static org.myteam.server.comment.domain.QInquiryComment.inquiryComment;
import static org.myteam.server.comment.domain.QNewsComment.newsComment;
import static org.myteam.server.comment.domain.QNoticeComment.noticeComment;
import static org.myteam.server.comment.dto.response.CommentResponse.*;
import static org.myteam.server.improvement.domain.QImprovement.improvement;
import static org.myteam.server.inquiry.domain.QInquiry.inquiry;
import static org.myteam.server.member.entity.QMember.member;
Expand Down Expand Up @@ -45,6 +46,7 @@
import org.myteam.server.comment.domain.QMatchComment;
import org.myteam.server.comment.domain.QNewsComment;
import org.myteam.server.comment.domain.QNoticeComment;
import org.myteam.server.comment.dto.response.CommentResponse;
import org.myteam.server.comment.dto.response.CommentResponse.BestCommentResponse;
import org.myteam.server.comment.dto.response.CommentResponse.CommentSaveResponse;
import org.myteam.server.comment.service.CommentRecommendReadService;
Expand All @@ -69,6 +71,20 @@ public class CommentQueryRepository {
private final CommentRepository commentRepository;
private final CommentRecommendReadService commentRecommendReadService;

public List<LatestCommentListResponse> getNewestComment(){
List<LatestCommentListResponse> comments=queryFactory
.select(Projections.constructor(LatestCommentListResponse.class,
comment1.id,
comment1.commentType,
comment1.comment.substring(0,20)))
.from(comment1)
.orderBy(comment1.createDate.desc())
.limit(10)
.fetch();

return comments;
}

/**
* 대댓글 목록 조회
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.myteam.server.comment.service;

import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.myteam.server.comment.domain.Comment;
import org.myteam.server.comment.domain.CommentType;
import org.myteam.server.comment.dto.request.CommentRequest.CommentListRequest;
import org.myteam.server.comment.dto.response.CommentResponse;
import org.myteam.server.comment.dto.response.CommentResponse.BestCommentResponse;
import org.myteam.server.comment.dto.response.CommentResponse.BestCommentSaveListResponse;
import org.myteam.server.comment.dto.response.CommentResponse.CommentSaveListResponse;
Expand All @@ -25,6 +27,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static org.myteam.server.comment.dto.response.CommentResponse.*;

@Slf4j
@Service
@RequiredArgsConstructor
Expand All @@ -36,6 +40,9 @@ public class CommentReadService {
private final SecurityReadService securityReadService;
private final CommentRecommendReadService commentRecommendReadService;

public List<LatestCommentListResponse> getLatestComments(){
return commentQueryRepository.getNewestComment();
}
public Comment findById(Long commentId) {
return commentRepository.findById(commentId)
.orElseThrow(() -> new PlayHiveException(ErrorCode.COMMENT_NOT_FOUND));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package org.myteam.server.global.util.redis.service;

import java.sql.Date;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import org.myteam.server.admin.utill.StaticDataType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
Expand All @@ -16,6 +24,7 @@
public class RedisService { // TODO: RedisReportService 로 변경.

private final RedisTemplate<String, String> redisTemplate;
private static final String BOARD_RANK_KEY=":BoardRank";
private static final String ADMIN_ALARM_KEY="ADMIN_ALARM";
private static final int ADMIN_LOGIN_MAX_REQUESTS=10;
private static final int MAX_REQUESTS = 3; // 제한 횟수 (기본값: 5분 동안 3회)
Expand Down Expand Up @@ -91,6 +100,32 @@ public void adminReadCheckUpdate(String adminIdentifier, StaticDataType staticDa
redisTemplate.expire(redisKey, Duration.ofDays(30L));
}
}

public void boardRecommendRankPerDay(Long contentId,Long delta){
LocalDateTime now = LocalDateTime.now().with(LocalTime.MIDNIGHT);
String key = now+BOARD_RANK_KEY;
LocalDateTime nextMidnight = now.plusDays(1).with(LocalTime.MIDNIGHT);
redisTemplate.opsForZSet().incrementScore(key,contentId.toString(),delta);
redisTemplate.expireAt(key,Date.valueOf(nextMidnight.toLocalDate()));
}
public List<Long> getBoardRecommendRankPerDay(){
LocalDateTime now=LocalDateTime.now().with(LocalTime.MIDNIGHT);
String key=now+BOARD_RANK_KEY;
List<Long> ids=redisTemplate.opsForZSet().reverseRangeWithScores(key,0,9)
.stream()
.filter(x->{
if(x.getScore()>0){
return true;
}
return false;
})
.map(x->{
return Long.parseLong(x.getValue());
})
.collect(Collectors.toList());
return ids;
}

/**
* 요청 제한을 적용할 Redis Key 생성
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.myteam.server.board.service.BoardRecommendReadService;
import org.myteam.server.global.exception.ErrorCode;
import org.myteam.server.global.exception.PlayHiveException;
import org.myteam.server.global.util.redis.service.RedisService;
import org.myteam.server.member.entity.Member;
import org.myteam.server.report.domain.DomainType;
import org.springframework.stereotype.Component;
Expand All @@ -20,6 +21,7 @@ public class BoardRecommendHandler implements RecommendHandler {
private final BoardRecommendReadService boardRecommendReadService;
private final BoardRecommendRepository boardRecommendRepository;
private final BoardRepository boardRepository;
private final RedisService redisService;

@Override
public boolean supports(DomainType type) {
Expand All @@ -39,10 +41,12 @@ public void saveRecommendation(Long contentId, Member member) {
.orElseThrow(() -> new PlayHiveException(ErrorCode.BOARD_NOT_FOUND));
BoardRecommend recommend = BoardRecommend.builder().board(board).member(member).build();
boardRecommendRepository.save(recommend);
redisService.boardRecommendRankPerDay(contentId,1L);
}

@Override
public void deleteRecommendation(Long contentId, UUID userId) {
boardRecommendRepository.deleteByBoardIdAndMemberPublicId(contentId, userId);
redisService.boardRecommendRankPerDay(contentId,-1L);
}
}
Loading
Loading