Browse Source

laanc 새로운 페이지에 따른 api 생성

pull/10/head
지대한 1 year ago
parent
commit
bc3888ec94
  1. 13
      pav-server/build.gradle
  2. 17
      pav-server/src/main/java/com/palnet/biz/api/bas/flight/controller/BasFlightController.java
  3. 112
      pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/service/TemplateService.java
  4. 18
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/controller/BasLaancController.java
  5. 8
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancMapper.java
  6. 41
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancService.java
  7. 41
      pav-server/src/main/java/com/palnet/biz/api/comn/file/controller/ComnFileController.java
  8. 21
      pav-server/src/main/java/com/palnet/biz/api/comn/file/model/LaancPdfModel.java
  9. 4
      pav-server/src/main/java/com/palnet/biz/api/comn/file/model/PdfBaseModel.java
  10. 148
      pav-server/src/main/java/com/palnet/biz/api/comn/file/service/ComnFileService.java
  11. 1
      pav-server/src/main/java/com/palnet/biz/config/WebSecurityConfig.java
  12. 1
      pav-server/src/main/java/com/palnet/biz/jpa/entity/ComFileBas.java
  13. 4
      pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComFileBasRepository.java
  14. 1
      pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java
  15. 205
      pav-server/src/main/java/com/palnet/comn/utils/PdfUtils.java
  16. 2
      pav-server/src/main/resources/application.yml
  17. 12
      pav-server/src/main/resources/static/css/pdf.css
  18. BIN
      pav-server/src/main/resources/templates/fonts/NanumGothic.ttf
  19. BIN
      pav-server/src/main/resources/templates/imgs/od-expo2030.png
  20. BIN
      pav-server/src/main/resources/templates/imgs/od-mlit.jpg
  21. 30
      pav-server/src/main/resources/templates/laanc/official_document.html
  22. 12
      pav-server/src/main/resources/templates/official_document.html
  23. 27
      pav-server/src/test/java/com/palnet/biz/api/comn/file/service/ComnFileServiceTest.java

13
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') {

17
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);
}

112
pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/service/TemplateService.java

@ -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);
}
}

18
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<? extends BasicResponse> validationLaanc(BasLaancPlanRq rq) {
public ResponseEntity<? extends BasicResponse> 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);
}
}

8
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);

41
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<PtyGroupBas> 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;
}

41
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);
}
}
}

21
pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/LaancPdfVO.java → 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");
}
}

4
pav-server/src/main/java/com/palnet/biz/api/bas/flight/template/vo/PdfBaseVO.java → 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;

148
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();
}
}

1
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",

1
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;

4
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<ComFileBas, Integer>{
public ComFileBas findFirstByOrderByFileSnoDesc();
ComFileBas findFirstByOrderByFileSnoDesc();
ComFileBas findFirstByOrderByFileGroupNoDesc();
}

1
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;

205
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 <T>
* @param pdfDto
* @return
*/
public <T extends PdfBaseVO> String getHtmlToString(T pdfDto){
public <T extends PdfBaseModel> String getHtmlToString(T pdfDto) {
Map<String, Object> param = pdfDto.getParam();
// Thymeleaf 방식 html에 입힐 데이터 바인딩
Context context = new Context();
Context context = new Context();
for(Entry<String, Object> entry : param.entrySet()){
for (Entry<String, Object> 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();
}
}
}
}
}

2
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/
---

12
pav-server/src/main/resources/static/css/pdf.css

@ -1,12 +0,0 @@
body{
font-family: NanumGothic;
}
p{
background-color: #e73a3a;
}
div {
background-color: #e73a3a;
}

BIN
pav-server/src/main/resources/static/font/NanumGothic.ttf → pav-server/src/main/resources/templates/fonts/NanumGothic.ttf

Binary file not shown.

BIN
pav-server/src/main/resources/templates/imgs/od-expo2030.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
pav-server/src/main/resources/templates/imgs/od-mlit.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

30
pav-server/src/main/resources/templates/laanc/official_document.html

@ -0,0 +1,30 @@
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
body {
font-family: NanumGothic, serif;
}
p {
background-color: #e73a3a;
}
div {
background-color: #e73a3a;
}
</style>
</head>
<!--<body style="font-family: NanumGothic, serif;">-->
<body>
<img style="width:100px; height:100px;" th:src="@{${imgMlit}}" alt="11"/>
<img style="width:100px; height:100px;" th:src="@{${imgExpo}}" alt="11"/>
<hr/>
<p style="color: #3ae743; height: 100px">Thymeleaf Tutorials</p>
<p>이름 : [[${userName}]]</p>
<p>나이 : [[${userAge}]]</p>
<p>성별 : [[${userGender}]]</p>
</body>
</html>

12
pav-server/src/main/resources/templates/official_document.html

@ -1,12 +0,0 @@
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<p>Thymeleaf Tutorials</p>
<p>이름 : [[${userName}]]</p>
<p>나이 : [[${userAge}]]</p>
<p>성별 : [[${userGender}]]</p>
</body>
</html>

27
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());
}
}
Loading…
Cancel
Save