From 4a3b0e482a1a8f34d26d21493abe1870e2c6202b Mon Sep 17 00:00:00 2001 From: "kelvin.yau" Date: Fri, 24 Apr 2026 19:15:05 +0800 Subject: [PATCH] Faster Canon Printer --- .../com/ffii/core/utils/CanonPrinterUtil.kt | 22 ++++-- .../service/DeliveryOrderService.kt | 73 ++++++++++++++----- .../web/DeliveryOrderController.kt | 17 ++++- .../master/print/A4PrintDriverRegistry.kt | 2 +- 4 files changed, 88 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/ffii/core/utils/CanonPrinterUtil.kt b/src/main/java/com/ffii/core/utils/CanonPrinterUtil.kt index fd0e8e9..939d58e 100644 --- a/src/main/java/com/ffii/core/utils/CanonPrinterUtil.kt +++ b/src/main/java/com/ffii/core/utils/CanonPrinterUtil.kt @@ -1,6 +1,7 @@ package com.ffii.core.utils import org.apache.pdfbox.pdmodel.PDDocument +import org.slf4j.LoggerFactory import java.io.File import java.io.OutputStream import java.net.Socket @@ -19,6 +20,7 @@ open class CanonPrinterUtil { } companion object { + private val log = LoggerFactory.getLogger(CanonPrinterUtil::class.java) /** * Detects if a PDF document is in landscape (horizontal) orientation. * @@ -105,13 +107,10 @@ open class CanonPrinterUtil { // 6. Read PDF file content val pdfContent = pdfFile.readBytes() - println("DEBUG: PDF file size: ${pdfContent.size} bytes") - // Print each copy for the specified quantity - repeat(printQty ?: 1) { copyIndex -> - println("DEBUG: Printing copy ${copyIndex + 1} of ${printQty ?: 1}") - - // 7. Send to printer via TCP/IP socket + val copies = printQty ?: 1 + repeat(copies) { copyIndex -> + val tSend = System.nanoTime() Socket(printerIp, printerPort).use { socket -> val os: OutputStream = socket.getOutputStream() @@ -126,8 +125,17 @@ open class CanonPrinterUtil { os.write("\u001B%-12345X".toByteArray(Charsets.US_ASCII)) os.flush() - println("DEBUG: Copy ${copyIndex + 1} sent to printer") } + val sendMs = (System.nanoTime() - tSend) / 1_000_000.0 + log.info( + "Canon printPdfToCanon: copy {} of {} sendMs={} printer={}:{} pdfBytes={} (high sendMs: check LAN/WiFi, firewall, or printer 9100 queue)", + copyIndex + 1, + copies, + sendMs, + printerIp, + printerPort, + pdfContent.size, + ) } } catch (e: Exception) { // Re-throw the exception with a more descriptive message diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt index f900240..e04f02d 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DeliveryOrderService.kt @@ -79,6 +79,8 @@ import com.ffii.fpsms.modules.master.entity.ItemsRepository import kotlin.collections.emptyMap import com.ffii.fpsms.modules.master.print.A4PrintDriverRegistry import com.ffii.core.response.RecordsRes +import net.sf.jasperreports.engine.JasperReport +import org.slf4j.LoggerFactory import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -87,6 +89,8 @@ import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLiteD import com.ffii.fpsms.modules.stock.entity.InventoryLotLine import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo import java.util.Locale +import org.slf4j.Logger + @Service open class DeliveryOrderService( private val deliveryOrderRepository: DeliveryOrderRepository, @@ -116,7 +120,7 @@ open class DeliveryOrderService( private val doPickOrderRepository: DoPickOrderRepository, private val doPickOrderLineRepository: DoPickOrderLineRepository, private val doPickOrderLineRecordRepository: DoPickOrderLineRecordRepository, - private val itemsRepository: ItemsRepository + private val itemsRepository: ItemsRepository, ) { open fun searchDoLiteByPage( code: String?, @@ -1064,26 +1068,31 @@ open class DeliveryOrderService( @Throws(IOException::class) @Transactional open fun exportDeliveryNote(request: ExportDeliveryNoteRequest): Map { - - // INPUT STREAM SETUP - val DELIVERYNOTE_PDF = "DeliveryNote/DeliveryNotePDF.jrxml" - val resource = ClassPathResource(DELIVERYNOTE_PDF) - if (!resource.exists()) { - throw FileNotFoundException("Report file not found: $DELIVERYNOTE_PDF") - } - - val inputStream = resource.inputStream - val deliveryNote = JasperCompileManager.compileReport(inputStream) + val tAll0 = System.nanoTime() + val tJ0 = System.nanoTime() + val deliveryNote = deliveryNoteJasperTemplate + val jasperGetMs = (System.nanoTime() - tJ0) / 1_000_000.0 val fields = mutableListOf>() val params = mutableMapOf() - // DRAFT & RECORD SEPARATION - if (request.isDraft) { - return exportDeliveryNoteFromDraft(request, deliveryNote, fields, params) + val tFill0 = System.nanoTime() + val result = if (request.isDraft) { + exportDeliveryNoteFromDraft(request, deliveryNote, fields, params) } else { - return exportDeliveryNoteFromRecord(request, deliveryNote, fields, params) - } + exportDeliveryNoteFromRecord(request, deliveryNote, fields, params) + } + val fillDataMs = (System.nanoTime() - tFill0) / 1_000_000.0 + val totalMs = (System.nanoTime() - tAll0) / 1_000_000.0 + log.info( + "DeliveryNote export timing: jasperGetMs={} fillDataMs={} totalMs={} doPickOrderId={} isDraft={}", + jasperGetMs, + fillDataMs, + totalMs, + request.doPickOrderId, + request.isDraft, + ) + return result } // DRAFT @@ -1413,6 +1422,7 @@ open class DeliveryOrderService( //Print Delivery Note @Transactional open fun printDeliveryNote(request: PrintDeliveryNoteRequest) { + val t0 = System.nanoTime() val printer = printerService.findById(request.printerId) ?: throw java.util.NoSuchElementException("No such printer") @@ -1429,15 +1439,30 @@ open class DeliveryOrderService( val tempPdfFile = File.createTempFile("print_job_", ".pdf") try { + val t1 = System.nanoTime() JasperExportManager.exportReportToPdfFile(jasperPrint, tempPdfFile.absolutePath) + val exportPdfToFileMs = (System.nanoTime() - t1) / 1_000_000.0 val printQty = if (request.printQty == null || request.printQty <= 0) 1 else request.printQty + val t2 = System.nanoTime() printer.ip?.let { ip -> val port = printer.port ?: 9100 val driver = A4PrintDriverRegistry.getDriver(printer.brand) driver.print(tempPdfFile, ip, port, printQty) } + val printToPrinterMs = (System.nanoTime() - t2) / 1_000_000.0 + val totalMs = (System.nanoTime() - t0) / 1_000_000.0 + log.info( + "DeliveryNote print-DN timing: exportPdfToFileMs={} printToPrinterMs={} totalMs={} doPickOrderId={} printerId={} printQty={} printerIp={}", + exportPdfToFileMs, + printToPrinterMs, + totalMs, + request.doPickOrderId, + request.printerId, + printQty, + printer.ip ?: "null", + ) updateRecordCartonQty(request.doPickOrderId, request.numOfCarton) } finally { //tempPdfFile.delete() @@ -2146,5 +2171,19 @@ val inventoryLotLine = illId?.let { inventoryLotLineMap[it] } problems = problems ) } + + private companion object { + private val log: Logger = LoggerFactory.getLogger(DeliveryOrderService::class.java) + + private const val DELIVERYNOTE_JRXML = "DeliveryNote/DeliveryNotePDF.jrxml" + + /** Compile once; avoids per-request JRXML recompilation (shared by download + print). */ + private val deliveryNoteJasperTemplate: JasperReport by lazy { + val resource = ClassPathResource(DELIVERYNOTE_JRXML) + if (!resource.exists()) { + throw FileNotFoundException("Report file not found: $DELIVERYNOTE_JRXML") + } + resource.inputStream.use { inputStream -> JasperCompileManager.compileReport(inputStream) } + } + } } - \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt index 2ddc236..9a4716f 100644 --- a/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/deliveryOrder/web/DeliveryOrderController.kt @@ -44,6 +44,7 @@ import com.ffii.fpsms.modules.deliveryOrder.web.models.Check4FTruckBatchResponse import com.ffii.fpsms.modules.deliveryOrder.web.models.DoSearchRowResponse import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLite import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfoLiteDto +import org.slf4j.LoggerFactory @RequestMapping("/do") @RestController @@ -53,6 +54,8 @@ class DeliveryOrderController( private val doPickOrderService: DoPickOrderService, ) { + private val log = LoggerFactory.getLogger(javaClass) + @PostMapping("/search-do-lite") fun searchDoLite(@RequestBody request: SearchDeliveryOrderInfoRequest): RecordsRes { println("DEBUG: searchDoLite - request: code=${request.code}, shopName=${request.shopName}, status=${request.status}") @@ -233,13 +236,25 @@ class DeliveryOrderController( @PostMapping("/DN") @Throws(UnsupportedEncodingException::class, NoSuchMessageException::class, ParseException::class, Exception::class) fun printDN(@Valid @RequestBody request: ExportDeliveryNoteRequest, response: HttpServletResponse){ + val t0 = System.nanoTime() response.characterEncoding = "utf-8" response.contentType = "application/pdf" val out: OutputStream = response.outputStream val pdf = deliveryOrderService.exportDeliveryNote(request) val jasperPrint = pdf["report"] as JasperPrint response.addHeader("filename", "${pdf["filename"]}.pdf") - out.write(JasperExportManager.exportReportToPdf(jasperPrint)) + val t1 = System.nanoTime() + val bytes = JasperExportManager.exportReportToPdf(jasperPrint) + val jasperExportToPdfBytesMs = (System.nanoTime() - t1) / 1_000_000.0 + out.write(bytes) + val totalHttpMs = (System.nanoTime() - t0) / 1_000_000.0 + log.info( + "DeliveryNote POST /do/DN (download) timing: jasperExportToPdfBytesMs={} totalResponseMs={} doPickOrderId={} isDraft={}", + jasperExportToPdfBytesMs, + totalHttpMs, + request.doPickOrderId, + request.isDraft, + ) } @GetMapping("/print-DN") diff --git a/src/main/java/com/ffii/fpsms/modules/master/print/A4PrintDriverRegistry.kt b/src/main/java/com/ffii/fpsms/modules/master/print/A4PrintDriverRegistry.kt index 7d59bce..5d071ba 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/print/A4PrintDriverRegistry.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/print/A4PrintDriverRegistry.kt @@ -3,7 +3,7 @@ package com.ffii.fpsms.modules.master.print object A4PrintDriverRegistry { private val drivers = mapOf( "Canon" to CanonA4Driver(), - "Brother" to BrotherA4Driver() + "Brother" to BrotherA4Driver(), ) private val defaultDriver = CanonA4Driver()