在 Spring 引导中保留文件上传的元数据
Preserve metadata for file upload in Spring Boot
我正在创建一个图像上传应用程序,用户可以在其中编辑图像元数据。我目前处理文件上传的方式是使用多部分文件。
fun handleFileUpload(@RequestParam files: Array<MultipartFile>): String {
这有效,但我无法访问图像的所有文件元数据。我想知道执行此操作以便我可以访问元数据的理想方法是什么?我知道 Java.io.File class 具有元数据访问权限。
我希望在 Angular 前端保留拖放功能。
文件元数据不是图像元数据...
在java中我们可以:
对于 Kotlin(后端)我发现:
- Scrimmage,这让我想到:
- ...
让我们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
“爬行”。
我正在创建一个图像上传应用程序,用户可以在其中编辑图像元数据。我目前处理文件上传的方式是使用多部分文件。
fun handleFileUpload(@RequestParam files: Array<MultipartFile>): String {
这有效,但我无法访问图像的所有文件元数据。我想知道执行此操作以便我可以访问元数据的理想方法是什么?我知道 Java.io.File class 具有元数据访问权限。
我希望在 Angular 前端保留拖放功能。
文件元数据不是图像元数据...
在java中我们可以:
对于 Kotlin(后端)我发现:
- Scrimmage,这让我想到:
- ...
让我们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
“爬行”。