diff --git a/backend/src/main/java/com/project/tamago/common/Constant.java b/backend/src/main/java/com/project/tamago/common/Constant.java index b32e7a31..c5b8574c 100644 --- a/backend/src/main/java/com/project/tamago/common/Constant.java +++ b/backend/src/main/java/com/project/tamago/common/Constant.java @@ -14,5 +14,7 @@ public class Constant { public static final String SLACK_ALARM_FORMAT = "[SlackAlarm] %s"; public static final int PRACTICE_SHORT_TYPING_SIZE = 30; public static final int EXAM_SHORT_TYPING_SIZE = 10; + public static final int ITEMS_PER_PAGE = 10; + public static final int LINES_PER_PAGE = 20; } diff --git a/backend/src/main/java/com/project/tamago/common/enums/SortOrder.java b/backend/src/main/java/com/project/tamago/common/enums/SortOrder.java new file mode 100644 index 00000000..e0d0c6db --- /dev/null +++ b/backend/src/main/java/com/project/tamago/common/enums/SortOrder.java @@ -0,0 +1,31 @@ +package com.project.tamago.common.enums; + +import org.springframework.data.domain.Sort; + +import lombok.Getter; + +@Getter +public enum SortOrder { + LATEST("latest"), + OLDEST("oldest"), + VIEW_COUNT("viewCount"); + + private final String desc; + + SortOrder(String desc) { + this.desc = desc; + } + + public static Sort getSort(String sortBy) { + if (LATEST.desc.equals(sortBy)) { + return Sort.by("createdDate").descending().and(Sort.by("updatedDate").descending()); + } + if (OLDEST.desc.equals(sortBy)) { + return Sort.by("createdDate").ascending().and(Sort.by("updatedDate").ascending()); + } + if (VIEW_COUNT.desc.equals(sortBy)) { + return Sort.by("viewCount").descending().and(Sort.by("updatedDate").descending()); + } + throw new IllegalArgumentException("Invalid sortBy parameter: " + sortBy); + } +} diff --git a/backend/src/main/java/com/project/tamago/controller/TypingController.java b/backend/src/main/java/com/project/tamago/controller/TypingController.java index a9e80a13..e900c288 100644 --- a/backend/src/main/java/com/project/tamago/controller/TypingController.java +++ b/backend/src/main/java/com/project/tamago/controller/TypingController.java @@ -14,16 +14,15 @@ import com.project.tamago.common.annotation.Ip; import com.project.tamago.common.annotation.Login; import com.project.tamago.common.enums.Language; -import com.project.tamago.common.response.CustomResponse; +import com.project.tamago.common.enums.ResponseCode; +import com.project.tamago.common.exception.CustomException; import com.project.tamago.common.exception.InvalidParameterException; +import com.project.tamago.common.response.CustomResponse; import com.project.tamago.dto.LoginResolverDto; +import com.project.tamago.dto.requestDto.LongTypingReqDto; import com.project.tamago.dto.responseDto.LongTypingDetailResDto; import com.project.tamago.dto.responseDto.LongTypingResDto; import com.project.tamago.dto.responseDto.ShortTypingListResDto; -import com.project.tamago.common.exception.CustomException; -import com.project.tamago.common.enums.ResponseCode; -import com.project.tamago.dto.requestDto.LongTypingReqDto; - import com.project.tamago.service.LongTypingService; import com.project.tamago.service.ShortTypingService; @@ -48,12 +47,14 @@ public CustomResponse findShortTypings(@RequestParam Stri @GetMapping("/long") public CustomResponse findLongTypings( - @RequestParam(required = false, defaultValue = "1") int page) { - return new CustomResponse<>(longTypingService.findLongTypings(page)); + @RequestParam(required = false, defaultValue = "1") int page, + @RequestParam(required = false, defaultValue = "latest") String sortBy) { + return new CustomResponse<>(longTypingService.findLongTypings(page, sortBy)); } @GetMapping("/long/detail") - public CustomResponse findLongTypingDetail(@Ip String ip, @RequestParam Integer longTypingId, + public CustomResponse findLongTypingDetail(@Ip String ip, + @RequestParam Integer longTypingId, @RequestParam(required = false, defaultValue = "1") int page) { return new CustomResponse<>(longTypingService.findLongTypingDetail(ip, longTypingId, page)); } diff --git a/backend/src/main/java/com/project/tamago/service/LongTypingService.java b/backend/src/main/java/com/project/tamago/service/LongTypingService.java index 20834546..4be97031 100644 --- a/backend/src/main/java/com/project/tamago/service/LongTypingService.java +++ b/backend/src/main/java/com/project/tamago/service/LongTypingService.java @@ -1,5 +1,6 @@ package com.project.tamago.service; +import static com.project.tamago.common.Constant.*; import static com.project.tamago.common.enums.ResponseCode.*; import java.time.Duration; @@ -12,13 +13,14 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.project.tamago.common.enums.SortOrder; +import com.project.tamago.common.exception.CustomException; import com.project.tamago.domain.LongTyping; import com.project.tamago.domain.User; +import com.project.tamago.dto.LongTypingDto; import com.project.tamago.dto.mapper.DataMapper; import com.project.tamago.dto.requestDto.LongTypingReqDto; import com.project.tamago.dto.responseDto.LongTypingDetailResDto; -import com.project.tamago.dto.LongTypingDto; -import com.project.tamago.common.exception.CustomException; import com.project.tamago.dto.responseDto.LongTypingResDto; import com.project.tamago.repository.LongTypingRepository; import com.project.tamago.repository.RegisterRepository; @@ -40,14 +42,14 @@ public class LongTypingService { private final RedisTemplate redisTemplate; @Transactional(readOnly = true) - public LongTypingResDto findLongTypings(int page) { - PageRequest pageRequest = PageRequest.of(page - 1, 20); + public LongTypingResDto findLongTypings(int page, String sortBy) { + PageRequest pageRequest = PageRequest.of(page - 1, ITEMS_PER_PAGE, SortOrder.getSort(sortBy)); Page longTypingPage = longTypingRepository.findAll(pageRequest); List longTypings = longTypingPage.stream() .map(DataMapper.INSTANCE::LongTypingToLongTypingResDto) .collect(Collectors.toList()); - int totalPage = longTypingPage.getTotalPages(); + int totalPage = longTypingPage.getTotalPages(); return new LongTypingResDto(totalPage, longTypings); } diff --git a/backend/src/main/java/com/project/tamago/util/TypingUtil.java b/backend/src/main/java/com/project/tamago/util/TypingUtil.java index 156fe713..e52c08cc 100644 --- a/backend/src/main/java/com/project/tamago/util/TypingUtil.java +++ b/backend/src/main/java/com/project/tamago/util/TypingUtil.java @@ -1,5 +1,7 @@ package com.project.tamago.util; +import static com.project.tamago.common.Constant.*; + import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -12,8 +14,6 @@ public class TypingUtil { - private static final int LINES_PER_PAGE = 20; - public static PageContentDto getPageContent(String content, Integer page) { String[] contentLines = content.replaceAll("\r\n", "\n").split("\n"); int startIndex = (page - 1) * LINES_PER_PAGE; @@ -23,8 +23,8 @@ public static PageContentDto getPageContent(String content, Integer page) { } public static PageContentDto getPageContent(String content) { - int totalPages = (int) Math.ceil((double) content.split("\r\n").length / LINES_PER_PAGE); - int randomPage = (int) (Math.random() * totalPages) + 1; + int totalPages = (int)Math.ceil((double)content.split("\r\n").length / LINES_PER_PAGE); + int randomPage = (int)(Math.random() * totalPages) + 1; return getPageContent(content, randomPage); } diff --git a/backend/src/test/java/com/project/tamago/service/LongTypingServiceTest.java b/backend/src/test/java/com/project/tamago/service/LongTypingServiceTest.java index 6ea6ffb9..1585c971 100644 --- a/backend/src/test/java/com/project/tamago/service/LongTypingServiceTest.java +++ b/backend/src/test/java/com/project/tamago/service/LongTypingServiceTest.java @@ -26,13 +26,14 @@ import org.springframework.security.test.context.support.WithMockUser; import com.project.tamago.common.enums.Language; +import com.project.tamago.common.enums.SortOrder; import com.project.tamago.domain.LongTyping; import com.project.tamago.domain.User; +import com.project.tamago.dto.LongTypingDto; import com.project.tamago.dto.PageContentDto; import com.project.tamago.dto.mapper.DataMapper; import com.project.tamago.dto.requestDto.LongTypingReqDto; import com.project.tamago.dto.responseDto.LongTypingDetailResDto; -import com.project.tamago.dto.LongTypingDto; import com.project.tamago.repository.LongTypingRepository; import com.project.tamago.repository.RegisterRepository; import com.project.tamago.repository.UserRepository; @@ -96,7 +97,8 @@ public void testFindLongTypings() { .collect(Collectors.toList()); // when - List actualLongTypingDtos = longTypingService.findLongTypings(1).getLongTypings(); + List actualLongTypingDtos = longTypingService.findLongTypings(1, SortOrder.LATEST.getDesc()) + .getLongTypings(); // then assertEquals(expectedLongTypingDtos, actualLongTypingDtos); @@ -121,13 +123,16 @@ public void testFindLongTypingSuccess() { .viewCount(100) .build(); - PageContentDto expectedPageContentDto = new PageContentDto(2, "line 21\nline 22\nline 23\nline 24\nline 25\nline 26\nline 27\nline 28\nline 29\nline 30"); - when(longTypingRepository.findByIdAndTotalPageGreaterThanEqual(longTypingId, page)).thenReturn(Optional.of(longTyping)); + PageContentDto expectedPageContentDto = new PageContentDto(2, + "line 21\nline 22\nline 23\nline 24\nline 25\nline 26\nline 27\nline 28\nline 29\nline 30"); + when(longTypingRepository.findByIdAndTotalPageGreaterThanEqual(longTypingId, page)).thenReturn( + Optional.of(longTyping)); when(redisTemplate.opsForValue().get(any(String.class))) .thenReturn("ON"); // mock the behavior of redisTemplate // when - LongTypingDetailResDto actualLongTypingDetailResDto = longTypingService.findLongTypingDetail(ip,longTypingId, page); + LongTypingDetailResDto actualLongTypingDetailResDto = longTypingService.findLongTypingDetail(ip, longTypingId, + page); // then assertEquals(expectedPageContentDto.getContent(), actualLongTypingDetailResDto.getContent()); @@ -173,12 +178,14 @@ public void testFindLongTypingFail() { + "line 18\n" + "line 19\n" + "line 20"); - when(longTypingRepository.findByIdAndTotalPageGreaterThanEqual(longTypingId, page)).thenReturn(Optional.of(longTyping)); + when(longTypingRepository.findByIdAndTotalPageGreaterThanEqual(longTypingId, page)).thenReturn( + Optional.of(longTyping)); when(redisTemplate.opsForValue().get(any(String.class))) .thenReturn("ON"); // mock the behavior of redisTemplate // when - LongTypingDetailResDto actualLongTypingDetailResDto = longTypingService.findLongTypingDetail(ip,longTypingId, page); + LongTypingDetailResDto actualLongTypingDetailResDto = longTypingService.findLongTypingDetail(ip, longTypingId, + page); // then assertNotEquals(expectedPageContentDto.getContent(), actualLongTypingDetailResDto.getContent());