11package hs.kr.entrydsm.application.global.pdf.data
22
3+ import com.amazonaws.services.s3.AmazonS3
4+ import com.amazonaws.services.s3.model.GetObjectRequest
5+ import hs.kr.entrydsm.application.global.storage.AwsProperties
36import hs.kr.entrydsm.domain.application.aggregates.Application
47import hs.kr.entrydsm.domain.application.values.ApplicationType
58import hs.kr.entrydsm.domain.application.values.EducationalStatus
69import hs.kr.entrydsm.domain.application.values.Gender
710import hs.kr.entrydsm.domain.school.interfaces.QuerySchoolContract
11+ import org.slf4j.LoggerFactory
812import org.springframework.stereotype.Component
913import java.net.URL
1014import java.time.LocalDate
1115import java.util.Base64
1216
13- /* *
14- * 지원서 정보를 PDF 템플릿용 데이터로 변환하는 Converter입니다.
15- *
16- * Application, Score 등의 도메인 객체를 HTML 템플릿에서 사용할 수 있는
17- * Key-Value 형태의 데이터로 변환합니다. 누락된 도메인 정보는 더미값으로 처리하며
18- * 향후 도메인이 추가되면 TODO 주석을 따라 연동할 수 있습니다.
19- */
2017@Component
2118class PdfDataConverter (
2219 private val querySchoolContract : QuerySchoolContract ,
20+ private val amazonS3 : AmazonS3 ,
21+ private val awsProperties : AwsProperties ,
2322) {
24- /* *
25- * 지원서 정보를 PDF 템플릿용 데이터로 변환합니다.
26- *
27- * @param application 지원서 정보
28- * @return 템플릿에 사용할 PdfData 객체
29- */
23+
24+ private val log by lazy { LoggerFactory .getLogger(this ::class .java) }
25+
3026 fun applicationToInfo (application : Application ): PdfData {
3127 val values: MutableMap <String , Any > = HashMap ()
3228 setReceiptCode(application, values)
@@ -45,43 +41,48 @@ class PdfDataConverter(
4541 setAttendanceAndVolunteer(application, values)
4642 setExtraScore(application, values)
4743 setTeacherInfo(application, values)
48- setBase64Image(application, values)
44+ setBase64Image(application, values) // ⭐️ 수정된 메서드가 호출됩니다.
4945
5046 return PdfData (values)
5147 }
5248
53- // ... (이하 다른 메서드들은 이전과 동일)
49+ private fun setBase64Image (
50+ application : Application ,
51+ values : MutableMap <String , Any >,
52+ ) {
53+ val photoPath = application.photoPath
54+ if (photoPath.isNullOrBlank()) {
55+ values[" base64Image" ] = " "
56+ return
57+ }
58+
59+ try {
60+ val objectKey = URL (photoPath).path.substring(1 )
61+
62+ val s3Object = amazonS3.getObject(GetObjectRequest (awsProperties.bucket, objectKey))
63+ val imageBytes = s3Object.objectContent.readAllBytes()
64+
65+ values[" base64Image" ] = Base64 .getEncoder().encodeToString(imageBytes)
66+ log.info(" Successfully fetched and encoded image from S3: {}" , objectKey)
67+
68+ } catch (e: Exception ) {
69+ log.error(" Failed to get image from S3. path: {}, error: {}" , photoPath, e.message)
70+ values[" base64Image" ] = " "
71+ }
72+ }
5473
55- /* *
56- * 지원서의 접수번호를 설정합니다.
57- *
58- * @param application 지원서 정보
59- * @param values 템플릿 데이터 맵
60- */
6174 private fun setReceiptCode (
6275 application : Application ,
6376 values : MutableMap <String , Any >,
6477 ) {
6578 values[" receiptCode" ] = application.receiptCode.toString()
6679 }
6780
68- /* *
69- * 입학년도를 설정합니다. (현재 년도 + 1)
70- *
71- * @param values 템플릿 데이터 맵
72- */
7381 private fun setEntranceYear (values : MutableMap <String , Any >) {
7482 val entranceYear: Int = LocalDate .now().plusYears(1 ).year
7583 values[" entranceYear" ] = entranceYear.toString()
7684 }
7785
78- /* *
79- * 지원자의 개인정보(이름, 성별, 주소, 생년월일 등)를 설정합니다.
80- * 일부 정보는 도메인에 없어서 더미값을 사용합니다.
81- *
82- * @param application 지원서 정보
83- * @param values 템플릿 데이터 맵
84- */
8586 private fun setPersonalInfo (
8687 application : Application ,
8788 values : MutableMap <String , Any >,
@@ -100,7 +101,6 @@ class PdfDataConverter(
100101 values[" region" ] = if (application.isDaejeon == true ) " 대전" else " 비대전"
101102 values[" applicationType" ] = application.applicationType.displayName
102103
103- // 특기사항: 국가유공자자녀 또는 특례입학대상
104104 val remarks = mutableListOf<String >()
105105 if (application.nationalMeritChild == true ) {
106106 remarks.add(" 국가유공자자녀" )
@@ -111,18 +111,10 @@ class PdfDataConverter(
111111 values[" applicationRemark" ] = if (remarks.isEmpty()) " 해당없음" else remarks.joinToString(" , " )
112112 }
113113
114- /* *
115- * 출석 및 봉사활동 정보를 설정합니다.
116- * 현재 관련 도메인이 없어서 더미값을 사용합니다.
117- *
118- * @param application 지원서 정보
119- * @param values 템플릿 데이터 맵
120- */
121114 private fun setAttendanceAndVolunteer (
122115 application : Application ,
123116 values : MutableMap <String , Any >,
124117 ) {
125- // 실제 출석/봉사활동 데이터 사용
126118 values[" absenceDayCount" ] = application.absence ? : 0
127119 values[" latenessCount" ] = application.tardiness ? : 0
128120 values[" earlyLeaveCount" ] = application.earlyLeave ? : 0
@@ -152,7 +144,7 @@ class PdfDataConverter(
152144 values.putAll(emptyGraduationClassification())
153145
154146 val currentYear = LocalDate .now().year
155- val graduationMonth = if (LocalDate .now().monthValue <= 2 ) 2 else 8 // 2월/8월 졸업
147+ val graduationMonth = if (LocalDate .now().monthValue <= 2 ) 2 else 8
156148
157149 when (application.educationalStatus) {
158150 EducationalStatus .GRADUATE -> {
@@ -198,7 +190,7 @@ class PdfDataConverter(
198190 " isProspectiveGraduate" to isProspectiveGraduate,
199191 " isDaejeon" to isDaejeon,
200192 " isNotDaejeon" to ! isDaejeon,
201- " isBasicLiving" to isSocial, // 사회통합전형인 경우 사회적배려 대상자로 추정
193+ " isBasicLiving" to isSocial,
202194 " isCommon" to isCommon,
203195 " isMeister" to (application.applicationType == ApplicationType .MEISTER ),
204196 " isSocialMerit" to isSocial,
@@ -213,7 +205,6 @@ class PdfDataConverter(
213205 application : Application ,
214206 values : MutableMap <String , Any >,
215207 ) {
216- // 실제 가산점 데이터 사용
217208 values[" hasCompetitionPrize" ] = toCircleBallotbox(application.algorithmAward ? : false )
218209 values[" hasCertificate" ] = toCircleBallotbox(application.infoProcessingCert ? : false )
219210 }
@@ -247,14 +238,12 @@ class PdfDataConverter(
247238 application : Application ,
248239 values : MutableMap <String , Any >,
249240 ) {
250- // 실제 성적 데이터 사용
251241 val subjects = listOf (" korean" , " social" , " history" , " math" , " science" , " english" , " techAndHome" )
252242
253243 subjects.forEach { subjectPrefix ->
254244 with (values) {
255245 put(" applicationCase" , " 기술∙가정" )
256246
257- // 졸업자인 경우 3-2학기 성적 포함
258247 if (application.educationalStatus == EducationalStatus .GRADUATE ) {
259248 put(" ${subjectPrefix} ThirdGradeSecondSemester" , getGradeDisplay(getSubjectScore(application, subjectPrefix, " 3_2" )))
260249 }
@@ -378,65 +367,6 @@ class PdfDataConverter(
378367 values[" parentRelation" ] = application.parentRelation ? : " "
379368 }
380369
381- private fun setRecommendations (
382- application : Application ,
383- values : MutableMap <String , Any >,
384- ) {
385- val isDaejeon = application.isDaejeon ? : false
386- val isMeister = application.applicationType == ApplicationType .MEISTER
387- val isSocialMerit = application.applicationType == ApplicationType .SOCIAL
388-
389- values[" isDaejeonAndMeister" ] = markIfTrue(isDaejeon && isMeister)
390- values[" isDaejeonAndSocialMerit" ] = markIfTrue(isDaejeon && isSocialMerit)
391- values[" isNotDaejeonAndMeister" ] = markIfTrue(! isDaejeon && isMeister)
392- values[" isNotDaejeonAndSocialMerit" ] = markIfTrue(! isDaejeon && isSocialMerit)
393- }
394-
395- private fun setBase64Image (
396- application : Application ,
397- values : MutableMap <String , Any >,
398- ) {
399- val photoPath = application.photoPath
400- if (photoPath.isNullOrBlank()) {
401- values[" base64Image" ] = " "
402- return
403- }
404-
405- try {
406- val imageUrl = URL (photoPath)
407- val imageBytes = imageUrl.readBytes()
408- values[" base64Image" ] = Base64 .getEncoder().encodeToString(imageBytes)
409- } catch (e: Exception ) {
410- // URL이 잘못되었거나, 네트워크 문제 등으로 이미지를 가져올 수 없는 경우 빈 문자열로 처리
411- values[" base64Image" ] = " "
412- }
413- }
414-
415- private fun markIfTrue (isTrue : Boolean ): String {
416- return if (isTrue) " ◯" else " "
417- }
418-
419- private fun emptySchoolInfo (): Map <String , Any > {
420- return mapOf (
421- " schoolCode" to " " ,
422- " schoolRegion" to " " ,
423- " schoolClass" to " " ,
424- " schoolTel" to " " ,
425- " schoolName" to " " ,
426- )
427- }
428-
429- private fun emptyGraduationClassification (): Map <String , Any > {
430- return mapOf (
431- " qualificationExamPassedYear" to " 20__" ,
432- " qualificationExamPassedMonth" to " __" ,
433- " graduateYear" to " 20__" ,
434- " graduateMonth" to " __" ,
435- " prospectiveGraduateYear" to " 20__" ,
436- " prospectiveGraduateMonth" to " __" ,
437- )
438- }
439-
440370 private fun setSchoolInfo (
441371 application : Application ,
442372 values : MutableMap <String , Any >,
@@ -452,20 +382,13 @@ class PdfDataConverter(
452382 values[" schoolTel" ] = toFormattedPhoneNumber(school.tel ? : " " )
453383 values[" schoolName" ] = school.name
454384 values[" schoolClass" ] = application.studentId?.let {
455- // studentId에서 학급 정보 추출 시도 (예: "30101" -> "1")
456385 if (it.length >= 2 ) it.substring(1 , 2 ) else " 3"
457386 } ? : " 3"
458387 } else {
459388 values.putAll(emptySchoolInfo())
460389 }
461390 }
462391
463- /* *
464- * 전화번호를 하이픈 포함 형태로 포맷팅합니다.
465- *
466- * @param phoneNumber 포맷팅할 전화번호
467- * @return 하이픈으로 구분된 전화번호 문자열
468- */
469392 private fun toFormattedPhoneNumber (phoneNumber : String? ): String {
470393 if (phoneNumber.isNullOrBlank()) {
471394 return " "
@@ -476,33 +399,32 @@ class PdfDataConverter(
476399 return phoneNumber.replace(" (\\ d{2,3})(\\ d{3,4})(\\ d{4})" .toRegex(), " $1-$2-$3" )
477400 }
478401
479- /* *
480- * null 값을 빈 문자열로 변환합니다.
481- *
482- * @param input 변환할 문자열
483- * @return 입력값이 null이면 빈 문자열, 그렇지 않으면 원래 값
484- */
485- private fun setBlankIfNull (input : String? ): String {
486- return input ? : " "
487- }
488-
489- /* *
490- * boolean 값을 체크박스 문자(☑/☐)로 변환합니다.
491- *
492- * @param isTrue 변환할 boolean 값
493- * @return true이면 "☑", false이면 "☐"
494- */
495402 private fun toBallotBox (isTrue : Boolean ): String {
496403 return if (isTrue) " ☑" else " ☐"
497404 }
498405
499- /* *
500- * boolean 값을 O/X 문자로 변환합니다.
501- *
502- * @param isTrue 변환할 boolean 값
503- * @return true이면 "O", false이면 "X"
504- */
505406 private fun toCircleBallotbox (isTrue : Boolean ): String {
506407 return if (isTrue) " O" else " X"
507408 }
409+
410+ private fun emptySchoolInfo (): Map <String , Any > {
411+ return mapOf (
412+ " schoolCode" to " " ,
413+ " schoolRegion" to " " ,
414+ " schoolClass" to " " ,
415+ " schoolTel" to " " ,
416+ " schoolName" to " " ,
417+ )
418+ }
419+
420+ private fun emptyGraduationClassification (): Map <String , Any > {
421+ return mapOf (
422+ " qualificationExamPassedYear" to " 20__" ,
423+ " qualificationExamPassedMonth" to " __" ,
424+ " graduateYear" to " 20__" ,
425+ " graduateMonth" to " __" ,
426+ " prospectiveGraduateYear" to " 20__" ,
427+ " prospectiveGraduateMonth" to " __" ,
428+ )
429+ }
508430}
0 commit comments