微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么下面的文件生成方法会在同时请求此端点时返回 FileNotFoundException?

如何解决为什么下面的文件生成方法会在同时请求此端点时返回 FileNotFoundException?

我编写了一个端点来返回一个包含多个 qr 的 zip,其中包含基于我的数据库中的详细信息的值。当我通过向该端点发出多个请求来进行负载测试时,它抛出 FileNotFoundException。但如果请求是在特定时间间隔内发出的,则不会发生这种情况。

@GetMapping(value = ["/{sysId}/code"],produces = ["application/zip"])
fun generateQrCode1(@PathVariable sysId: Int): ResponseEntity<InputStreamResource> {
    val sysDetails = sysService.getById(sysId)
    val productDetails = productService.getProductByProductId(sysDetails.productId)
    val zipName = sysDetails.productId.toString() + ".zip"
    FileOutputStream(zipName).use { fileOutputStream ->
        ZipOutputStream(fileOutputStream).use { zipOutputStream ->
            for (i in 1..sysDetails.length) {
                val u = "http://" + "$domain/" + "?sysId=${sysId}&pid=$i"
                val x = generateQRCodeWithText(u,350,300,arrayOf("QR CODE TEST"))
                val byteArrayOutputStream = ByteArrayOutputStream()
                byteArrayOutputStream.write(x!!)
                val zipEntry = ZipEntry(
                    "${
                        productDetails.name
                    }-${sysId}-$i.jpg"
                )
                zipOutputStream.putNextEntry(zipEntry)
                byteArrayOutputStream.writeto(zipOutputStream)
            }
        }
    }
    try {
        return ResponseEntity
            .ok()
            .header("Content-disposition","attachment; filename=\"$zipName")
            .body(InputStreamResource(FileInputStream(zipName)))
    } finally {
        java.nio.file.Files.deleteIfExists(Paths.get(zipName))
    }
  
    fun generateQRCodeWithText(data: String?,width: Int?,height: Int,text: Array<String?>): ByteArray? {
    return try {
        val qrCodeWriter = QRCodeWriter()
        val bitMatrix = qrCodeWriter.encode(data,BarcodeFormat.QR_CODE,width!!,height)
        val pngOutputStream = ByteArrayOutputStream()
        MatrixToImageWriter.writetoStream(bitMatrix,"PNG",pngOutputStream)
        var pngData = pngOutputStream.toByteArray()

        if (text.size > 0) {
            val totalTextLinetoadd = text.size
            val `in`: InputStream = ByteArrayInputStream(pngData)
            val image: BufferedImage = ImageIO.read(`in`)
            val outputimage =
                BufferedImage(image.width,image.height + 25 * totalTextLinetoadd,BufferedImage.TYPE_INT_ARGB)
            val g: Graphics = outputimage.graphics
            val g2d = g as Graphics2D
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g.setColor(Color.WHITE)
            g.fillRect(0,outputimage.width,outputimage.height)
            g.drawImage(image,image.width,image.height,null)
            g.setFont(Font("Arial Black",Font.BOLD,20))
            val textColor: Color = Color.BLUE
            g.setColor(textColor)
            val fm: FontMetrics = g.getFontMetrics()
            var startingYposition = height + 5
            for (displayText in text) {
                g.drawString(
                    displayText,outputimage.width / 2 - fm.stringWidth(displayText) / 2,startingYposition
                )
                startingYposition += 20
            }
            val baos = ByteArrayOutputStream()
            ImageIO.write(outputimage,baos)
            baos.flush()
            pngData = baos.toByteArray()
            baos.close()
        }
        pngData
    } catch (ex: WriterException) {
        throw ex
    } catch (ex: IOException) {
        throw ex
    }
}

多个请求同时出错:

java.io.FileNotFoundException: 2889.zip (No such file or directory)
at java.io.FileInputStream.open0(Native Method) ~[?:1.8.0_292]
 at java.io.FileInputStream.open(FileInputStream.java:195) ~[?:1.8.0_292]
at java.io.FileInputStream.<init>(FileInputStream.java:138) ~[?:1.8.0_292]
 at java.io.FileInputStream.<init>(FileInputStream.java:93) ~[?:1.8.0_292]
 at com.mangoChain.qrApi.QrApi.generateQrCode1(QrApi.kt:136) ~[classes!/:?]

解决方法

您应该确保您的本地文件名 (zipName) 是唯一的,否则多个线程可能会删除彼此的文件。

您在评论中提到 productId 可能会发生冲突,因此您可以基于 sysId 而不是(或除了)productId 来命名您的文件。例如:

val zipName = "$sysId-${sysDetails.productId}.zip"

请注意,您只需要使本地文件名唯一 (zipName),但您仍然可以在 Content-Disposition 标题中保留用户可见的文件名:

return ResponseEntity
    .ok()
    .header("Content-Disposition","attachment; filename=\"${sysDetails.productId}.zip\"")
    .body(InputStreamResource(FileInputStream(zipName)))

作为旁注,您可能应该使用临时文件夹而不仅仅是普通的文件名,因为目前这些文件是在当前工作目录中创建的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。