在 Spring 引导中保留文件上传的元数据

Preserve metadata for file upload in Spring Boot

我正在创建一个图像上传应用程序,用户可以在其中编辑图像元数据。我目前处理文件上传的方式是使用多部分文件。

fun handleFileUpload(@RequestParam files: Array<MultipartFile>): String {

这有效,但我无法访问图像的所有文件元数据。我想知道执行此操作以便我可以访问元数据的理想方法是什么?我知道 Java.io.File class 具有元数据访问权限。

我希望在 Angular 前端保留拖放功能。

文件元数据不是图像元数据...

在java中我们可以:

对于 Kotlin(后端)我发现:

让我们try/compare:

package com.satckoverflow.imagemeta

import com.drew.imaging.ImageMetadataReader
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.multipart.MultipartFile
import org.w3c.dom.NamedNodeMap
import org.w3c.dom.Node
import javax.imageio.ImageIO
import javax.imageio.ImageReader
import kotlin.text.StringBuilder


fun main(args: Array<String>) {
    runApplication<ImageMetaDataApplication>(*args)
}

@SpringBootApplication
@Controller("/")
class ImageMetaDataApplication {

    @GetMapping
    fun show(): String {
        return "index"
    }

    @PostMapping
    fun handleFileUpload(@RequestParam files: Array<MultipartFile>, model: Model): String {
        val images = ArrayList<MyImage>()
        for (file in files) {
            // adopted from http://johnbokma.com/java/obtaining-image-metadata.html
            val iis = ImageIO.createImageInputStream(file.inputStream)
            val readers: Iterator<ImageReader> = ImageIO.getImageReaders(iis)
            if (readers.hasNext()) {
                // pick the first available ImageReader
                val reader = readers.next()
                // attach source to the reader
                reader.setInput(iis, true)
                // read metadata of first image
                val metadata = reader.getImageMetadata(0)
                val names = metadata.metadataFormatNames
                val length = names.size
                for (i in 0 until length) {
                    images.add(MyImage(file.originalFilename, names[i], displayMetadata(metadata.getAsTree(names[i]))))
                }
            }
        }
        model.addAttribute("images", images)
        return "index"
    }

    @PostMapping(params = ["3rdparty"])
    fun handleFileUploadScrimage(@RequestParam files: 
        Array<MultipartFile>, model: Model): String {
        val images = ArrayList<MyImage>()
        for (file in filesS) {
          val meta = ImageMetadataReader.readMetadata(file.inputStream, file.size)
          meta.directories.forEach { dir ->
            dir.tags.forEach { tag ->
                images.add(MyImage(file.originalFilename, dir.name, tag.toString()))
            }
          }
        }
        model.addAttribute("images", images)
        return "index"
    }
    
}

// adopted from http://johnbokma.com/java/obtaining-image-metadata.html
private fun displayMetadata(root: Node): String {
    val sb = StringBuilder()
    displayMetadata(root, 0, sb)
    return sb.toString()
}

private fun indent(level: Int, sb: StringBuilder) {
    for (i in 0 until level) sb.append("  ")
}

private fun displayMetadata(node: Node, level: Int, sb: StringBuilder): String {
    // print open tag of element
    if (level > 0) {
        sb.append(System.lineSeparator())
    }
    indent(level, sb)
    sb.append('<').append(node.nodeName)
    val map: NamedNodeMap = node.attributes
    // print attribute values
    val length = map.length
    for (i in 0 until length) {
        val attr: Node = map.item(i)
        sb.append(' ').append(attr.nodeName).append('=').append('"').append(attr.nodeValue).append('"')
    }
    var child = node.firstChild
    if (child == null) {
        // no children, so close element and return
        sb.append("/>")
    } else {
        // children, so close current tag
        sb.append('>')
        while (child != null) {
            // print children recursively
            displayMetadata(child, level + 1, sb)
            child = child.nextSibling
        }
        // print close tag of element
        sb.append(System.lineSeparator())
        indent(level, sb)
        sb.append("</").append(node.nodeName).append('>')
    }
    return sb.toString()
}
// adopted-end

data class MyImage(val name: String?, val key: String?, val vali: String?)

用这个 src/main/resources/templates/index.html(对不起百里香,“没有设计”,只有 2 个输入..):

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Image meta data upload Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <style>
      table td, table td * {
        vertical-align: top;
      }
      pre {
        white-space: pre-wrap;
      }

    </style>
  </head>
  <body>
    <h2>Standard java</h2>
    <form action="#" method="post" th:action="@{/}" enctype="multipart/form-data">
      <label for="files0">File 1:</label>
      <input type="file" id="files0" name="files" accept="image/*"/>
      <label for="files1">File 2:</label>
      <input type="file" id="files1" name="files" accept="image/*"/>
      <input type="submit"/>
    </form>
    <hr/>
    <h2>additional lib</h2>
    <form action="#" method="post" th:action="@{/}" enctype="multipart/form-data">
      <label for="files2">File 1:</label>
      <input type="file" id="files2" name="files" accept="image/*"/>
      <label for="files3">File 2:</label>
      <input type="file" id="files3" name="files" accept="image/*"/>
      <input type="submit"/>
      <input type="hidden" name="3rdparty" />
    </form>
    <hr/>
    <table th:if="${images}">
      <thead>
        <tr>
          <th>Name</th>
          <th>Meta-Data-Key</th>
          <th>Meta-Data-Value</th>
        </tr>
      </thead>
      <tbody>
        <tr th:each="img: ${images}">
          <td th:text="${img.name}">some file</td>
          <td th:text="${img.key}">some text</td>
          <td>
            <pre th:text="${img.vali}">some text</pre>
          </td>
        </tr>
      </tbody>
    </table>
  </body>
</html>

我们可以得到一些东西,比如(没有额外的库,但有一些 xml-爬行代码):

还有:

<dependency>
  <groupId>com.drewnoakes</groupId>
  <artifactId>metadata-extractor</artifactId>
  <version>2.16.0</version>
</dependency>

我们得到(几行)更像这样的东西:

感谢 blog javax.imageio“爬行”。