0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>Не JSON-ом единым оперируют back-end-ы приложения. В дикой природе встречаются Web-сервисы, которые на работают с XML (да, мы не о SOAP, а именно об XML). SpringMVC прекрасно поддерживает данную возможность, причём разными способами.</p>
1
<p>Не JSON-ом единым оперируют back-end-ы приложения. В дикой природе встречаются Web-сервисы, которые на работают с XML (да, мы не о SOAP, а именно об XML). SpringMVC прекрасно поддерживает данную возможность, причём разными способами.</p>
2
<h2>JSON c Jackson</h2>
2
<h2>JSON c Jackson</h2>
3
<p>По умолчанию spring-boot-starter-web содержит настроенный Jackson для маппинга request/response DTO в JSON.</p>
3
<p>По умолчанию spring-boot-starter-web содержит настроенный Jackson для маппинга request/response DTO в JSON.</p>
4
<p>Раз:</p>
4
<p>Раз:</p>
5
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency><p>(включает в себя jackson-databind)</p>
5
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency><p>(включает в себя jackson-databind)</p>
6
<p>Два:</p>
6
<p>Два:</p>
7
@RequiredArgsConstructor @Getter public class PersonJsonDto { @JsonProperty("firstName") private final String name; private final int age; }<p>Три:</p>
7
@RequiredArgsConstructor @Getter public class PersonJsonDto { @JsonProperty("firstName") private final String name; private final int age; }<p>Три:</p>
8
@RestController public class PersonJsonController { @GetMapping("/api/json") public PersonJsonDto json() { return new PersonJsonDto("Ivan", 18); } }<p>Данный контроллер содержит аннотацию @RestController, которая содержит @ResponseBody, которая в свою очередь говорит Spring MVC преобразовывать объект, используя существующие мапперы. Да, по умолчанию подразумевается application/json, для которого уже есть настроенный Jackson.</p>
8
@RestController public class PersonJsonController { @GetMapping("/api/json") public PersonJsonDto json() { return new PersonJsonDto("Ivan", 18); } }<p>Данный контроллер содержит аннотацию @RestController, которая содержит @ResponseBody, которая в свою очередь говорит Spring MVC преобразовывать объект, используя существующие мапперы. Да, по умолчанию подразумевается application/json, для которого уже есть настроенный Jackson.</p>
9
<p>Проверяем:</p>
9
<p>Проверяем:</p>
10
GET http://localhost:8080/api/json HTTP/1.1 200 Content-Type: application/json ... { "age": 18, "firstName": "Ivan" }<h2>XML c Jackson</h2>
10
GET http://localhost:8080/api/json HTTP/1.1 200 Content-Type: application/json ... { "age": 18, "firstName": "Ivan" }<h2>XML c Jackson</h2>
11
<p>Jackson, на самом деле, не “библиотека для маппинга в JSON”, а полноценный фреймворк для маппинга объектов не только в JSON, но и в XML, YAML и даже в бинарных форматах.</p>
11
<p>Jackson, на самом деле, не “библиотека для маппинга в JSON”, а полноценный фреймворк для маппинга объектов не только в JSON, но и в XML, YAML и даже в бинарных форматах.</p>
12
<p>Подобные расширения Jacson называются dataformat.</p>
12
<p>Подобные расширения Jacson называются dataformat.</p>
13
<p>Подключим соответствующую JAR:</p>
13
<p>Подключим соответствующую JAR:</p>
14
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency><p>В лучших традициях Spring Boot эта библиотека сразу будет настроена spring-boot-starter-mvc.</p>
14
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency><p>В лучших традициях Spring Boot эта библиотека сразу будет настроена spring-boot-starter-mvc.</p>
15
<p>Напишем соответствующий DTO:</p>
15
<p>Напишем соответствующий DTO:</p>
16
@JacksonXmlRootElement( namespace = "http://otus.ru/spring", localName = "person" ) @RequiredArgsConstructor @Getter public class PersonXmlDto { private final String name; private final int age; }<p>Да, стоит отметить, что c маппингом XML не всё так просто. Теперь поля объекта могут быть как вложенными тегами, так и атрибутами. И не стоит забывать про namespaces элементов. Пример, представленный здесь, не лишён недостатков, поэтому искушённым читателям предлагается прочитать<a>документацию</a>.</p>
16
@JacksonXmlRootElement( namespace = "http://otus.ru/spring", localName = "person" ) @RequiredArgsConstructor @Getter public class PersonXmlDto { private final String name; private final int age; }<p>Да, стоит отметить, что c маппингом XML не всё так просто. Теперь поля объекта могут быть как вложенными тегами, так и атрибутами. И не стоит забывать про namespaces элементов. Пример, представленный здесь, не лишён недостатков, поэтому искушённым читателям предлагается прочитать<a>документацию</a>.</p>
17
<p>И напишем контроллер:</p>
17
<p>И напишем контроллер:</p>
18
@RestController public class PersonXmlController { @GetMapping( value = "/api/jackson-xml", produces = "application/xml" ) public PersonXmlDto jacksonXml() { return new PersonXmlDto("Ivan", 18); } }<p>Обратите внимание на параметр аннотации produces - здесь мы задали application/xml, чтобы сработал именно XML-маппер.</p>
18
@RestController public class PersonXmlController { @GetMapping( value = "/api/jackson-xml", produces = "application/xml" ) public PersonXmlDto jacksonXml() { return new PersonXmlDto("Ivan", 18); } }<p>Обратите внимание на параметр аннотации produces - здесь мы задали application/xml, чтобы сработал именно XML-маппер.</p>
19
<p>Если мы ничего не напишем, то значение по умолчанию - application/json и будет действовать именно Jackson JSON dataformat, как в предыдущем примере.</p>
19
<p>Если мы ничего не напишем, то значение по умолчанию - application/json и будет действовать именно Jackson JSON dataformat, как в предыдущем примере.</p>
20
<p>Кстати, если мы будем принимать XML на вход с помощью @RequestBody, то нам необходимо будет указать уже consumes.</p>
20
<p>Кстати, если мы будем принимать XML на вход с помощью @RequestBody, то нам необходимо будет указать уже consumes.</p>
21
<p>Проверяем:</p>
21
<p>Проверяем:</p>
22
GET http://localhost:8080/api/jackson-xml HTTP/1.1 200 Content-Type: application/xml ... <person xmlns="http://otus.ru/spring"> <name xmlns="">Ivan</name> <age xmlns="">18</age> </person><h2>JAXB и Spring MVC</h2>
22
GET http://localhost:8080/api/jackson-xml HTTP/1.1 200 Content-Type: application/xml ... <person xmlns="http://otus.ru/spring"> <name xmlns="">Ivan</name> <age xmlns="">18</age> </person><h2>JAXB и Spring MVC</h2>
23
<p>Говоря об XML в Java, часто подразумевают именно JAXB. JAXB исключена из стандартной поставки Java 11, поэтому добавим вместо jackson-dataformat-xml зависимость:</p>
23
<p>Говоря об XML в Java, часто подразумевают именно JAXB. JAXB исключена из стандартной поставки Java 11, поэтому добавим вместо jackson-dataformat-xml зависимость:</p>
24
<dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> </dependency><p>DTO выглядит похожим образом:</p>
24
<dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> </dependency><p>DTO выглядит похожим образом:</p>
25
@XmlRootElement( namespace = "http://spring.otus.ru", name = "person-jaxb" ) @NoArgsConstructor @AllArgsConstructor @Getter @Setter public class PersonJaxbDto { private String name; private int age; }<p>И, как мы уже знаем, необходимо написать соответствующим образом контроллер:</p>
25
@XmlRootElement( namespace = "http://spring.otus.ru", name = "person-jaxb" ) @NoArgsConstructor @AllArgsConstructor @Getter @Setter public class PersonJaxbDto { private String name; private int age; }<p>И, как мы уже знаем, необходимо написать соответствующим образом контроллер:</p>
26
@RestController public class PersonJaxbController { @GetMapping( value = "/api/jaxb-xml", produces = "application/xml" ) public PersonJaxbDto jacksonXml() { return new PersonJaxbDto("Ivan", 18); } }<p>И, наконец, пробуем!</p>
26
@RestController public class PersonJaxbController { @GetMapping( value = "/api/jaxb-xml", produces = "application/xml" ) public PersonJaxbDto jacksonXml() { return new PersonJaxbDto("Ivan", 18); } }<p>И, наконец, пробуем!</p>
27
GET http://localhost:8080/api/jaxb-xml Content-Type: application/xml ... <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns2:person-jaxb xmlns:ns2="http://spring.otus.ru"> <age>18</age> <name>Ivan</name> </ns2:person-jaxb><p>Весь код доступен по<a>ссылке</a>. Успехов!</p>
27
GET http://localhost:8080/api/jaxb-xml Content-Type: application/xml ... <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns2:person-jaxb xmlns:ns2="http://spring.otus.ru"> <age>18</age> <name>Ivan</name> </ns2:person-jaxb><p>Весь код доступен по<a>ссылке</a>. Успехов!</p>
28
28