From c6c9e91a9ef91d3bc6182509be0d0ad2429ee01b Mon Sep 17 00:00:00 2001 From: "aj4941@naver.com" Date: Thu, 30 Nov 2023 20:34:00 +0900 Subject: [PATCH] =?UTF-8?q?:recycle:=20[FIX]=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=8B=9C=EC=9E=91=20=EB=AC=B8=EC=A0=9C=20=EC=B6=94=EC=B6=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=84=B1=EB=8A=A5=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 테스트 문제를 추출할 때 동기적으로 호출되는 상태를 비동기로 전환하여 실행 속도를 향상시켰습니다. --- .../domain/problem/dto/BojProblem.java | 25 +++- .../testStart/service/GetProblemsService.java | 134 ++++++------------ .../testStart/service/TestStartUseCase.java | 21 ++- .../service/GetProblemsServiceTest.java | 10 ++ 4 files changed, 86 insertions(+), 104 deletions(-) create mode 100644 src/test/java/swm_nm/morandi/domain/testStart/service/GetProblemsServiceTest.java diff --git a/src/main/java/swm_nm/morandi/domain/problem/dto/BojProblem.java b/src/main/java/swm_nm/morandi/domain/problem/dto/BojProblem.java index 08d06daf..cba704aa 100644 --- a/src/main/java/swm_nm/morandi/domain/problem/dto/BojProblem.java +++ b/src/main/java/swm_nm/morandi/domain/problem/dto/BojProblem.java @@ -3,6 +3,10 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.*; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; + @Getter @Setter @AllArgsConstructor @NoArgsConstructor @@ -12,6 +16,21 @@ public class BojProblem { private Long testProblemId; private Long problemId; // baekjoon problem id (바꾸면 절대 안 됨 ObjectMapper 때문에) - private Integer level; - private String levelToString; -} + private String startLevel; + private String endLevel; + public static List initBojProblems(List difficultyRanges) { + List bojProblems = new ArrayList<>(); + IntStream.range(0, difficultyRanges.size()).forEach(i -> { + String startLevel = difficultyRanges.get(i).getStart().getShortName(); + String endLevel = difficultyRanges.get(i).getEnd().getShortName(); + BojProblem bojProblem = BojProblem.builder() + .testProblemId((long) i) + .problemId(null) + .startLevel(startLevel) + .endLevel(endLevel) + .build(); + bojProblems.add(bojProblem); + }); + return bojProblems; + } +} \ No newline at end of file diff --git a/src/main/java/swm_nm/morandi/domain/testStart/service/GetProblemsService.java b/src/main/java/swm_nm/morandi/domain/testStart/service/GetProblemsService.java index 86e5933e..2abf078a 100644 --- a/src/main/java/swm_nm/morandi/domain/testStart/service/GetProblemsService.java +++ b/src/main/java/swm_nm/morandi/domain/testStart/service/GetProblemsService.java @@ -20,6 +20,7 @@ import swm_nm.morandi.global.exception.errorcode.TestErrorCode; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -28,81 +29,54 @@ @Slf4j public class GetProblemsService { - private final TypeProblemListRepository typeProblemListRepository; - - public void getProblemsByTestType(TestType testType, List bojProblems) { - List typeProblemLists = typeProblemListRepository.findByTestType_TestTypeId(testType.getTestTypeId()); - List problems = typeProblemLists.stream().map(TypeProblemList::getProblem).collect(Collectors.toList()); + private final ObjectMapper objectMapper; + public List getProblemsByApi(TestType testType, String bojId) { List difficultyRanges = testType.getDifficultyRanges(); - long index = 1; - for (DifficultyRange difficultyRange : difficultyRanges) { - int start = DifficultyLevel.getLevelByValue(difficultyRange.getStart()); - int end = DifficultyLevel.getLevelByValue(difficultyRange.getEnd()); - boolean flag = false; - for (Problem problem : problems) { - int problemLevel = DifficultyLevel.getLevelByValue(problem.getProblemDifficulty()); - if (start <= problemLevel && problemLevel <= end) { - BojProblem bojProblem = BojProblem.builder() - .testProblemId(index++) - .problemId(problem.getBojProblemId()) - .level(DifficultyLevel.getLevelByValue(problem.getProblemDifficulty())) - .levelToString(problem.getProblemDifficulty().getFullName()).build(); - bojProblems.add(bojProblem); - flag = true; - break; - } - } + List bojProblems = BojProblem.initBojProblems(difficultyRanges); + String apiUrl = "https://solved.ac/api/v3/search/problem"; - if (!flag) { - BojProblem bojProblem = BojProblem.builder() - .testProblemId(index++) - .problemId(0L) - .build(); - bojProblems.add(bojProblem); - } - } - } + List> futures = bojProblems.stream() + .map(bojProblem -> CompletableFuture.runAsync(() -> { + String start = bojProblem.getStartLevel(); + String end = bojProblem.getEndLevel(); + String query = getString(testType, bojId, start, end); + String URL = apiUrl + "?query=" + query + "&page=1" + "&sort=random"; - public void getProblemsByApi(TestType testType, String bojId, List bojProblems) { - System.out.println("testType : " + testType); - List difficultyRanges = testType.getDifficultyRanges(); - long index = 1; - for (DifficultyRange difficultyRange : difficultyRanges) { - if (bojProblems.get((int) (index - 1)).getProblemId() != 0) { - index++; - continue; - } - String start = difficultyRange.getStart().getShortName(); - String end = difficultyRange.getEnd().getShortName(); - String apiUrl = "https://solved.ac/api/v3/search/problem"; - while (true) { - String query = getString(testType, bojId, start, end); - WebClient webClient = WebClient.builder().build(); - String jsonString = webClient.get() - .uri(apiUrl + "?query=" + query + "&page=1" + "&sort=random") - .retrieve() - .bodyToMono(String.class) - .block(); - - ObjectMapper mapper = new ObjectMapper(); - try { - JsonNode rootNode = mapper.readTree(jsonString); - JsonNode itemsArray = rootNode.get("items"); - if (itemsArray != null && itemsArray.isArray() && itemsArray.size() > 0) { - if (!isKorean(itemsArray)) continue; - long prev = index; - index = getProblem(bojProblems, index, mapper, itemsArray); - if (prev == index) continue; - break; + while (true) { + WebClient webClient = WebClient.builder().build(); + String jsonString = webClient.get() + .uri(URL) + .retrieve() + .bodyToMono(String.class) + .block(); + try { + JsonNode jsonNode = objectMapper.readTree(jsonString); + JsonNode itemsArray = jsonNode.get("items"); + if (itemsArray != null && itemsArray.isArray() && itemsArray.size() > 0) { + if (getProblem(bojProblem, itemsArray)) + break; + } + } catch (JsonProcessingException e) { + throw new MorandiException(TestErrorCode.JSON_PARSE_ERROR); + } } - } catch (JsonProcessingException e) { - log.error("JsonProcessingException : {}", e.getMessage()); - throw new MorandiException(TestErrorCode.JSON_PARSE_ERROR); - } - } - } + })).collect(Collectors.toList()); + + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + + return bojProblems; } + private boolean getProblem(BojProblem bojProblem, JsonNode itemsArray) { + for (JsonNode jsonNode : itemsArray) { + Long problemId = jsonNode.get("problemId").asLong(); + String title = jsonNode.get("titleKo").asText(); + if (problemId > 28000 || !title.matches(".*[가-힣]+.*")) continue; + bojProblem.setProblemId(problemId); + return true; + } + return false; + } private static String getString(TestType testType, String bojId, String start, String end) { String query = testType.getTestTypeId() == 7 ? String.format("tier:%s..%s ~solved_by:%s tag:simulation ~tag:ad_hoc ~tag:constructive ~tag:geometry" + @@ -111,24 +85,4 @@ private static String getString(TestType testType, String bojId, String start, S " ~tag:number_theory ~tag:simulation ~tag:math solved:200.. solved:..5000", start, end, bojId); return query; } - - private static long getProblem(List bojProblems, long index, ObjectMapper mapper, JsonNode itemsArray) - throws JsonProcessingException { - JsonNode firstProblem = itemsArray.get(0); - BojProblem apiProblem = mapper.treeToValue(firstProblem, BojProblem.class); - if (apiProblem.getProblemId() > 28000) - return index; - BojProblem bojProblem = bojProblems.get((int) (index - 1)); - bojProblem.setProblemId(apiProblem.getProblemId()); - bojProblem.setLevel(apiProblem.getLevel()); - bojProblem.setTestProblemId(index++); - bojProblem.setLevelToString(DifficultyLevel.getValueByLevel(bojProblem.getLevel())); - return index; - } - - private static boolean isKorean(JsonNode itemsArray) { - JsonNode firstItemNode = itemsArray.get(0); - String title = firstItemNode.get("titleKo").asText(); - return title.matches(".*[가-힣]+.*"); - } -} +} \ No newline at end of file diff --git a/src/main/java/swm_nm/morandi/domain/testStart/service/TestStartUseCase.java b/src/main/java/swm_nm/morandi/domain/testStart/service/TestStartUseCase.java index 502b9ccb..b44a7d94 100644 --- a/src/main/java/swm_nm/morandi/domain/testStart/service/TestStartUseCase.java +++ b/src/main/java/swm_nm/morandi/domain/testStart/service/TestStartUseCase.java @@ -66,13 +66,12 @@ public TestStartResponseDto getTestStartsData(Long testTypeId) { test = addTestService.startTestByTestTypeId(testType, member); String bojId = memberInfoService.getMemberInfo().getBojId(); - List bojProblems = new ArrayList<>(); // 테스트 시작시 문제 가져오기 - getProblemsService.getProblemsByTestType(testType, bojProblems); + // getProblemsService.getProblemsByTestType(testType, bojProblems); // API로 문제 가져오기 - getProblemsService.getProblemsByApi(testType, bojId, bojProblems); + List bojProblems = getProblemsService.getProblemsByApi(testType, bojId); // 테스트 시작시 문제 저장 saveProblemsService.saveAttemptProblems(member, test, bojProblems); @@ -88,10 +87,10 @@ public TestStartResponseDto getTestStartsData(Long testTypeId) { private TestStartResponseDto getTestStartResponseDto(Tests test, List bojProblems, TempCodeDto tempCodeDto) { List bojProblemDtos = bojProblems.stream().map(bojProblem -> - BojProblemDto.builder() - .isSolved(false) - .bojProblemId(bojProblem.getProblemId()) - .build()) + BojProblemDto.builder() + .isSolved(false) + .bojProblemId(bojProblem.getProblemId()) + .build()) .collect(Collectors.toList()); Integer problemCount = test.getProblemCount(); @@ -122,9 +121,9 @@ private TestStartResponseDto getTestStartResponseDto(Tests test) { List bojProblemDtos = attemptProblems.stream().map(attemptProblem -> BojProblemDto.builder() - .isSolved(attemptProblem.getIsSolved()) - .bojProblemId(attemptProblem.getProblem().getBojProblemId()) - .build()).collect(Collectors.toList()); + .isSolved(attemptProblem.getIsSolved()) + .bojProblemId(attemptProblem.getProblem().getBojProblemId()) + .build()).collect(Collectors.toList()); List testCodeDtos = getTestCodeDtos(test); @@ -138,4 +137,4 @@ private TestStartResponseDto getTestStartResponseDto(Tests test) { // 테스트 시작에 대한 ResponseDto 반환 return testStartResponseDto; } -} +} \ No newline at end of file diff --git a/src/test/java/swm_nm/morandi/domain/testStart/service/GetProblemsServiceTest.java b/src/test/java/swm_nm/morandi/domain/testStart/service/GetProblemsServiceTest.java new file mode 100644 index 00000000..1484974b --- /dev/null +++ b/src/test/java/swm_nm/morandi/domain/testStart/service/GetProblemsServiceTest.java @@ -0,0 +1,10 @@ +package swm_nm.morandi.domain.testStart.service; + +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class GetProblemsServiceTest { + +} \ No newline at end of file