Статьи

Получите любые метаданные изображения с помощью Spring Boot и Docker

Это вторая часть серии из трех статей, но я решил сконцентрироваться на двух, чтобы освободить место для другой статьи. Первая часть доступна на этом сайте по адресу https://www.javaadvent.com/2017/12/microservices-architecture.html .

В этой части мы собираемся разработать микросервис, который считывает метаданные из изображения в формате JSON или XML. Я использую Docker и Java (проверьте часть 1, если вам нужен образ Java для Docker), Spring Boot, Gradle, Groovy и экстрактор метаданных от drewnoakes.

Gradle

Gradle — это инструмент сборки, как и Maven, и я решил переключиться на Gradle после использования Maven в течение многих лет, потому что я нашел его более богатым и практичным, но в конце концов, какой инструмент сборки вы используете, зависит от вас — до тех пор, пока Вы получаете то, что хотите, и вы счастливы. Я должен сказать, что переезд в Gradle был не таким быстрым, как многие говорили мне, но я считаю, что как только я понял основы, это стало радостью, поэтому, на мой взгляд, стоит потратить некоторое время на изучение этого «нового» инструмента.

Я вернусь к Gradle в конце этой статьи с полным сценарием сборки.

Groovy

Микросервис написан на Groovy, но не волнуйтесь: вы получите все, даже не зная Groovy!

В Groovy любой элемент по умолчанию является общедоступным, поэтому классы и методы, которые вы увидите в модификаторе, являются общедоступными.

Metadata-экстрактор

Я не копаюсь в этой библиотеке, потому что на https://github.com/drewnoakes/metadata-extractor достаточно документации. Важным моментом в этой библиотеке является то, что позволяет читать метаданные из нескольких типов изображений.

Для использования в нашем проекте нам нужно добавить следующую строку в наш скрипт сборки Gradle:

1
compile group: 'com.drewnoakes', name: 'metadata-extractor', version: '2.10.0'

Мы будем использовать ImageMetadataReader для получения метаданных, используя ответ / метаданные контроллера.

Весенний ботинок

Почти все, кто работает с Java, знают Spring, хотя не все его используют. Spring также известен тем, что он долго настраивал новый проект, и я знаю многих людей, приносящих почти одинаковую конфигурацию для любого нового проекта. Это может работать в некоторых ситуациях, но риск состоит в том, чтобы принести вещи, которые не нужны. ** Spring Boot позволяет легко создавать автономные, производственные Spring-приложения, которые вы можете «просто запустить». Мы принимаем взвешенное мнение о платформе Spring и сторонних библиотеках, чтобы вы могли начать работу с минимальными усилиями. Большинству приложений Spring Boot требуется очень небольшая конфигурация Spring. ** (С https://projects.spring.io/spring-boot/ ) я не мог описать это лучше, и он действительно делает то, что говорит на банке.

Чтобы использовать загрузку Spring в нашем проекте, нам нужно добавить следующие строки в наш скрипт сборки Gradle:

01
02
03
04
05
06
07
08
09
10
11
12
13
buildscript {
 
    ext {
        springBootVersion = '1.5.1.RELEASE'
    }
 
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
 
}
 
apply plugin: 'org.springframework.boot'

и определим некоторые зависимости:

1
2
3
4
5
6
7
8
dependencies {
 
compile 'org.springframework.boot:spring-boot-starter-groovy-templates'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.springframework.boot:spring-boot-starter-logging'
 
}

Все, что нам нужно для запуска нашего микросервиса, это класс:

01
02
03
04
05
06
07
08
09
10
11
12
13
package com.daftano.metadata
 
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
 
@SpringBootApplication
class MetadataApplication {
 
    static void main(String[] args) {
        SpringApplication.run(MetadataApplication.class, args)
    }
 
}

А Spring Boot настроит все необходимые зависимости. То, как Spring Boot знает, что нужно загружать и настраивать, зависит от библиотек, загруженных в приложение (в нашем случае они настроены в блоке зависимостей Gradle).

Spring Controller

Наш Microservice — это REST-сервис с одним контроллером MetadataController. Все, что нам нужно сделать, чтобы указать Spring для прослушивания запросов к / метаданным, использует эти две аннотации:

1
2
3
@Controller
@RequestMapping("/metadata")
class MetadataController

Вот и все.

Другая конфигурация, которую мы хотим сделать, — это определить параметры, которые мы хотим получить из запроса, и мы делаем это с помощью еще трех аннотаций:

1
2
@RequestMapping(method= RequestMethod.GET)
@ResponseBody Metadata getMetadata(@RequestParam(value="url") String urlAddress)

Кроме того, мы сообщаем Spring, что getMetadata разрешает только запросы GET и требует параметра с именем url, который является URL-адресом изображения, которое мы хотим использовать для извлечения метаданных. На самом деле это URI, но в качестве микросервиса вы используете его для чтения изображений из Интернета.

Что нам действительно нужно сделать в этом методе, это вызвать

1
ImageMetadataReader.readMetadata(url.openStream())

Где URL — это полированный адрес URL.

Микросервис в действии

Что еще? Ну, мы на самом деле сделали!

Все, что вам нужно сделать, чтобы извлечь метаданные из моего Gravatar, это запустить службу и перейти к

Чтобы получить следующий вывод:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
{
    "directories": [
        {
            "name": "JPEG",
            "imageWidth": 160,
            "imageHeight": 160,
            "numberOfComponents": 3,
            "empty": false,
            "parent": null,
            "errors": [
            ],
            "errorCount": 0,
            "tags": [
                {
                    "tagType": -3,
                    "tagTypeHex": "0xfffffffd",
                    "directoryName": "JPEG",
                    "tagName": "Compression Type",
                    "description": "Baseline"
                },
                {
                    "tagType": 0,
                    "tagTypeHex": "0x0000",
                    "directoryName": "JPEG",
                    "tagName": "Data Precision",
                    "description": "8 bits"
                },
                {
                    "tagType": 1,
                    "tagTypeHex": "0x0001",
                    "directoryName": "JPEG",
                    "tagName": "Image Height",
                    "description": "160 pixels"
                },
                {
                    "tagType": 3,
                    "tagTypeHex": "0x0003",
                    "directoryName": "JPEG",
                    "tagName": "Image Width",
                    "description": "160 pixels"
                },
                {
                    "tagType": 5,
                    "tagTypeHex": "0x0005",
                    "directoryName": "JPEG",
                    "tagName": "Number of Components",
                    "description": "3"
                },
                {
                    "tagType": 6,
                    "tagTypeHex": "0x0006",
                    "directoryName": "JPEG",
                    "tagName": "Component 1",
                    "description": "Y component: Quantization table 0, Sampling factors 2 horiz/2 vert"
                },
                {
                    "tagType": 7,
                    "tagTypeHex": "0x0007",
                    "directoryName": "JPEG",
                    "tagName": "Component 2",
                    "description": "Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert"
                },
                {
                    "tagType": 8,
                    "tagTypeHex": "0x0008",
                    "directoryName": "JPEG",
                    "tagName": "Component 3",
                    "description": "Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert"
                }
            ],
            "tagCount": 8
        },
        {
            "name": "JpegComment",
            "empty": false,
            "parent": null,
            "errors": [
            ],
            "errorCount": 0,
            "tags": [
                {
                    "tagType": 0,
                    "tagTypeHex": "0x0000",
                    "directoryName": "JpegComment",
                    "tagName": "JPEG Comment",
                    "description": "CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90\n"
                }
            ],
            "tagCount": 1
        },
        {
            "name": "JFIF",
            "imageWidth": 1,
            "imageHeight": 1,
            "resUnits": 0,
            "resY": 1,
            "resX": 1,
            "version": 257,
            "empty": false,
            "parent": null,
            "errors": [
            ],
            "errorCount": 0,
            "tags": [
                {
                    "tagType": 5,
                    "tagTypeHex": "0x0005",
                    "directoryName": "JFIF",
                    "tagName": "Version",
                    "description": "1.1"
                },
                {
                    "tagType": 7,
                    "tagTypeHex": "0x0007",
                    "directoryName": "JFIF",
                    "tagName": "Resolution Units",
                    "description": "none"
                },
                {
                    "tagType": 8,
                    "tagTypeHex": "0x0008",
                    "directoryName": "JFIF",
                    "tagName": "X Resolution",
                    "description": "1 dot"
                },
                {
                    "tagType": 10,
                    "tagTypeHex": "0x000a",
                    "directoryName": "JFIF",
                    "tagName": "Y Resolution",
                    "description": "1 dot"
                },
                {
                    "tagType": 12,
                    "tagTypeHex": "0x000c",
                    "directoryName": "JFIF",
                    "tagName": "Thumbnail Width Pixels",
                    "description": "0"
                },
                {
                    "tagType": 13,
                    "tagTypeHex": "0x000d",
                    "directoryName": "JFIF",
                    "tagName": "Thumbnail Height Pixels",
                    "description": "0"
                }
            ],
            "tagCount": 6
        },
        {
            "name": "Huffman",
            "numberOfTables": 4,
            "typical": true,
            "optimized": false,
            "empty": false,
            "parent": null,
            "errors": [
            ],
            "errorCount": 0,
            "tags": [
                {
                    "tagType": 1,
                    "tagTypeHex": "0x0001",
                    "directoryName": "Huffman",
                    "tagName": "Number of Tables",
                    "description": "4 Huffman tables"
                }
            ],
            "tagCount": 1
        }
    ],
    "directoryCount": 4
}

Пока это было очень просто, но если вы помните, я сказал, что предпочитаю поддерживать как JSON, так и XML в моих микросервисах, и для получения XML-ответа все, что нам нужно сделать, — это запросить /metadata.xml. Единственное, что нам нужно было добавить в наш проект, это следующая зависимость, и Spring Boot выполнил остальную часть работы:

1
compile group: 'com.fasterxml.jackson.dataformat', name:'jackson-dataformat-xml', version: '2.6.3'

Скрипт сборки

Это полный скрипт сборки, который нам нужен для запуска этой службы.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
buildscript {
    ext {
        springBootVersion = '1.5.1.RELEASE'
    }
 
    repositories {
        mavenCentral()
    }
 
    dependencies {
       classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
 
}
 
apply plugin: 'groovy'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
 
jar {
    baseName = ‘image-metadata'
    version = '1.0.0'
    manifest {
        attributes("Implementation-Title": "Gradle",
                   "Implementation-Version": version,
                   "Main-Class": "com.daftano.metadata.MetadataApplication”
        )
    }
}
 
repositories {
    mavenCentral()
}
 
dependencies {
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-groovy-templates'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-logging'
    compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.22'
    compile group: 'com.drewnoakes', name: 'metadata-extractor', version: '2.10.0'
    compile group: 'com.fasterxml.jackson.dataformat', name:'jackson-dataformat-xml', version: '2.6.3'
 
    testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test'
 
}

докер

Теперь, когда у нас есть работающее приложение, давайте создадим наш образ докера.

1
2
3
4
5
6
7
8
9
FROM daftano/java:8
 
LABEL maintainer-twitter="@daftano"
 
EXPOSE 8080
 
ADD build/image-metadata-1.0.0.jar /opt/image-metadata.jar
 
ENTRYPOINT java -jar /opt/image-metadata.jar

Я уже говорил об этом образе, когда представил сервис HelloWorld, но на этот раз я добавил EXPOSE.

Создайте образ Docker и запустите его, и у вас будет Microservice для извлечения метаданных размером 63K.

Посмотрите оригинальную статью здесь: получите метаданные любого изображения с помощью Spring Boot и Docker.

Мнения, высказанные участниками Java Code Geeks, являются их собственными.