Spring Boot支持與三種JSON mapping庫(kù)集成:Gson、Jackson和JSON-B。Jackson是首選和默認(rèn)的。
公司主營(yíng)業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)推出新沂免費(fèi)做網(wǎng)站回饋大家。
Jackson是spring-boot-starter-json依賴中的一部分,spring-boot-starter-web中包含spring-boot-starter-json。也就是說(shuō),當(dāng)項(xiàng)目中引入spring-boot-starter-web后會(huì)自動(dòng)引入spring-boot-starter-json。
org.springframework.boot
spring-boot-starter-web
ObjectMapper是jackson-databind包中的一個(gè)類(lèi),提供讀寫(xiě)JSON的功能,可以方便的進(jìn)行對(duì)象和JSON轉(zhuǎn)換:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public final class JsonUtil {
private static ObjectMapper mapper = new ObjectMapper();
private JsonUtil() {
}
/**
* Serialize any Java value as a String.
*/
public static String generate(Object object) throws JsonProcessingException {
return mapper.writeValueAsString(object);
}
/**
* Deserialize JSON content from given JSON content String.
*/
public static T parse(String content, Class valueType) throws IOException {
return mapper.readValue(content, valueType);
}
}
編寫(xiě)一簡(jiǎn)單POJO測(cè)試類(lèi):
import java.util.Date;
public class Hero {
private String name;
private Date birthday;
public static void main(String[] args) throws Exception {
System.out.println(JsonUtil.generate(new Hero("Jason", new Date())));
}
public Hero() {
}
public Hero(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public Date getBirthday() {
return birthday;
}
}
運(yùn)行后輸出結(jié)果如下:
{"name":"Jason","birthday":1540909420353}
上例,默認(rèn)日期轉(zhuǎn)換為長(zhǎng)整型。
ObjectMapper默認(rèn)序列化配置啟用了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,日期將轉(zhuǎn)換為T(mén)imestamp。可查看如下源碼:
public ObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {
...
BaseSettings base = DEFAULT_BASE.withClassIntrospector(defaultClassIntrospector());
_configOverrides = new ConfigOverrides();
_serializationConfig = new SerializationConfig(base, _subtypeResolver, mixins, rootNames, _configOverrides);
...
}
public SerializationConfig(BaseSettings base, SubtypeResolver str, SimpleMixInResolver mixins, RootNameLookup rootNames,
ConfigOverrides configOverrides)
{
super(base, str, mixins, rootNames, configOverrides);
_serFeatures = collectFeatureDefaults(SerializationFeature.class);
_filterProvider = null;
_defaultPrettyPrinter = DEFAULT_PRETTY_PRINTER;
_generatorFeatures = 0;
_generatorFeaturesToChange = 0;
_formatWriteFeatures = 0;
_formatWriteFeaturesToChange = 0;
}
默認(rèn)情況下,Date類(lèi)型序列化將調(diào)用DateSerializer的_timestamp 方法:
/**
* For efficiency, we will serialize Dates as longs, instead of
* potentially more readable Strings.
*/
@JacksonStdImpl
@SuppressWarnings("serial")
public class DateSerializer extends DateTimeSerializerBase {
...
@Override
protected long _timestamp(Date value) {
return (value == null) ? 0L : value.getTime();
}
@Override
public void serialize(Date value, JsonGenerator g, SerializerProvider provider) throws IOException {
if (_asTimestamp(provider)) {
g.writeNumber(_timestamp(value));
return;
}
_serializeAsString(value, g, provider);
}
}
DateTimeSerializerBase的_asTimestamp方法:
protected boolean _asTimestamp(SerializerProvider serializers)
{
if (_useTimestamp != null) {
return _useTimestamp.booleanValue();
}
if (_customFormat == null) {
if (serializers != null) {
return serializers.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
// 12-Jun-2014, tatu: Is it legal not to have provider? Was NPE:ing earlier so leave a check
throw new IllegalArgumentException("Null SerializerProvider passed for "+handledType().getName());
}
return false;
}
禁用WRITE_DATES_AS_TIMESTAMPS
若要將日期序列化為字符串,可禁用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS:
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
這時(shí)序列化將調(diào)用StdDateFormat的format()方法,使用ISO-8601兼容格式"yyyy-MM-dd'T'HH:mm:ss.SSSZ",輸出內(nèi)容如下:
{"name":"Jason","birthday":"2018-10-31T03:07:34.485+0000"}
StdDateFormat反序列化支持ISO-8601兼容格式和RFC-1123("EEE, dd MMM yyyy HH:mm:ss zzz")格式。
@JsonFormat
使用@JsonFormat注解,代替全局設(shè)置,是一種更靈活的方法:
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Date birthday;
還可以定義pattern:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date birthday;
當(dāng)自定義pattern后,將創(chuàng)建新的SimpleDateFormat實(shí)例來(lái)序列化日期,參見(jiàn)DateTimeSerializerBase的createContextual()方法:
public JsonSerializer> createContextual(SerializerProvider serializers, BeanProperty property) throws JsonMappingException
{
...
if (format.hasPattern()) {
final Locale loc = format.hasLocale() ? format.getLocale() : serializers.getLocale();
SimpleDateFormat df = new SimpleDateFormat(format.getPattern(), loc);
TimeZone tz = format.hasTimeZone() ? format.getTimeZone() : serializers.getTimeZone();
df.setTimeZone(tz);
return withFormat(Boolean.FALSE, df);
}
...
}
不過(guò)多解釋各注解的作用,請(qǐng)看輸出結(jié)果。
示例1
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder({"firstName", "lastName"})
@JsonIgnoreProperties({"id"})
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Hero {
private Integer id;
// define one or more alternative names for a property during deserialization.
@JsonAlias({"fName", "f_name"})
private String firstName;
private String lastName;
public static void main(String[] args) throws Exception {
System.out.println(JsonUtil.generate(new Hero(1, "Jason", "Sun")));
System.out.println(JsonUtil.generate(new Hero(1, "Jason", null)));
System.out.println(JsonUtil.parse("{\"fName\":\"Jason\",\"lastName\":\"Sun\"}", Hero.class).getFirstName());
}
public Hero() {
}
public Hero(Integer id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
// getter and setter
}
輸出結(jié)果:
{"firstName":"Jason","lastName":"Sun"}
{"firstName":"Jason"}
Jason
示例2
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreType;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Hero {
@JsonIgnore
private Integer id;
private String nickname;
private Name name;
@JsonProperty("mail")
private String email;
@JsonIgnoreType
public static class Name {
private String firstName;
private String lastName;
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// getter and setter
}
public static void main(String[] args) throws Exception {
System.out.println(JsonUtil.generate(new Hero(1, "chuanchuan", new Name("Jason", "Sun"), "jason@163.com")));
}
public Hero() {
}
public Hero(Integer id, String nickname, Name name, String email) {
this.id = id;
this.nickname = nickname;
this.name = name;
this.email = email;
}
// getter and setter
}
輸出結(jié)果:
{"nickname":"chuanchuan","mail":"jason@163.com"}
示例3
使用@JsonValue控制整個(gè)類(lèi)序列化的結(jié)果,一個(gè)類(lèi)中最多只能含有一個(gè)@JsonValue。
import com.fasterxml.jackson.annotation.JsonValue;
public class HeroWithValue {
private Integer id;
@JsonValue
private String name;
private String email;
public static void main(String[] args) throws Exception {
System.out.println(JsonUtil.generate(new HeroWithValue(1, "Jason", "jason@163.com")));
}
public HeroWithValue(Integer id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// getter and setter
}
輸出結(jié)果:
"Jason"
示例4
public class Views {
public static class Public {
}
public static class Internal extends Public {
}
}
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.ObjectMapper;
public class HeroWithView {
@JsonView(Views.Public.class)
private int id;
@JsonView(Views.Public.class)
private String name;
@JsonView(Views.Internal.class)
private String email;
public static void main(String[] args) throws Exception {
HeroWithView hero = new HeroWithView(1, "Jason", "jason@163.com");
String publicResult = new ObjectMapper().writerWithView(Views.Public.class).writeValueAsString(hero);
String internalResult = new ObjectMapper().writerWithView(Views.Internal.class).writeValueAsString(hero);
System.out.println(publicResult);
System.out.println(internalResult);
}
public HeroWithView(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
}
輸出結(jié)果:
{"id":1,"name":"Jason"}
{"id":1,"name":"Jason","email":"jason@163.com"}
示例5
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
@JsonRootName(value = "hero")
public class UnwrappedHero {
private int id;
@JsonUnwrapped
private Name name;
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
System.out.println(mapper.writeValueAsString(new UnwrappedHero(1, new Name("Jason", "Sun"))));
}
public UnwrappedHero(int id, Name name) {
this.id = id;
this.name = name;
}
public static class Name {
private String firstName;
private String lastName;
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// getter and setter
}
// getter and setter
}
示例6
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
public class Zoo {
private Animal animal;
public Zoo(Animal animal) {
this.animal = animal;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public static class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@JsonTypeName("dog")
public static class Dog extends Animal {
private double barkVolume;
public Dog(String name) {
super(name);
}
public double getBarkVolume() {
return barkVolume;
}
public void setBarkVolume(double barkVolume) {
this.barkVolume = barkVolume;
}
}
@JsonTypeName("cat")
public static class Cat extends Animal {
private boolean likesCream;
private int lives;
public Cat(String name) {
super(name);
}
public boolean isLikesCream() {
return likesCream;
}
public void setLikesCream(boolean likesCream) {
this.likesCream = likesCream;
}
public int getLives() {
return lives;
}
public void setLives(int lives) {
this.lives = lives;
}
}
public static void main(String[] args) throws Exception {
System.out.println(JsonUtil.generate(new Zoo(new Dog("lacy"))));
System.out.println(JsonUtil.generate(new Zoo(new Cat("tom"))));
}
public Animal getAnimal() {
return animal;
}
public void setAnimal(Animal animal) {
this.animal = animal;
}
}
輸出結(jié)果:
{"animal":{"type":"dog","name":"lacy","barkVolume":0.0}}
{"animal":{"type":"cat","name":"tom","likesCream":false,"lives":0}}
示例7
雙向關(guān)聯(lián)時(shí)如未做處理,會(huì)發(fā)生錯(cuò)誤:com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError),可組合使用@JsonManagedReference和@JsonBackReference。
public class Hero {
private Integer id;
private String name;
@JsonManagedReference
private List races = new ArrayList<>();
public static void main(String[] args) throws Exception {
Hero hero = new Hero(1, "jason");
Race race = new Race(1, "marathon", 42.195f);
hero.addRace(race);
System.out.println(JsonUtil.generate(hero));
System.out.println(JsonUtil.generate(race));
}
public Hero(Integer id, String name) {
this.id = id;
this.name = name;
}
public void addRace(Race race) {
races.add(race);
race.setHero(this);
}
// getter and setter
}
import com.fasterxml.jackson.annotation.JsonBackReference;
public class Race {
private Integer id;
private String type;
private Float distance;
@JsonBackReference
private Hero hero;
public Race(Integer id, String type, Float distance) {
this.id = id;
this.type = type;
this.distance = distance;
}
// getter and setter
}
輸出結(jié)果:
{"id":1,"name":"jason","races":[{"id":1,"type":"marathon","distance":42.195}]}
{"id":1,"type":"marathon","distance":42.195}
示例8
雙向關(guān)聯(lián)的另一種解決方案,使用@JsonIdentityInfo。
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import java.util.ArrayList;
import java.util.List;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Hero {
private Integer id;
private String name;
private List races = new ArrayList<>();
public static void main(String[] args) throws Exception {
Hero hero = new Hero(1, "jason");
Race race = new Race(1, "marathon", 42.195f);
hero.addRace(race);
System.out.println(JsonUtil.generate(hero));
System.out.println(JsonUtil.generate(race));
}
public Hero(Integer id, String name) {
this.id = id;
this.name = name;
}
public void addRace(Race race) {
races.add(race);
race.setHero(this);
}
// getter and setter
}
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Race {
private Integer id;
private String type;
private Float distance;
private Hero hero;
public Race(Integer id, String type, Float distance) {
this.id = id;
this.type = type;
this.distance = distance;
}
// getter and setter
}
輸出結(jié)果:
{"id":1,"name":"jason","races":[{"id":1,"type":"marathon","distance":42.195,"hero":1}]}
{"id":1,"type":"marathon","distance":42.195,"hero":{"id":1,"name":"jason","races":[1]}}
示例9
上例,如果要Race序列化結(jié)果僅含有hero id,可以組合使用@JsonIdentityInfo和@JsonIdentityReference。
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import java.util.ArrayList;
import java.util.List;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", resolver = HeroIdResolver.class)
public class Hero {
private Integer id;
private String name;
private List races = new ArrayList<>();
public static void main(String[] args) throws Exception {
Hero hero = new Hero(1, "jason");
Race race = new Race(1, "marathon", 42.195f);
hero.addRace(race);
System.out.println(JsonUtil.generate(hero));
System.out.println(JsonUtil.generate(race));
}
public Hero(Integer id) {
this.id = id;
}
public Hero(Integer id, String name) {
this.id = id;
this.name = name;
}
public void addRace(Race race) {
races.add(race);
race.setHero(this);
}
// getter and setter
}
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Race {
private Integer id;
private String type;
private Float distance;
@JsonIdentityReference(alwaysAsId = true)
@JsonProperty("heroId")
private Hero hero;
public Race(Integer id, String type, Float distance) {
this.id = id;
this.type = type;
this.distance = distance;
}
// getter and setter
}
為了支持反序列化,需要自定義ObjectIdResolver:
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
public class HeroIdResolver implements ObjectIdResolver {
@Override
public void bindItem(ObjectIdGenerator.IdKey id, Object pojo) {
}
@Override
public Object resolveId(ObjectIdGenerator.IdKey id) {
return new Hero((Integer) id.key);
}
@Override
public ObjectIdResolver newForDeserialization(Object context) {
return new HeroIdResolver();
}
@Override
public boolean canUseFor(ObjectIdResolver resolverType) {
return resolverType.getClass() == getClass();
}
}
輸出結(jié)果:
{"id":1,"name":"jason","races":[{"id":1,"type":"marathon","distance":42.195,"heroId":1}]}
{"id":1,"type":"marathon","distance":42.195,"heroId":1}
示例10
自定義Annotation,將多個(gè)Annotation組合起來(lái)。
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"name", "id", "dateCreated"})
public @interface CustomAnnotation {
}
import java.util.Date;
@CustomAnnotation
public class HeroWithCustomAnnotation {
private Integer id;
private String name;
private Date dateCreated;
public static void main(String[] args) throws Exception {
System.out.println(JsonUtil.generate(new HeroWithCustomAnnotation(1, "Jason", null)));
}
public HeroWithCustomAnnotation(Integer id, String name, Date dateCreated) {
this.id = id;
this.name = name;
this.dateCreated = dateCreated;
}
// getter and setter
}
輸出結(jié)果:
{"name":"Jason","id":1}
Spring Boot使用HttpMessageConverters處理HTTP交換中的內(nèi)容轉(zhuǎn)換。當(dāng)classpath中存在Jackson時(shí),Jackson2ObjectMapperBuilder提供默認(rèn)的Converter,源碼請(qǐng)查看HttpMessageConverters和WebMvcConfigurationSupport:
HttpMessageConverters
private List> getDefaultConverters() {
List> converters = new ArrayList<>();
if (ClassUtils.isPresent("org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport", null)) {
converters.addAll(new WebMvcConfigurationSupport() {
public List> defaultMessageConverters() {
return super.getMessageConverters();
}
}.defaultMessageConverters());
}
else {
converters.addAll(new RestTemplate().getMessageConverters());
}
reorderXmlConvertersToEnd(converters);
return converters;
}
WebMvcConfigurationSupport
protected final void addDefaultHttpMessageConverters(List> messageConverters) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(stringHttpMessageConverter);
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
messageConverters.add(new SourceHttpMessageConverter<>());
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
...
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
...
}
Jackson2ObjectMapperBuilder創(chuàng)建ObjectMapper實(shí)例:
Jackson2ObjectMapperBuilder
public T build() {
ObjectMapper mapper;
if (this.createXmlMapper) {
mapper = (this.defaultUseWrapper != null ?
new XmlObjectMapperInitializer().create(this.defaultUseWrapper) :
new XmlObjectMapperInitializer().create());
}
else {
mapper = (this.factory != null ? new ObjectMapper(this.factory) : new ObjectMapper());
}
configure(mapper);
return (T) mapper;
}
...
private void customizeDefaultFeatures(ObjectMapper objectMapper) {
if (!this.features.containsKey(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
configureFeature(objectMapper, MapperFeature.DEFAULT_VIEW_INCLUSION, false);
}
if (!this.features.containsKey(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
configureFeature(objectMapper, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
默認(rèn)禁用了MapperFeature.DEFAULT_VIEW_INCLUSION、DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES。
Auto Configurationk中默認(rèn)禁用了WRITE_DATES_AS_TIMESTAMPS:
JacksonAutoConfiguration
static {
Map
針對(duì)ObjectMapper的六種Feature,Spring Boot都提供了相應(yīng)的配置,列表如下:
Feature(Enum) | Spring Boot Property | Values |
---|---|---|
com.fasterxml.jackson.databind.DeserializationFeature | spring.jackson.deserialization.feature_name | true, false |
com.fasterxml.jackson.core.JsonGenerator.Feature | spring.jackson.generator.feature_name | true, false |
com.fasterxml.jackson.databind.MapperFeature | spring.jackson.mapper.feature_name | true, false |
com.fasterxml.jackson.core.JsonParser.Feature | spring.jackson.parser.feature_name | true, false |
com.fasterxml.jackson.databind.SerializationFeature | spring.jackson.serialization.feature_name | true, false |
com.fasterxml.jackson.annotation.JsonInclude.Include | spring.jackson.default-property-inclusion | always, non_null, non_absent, non_default, non_empty |
例如,為啟用美化打印,設(shè)置spring.jackson.serialization.indent_output=true,相當(dāng)于啟用SerializationFeature.INDENT_OUTPUT,配置中忽略feature_name大小寫(xiě)。
其他的Jackson配置屬性:
yyyy-MM-dd HH:mm:ss
.其中spring.jackson.date-format默認(rèn)值為com.fasterxml.jackson.databind.util.StdDateFormat。
在REST編程中,當(dāng)提交application/json的POST/PUT請(qǐng)求時(shí),JSON會(huì)通過(guò)Jackson進(jìn)行轉(zhuǎn)換。當(dāng)提交GET請(qǐng)求時(shí),如參數(shù)中包含日期,后臺(tái)代碼需要使用注解@DateTimeFormat:
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
兩者可以同時(shí)使用:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;
@RestController
@RequestMapping(value = "/api", produces = MediaType.APPLICATION_JSON_VALUE)
@Api(tags = {"Hello Controller"})
public class HelloController {
...
}
JSON MediaType為"application/json;charset=UTF-8",默認(rèn)charset為"UTF-8"。
如果遺留代碼使用了GBK編碼,我們修改produces為"application/json;charset=GBK",會(huì)生效么?根據(jù)JSON規(guī)范The JavaScript Object Notation (JSON) Data Interchange Format - Character Encoding,JSON僅支持UTF-8、UTF-16、UTF-32編碼。
查看源碼驗(yàn)證一下:
AbstractJackson2HttpMessageConverter
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter
JsonEncoding
public enum JsonEncoding {
UTF8("UTF-8", false, 8), // N/A for big-endian, really
UTF16_BE("UTF-16BE", true, 16),
UTF16_LE("UTF-16LE", false, 16),
UTF32_BE("UTF-32BE", true, 32),
UTF32_LE("UTF-32LE", false, 32)
...
}
可以看到JsonEncoding僅包含UTF-8、UTF-16BE、UTF-16LE、UTF-32BE、UTF-32LE幾種編碼。
Jackson Annotation Examples