From 0f5563277b6aa7b4e12385c2818ddf36092d3e4d Mon Sep 17 00:00:00 2001 From: minahYu Date: Sun, 24 Nov 2024 19:17:31 +0900 Subject: [PATCH 1/6] =?UTF-8?q?chore:=20commonmark=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index dce5710..a246b01 100644 --- a/build.gradle +++ b/build.gradle @@ -46,6 +46,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // flying saucer implementation 'org.xhtmlrenderer:flying-saucer-pdf:9.9.1' + // markdown + implementation 'org.commonmark:commonmark:0.21.0' // postgre implementation 'org.postgresql:postgresql:42.7.4' runtimeOnly 'org.postgresql:postgresql' From b661586c2c600629cc71366669259c3582b6e021 Mon Sep 17 00:00:00 2001 From: minahYu Date: Sun, 24 Nov 2024 19:18:32 +0900 Subject: [PATCH 2/6] =?UTF-8?q?refac:=20ReportingResponse=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...{ReportingSummaryRequest.java => ReportingResponse.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/{ReportingSummaryRequest.java => ReportingResponse.java} (53%) diff --git a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingSummaryRequest.java b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java similarity index 53% rename from src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingSummaryRequest.java rename to src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java index e941d8f..10d9d7d 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingSummaryRequest.java +++ b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java @@ -3,9 +3,9 @@ import lombok.Builder; @Builder -public record ReportingSummaryRequest( - String title, - String content +public record ReportingResponse( + String summary, + String pdf ) { } \ No newline at end of file From 5a9d67eaae48bb1607615c35e9704d98a062ef2f Mon Sep 17 00:00:00 2001 From: minahYu Date: Sun, 24 Nov 2024 19:20:00 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refac:=20createReportingPdf=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/report/service/ReportService.java | 12 ++--- .../report/service/ReportServiceImpl.java | 45 ++++++++++++++----- .../web/controller/ReportController.java | 33 +++++++------- .../reporting-summary-template.html | 4 +- 4 files changed, 56 insertions(+), 38 deletions(-) rename src/main/resources/{template => templates}/reporting-summary-template.html (85%) diff --git a/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportService.java b/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportService.java index e5f0402..e568b89 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportService.java +++ b/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportService.java @@ -1,14 +1,8 @@ package com.swOnCampus.AIPlatform.domain.report.service; -import com.swOnCampus.AIPlatform.domain.report.web.dto.ReportingSummaryRequest; +import com.swOnCampus.AIPlatform.domain.report.web.dto.ReportingResponse; public interface ReportService { - /** - * 리포팅 요약된 내용을 html로 변환 하여 pdf를 생성하는 메서드 - * - * @param request : 리포팅 요약 데이터를 담은 request 객체 - * @return : 생성된 PDF 파일의 바이트 배열 - */ - byte[] createReportingSummaryPdf(ReportingSummaryRequest request); -} + ReportingResponse createReportingPdf(Long memberId, Long companyId); +} \ No newline at end of file diff --git a/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportServiceImpl.java b/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportServiceImpl.java index 7d09469..dc9c2f0 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportServiceImpl.java +++ b/src/main/java/com/swOnCampus/AIPlatform/domain/report/service/ReportServiceImpl.java @@ -1,13 +1,18 @@ package com.swOnCampus.AIPlatform.domain.report.service; import com.lowagie.text.pdf.BaseFont; -import com.swOnCampus.AIPlatform.domain.report.web.dto.ReportingSummaryRequest; +import com.swOnCampus.AIPlatform.domain.consulting.entity.Consulting; +import com.swOnCampus.AIPlatform.domain.consulting.exception.ConsultingErrorCode; +import com.swOnCampus.AIPlatform.domain.consulting.repository.ConsultingRepository; +import com.swOnCampus.AIPlatform.domain.report.exception.ReportErrorCode; +import com.swOnCampus.AIPlatform.domain.report.web.dto.ReportingResponse; import com.swOnCampus.AIPlatform.global.exception.GlobalException; import java.io.ByteArrayOutputStream; +import java.util.Base64; import java.util.Map; - -import com.swOnCampus.AIPlatform.domain.report.exception.ReportErrorCode; import lombok.RequiredArgsConstructor; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; @@ -20,19 +25,31 @@ public class ReportServiceImpl implements ReportService { private final TemplateEngine templateEngine; + private final ConsultingRepository consultingRepository; @Value(value = "${report.font.path}") private String fontPath; @Override - public byte[] createReportingSummaryPdf(ReportingSummaryRequest request) { + public ReportingResponse createReportingPdf(Long memberId, Long companyId) { + Consulting consulting = consultingRepository.findByCompanyId(companyId) + .orElseThrow(() -> new GlobalException(ConsultingErrorCode.NOT_EXIST_CONSULTING)); + + String summaryHtml = consulting.getSummary().replace("\n", "
"); + String renderedMarkdown = renderMarkdown(summaryHtml); + Map contextVariables = Map.of( - "title", request.title(), - "content", request.content() + "content", renderedMarkdown ); String html = createHtmlFromTemplate(contextVariables); + byte[] pdfBytes = convertHtmlToPdf(html); - return convertHtmlToPdf(html); + ReportingResponse response = new ReportingResponse( + consulting.getSummary(), + Base64.getEncoder().encodeToString(pdfBytes) + ); + + return response; } private String createHtmlFromTemplate(Map contextVariables) { @@ -57,12 +74,18 @@ private byte[] convertHtmlToPdf(String html) { private void setFont(ITextRenderer renderer) { try { renderer.getFontResolver().addFont( - new ClassPathResource(fontPath).getURL().toString(), - BaseFont.IDENTITY_H, - BaseFont.EMBEDDED + new ClassPathResource(fontPath).getURL().toString(), + BaseFont.IDENTITY_H, + BaseFont.EMBEDDED ); } catch (Exception e) { throw new GlobalException(ReportErrorCode.NOT_FOUND_FONT); } } -} + + private String renderMarkdown(String markdownText) { + Parser parser = Parser.builder().build(); + HtmlRenderer renderer = HtmlRenderer.builder().build(); + return renderer.render(parser.parse(markdownText)); + } +} \ No newline at end of file diff --git a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java index 905eb37..d0bd02f 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java +++ b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java @@ -1,13 +1,16 @@ package com.swOnCampus.AIPlatform.domain.report.web.controller; +import com.swOnCampus.AIPlatform.domain.member.entity.Member; import com.swOnCampus.AIPlatform.domain.report.service.ReportService; -import com.swOnCampus.AIPlatform.domain.report.web.dto.ReportingSummaryRequest; +import com.swOnCampus.AIPlatform.domain.report.web.dto.ReportingResponse; +import com.swOnCampus.AIPlatform.global.annotation.LoginMember; +import com.swOnCampus.AIPlatform.global.response.ApiResponse; import lombok.RequiredArgsConstructor; -import org.springframework.http.MediaType; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RequiredArgsConstructor @@ -18,19 +21,17 @@ public class ReportController { private final ReportService reportService; @GetMapping() - public ResponseEntity createReportingSummaryPdf(Model model) { - model.addAttribute("title", "리포팅 요약"); - model.addAttribute("content", "내용"); + public ResponseEntity> createReportingPdf( + @LoginMember Member member, + @RequestParam Long companyId // 채팅방 id + ) { + ReportingResponse reportingResponse = reportService.createReportingPdf( + member.getMemberId(), companyId); - ReportingSummaryRequest request = ReportingSummaryRequest.builder() - .title(model.getAttribute("title").toString()) - .content(model.getAttribute("content").toString()) - .build(); + ApiResponse response = ApiResponse.createSuccess(HttpStatus.OK.value(), + reportingResponse, + "PDF 파일이 생성되었습니다."); - byte[] pdfData = reportService.createReportingSummaryPdf(request); - - return ResponseEntity.ok() - .contentType(MediaType.APPLICATION_PDF) - .body(pdfData); + return ResponseEntity.ok(response); } -} +} \ No newline at end of file diff --git a/src/main/resources/template/reporting-summary-template.html b/src/main/resources/templates/reporting-summary-template.html similarity index 85% rename from src/main/resources/template/reporting-summary-template.html rename to src/main/resources/templates/reporting-summary-template.html index 6019212..daa2306 100644 --- a/src/main/resources/template/reporting-summary-template.html +++ b/src/main/resources/templates/reporting-summary-template.html @@ -16,7 +16,7 @@ -

-

+

컨설팅 결과

+

\ No newline at end of file From 603db45596cb3fb1cb9b1d1836029e25c9b2691c Mon Sep 17 00:00:00 2001 From: minahYu Date: Sun, 24 Nov 2024 19:20:12 +0900 Subject: [PATCH 4/6] =?UTF-8?q?chore:=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EC=8A=A4=EC=BA=94=20=EB=B2=94=EC=9C=84=EC=97=90=20consulting?= =?UTF-8?q?=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/swOnCampus/AIPlatform/AiPlatformApplication.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/swOnCampus/AIPlatform/AiPlatformApplication.java b/src/main/java/com/swOnCampus/AIPlatform/AiPlatformApplication.java index 85e946f..cc053a6 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/AiPlatformApplication.java +++ b/src/main/java/com/swOnCampus/AIPlatform/AiPlatformApplication.java @@ -10,12 +10,13 @@ @EnableJpaRepositories @SpringBootApplication @EntityScan(basePackages = { - "com/swOnCampus/AIPlatform/domain/member/entity" + "com/swOnCampus/AIPlatform/domain/member/entity", + "com/swOnCampus/AIPlatform/domain/consulting/entity" }) public class AiPlatformApplication { - public static void main(String[] args) { - SpringApplication.run(AiPlatformApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(AiPlatformApplication.class, args); + } } From 7f67b880cd5d1cfab006c066ad48839ddc253207 Mon Sep 17 00:00:00 2001 From: minahYu Date: Sun, 24 Nov 2024 20:34:11 +0900 Subject: [PATCH 5/6] =?UTF-8?q?docs:=20=EC=BB=A8=EC=84=A4=ED=8C=85=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20PDF=20API=20=EA=B4=80=EB=A0=A8=20Swagger?= =?UTF-8?q?=20=EB=AA=85=EC=84=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/controller/ReportController.java | 26 +++++++++++++++++-- .../report/web/dto/ReportingResponse.java | 3 +++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java index d0bd02f..dfadebd 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java +++ b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/controller/ReportController.java @@ -5,6 +5,11 @@ import com.swOnCampus.AIPlatform.domain.report.web.dto.ReportingResponse; import com.swOnCampus.AIPlatform.global.annotation.LoginMember; import com.swOnCampus.AIPlatform.global.response.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -13,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +@Tag(name = "컨설팅 PDF 생성 API", description = "컨설팅 결과 PDF 생성 관련 API") @RequiredArgsConstructor @RestController @RequestMapping("/api/v1/report") @@ -20,6 +26,20 @@ public class ReportController { private final ReportService reportService; + @Operation(summary = "컨설팅 PDF API 요청", description = "컨설팅 결과 PDF 생성 API 요청") + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "COMMON200", + description = "요청 성공", + content = { + @Content( + schema = @Schema( + implementation = ReportingResponse.class + ) + ) + } + ) + }) @GetMapping() public ResponseEntity> createReportingPdf( @LoginMember Member member, @@ -28,9 +48,11 @@ public ResponseEntity> createReportingPdf( ReportingResponse reportingResponse = reportService.createReportingPdf( member.getMemberId(), companyId); - ApiResponse response = ApiResponse.createSuccess(HttpStatus.OK.value(), + ApiResponse response = ApiResponse.createSuccess( + HttpStatus.OK.value(), reportingResponse, - "PDF 파일이 생성되었습니다."); + "PDF 파일이 생성되었습니다." + ); return ResponseEntity.ok(response); } diff --git a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java index 10d9d7d..5aecb3c 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java +++ b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java @@ -1,10 +1,13 @@ package com.swOnCampus.AIPlatform.domain.report.web.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; @Builder public record ReportingResponse( + @Schema(description = "컨설팅 요약 내용", example = "컨설팅 요약") String summary, + @Schema(description = "컨설팅 전체 내용 PDF", example = "byte") String pdf ) { From 6e3bfbbe8ed6a02cd13824fc0f9e4d19275e33ae Mon Sep 17 00:00:00 2001 From: minahYu Date: Sun, 24 Nov 2024 20:51:40 +0900 Subject: [PATCH 6/6] =?UTF-8?q?docs:=20=EC=BB=A8=EC=84=A4=ED=8C=85=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20PDF=20API=20=EA=B4=80=EB=A0=A8=20Swagger?= =?UTF-8?q?=20=EB=AA=85=EC=84=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AIPlatform/domain/report/web/dto/ReportingResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java index 5aecb3c..33c9b46 100644 --- a/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java +++ b/src/main/java/com/swOnCampus/AIPlatform/domain/report/web/dto/ReportingResponse.java @@ -7,7 +7,7 @@ public record ReportingResponse( @Schema(description = "컨설팅 요약 내용", example = "컨설팅 요약") String summary, - @Schema(description = "컨설팅 전체 내용 PDF", example = "byte") + @Schema(description = "컨설팅 전체 내용 PDF 파일의 Base64 인코딩 데이터", example = "byte") String pdf ) {