diff --git a/data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java b/data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java index 1899853..6eb5fc8 100644 --- a/data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java +++ b/data/com/src/main/java/kr/co/palnet/kac/data/com/domain/ComConfirmBas.java @@ -6,7 +6,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.time.Instant; +import java.time.LocalDateTime; @Data @Builder @@ -61,7 +61,7 @@ public class ComConfirmBas { // 생성일시 @Column(name = "CREATE_DT", columnDefinition = "datetime", updatable = false, nullable = false) - private Instant createDt; + private LocalDateTime createDt; // 수정사용자ID @Column(name = "UPDATE_USER_ID", length = 30, nullable = false) @@ -69,6 +69,6 @@ public class ComConfirmBas { // 수정일시 @Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false) - private Instant updateDt; + private LocalDateTime updateDt; } diff --git a/data/com/src/main/java/kr/co/palnet/kac/data/com/service/ComConfirmDomainService.java b/data/com/src/main/java/kr/co/palnet/kac/data/com/service/ComConfirmDomainService.java new file mode 100644 index 0000000..92f48f7 --- /dev/null +++ b/data/com/src/main/java/kr/co/palnet/kac/data/com/service/ComConfirmDomainService.java @@ -0,0 +1,20 @@ +package kr.co.palnet.kac.data.com.service; + +import kr.co.palnet.kac.data.com.domain.ComConfirmBas; +import kr.co.palnet.kac.data.com.repository.ComConfirmBasRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +@RequiredArgsConstructor +public class ComConfirmDomainService { + + private final ComConfirmBasRepository comConfirmBasRepository; + + public ComConfirmBas saveComConfirmBas(ComConfirmBas entity){ + return comConfirmBasRepository.save(entity); + } + +} diff --git a/web/api-flight/build.gradle b/web/api-flight/build.gradle index 37fd150..f3561b8 100644 --- a/web/api-flight/build.gradle +++ b/web/api-flight/build.gradle @@ -9,6 +9,8 @@ dependencies { implementation 'org.apache.httpcomponents.client5:httpclient5:5.3' implementation 'org.apache.commons:commons-io:1.3.2' implementation 'com.itextpdf:html2pdf:5.0.3' + implementation 'com.google.zxing:core:3.5.2' + implementation 'com.google.zxing:javase:3.5.2' compileOnly 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' implementation project(":common:core") diff --git a/web/api-flight/src/main/java/kr/co/palnet/kac/api/external/model/TsQRcodeRQ.java b/web/api-flight/src/main/java/kr/co/palnet/kac/api/external/model/TsQRcodeRQ.java new file mode 100644 index 0000000..3e6e072 --- /dev/null +++ b/web/api-flight/src/main/java/kr/co/palnet/kac/api/external/model/TsQRcodeRQ.java @@ -0,0 +1,30 @@ +package kr.co.palnet.kac.api.external.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +public class TsQRcodeRQ { + private String type; // 5 (한국공항공사) - 고정 + private String rtnUrl; // 리턴 url - 고정 + private String reqId; // 추적 코드 + private String submittype; // 기체신고번호 + private String applyUser; // 사용자 인증 코드 ci + + public TsQRcodeRQ() { + this.type = "5"; + this.rtnUrl = ""; + } + + @Builder + public TsQRcodeRQ(String rtnUrl, String reqId, String submittype, String applyUser) { + this.type = "5"; + this.rtnUrl = rtnUrl; + this.reqId = reqId; + this.submittype = submittype; + this.applyUser = applyUser; + } + +} diff --git a/web/api-flight/src/main/java/kr/co/palnet/kac/api/external/service/TsService.java b/web/api-flight/src/main/java/kr/co/palnet/kac/api/external/service/TsService.java new file mode 100644 index 0000000..2c1b3a4 --- /dev/null +++ b/web/api-flight/src/main/java/kr/co/palnet/kac/api/external/service/TsService.java @@ -0,0 +1,44 @@ +package kr.co.palnet.kac.api.external.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.client.j2se.MatrixToImageConfig; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.WriterException; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +@Service +@Slf4j +@RequiredArgsConstructor +public class TsService { + public byte[] createQrcode(String params) throws WriterException, IOException { + // 바코드 색상 값 +// int qrcodeColor = 0xFF2e4e96; + int qrcodeColor = 0xFF000000; + // 배경 색상 값 + int backgroundColor = 0xFFFFFFFF; + + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + + // 300x300 + BitMatrix bitMatrix = qrCodeWriter.encode(params, BarcodeFormat.QR_CODE, 300, 300); + + MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(qrcodeColor, backgroundColor); + BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig); + // ImageIO를 사용한 바코드 파일쓰기 +// boolean png = ImageIO.write(bufferedImage, "png", new File("stoneQR2.png")); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ImageIO.write(bufferedImage, "png", outputStream); + return outputStream.toByteArray(); + } +} diff --git a/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/controller/FlightLaancController.java b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/controller/FlightLaancController.java index f6a29aa..cb83a7a 100644 --- a/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/controller/FlightLaancController.java +++ b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/controller/FlightLaancController.java @@ -1,29 +1,44 @@ package kr.co.palnet.kac.api.v1.flight.laanc.controller; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import kr.co.palnet.kac.api.v1.flight.laanc.model.create.CreateLaancPlanRQ; +import kr.co.palnet.kac.api.v1.flight.laanc.model.create.CreateLaancPlanRS; +import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRQ; +import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRS; import kr.co.palnet.kac.api.v1.flight.laanc.service.FlightLaancService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -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 org.springframework.web.bind.annotation.*; @RestController @Slf4j @RequestMapping("/v1/flight/laanc") @RequiredArgsConstructor +@Tag(name = "비행 - Laanc", description = "Laanc 관련 API") public class FlightLaancController { private final FlightLaancService flightLaancService; @PostMapping("/create/plan") - public ResponseEntity createPlan(@RequestBody CreateLaancPlanRQ rq) { + @Operation(summary = "비행계획서 생성", description = "비행계획서를 생성합니다.") + public ResponseEntity createPlan(@RequestBody CreateLaancPlanRQ rq) { - flightLaancService.createPlan(rq); + CreateLaancPlanRS result = flightLaancService.createPlan(rq); - return ResponseEntity.status(HttpStatus.CREATED).body(null); + return ResponseEntity.status(HttpStatus.CREATED).body(result); } + + @PostMapping("/ts/qr") + @Operation(summary = "TS QR 코드 생성", description = "조종사 자격증명 및 기체 보험 여부 등 조회하기 위한 QR 코드 생성") + public ResponseEntity createQRcode(LaancTsQRcodeRQ rq){ + + LaancTsQRcodeRS result = flightLaancService.createQRcode(rq); + + return ResponseEntity.status(HttpStatus.CREATED).body(result); + } + + } diff --git a/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/ComConfirmBasDTO.java b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/ComConfirmBasDTO.java new file mode 100644 index 0000000..aa3b837 --- /dev/null +++ b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/ComConfirmBasDTO.java @@ -0,0 +1,22 @@ +package kr.co.palnet.kac.api.v1.flight.laanc.model; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ComConfirmBasDTO { + + private Long confirmSno; + private String confirmKey; // 확인키 + private String status; // 상태값 [ GENERATED, RECEIVED, CHECKED, FAILED, EXPIRED ] + private String targetType; // 대상구분 + private String rqData; // RQ 데이터 + private String rsData; // RS 데이터 + private String rm; // 비고 + private String createUserId; // 생성사용자ID + private LocalDateTime createDt; // 생성일시 + private String updateUserId; // 수정사용자ID + private LocalDateTime updateDt; // 수정일시 +} diff --git a/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/tsqr/LaancTsQRcodeRQ.java b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/tsqr/LaancTsQRcodeRQ.java new file mode 100644 index 0000000..4d38c75 --- /dev/null +++ b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/tsqr/LaancTsQRcodeRQ.java @@ -0,0 +1,18 @@ +package kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class LaancTsQRcodeRQ { + + @Schema(description = "기체신고번호", example = "C1CM0231251") + private String idntfNum; // 기체신고번호 + +} diff --git a/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/tsqr/LaancTsQRcodeRS.java b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/tsqr/LaancTsQRcodeRS.java new file mode 100644 index 0000000..36ec5e5 --- /dev/null +++ b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/model/tsqr/LaancTsQRcodeRS.java @@ -0,0 +1,17 @@ +package kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class LaancTsQRcodeRS { + + private byte[] qrcode; // qr코드 + private String confirmKey; // 인증번호 + +} diff --git a/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/service/FlightLaancService.java b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/service/FlightLaancService.java index ca8575f..8a5d5d2 100644 --- a/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/service/FlightLaancService.java +++ b/web/api-flight/src/main/java/kr/co/palnet/kac/api/v1/flight/laanc/service/FlightLaancService.java @@ -1,9 +1,15 @@ package kr.co.palnet.kac.api.v1.flight.laanc.service; +import kr.co.palnet.kac.api.external.model.TsQRcodeRQ; import kr.co.palnet.kac.api.external.service.CtrTrnsLctnService; +import kr.co.palnet.kac.api.external.service.TsService; import kr.co.palnet.kac.api.v1.flight.laanc.model.create.CstmrModel; import kr.co.palnet.kac.api.v1.flight.laanc.model.*; import kr.co.palnet.kac.api.v1.flight.laanc.model.create.*; +import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRQ; +import kr.co.palnet.kac.api.v1.flight.laanc.model.tsqr.LaancTsQRcodeRS; +import kr.co.palnet.kac.data.com.domain.ComConfirmBas; +import kr.co.palnet.kac.data.com.service.ComConfirmDomainService; import kr.co.palnet.kac.data.other.service.OtherDomainService; import kr.co.palnet.kac.api.external.model.ComnSmsLaancAprovModel; import kr.co.palnet.kac.api.external.model.CtrTrnsLctnModel; @@ -29,13 +35,19 @@ import kr.co.palnet.kac.api.util.model.LaancPdfModel; import kr.co.palnet.kac.util.EncryptUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponentsBuilder; +import com.google.zxing.WriterException; + +import java.io.IOException; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; +import java.util.UUID; @Service @Slf4j @@ -52,23 +64,33 @@ public class FlightLaancService { private final ComFileDomainService comFileDomainService; + private final ComConfirmDomainService confirmDomainService; + private final OtherDomainService otherDomainService; private final CtrTrnsLctnService ctrTrnsLctnService; private final ComnSmsService comnSmsService; + + private final TsService tsService; // private final FileUtils fileUtils; + @Value("${app.host}") + private String APP_HOST; + + @Value("${external.ts.return.uri}") + private String TS_RETURN_URI; + @Transactional public CreateLaancPlanRS createPlan(CreateLaancPlanRQ rq) { - Long cstmrnSno = SessionHelper.getCstmrSno(); + Long cstmrSno = SessionHelper.getCstmrSno(); String userId = SessionHelper.getUserId(); // 비행계획서 INSERT - Optional userEntityData = ptyCstmrDomainService.findPtyCstmrBasById(cstmrnSno); - Optional userDetailEntityData = ptyCstmrDomainService.findPtyCstmrDtlById(cstmrnSno); + Optional userEntityData = ptyCstmrDomainService.findPtyCstmrBasById(cstmrSno); + Optional userDetailEntityData = ptyCstmrDomainService.findPtyCstmrDtlById(cstmrSno); if(userEntityData.isEmpty() || userDetailEntityData.isEmpty()) throw new BaseException(BaseErrorCode.DATA_EMPTY); @@ -280,4 +302,80 @@ public class FlightLaancService { .build(); } + @Transactional + public LaancTsQRcodeRS createQRcode(LaancTsQRcodeRQ rq) { + Long cstmrSno = SessionHelper.getCstmrSno(); + String userId = SessionHelper.getUserId(); + Optional userEntityData = ptyCstmrDomainService.findPtyCstmrBasById(cstmrSno); + Optional userDetailEntityData = ptyCstmrDomainService.findPtyCstmrDtlById(cstmrSno); + + if(userEntityData.isEmpty() || userDetailEntityData.isEmpty()) throw new BaseException(BaseErrorCode.DATA_EMPTY); + + CstmrModel cstmrInfo = CstmrModel.toModel(userEntityData.get(), userDetailEntityData.get()); + String userCi = cstmrInfo.getIpinCi(); + + + String idntfNum = null; + if (rq != null && rq.getIdntfNum() != null && !rq.getIdntfNum().isEmpty()) { + idntfNum = rq.getIdntfNum(); + } + + String confirmKey = UUID.randomUUID().toString(); + String params = null; + byte[] qr = null; + try { + TsQRcodeRQ tsRq = TsQRcodeRQ.builder() + .rtnUrl(this.APP_HOST + this.TS_RETURN_URI) + .reqId(confirmKey) + .submittype(idntfNum) + .applyUser(userCi) + .build(); + +// params = JsonUtils.toJson(tsRq); +/* + + tsdronewallet://kotsa.or.kr + ? type=5 + & rtnUrl= http://121.190.193.50:6081/api/external/laanc/vc/callback + & reqId=0b42b0af-3875-4a21-b57b-bb93ffcb3cfc + & submittype=C1CM0231251 + & applyUser=dzT9zrm1JJRbrT1oRsUbvXYDfbAtXG5QOZjbIVHPaklSZ2PTw8ojYdJyeTrdQdtKIGFM5Z7xfrN/Crm6iGRLkA== + */ + + params = UriComponentsBuilder + .fromUriString("tsdronewallet://kotsa.or.kr") + .queryParam("type", tsRq.getType()) + .queryParam("rtnUrl", tsRq.getRtnUrl()) + .queryParam("reqId", tsRq.getReqId()) + .queryParam("submittype", tsRq.getSubmittype()) + .queryParam("applyUser", tsRq.getApplyUser()) + .build() + .toUriString(); + + qr = tsService.createQrcode(params); + } catch (WriterException | IOException e) { + log.error("ERROR: ", e); + throw new BaseException(BaseErrorCode.FAILED, "QR코드 생성 실패"); + } + + // db 저장 - confirmKey(uuid) + ComConfirmBas comConfirmBas = ComConfirmBas.builder() + .confirmKey(confirmKey) + .status("GENERATED") + .targetType("TS_QRCODE") + .rqData(params) + .createUserId(userId) + .createDt(LocalDateTime.now()) + .updateUserId(userId) + .updateDt(LocalDateTime.now()) + .build(); + + confirmDomainService.saveComConfirmBas(comConfirmBas); + + log.info(">>> confirmKey [GENERATED] ", confirmKey); + return LaancTsQRcodeRS.builder() + .qrcode(qr) + .confirmKey(confirmKey) + .build(); + } } diff --git a/web/api-flight/src/main/resources/application.properties b/web/api-flight/src/main/resources/application.properties index fbf17f3..d70712d 100644 --- a/web/api-flight/src/main/resources/application.properties +++ b/web/api-flight/src/main/resources/application.properties @@ -14,4 +14,6 @@ naver.api.url=https://naveropenapi.apigw.ntruss.com/map-reversegeocode/v2/gc external.ts.url=http://121.137.95.45:8170 external.ts.return.uri=/api/external/laanc/vc/callback -url.base.file=files/ \ No newline at end of file +url.base.file=files/ + +app.host=http://localhost:8080