Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
})
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);
}

}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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", "<br />");
String renderedMarkdown = renderMarkdown(summaryHtml);

Map<String, Object> 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<String, Object> contextVariables) {
Expand All @@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,59 @@
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 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.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;

@Tag(name = "컨설팅 PDF 생성 API", description = "컨설팅 결과 PDF 생성 관련 API")
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/v1/report")
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<byte[]> createReportingSummaryPdf(Model model) {
model.addAttribute("title", "리포팅 요약");
model.addAttribute("content", "내용");
public ResponseEntity<ApiResponse<?>> 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<ReportingResponse> 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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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 파일의 Base64 인코딩 데이터", example = "byte")
String pdf
) {

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</style>
</head>
<body>
<h1 th:text="${title}"></h1>
<p th:text="${content}"></p>
<h1>컨설팅 결과</h1>
<p th:utext="${content}"></p>
</body>
</html>