diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 72b3537..3452604 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -17,6 +17,13 @@ jobs: steps: - name: 체크아웃 uses: actions/checkout@v4 + with: + submodules: true + token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + + - name: 서브모듈 업데이트 + run: | + git submodule update --remote - name: JDK 11 설치 uses: actions/setup-java@v4 diff --git a/src/main/java/com/app/domain/categorizedproblem/service/CategorizedProblemService.java b/src/main/java/com/app/domain/categorizedproblem/service/CategorizedProblemService.java index 9308e16..c488021 100644 --- a/src/main/java/com/app/domain/categorizedproblem/service/CategorizedProblemService.java +++ b/src/main/java/com/app/domain/categorizedproblem/service/CategorizedProblemService.java @@ -6,17 +6,21 @@ import com.app.domain.category.service.CategoryService; import com.app.domain.member.entity.Member; import com.app.domain.member.service.MemberService; +import com.app.domain.problem.aigeneratedproblem.dto.ProblemFile.AiRequest.AiGenerateProblemFromAiDto; import com.app.domain.problem.entity.Problem; import com.app.domain.problem.membersavedproblem.dto.MemberSavedProblemDto; import com.app.domain.problem.membersavedproblem.mapper.MemberSavedProblemMapper; import com.app.domain.problem.service.ProblemService; import com.app.domain.summary.membersavedsummary.dto.MemberSavedSummaryDto; +import com.app.global.config.ENUM.PdfType; import com.app.global.config.ENUM.ProblemType; import com.app.global.error.ErrorCode; import com.app.global.error.exception.BusinessException; import com.app.global.error.exception.EntityNotFoundException; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -32,6 +36,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import static com.app.global.pdf.ProblemPdfMaker.CreatePdfFile; + @Service @Transactional @RequiredArgsConstructor @@ -132,101 +138,42 @@ public MemberSavedSummaryDto.pdfResponse createCategorizedProblemsAnswerPdf(Long } } - public MemberSavedSummaryDto.pdfResponse createCategorizedProblemsPdf(Long categoryId) throws IOException { + public MemberSavedSummaryDto.pdfResponse createCategorizedProblemsPdf(Long categoryId){ List categorizedProblemList = categorizedProblemRepository.findByCategoryCategoryId(categoryId); Category category = categoryService.findVerifiedCategoryByCategoryId(categoryId); String title = category.getCategoryName(); - try (PDDocument document = new PDDocument()) { - PDPage page = new PDPage(); - document.addPage(page); - PDPageContentStream contentStream = new PDPageContentStream(document, page); - PDType0Font font = PDType0Font.load(document, getClass().getResourceAsStream("/fonts/malgun.ttf")); - contentStream.setFont(font, 12); - float yPosition = page.getMediaBox().getHeight() - 50; - int linesInCurrentPage = 0; - int maxLinesPerPage = 45; - int problemNumber = 0; // 문제 번호 + // Pdf 생성 DTO 변환 + AiGenerateProblemFromAiDto[] problems = new AiGenerateProblemFromAiDto[categorizedProblemList.size()]; + for(int i = 0; i < categorizedProblemList.size(); i++) { + Problem problem = categorizedProblemList.get(i).getProblem(); + problems[i] = AiGenerateProblemFromAiDto.create( + problem.getProblemName(), + problem.getProblemChoices(), + problem.getProblemAnswer(), + problem.getProblemCommentary() + ); + } - for (CategorizedProblem categorizedProblem : categorizedProblemList) { - problemNumber++; - Problem problem = categorizedProblem.getProblem(); - String problemName = problemNumber + ". " + problem.getProblemName(); + File tempFile = null; + byte[] pdfContent = null; - List problemChoices = new ArrayList<>(); - if (problem.getProblemType() == ProblemType.MULTIPLE) { - problemChoices = problem.getProblemChoices(); - } - float maxWidth = page.getMediaBox().getWidth() - 100; // 페이지 폭에서 양쪽 여백을 뺀 값 - List wrappedProblemName = wrapText(problemName, font, 12, maxWidth); + try { + tempFile = CreatePdfFile(category.getCategoryName(), problems, PdfType.PROBLEM); // Problem PDF 생성 - for (String line : wrappedProblemName) { - if (linesInCurrentPage >= maxLinesPerPage || yPosition < 50) { - contentStream.close(); - page = new PDPage(); - document.addPage(page); - contentStream = new PDPageContentStream(document, page); - contentStream.setFont(font, 12); - yPosition = page.getMediaBox().getHeight() - 50; - linesInCurrentPage = 0; - } + // 파일을 바이트 배열로 변환 + pdfContent = Files.readAllBytes(tempFile.toPath()); - contentStream.beginText(); - contentStream.newLineAtOffset(50, yPosition); - contentStream.showText(line); - contentStream.endText(); - yPosition -= 15; // 줄 간의 간격 - linesInCurrentPage++; - } - yPosition -= 10; // 문제명과 선택지 사이의 간격 조정 - - // 보기 리스트 출력 - if (problemChoices != null) { - char choiceLetter = 'A'; // 선지 번호 (알파벳) - int totalChoices = problemChoices.size(); - - for (String choice : problemChoices) { - List wrappedText = wrapText(choice, font, 12, maxWidth); - boolean isFirstLineOfChoice = true; - - for (String line : wrappedText) { - if (linesInCurrentPage >= maxLinesPerPage || yPosition < 50) { - contentStream.close(); - page = new PDPage(); - document.addPage(page); - contentStream = new PDPageContentStream(document, page); - contentStream.setFont(font, 12); - yPosition = page.getMediaBox().getHeight() - 50; - linesInCurrentPage = 0; - } - - contentStream.beginText(); - contentStream.newLineAtOffset(50, yPosition); - - if (isFirstLineOfChoice) { - contentStream.showText(choiceLetter + ". " + line); // 알파벳 번호 추가 - isFirstLineOfChoice = false; // 첫 줄 출력 후 false로 변경 - } else { - contentStream.showText(line); - } - contentStream.endText(); - yPosition -= 15; - linesInCurrentPage++; - } - if (choiceLetter == 'A' + totalChoices - 1) { // 마지막 선지 확인 - yPosition -= 20; // 마지막 선지 이후에 더 큰 간격 추가 - } - choiceLetter++; // 다음 선지를 위해 알파벳 증가 - } - } + } catch (IOException e) { + throw new BusinessException(ErrorCode.NOT_UPLOAD_PROBLEM); + } finally { + // 임시 파일 삭제 + if (tempFile != null && tempFile.exists()) { + tempFile.delete(); } - - contentStream.close(); - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - document.save(byteArrayOutputStream); // 문서를 ByteArrayOutputStream에 저장 - document.close(); // 문서를 닫아 리소스를 해제 - return new MemberSavedSummaryDto.pdfResponse(byteArrayOutputStream.toByteArray(), title); } + + return new MemberSavedSummaryDto.pdfResponse(pdfContent, title); } diff --git a/src/main/java/com/app/domain/problem/aigeneratedproblem/dto/ProblemFile/AiRequest/AiGenerateProblemFromAiDto.java b/src/main/java/com/app/domain/problem/aigeneratedproblem/dto/ProblemFile/AiRequest/AiGenerateProblemFromAiDto.java index fb48dd6..09789f0 100644 --- a/src/main/java/com/app/domain/problem/aigeneratedproblem/dto/ProblemFile/AiRequest/AiGenerateProblemFromAiDto.java +++ b/src/main/java/com/app/domain/problem/aigeneratedproblem/dto/ProblemFile/AiRequest/AiGenerateProblemFromAiDto.java @@ -25,4 +25,8 @@ public class AiGenerateProblemFromAiDto { @Schema(description = "문제 해설", example = "문제 해설 예시") private String problemCommentary; + + public static AiGenerateProblemFromAiDto create(String problemName, List problemChoices, String problemAnswer, String problemCommentary) { + return new AiGenerateProblemFromAiDto(problemName, problemChoices, problemAnswer, problemCommentary); + } } diff --git a/src/main/java/com/app/domain/problem/aigeneratedproblem/service/ProblemFileService.java b/src/main/java/com/app/domain/problem/aigeneratedproblem/service/ProblemFileService.java index 26c0b6e..4f6e014 100644 --- a/src/main/java/com/app/domain/problem/aigeneratedproblem/service/ProblemFileService.java +++ b/src/main/java/com/app/domain/problem/aigeneratedproblem/service/ProblemFileService.java @@ -268,8 +268,7 @@ public void UploadS3(AiGenerateProblemFromAiDto[] aiGenerateProblemFromAiDto, Ai } catch (IOException e) { - - throw new BusinessException(ErrorCode.NOT_UPLOAD_PROBLEM); + e.printStackTrace(); } finally { if (tempFile != null) { tempFile.delete(); // 방금 생성한 파일 삭제 diff --git a/src/main/java/com/app/domain/summary/aigeneratedsummary/service/SummaryFileService.java b/src/main/java/com/app/domain/summary/aigeneratedsummary/service/SummaryFileService.java index 8039db7..04f5edb 100644 --- a/src/main/java/com/app/domain/summary/aigeneratedsummary/service/SummaryFileService.java +++ b/src/main/java/com/app/domain/summary/aigeneratedsummary/service/SummaryFileService.java @@ -207,7 +207,7 @@ public void UploadS3(AiGenerateSummaryFromAiDto aiGenerateSummaryFromAiDto, AiGe } catch (IOException e) { - throw new BusinessException(ErrorCode.NOT_UPLOAD_PROBLEM); + e.printStackTrace(); } finally { if (tempFile != null) { tempFile.delete(); // 방금 생성한 파일 삭제