diff --git a/pav-server/build.gradle b/pav-server/build.gradle index 25d04446..987c5d7a 100644 --- a/pav-server/build.gradle +++ b/pav-server/build.gradle @@ -49,9 +49,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' // pdf create - implementation 'com.itextpdf:itextpdf:5.5.13' - implementation 'com.itextpdf.tool:xmlworker:5.5.13' - implementation 'com.itextpdf:pdfa:7.2.3' + implementation 'com.itextpdf:html2pdf:5.0.1' + + // db runtimeOnly 'mysql:mysql-connector-java' @@ -80,8 +80,9 @@ dependencies { implementation 'io.jsonwebtoken:jjwt:0.9.1' implementation 'io.netty:netty-all:4.1.9.Final' implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4:1.16' - implementation 'org.apache.httpcomponents:httpclient' - implementation 'org.apache.commons:commons-lang3' + implementation 'org.apache.httpcomponents:httpclient:4.5.13' + implementation 'org.apache.commons:commons-lang3:3.12.0' + implementation 'org.apache.commons:commons-io:1.3.2' implementation 'commons-httpclient:commons-httpclient:3.1' implementation 'com.googlecode.json-simple:json-simple:1.1.1' implementation 'io.springfox:springfox-boot-starter:3.0.0' @@ -102,7 +103,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testAnnotationProcessor "org.mapstruct:mapstruct-processor:1.5.5.Final" - + } tasks.named('test') { diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/controller/BasFlightController.java b/pav-server/src/main/java/com/palnet/biz/api/bas/flight/controller/BasFlightController.java index 4ea55774..9a6d1991 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/controller/BasFlightController.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/flight/controller/BasFlightController.java @@ -2,13 +2,11 @@ package com.palnet.biz.api.bas.flight.controller; import com.palnet.biz.api.bas.flight.model.*; import com.palnet.biz.api.bas.flight.service.BasFlightService; -import com.palnet.biz.api.bas.flight.template.service.TemplateService; -import com.palnet.biz.api.bas.flight.template.vo.LaancPdfVO; +import com.palnet.biz.api.comn.file.service.ComnFileService; import com.palnet.biz.api.comn.model.ComnPagingRs; import com.palnet.biz.api.comn.response.BasicResponse; import com.palnet.biz.api.comn.response.ErrorResponse; import com.palnet.biz.api.comn.response.SuccessResponse; -import com.palnet.biz.jpa.entity.ComFileBas; import com.palnet.biz.scheduler.ctr.service.CtrTrnsLctnService; import com.palnet.comn.exception.CustomException; import com.palnet.comn.utils.AreaUtils; @@ -47,7 +45,7 @@ public class BasFlightController { private final Environment env; private final CtrTrnsLctnService ctrTrnsLctnService; private final AreaUtils utils; - private final TemplateService templateService; + private final ComnFileService comnFileService; private final PdfUtils pdfUtils; @GetMapping("/area") @@ -376,17 +374,6 @@ public class BasFlightController { } } - @PostMapping("/laanc-pdf/create") - @Tag(name = "비행계획서", description = "비행계획서 관련 API") - @ApiOperation(value = "Laanc 공문 PDF생성") - public void createLancePDF(@RequestBody LaancPdfVO vo) { - - // PDF 생성 및 저장 - ComFileBas comFileBas = templateService.makeLaancPdf(vo); - - // DB 저장 - templateService.save(comFileBas); - } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/service/TemplateService.java b/pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/service/TemplateService.java deleted file mode 100644 index 6e3d53c0..00000000 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/service/TemplateService.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.palnet.biz.api.bas.flight.template.service; - -import java.time.Instant; - -import javax.transaction.Transactional; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil; -import com.palnet.biz.api.bas.flight.template.vo.LaancPdfVO; -import com.palnet.biz.jpa.entity.ComFileBas; -import com.palnet.biz.jpa.repository.com.ComFileBasRepository; -import com.palnet.comn.code.ErrorCode; -import com.palnet.comn.exception.CustomException; -import com.palnet.comn.utils.InstantUtils; -import com.palnet.comn.utils.PdfUtils; - -@Service -public class TemplateService { - - @Autowired - private PdfUtils pdfUtils; - - @Autowired - private JwtTokenUtil jwtTokenUtil; - - @Autowired - private ComFileBasRepository comFileBasRepository; - - @Value("${base-url}") - private String BASE_PATH; - - private final String FILE_EXTENSION = ".pdf"; - - /** - * 파일명 만들기, 앞에 기본으로 금일 날짜있음 - * [예시] 20230102_[추가파라미터] - * @param etcName - * @return - */ - private String getLaancSaveName(String ...etcName){ - - String date = InstantUtils.toDateString(Instant.now()).replace("-", ""); - - StringBuilder result = new StringBuilder(); - result.append(date); - - for(String name : etcName){ - result.append("-") - .append(name); - } - - result.append(this.FILE_EXTENSION); - - return result.toString(); - } - - /** - * PDF 생성 - * @param vo - * @return - */ - public ComFileBas makeLaancPdf(LaancPdfVO vo){ - - String airUser = vo.getUserName(); - String etc = String.valueOf(System.currentTimeMillis()); // 동명이인 방지 - String fileName = getLaancSaveName(airUser, etc); - - String htmlContent = pdfUtils.getHtmlToString(vo); - ComFileBas comFileBas = pdfUtils.generatePDF(htmlContent, fileName); - - String userId = jwtTokenUtil.getUserIdByToken(); - comFileBas.setCreateUserId(userId); - - return comFileBas; - } - - - - /** - * DB 인서트, 최신데이터 가져온 후 Group NO 1추가함 - * @param comFileBas - */ - @Transactional - public void save(ComFileBas comFileBas){ - - // DB Insert - ComFileBas lastComFileBas = comFileBasRepository.findFirstByOrderByFileSnoDesc(); - int fileGroupNo = (lastComFileBas == null) ? 1 : lastComFileBas.getFileGroupNo() + 1; - - comFileBas.setFileGroupNo(fileGroupNo); - - comFileBasRepository.save(comFileBas); - } - - /** - * 파일 다운로드 - * @param fileSno - * @param response - */ - public void fileDownload(int fileSno) { - - ComFileBas comFileBas = comFileBasRepository.findById(fileSno).orElse(null); - if(comFileBas == null) throw new CustomException(ErrorCode.DATA_NOTFIND); - - pdfUtils.fileDownload(comFileBas); - - } - -} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/controller/BasLaancController.java b/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/controller/BasLaancController.java index 86e51ca5..c6054505 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/controller/BasLaancController.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/controller/BasLaancController.java @@ -1,8 +1,7 @@ package com.palnet.biz.api.bas.laanc.controller; -import com.palnet.biz.api.bas.flight.template.service.TemplateService; -import com.palnet.biz.api.bas.laanc.model.BasLaancPlanRq; import com.palnet.biz.api.bas.laanc.model.BasLaancLastRs; +import com.palnet.biz.api.bas.laanc.model.BasLaancPlanRq; import com.palnet.biz.api.bas.laanc.model.BasLaancValidatedRs; import com.palnet.biz.api.bas.laanc.service.BasLaancService; import com.palnet.biz.api.comn.response.BasicResponse; @@ -16,7 +15,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @@ -40,13 +42,12 @@ import java.util.Map; public class BasLaancController { private final BasLaancService basLaancService; - private final TemplateService templateService; // LAANC 검증 @PostMapping(value = "/plan/valid") @ApiOperation(value = "LAANC 검증") @Tag(name = "LAANC 검증", description = "LAANC 관련 API") - public ResponseEntity validationLaanc(BasLaancPlanRq rq) { + public ResponseEntity validationLaanc(@RequestBody BasLaancPlanRq rq) { BasLaancValidatedRs rs = null; try { log.debug(">>> rq : {}", rq); @@ -93,11 +94,4 @@ public class BasLaancController { return ResponseEntity.ok().body(new SuccessResponse<>(rs)); } - @GetMapping("/laanc-pdf/download") - @Tag(name = "비행계획서", description = "비행계획서 관련 API") - @ApiOperation(value = "Laanc 공문 다운로드") - public void downloadPDF(int fileSno) { - - templateService.fileDownload(fileSno); - } } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancMapper.java b/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancMapper.java index cc741423..022a7232 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancMapper.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancMapper.java @@ -6,9 +6,7 @@ import com.palnet.biz.api.bas.laanc.model.BasLaancAreaCoordModel; import com.palnet.biz.api.bas.laanc.model.BasLaancAreaModel; import com.palnet.biz.api.bas.laanc.model.BasLaancPlanRq; import com.palnet.biz.jpa.entity.*; -import org.mapstruct.Mapper; -import org.mapstruct.MappingTarget; -import org.mapstruct.ReportingPolicy; +import org.mapstruct.*; import org.mapstruct.factory.Mappers; /** @@ -22,12 +20,14 @@ import org.mapstruct.factory.Mappers; * ----------------------------------------------------------- * 2023-09-22(022) dhji 최초 생성 */ -@Mapper(unmappedSourcePolicy = ReportingPolicy.IGNORE, unmappedTargetPolicy = ReportingPolicy.IGNORE) +@Mapper(unmappedSourcePolicy = ReportingPolicy.IGNORE, unmappedTargetPolicy = ReportingPolicy.IGNORE, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface BasLaancMapper { BasLaancMapper MAPPER = Mappers.getMapper(BasLaancMapper.class); FltPlanBas mergeToEntity(@MappingTarget FltPlanBas rq1, FltPlanBas rq2); + @Mapping(source = "updateUserId", target = "updateUserId", ignore = true) + @Mapping(source = "updateDt", target = "updateDt", ignore = true) FltPlanBas modelToPlanEntity(AnctCstmrModel rq); FltPlanBas modelToPlanEntity(BasLaancPlanRq rq); diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancService.java b/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancService.java index f47d1cd4..1b0e6bf2 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancService.java @@ -4,12 +4,15 @@ import com.palnet.biz.api.acnt.cstmr.model.AnctCstmrModel; import com.palnet.biz.api.acnt.cstmr.model.AnctCstmrTermsModel; import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil; import com.palnet.biz.api.bas.laanc.model.*; +import com.palnet.biz.api.comn.file.model.LaancPdfModel; +import com.palnet.biz.api.comn.file.service.ComnFileService; import com.palnet.biz.api.external.model.PilotValidRq; import com.palnet.biz.api.external.model.PilotValidRs; import com.palnet.biz.api.external.service.TsService; import com.palnet.biz.jpa.entity.*; import com.palnet.biz.jpa.repository.flt.*; import com.palnet.biz.jpa.repository.pty.PtyCstmrQueryRepository; +import com.palnet.biz.jpa.repository.pty.PtyGroupBasRepository; import com.palnet.biz.jpa.repository.pty.PtyGroupQueryRepository; import com.palnet.biz.jpa.repository.pty.PtyTermsAgreeTxnRepository; import com.palnet.biz.scheduler.ctr.service.CtrTrnsLctnService; @@ -23,6 +26,7 @@ import lombok.extern.slf4j.Slf4j; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.time.Instant; import java.util.ArrayList; @@ -46,20 +50,20 @@ import java.util.stream.Collectors; public class BasLaancService { - private final CtrTrnsLctnService ctrTrnsLctnService; + private final PtyGroupBasRepository ptyGroupBasRepository; private final FltPlanBasRepository fltPlanBasRepository; private final FltPlanArcrftRepository fltPlanArcrftRepository; private final FltPlanAreaRepository fltPlanAreaRepository; private final FltPlanAreaCoordRepository fltPlanAreaCoordRepository; private final FltPlanPilotRepository fltPlanPilotRepository; - private final FltPlanQueryRepository fltPlanQueryRepository; - private final PtyGroupQueryRepository ptyPlanQueryRepository; private final PtyCstmrQueryRepository ptyCstmrQueryRepository; private final PtyTermsAgreeTxnRepository ptyTermsAgreeTxnRepository; private final TsService tsService; + private final ComnFileService comnFileService; private final JwtTokenUtil jwtTokenUtil; private final AreaUtils areaUtils; + private final String FILE_DOWNLOAD_URL = "/api/comn/file/download"; // LAANC 검증 public BasLaancValidatedRs validationLaanc(BasLaancPlanRq rq) { @@ -88,6 +92,7 @@ public class BasLaancService { } // 비행계획서 등록, 약관 등록, 공문 생성 + @Transactional public BasLaancLastRs createFlightPlan(BasLaancPlanRq rq) { BasLaancValidatedRs basLaancValidatedRs = this.validationAreaAndArcrft(rq); // LAANC가 검증된것들만 DB저장 @@ -99,14 +104,24 @@ public class BasLaancService { Integer cstmrSno = jwtTokenUtil.getCstmrSnoByToken(); // 개인정보 가져오기 - 비행계획서 작성자 정보, 조종사 정보 AnctCstmrModel cstmrInfo = ptyCstmrQueryRepository.findByCstmrSno(cstmrSno); - FltPlanBas cstmrFltPlanBas = BasLaancMapper.MAPPER.modelToPlanEntity(cstmrInfo); + FltPlanBas fltPlanBas = BasLaancMapper.MAPPER.modelToPlanEntity(cstmrInfo); FltPlanBas rqFltPlanBas = BasLaancMapper.MAPPER.modelToPlanEntity(rq); - FltPlanBas fltPlanBas = BasLaancMapper.MAPPER.mergeToEntity(rqFltPlanBas, cstmrFltPlanBas); + BasLaancMapper.MAPPER.mergeToEntity(fltPlanBas, rqFltPlanBas); fltPlanBas.setDelYn("N"); - fltPlanBas.setAprvlYn("N"); + fltPlanBas.setAprvlYn("Y"); fltPlanBas.setCreateUserId(userId); fltPlanBas.setUpdateUserId(userId); + + // KAC 그룹 ID - LAANC에서는 KAC 그룹으로만 보여주도록 함. + String groupId = ""; + String groupNm = ""; + List kac = ptyGroupBasRepository.findByGroupNm("KAC"); + if(kac != null && !kac.isEmpty()) { + groupId = kac.get(0).getGroupId(); + groupNm = kac.get(0).getGroupNm(); + } + fltPlanBas.setGroupId(groupId); // 사업자 유무 - TS 데이터 fltPlanBas.setCorpRegYn(rq.getValidatedRs().getCorpRegYn()); // 사업자유무 fltPlanBas.setServiceType("PAV-KAC"); @@ -139,6 +154,7 @@ public class BasLaancService { // 조종사 - 사용자 정보로 저장 FltPlanPilot pilotEntity = BasLaancMapper.MAPPER.modelToPilotEntity(cstmrInfo); pilotEntity.setPlanSno(planSno); + pilotEntity.setGroupNm(groupNm); pilotEntity.setCreateUserId(userId); pilotEntity.setUpdateUserId(userId); fltPlanPilotRepository.save(pilotEntity); @@ -177,10 +193,19 @@ public class BasLaancService { } else { throw new CustomException(ErrorCode.FAIL, "약관등록 실패"); } - // TODO PDF 생성 후 URL 가져오기 + // PDF 생성 후 URL 가져오기 + LaancPdfModel laancPdfModel = new LaancPdfModel(); + laancPdfModel.setUserName(fltPlanBas.getMemberName()); + ComFileBas comFileBas = comnFileService.makePdf(laancPdfModel); + + StringBuilder sb = new StringBuilder(); + sb.append(FILE_DOWNLOAD_URL) + .append("?fileSno=") + .append(comFileBas.getFileSno()); BasLaancLastRs rs = BasLaancLastRs.builder() - .pdfUrl("....") + .pdfUrl(sb.toString()) .build(); + return rs; } diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/file/controller/ComnFileController.java b/pav-server/src/main/java/com/palnet/biz/api/comn/file/controller/ComnFileController.java new file mode 100644 index 00000000..6e8ba7fe --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/file/controller/ComnFileController.java @@ -0,0 +1,41 @@ +package com.palnet.biz.api.comn.file.controller; + +import com.palnet.biz.api.comn.file.service.ComnFileService; +import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * packageName : com.palnet.biz.api.comn.file.controller + * fileName : ComnFileController + * author : dhji + * date : 2023-09-25(025) + * description : + * =========================================================== + * DATE AUTHOR NOTE + * ----------------------------------------------------------- + * 2023-09-25(025) dhji 최초 생성 + */ +@Slf4j +@Tag(name = "공통 파일", description = "공통 파일 관련 API") +@RequiredArgsConstructor +@RequestMapping("/api/comn/file") +@RestController +public class ComnFileController { + + private final ComnFileService comnFileService; + + @GetMapping("/download") + @ApiOperation(value = "파일 다운로드") + public void downloadPDF(int fileSno) { + try { + comnFileService.fileDownload(fileSno); + } catch (Exception e) { + log.error("ERROR: ", e); + } + } +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/LaancPdfVO.java b/pav-server/src/main/java/com/palnet/biz/api/comn/file/model/LaancPdfModel.java similarity index 74% rename from pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/LaancPdfVO.java rename to pav-server/src/main/java/com/palnet/biz/api/comn/file/model/LaancPdfModel.java index 5ac4fed0..6f7cdabe 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/LaancPdfVO.java +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/file/model/LaancPdfModel.java @@ -1,16 +1,13 @@ -package com.palnet.biz.api.bas.flight.template.vo; +package com.palnet.biz.api.comn.file.model; import java.lang.reflect.Field; import java.util.HashMap; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import lombok.*; -@Getter -@Setter -@ToString -public class LaancPdfVO extends PdfBaseVO{ +@Data +@EqualsAndHashCode(callSuper = true) +public class LaancPdfModel extends PdfBaseModel { // TODO : 아직 파라미터가 정해지지 않음 private String userName; // 조종사 이름 @@ -19,8 +16,12 @@ public class LaancPdfVO extends PdfBaseVO{ private String userGender; // 조종사 성별 + // 정적 이미지 + private String imgMlit; + private String imgExpo; - public LaancPdfVO (){ + + public LaancPdfModel(){ init(); } @@ -48,7 +49,7 @@ public class LaancPdfVO extends PdfBaseVO{ @Override public void init() { - super.setTemplate("official_document"); + super.setTemplate("laanc/official_document"); } } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/PdfBaseVO.java b/pav-server/src/main/java/com/palnet/biz/api/comn/file/model/PdfBaseModel.java similarity index 65% rename from pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/PdfBaseVO.java rename to pav-server/src/main/java/com/palnet/biz/api/comn/file/model/PdfBaseModel.java index 624c17bc..ea8fc9b0 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/PdfBaseVO.java +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/file/model/PdfBaseModel.java @@ -1,11 +1,11 @@ -package com.palnet.biz.api.bas.flight.template.vo; +package com.palnet.biz.api.comn.file.model; import java.util.Map; import lombok.Data; @Data -public abstract class PdfBaseVO { +public abstract class PdfBaseModel { private String template; diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/file/service/ComnFileService.java b/pav-server/src/main/java/com/palnet/biz/api/comn/file/service/ComnFileService.java new file mode 100644 index 00000000..d008dd79 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/file/service/ComnFileService.java @@ -0,0 +1,148 @@ +package com.palnet.biz.api.comn.file.service; + +import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil; +import com.palnet.biz.api.comn.file.model.LaancPdfModel; +import com.palnet.biz.jpa.entity.ComFileBas; +import com.palnet.biz.jpa.repository.com.ComFileBasRepository; +import com.palnet.comn.code.ErrorCode; +import com.palnet.comn.exception.CustomException; +import com.palnet.comn.utils.InstantUtils; +import com.palnet.comn.utils.PdfUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.io.File; +import java.io.IOException; +import java.time.Instant; +import java.util.Base64; + +@Slf4j +@RequiredArgsConstructor +@Service +public class ComnFileService { + + private final PdfUtils pdfUtils; + private final JwtTokenUtil jwtTokenUtil; + private final ComFileBasRepository comFileBasRepository; + + private final String FILE_EXTENSION = ".pdf"; + + /** + * 파일명 만들기, 앞에 기본으로 금일 날짜있음 + * [예시] 20230102_[추가파라미터] + * + * @param etcName + * @return + */ + private String getLaancSaveName(String... etcName) { + + String date = InstantUtils.toDatetimeStringByFormat(Instant.now(), "yyyyMMddHHmmss"); + + StringBuilder result = new StringBuilder(); + result.append(date); + + for (String name : etcName) { + result.append("-") + .append(name); + } + + result.append(this.FILE_EXTENSION); + + return result.toString(); + } + + /** + * PDF 생성 + * + * @param model + * @return + */ + public ComFileBas makePdf(LaancPdfModel model) { + + String airUser = model.getUserName(); + String etc = String.valueOf(System.currentTimeMillis()); // 동명이인 방지 + String fileName = getLaancSaveName(airUser, etc); + + // TODO 추후 img tag의 src로 들어가는 이미지들을 base64로 변환하여 html에 넣어줘야함 + // images 넣기(임시) + log.debug(">>> {}", model.getTemplate()); + if ("laanc/official_document".equals(model.getTemplate())) { + System.out.println("!!!!! official_document.html"); + String imgMlit = imagesToBase64ForSrc("templates/imgs/od-mlit.jpg"); + model.setImgMlit(imgMlit); + String imgExpo = imagesToBase64ForSrc("templates/imgs/od-expo2030.png"); + model.setImgExpo(imgExpo); + } + + String htmlContent = pdfUtils.getHtmlToString(model); + System.out.println(">>>" + htmlContent); + ComFileBas comFileBas = pdfUtils.generatePDF(htmlContent, fileName); + + String userId = jwtTokenUtil.getUserIdByToken(); + if (userId == null) userId = "NONE"; + comFileBas.setCreateUserId(userId); + return this.save(comFileBas); + } + + /** + * DB 인서트, 최신데이터 가져온 후 Group NO 1추가함 + * + * @param comFileBas + * @return + */ + @Transactional + public ComFileBas save(ComFileBas comFileBas) { + + // DB Insert +// ComFileBas lastComFileBas = comFileBasRepository.findFirstByOrderByFileSnoDesc(); + ComFileBas lastComFileBas = comFileBasRepository.findFirstByOrderByFileGroupNoDesc(); + int fileGroupNo = (lastComFileBas == null) ? 1 : lastComFileBas.getFileGroupNo() + 1; + + comFileBas.setFileGroupNo(fileGroupNo); + + return comFileBasRepository.save(comFileBas); + } + + /** + * 파일 다운로드 + * + * @param fileSno + */ + public void fileDownload(int fileSno) { + + ComFileBas comFileBas = comFileBasRepository.findById(fileSno).orElse(null); + if (comFileBas == null) throw new CustomException(ErrorCode.DATA_NOTFIND); + + pdfUtils.fileDownload(comFileBas); + + } + + public String imagesToBase64ForSrc(String path) { + StringBuilder str = new StringBuilder(); + ClassPathResource resource = new ClassPathResource(path); + File file = null; + try { + file = resource.getFile(); + System.out.println(file.getName()); + String ext = FilenameUtils.getExtension(file.getName()); + byte[] fileContent = FileUtils.readFileToByteArray(file); + String encodedString = Base64.getEncoder().encodeToString(fileContent); + str + .append("data:image/") + .append(ext) + .append(";base64,") + .append(encodedString); + + } catch (IOException e) { + throw new RuntimeException(e); + } + return str.toString(); + } + + +} diff --git a/pav-server/src/main/java/com/palnet/biz/config/WebSecurityConfig.java b/pav-server/src/main/java/com/palnet/biz/config/WebSecurityConfig.java index 80fe559a..22c1a1aa 100644 --- a/pav-server/src/main/java/com/palnet/biz/config/WebSecurityConfig.java +++ b/pav-server/src/main/java/com/palnet/biz/config/WebSecurityConfig.java @@ -39,6 +39,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { "/api/acnt/**", "/api/ctr/cntrl/id/**", "/api/server/**", +// "/api/comn/file/download", /* swagger v2 */ "/v2/api-docs", "/swagger-resources", diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/entity/ComFileBas.java b/pav-server/src/main/java/com/palnet/biz/jpa/entity/ComFileBas.java index 146f7bf9..f4aff75f 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/entity/ComFileBas.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/entity/ComFileBas.java @@ -19,6 +19,7 @@ public class ComFileBas implements Serializable { private static final long serialVersionUID = 1L; @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="FILE_SNO") private int fileSno; diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComFileBasRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComFileBasRepository.java index 552c6620..0586623d 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComFileBasRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComFileBasRepository.java @@ -8,5 +8,7 @@ import com.palnet.biz.jpa.entity.ComFileBas; @Repository public interface ComFileBasRepository extends JpaRepository{ - public ComFileBas findFirstByOrderByFileSnoDesc(); + ComFileBas findFirstByOrderByFileSnoDesc(); + + ComFileBas findFirstByOrderByFileGroupNoDesc(); } diff --git a/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java index e453e2fc..7285d7dd 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java @@ -4,7 +4,6 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.tomcat.util.modeler.FeatureInfo; import org.geotools.geojson.feature.FeatureJSON; import org.geotools.geojson.geom.GeometryJSON; import org.json.simple.JSONArray; diff --git a/pav-server/src/main/java/com/palnet/comn/utils/PdfUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/PdfUtils.java index 21242f01..7f75825f 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/PdfUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/PdfUtils.java @@ -1,15 +1,26 @@ package com.palnet.comn.utils; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.StringReader; +import com.itextpdf.html2pdf.ConverterProperties; +import com.itextpdf.html2pdf.HtmlConverter; +import com.itextpdf.io.font.PdfEncodings; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfWriter; +import com.itextpdf.layout.font.FontProvider; +import com.palnet.biz.api.comn.file.model.PdfBaseModel; +import com.palnet.biz.jpa.entity.ComFileBas; +import com.palnet.comn.code.ErrorCode; +import com.palnet.comn.exception.CustomException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; import java.net.URLEncoder; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.time.Instant; @@ -17,44 +28,13 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.thymeleaf.TemplateEngine; -import org.thymeleaf.context.Context; - -import com.itextpdf.text.Document; -import com.itextpdf.text.DocumentException; -import com.itextpdf.text.pdf.PdfWriter; -import com.itextpdf.tool.xml.XMLWorker; -import com.itextpdf.tool.xml.XMLWorkerFontProvider; -import com.itextpdf.tool.xml.XMLWorkerHelper; -import com.itextpdf.tool.xml.css.CssFile; -import com.itextpdf.tool.xml.css.StyleAttrCSSResolver; -import com.itextpdf.tool.xml.html.CssAppliers; -import com.itextpdf.tool.xml.html.CssAppliersImpl; -import com.itextpdf.tool.xml.html.Tags; -import com.itextpdf.tool.xml.parser.XMLParser; -import com.itextpdf.tool.xml.pipeline.css.CSSResolver; -import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline; -import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline; -import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline; -import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext; -import com.palnet.biz.api.bas.flight.template.vo.PdfBaseVO; -import com.palnet.biz.jpa.entity.ComFileBas; -import com.palnet.comn.code.ErrorCode; -import com.palnet.comn.exception.CustomException; - +@Slf4j +@RequiredArgsConstructor @Component public class PdfUtils { - - @Autowired - private HttpServletResponse response; - @Autowired - private TemplateEngine templateEngine; + private final HttpServletResponse response; + private final TemplateEngine templateEngine; @Value("${base-url}") private String BASE_PATH; @@ -64,20 +44,21 @@ public class PdfUtils { /** * Thymeleaf HTML 파일을 데이터 바인딩하여 String으로 변환 + * * @param * @param pdfDto * @return */ - public String getHtmlToString(T pdfDto){ + public String getHtmlToString(T pdfDto) { Map param = pdfDto.getParam(); // Thymeleaf 방식 html에 입힐 데이터 바인딩 - Context context = new Context(); + Context context = new Context(); - for(Entry entry : param.entrySet()){ + for (Entry entry : param.entrySet()) { String key = entry.getKey(); - + context.setVariable(key, param.get(key)); } @@ -90,86 +71,51 @@ public class PdfUtils { /** * HTML 태그로 이루어진 String값을 PDF로 변환 + * * @param htmlContent * @param fileName * @return */ - public ComFileBas generatePDF(String htmlContent, String fileName){ - - // PDF 용지 설정하기 - Document pdfDocument = new Document(); + public ComFileBas generatePDF(String htmlContent, String fileName) { + ComFileBas result = new ComFileBas(); - - String pdfPath = new StringBuilder() - .append(this.BASE_PATH) - .append(InstantUtils.toDateString(Instant.now()).replace("-", "")) - .append("/").toString(); - try { - - // 폴더 생성 - new File(pdfPath).mkdirs(); - - // File 저장 기본경로는 main 아래로 기본으로 잡힘 - PdfWriter writer = PdfWriter.getInstance(pdfDocument, new FileOutputStream(pdfPath + fileName)); - writer.setInitialLeading(12.5f); - - pdfDocument.open(); - - /* - CSS 설정 - TODO : CSS 파일이 따로 있을시 임포트해주는 방법, CSS 파일 적용은 필수는 아니지만, 글꼴 적용은 꼭해야만 함 - jar변환 시 CSS파일을 못 찾을수도 있어서 InputStream 사용 - CSS의 색깔은 키워드로 표기 X, #e73a3a 등 16진법으로 표기 해야함 - */ - InputStream cssStream = getClass().getClassLoader().getResourceAsStream("static/css/pdf.css"); - CssFile cssFile = XMLWorkerHelper.getCSS(cssStream); - CSSResolver cssResolver = new StyleAttrCSSResolver(); - cssResolver.addCss(cssFile); - - // Font 설정 - XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS); - fontProvider.register("static/font/NanumGothic.ttf", "NanumGothic"); - CssAppliers cssAppliers = new CssAppliersImpl(fontProvider); - - // XML Worker에 넣을 PipeLine객체 생성, CssResolverPipeline 이 객체를 최종적으로 넣어야 Font,Css가 적용됨 - HtmlPipelineContext htmlPipelineContext = new HtmlPipelineContext(cssAppliers); - htmlPipelineContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); - - PdfWriterPipeline pdfWriterPipeline = new PdfWriterPipeline(pdfDocument, writer); - HtmlPipeline htmlPipeline = new HtmlPipeline(htmlPipelineContext, pdfWriterPipeline); - CssResolverPipeline cssResolverPipeline = new CssResolverPipeline(cssResolver, htmlPipeline); - - StringReader stringReader = new StringReader(htmlContent); - - XMLWorker xmlWorker = new XMLWorker(cssResolverPipeline, true); - XMLParser xmlParser = new XMLParser(xmlWorker, Charset.forName("UTF-8")); - - xmlParser.parse(stringReader); + String pdfPath = this.BASE_PATH + InstantUtils.toDateStringByFormat(Instant.now(), "yyyyMMdd") + "/"; + String pdfFilePath = pdfPath + fileName; + + File path = new File(pdfPath); + boolean mkdirs = path.mkdirs(); + log.debug(">>> 폴더 생성여부 : {}", mkdirs); + + // PDF 생성 + try (FileOutputStream fileOutputStream = new FileOutputStream(pdfFilePath)) { + PdfWriter pdfWriter = new PdfWriter(fileOutputStream); + PdfDocument pdfDoc = new PdfDocument(pdfWriter); + ConverterProperties converterProperties = new ConverterProperties(); + + // FontProvider를 사용하여 한글 폰트 지정 + FontProvider fontProvider = new FontProvider(); + fontProvider.addFont("templates/fonts/NanumGothic.ttf", PdfEncodings.IDENTITY_H); + converterProperties.setFontProvider(fontProvider); + + HtmlConverter.convertToPdf(htmlContent, pdfDoc, converterProperties); } catch (IOException e) { - e.printStackTrace(); - } catch (DocumentException e){ - e.printStackTrace(); - } catch (Exception e){ - e.printStackTrace(); - } - finally{ - pdfDocument.close(); - } - + throw new RuntimeException(e); + } + result.setFileGroupNo(0); result.setFilePath(pdfPath); result.setFileExt(this.FILE_EXTENSION); - result.setCreateDt(Instant.now()); + result.setCreateDt(Instant.now()); result.setFileSaveNm(fileName); result.setFileOriNm(fileName); - try { + try { String filePath = result.getFileOriNm(); long fileSize = Files.size(Paths.get(pdfPath + filePath)) / 1024; - if(fileSize >= 0) result.setFileSize(String.valueOf(fileSize)); + if (fileSize >= 0) result.setFileSize(String.valueOf(fileSize)); } catch (IOException e) { e.printStackTrace(); } @@ -179,52 +125,53 @@ public class PdfUtils { /** * 파일 Download + * * @param comFileBas */ - public void fileDownload(ComFileBas comFileBas){ + public void fileDownload(ComFileBas comFileBas) { InputStream inputStream = null; OutputStream outputStream = null; try { - File pdfFile = new File(comFileBas.getFilePath() + comFileBas.getFileSaveNm()); - inputStream = new FileInputStream(pdfFile); + File pdfFile = new File(comFileBas.getFilePath() + comFileBas.getFileSaveNm()); + inputStream = new FileInputStream(pdfFile); String fileOriName = comFileBas.getFileOriNm(); - fileOriName = URLEncoder.encode(comFileBas.getFileOriNm(), "UTF-8"); + fileOriName = URLEncoder.encode(comFileBas.getFileOriNm(), StandardCharsets.UTF_8); response.setContentType("application/octet-stream"); response.setCharacterEncoding("UTF-8"); - response.setHeader("Content-Disposition", "attachment; filename=\"" + fileOriName + "\""); + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileOriName + "\""); // response.setContentLengthLong(Long.parseLong(comFileBas.getFileSize())); // response.setStatus(HttpServletResponse.SC_OK); outputStream = response.getOutputStream(); byte[] buffer = new byte[1024]; //1KB 설정 - int length; - - while((length = inputStream.read(buffer)) != -1) { - outputStream.write(buffer); - } + int length; + + while ((length = inputStream.read(buffer)) != -1) { + outputStream.write(buffer); + } } catch (FileNotFoundException e) { throw new CustomException(ErrorCode.DATA_NO); - } catch (IOException e){ + } catch (IOException e) { e.printStackTrace(); - } finally { + } finally { try { - if(outputStream != null){ + if (outputStream != null) { Objects.requireNonNull(outputStream).flush(); - outputStream.close(); + outputStream.close(); } - if(inputStream != null){ + if (inputStream != null) { inputStream.close(); - } + } } catch (IOException e) { e.printStackTrace(); } - - } + + } } } diff --git a/pav-server/src/main/resources/application.yml b/pav-server/src/main/resources/application.yml index 691dc309..a3b9a4e8 100644 --- a/pav-server/src/main/resources/application.yml +++ b/pav-server/src/main/resources/application.yml @@ -63,7 +63,7 @@ api: client-secret-key: Q4K4OtUYol search-url : https://openapi.naver.com/v1/search/local.json -base-url: +base-url: files/ --- diff --git a/pav-server/src/main/resources/static/css/pdf.css b/pav-server/src/main/resources/static/css/pdf.css deleted file mode 100644 index 2567b876..00000000 --- a/pav-server/src/main/resources/static/css/pdf.css +++ /dev/null @@ -1,12 +0,0 @@ - -body{ - font-family: NanumGothic; -} - -p{ - background-color: #e73a3a; -} - -div { - background-color: #e73a3a; -} \ No newline at end of file diff --git a/pav-server/src/main/resources/static/font/NanumGothic.ttf b/pav-server/src/main/resources/templates/fonts/NanumGothic.ttf similarity index 52% rename from pav-server/src/main/resources/static/font/NanumGothic.ttf rename to pav-server/src/main/resources/templates/fonts/NanumGothic.ttf index 75d010a5..009887a1 100644 Binary files a/pav-server/src/main/resources/static/font/NanumGothic.ttf and b/pav-server/src/main/resources/templates/fonts/NanumGothic.ttf differ diff --git a/pav-server/src/main/resources/templates/imgs/od-expo2030.png b/pav-server/src/main/resources/templates/imgs/od-expo2030.png new file mode 100644 index 00000000..dd9f427c Binary files /dev/null and b/pav-server/src/main/resources/templates/imgs/od-expo2030.png differ diff --git a/pav-server/src/main/resources/templates/imgs/od-mlit.jpg b/pav-server/src/main/resources/templates/imgs/od-mlit.jpg new file mode 100644 index 00000000..eca1d242 Binary files /dev/null and b/pav-server/src/main/resources/templates/imgs/od-mlit.jpg differ diff --git a/pav-server/src/main/resources/templates/laanc/official_document.html b/pav-server/src/main/resources/templates/laanc/official_document.html new file mode 100644 index 00000000..fc3b157d --- /dev/null +++ b/pav-server/src/main/resources/templates/laanc/official_document.html @@ -0,0 +1,30 @@ + + + + + + + + +11 +11 +
+

Thymeleaf Tutorials

+

이름 : [[${userName}]]

+

나이 : [[${userAge}]]

+

성별 : [[${userGender}]]

+ + diff --git a/pav-server/src/main/resources/templates/official_document.html b/pav-server/src/main/resources/templates/official_document.html deleted file mode 100644 index ed34dda2..00000000 --- a/pav-server/src/main/resources/templates/official_document.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - -

Thymeleaf Tutorials

-

이름 : [[${userName}]]

-

나이 : [[${userAge}]]

-

성별 : [[${userGender}]]

- - diff --git a/pav-server/src/test/java/com/palnet/biz/api/comn/file/service/ComnFileServiceTest.java b/pav-server/src/test/java/com/palnet/biz/api/comn/file/service/ComnFileServiceTest.java new file mode 100644 index 00000000..b10f75ed --- /dev/null +++ b/pav-server/src/test/java/com/palnet/biz/api/comn/file/service/ComnFileServiceTest.java @@ -0,0 +1,27 @@ +package com.palnet.biz.api.comn.file.service; + +import com.palnet.biz.api.comn.file.model.LaancPdfModel; +import com.palnet.biz.jpa.entity.ComFileBas; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + + +@ActiveProfiles("local") +@SpringBootTest +class ComnFileServiceTest { + + @Autowired + private ComnFileService comnFileService; + + @Test + void makePdf() { + LaancPdfModel model = new LaancPdfModel(); + model.setUserName("test"); + model.setUserGender("M"); + model.setUserName("쿠쿠다스"); + ComFileBas comFileBas = comnFileService.makePdf(model); + System.out.println(comFileBas.toString()); + } +} \ No newline at end of file