Spring Boot JSON
最后修改于 2023 年 7 月 28 日
Spring Boot JSON 教程展示了如何在 Spring Boot 注解中提供 JSON 数据。
Spring 是一个流行的 Java 应用程序框架,而 Spring Boot 是 Spring 的一个演进,它有助于轻松创建独立的、生产级的基于 Spring 的应用程序。
JSON
JSON (JavaScript 对象表示法) 是一种轻量级的数据交换格式。它易于人类阅读和编写,也易于机器解析和生成。JSON 的官方互联网媒体类型是 application/json
。JSON 文件扩展名是 .json
。
Spring Boot JSON
Spring Boot 提供了与三个 JSON 映射库的集成
- Gson
- Jackson
- JSON-B
Jackson 是首选和默认的库。
spring.http.converters.preferred-json-mapper=jsonb
可以使用 spring.http.converters.preferred-json-mapper
属性设置首选的 JSON 转换器。
Jackson
Jackson 是一个用于 Java 的数据处理工具套件。它允许以 JSON、Avro、BSON、CBOR、CSV、Smile、(Java)Properties、Protobuf、XML 或 YAML 格式读写数据。
Jackson 是自动配置的。它附带了 spring-boot-starter-json
。当 Jackson 位于类路径上时,会自动配置一个 ObjectMapper
bean。spring-boot-starter-json
与 spring-boot-starter-web
一起被引入。
在 Spring 中,对象使用 Jackson 库自动转换为 JSON。Spring 也可以配置为转换为 XML。
spring.jackson.date-format= # For instance, `yyyy-MM-dd HH:mm:ss`. spring.jackson.default-property-inclusion= # including properties during serialization. spring.jackson.deserialization.*= # Jackson on/off features for deserialization. spring.jackson.generator.*= # Jackson on/off features for generators. spring.jackson.joda-date-time-format= # Joda date time format string. spring.jackson.locale= # Locale used for formatting. spring.jackson.mapper.*= # Jackson general purpose on/off features. spring.jackson.parser.*= # Jackson on/off features for parsers. spring.jackson.property-naming-strategy= # PropertyNamingStrategy. spring.jackson.serialization.*= # Jackson on/off features for serialization. spring.jackson.time-zone= # Time zone spring.jackson.visibility.*= # To limit which methods (and fields) are auto-detected.
Jackson 可以使用应用程序属性进行配置。
@Configuration public class WebConfig { @Bean public ObjectMapper customJson() { return new Jackson2ObjectMapperBuilder() .indentOutput(true) .propertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE) .build(); } }
Jackson 可以使用 Jackson2ObjectMapperBuilder
进行配置。
@Bean public Jackson2ObjectMapperBuilderCustomizer customJson() { return builder -> { builder.indentOutput(true); builder.propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); }; }
可以使用 Jackson2ObjectMapperBuilderCustomizer
修改现有配置。
Spring Boot JSON 示例
以下应用程序将 JSON 数据返回给客户端。Jackson 以三种不同的方式配置。
build.gradle ... src ├───main │ ├───java │ │ └───com │ │ └───zetcode │ │ │ Application.java │ │ ├───config │ │ │ WebConfig.java │ │ ├───controller │ │ │ MyController.java │ │ ├───model │ │ │ City.java │ │ └───service │ │ CityService.java │ │ ICityService.java │ └───resources │ application.yml └── test ├── java └── resources
这是项目结构。
plugins { id 'org.springframework.boot' version '3.1.1' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' }
这是 Gradle build.gradle
文件。
spring: main: log-startup-info: false jackson: property-naming-strategy: UPPER_CAMEL_CASE serialization: indent-output: true
在 application.yml
文件中,我们设置 Jackson 属性。这些设置可以使用配置 bean 进行覆盖或自定义。
package com.zetcode.model; import com.fasterxml.jackson.annotation.JsonIgnore; import java.util.Objects; public class City { @JsonIgnore private Long id; private String name; private int population; public City() { } public City(Long id, String name, int population) { this.id = id; this.name = name; this.population = population; } public Long getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPopulation() { return population; } public void setPopulation(int population) { this.population = population; } @Override public int hashCode() { int hash = 7; hash = 79 * hash + Objects.hashCode(this.id); hash = 79 * hash + Objects.hashCode(this.name); hash = 79 * hash + this.population; return hash; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final City other = (City) obj; if (this.population != other.population) { return false; } if (!Objects.equals(this.name, other.name)) { return false; } return Objects.equals(this.id, other.id); } @Override public String toString() { final StringBuilder sb = new StringBuilder("City{"); sb.append("id=").append(id); sb.append(", name='").append(name).append('\''); sb.append(", population=").append(population); sb.append('}'); return sb.toString(); } }
我们有一个 City
模型类。
@JsonIgnore private Long id;
使用 @JsonIgnore
,我们从 JSON 序列化中删除 id
。
package com.zetcode.service; import com.zetcode.model.City; import java.util.List; public interface ICityService { List<City> getCities(); }
ICityService
包含 getCities
合约方法。
package com.zetcode.service; import com.zetcode.model.City; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class CityService implements ICityService { public List<City> getCities() { List<City> cities = new ArrayList<>(); cities.add(new City(1L, "Bratislava", 432000)); cities.add(new City(2L, "Budapest", 1759000)); cities.add(new City(3L, "Prague", 1280000)); cities.add(new City(4L, "Warsaw", 1748000)); cities.add(new City(5L, "Los Angeles", 3971000)); cities.add(new City(6L, "New York", 8550000)); cities.add(new City(7L, "Edinburgh", 464000)); cities.add(new City(8L, "Berlin", 3671000)); return cities; } }
CityService
返回一个城市对象列表。我们没有使用数据库来简化示例。
package com.zetcode.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; @Configuration public class WebConfig { // @Bean public ObjectMapper configureJson() { return new Jackson2ObjectMapperBuilder() .indentOutput(true) .propertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE) .build(); } @Bean public Jackson2ObjectMapperBuilderCustomizer customizeJson() { return builder -> { builder.indentOutput(true); builder.propertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE); }; } }
在 WebConfig
中,我们有覆盖和自定义 Jackson 设置的 bean。尝试不同的设置并查看它们的应用方式。启用或禁用 bean(通过注释 @Bean
)并比较结果。
package com.zetcode.controller; import com.zetcode.model.City; import com.zetcode.service.ICityService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class MyController { private final ICityService cityService; public MyController(ICityService cityService) { this.cityService = cityService; } @GetMapping("/cities") public List<City> getCities() { return cityService.getCities(); } }
为了将数据写入响应正文,我们使用 @RestController
或 @Controller
/@ResponseBody
组合。
@GetMapping("/cities") public List<City> getCities() { return cityService.getCities(); }
getCities
方法返回一个城市对象列表。这些对象会自动序列化为 JSON。
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Application
是设置 Spring Boot 应用程序的入口点。
我们使用 ./gradlew bootRun
运行应用程序。
$ curl localhost:8080/cities [ { "Name" : "Bratislava", "Population" : 432000 }, { "Name" : "Budapest", "Population" : 1759000 }, { "Name" : "Prague", "Population" : 1280000 }, { "Name" : "Warsaw", "Population" : 1748000 }, { "Name" : "Los Angeles", "Population" : 3971000 }, { "Name" : "New York", "Population" : 8550000 }, { "Name" : "Edinburgh", "Population" : 464000 }, { "Name" : "Berlin", "Population" : 3671000 } ]
这是一个示例输出。JSON 数据被缩进,并且属性命名策略是 UPPER_CAMEL_CASE。
在本文中,我们展示了如何在 Spring Boot 应用程序中向客户端提供 JSON 数据。