Spring Boot支持与三种JSON mapping库集成:Gson、Jackson和JSON-B。Jackson是首选和默认的。
Jackson是spring-boot-starter-json的一部分,spring-boot-starter-web中包含spring-boot-starter-json。也就是说,当项目中引入spring-boot-starter-web后会自动引入spring-boot-starter-json。
-
<dependency> -
<groupId>org.springframework.boot</groupId> -
<artifactId>spring-boot-starter-web</artifactId> -
</dependency>
ObjectMapper
ObjectMapper是jackson-databind包中的一个类,提供读写JSON的功能,可以方便的进行对象和JSON转换:
-
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> T parse(String content, Class<T> valueType) throws IOException { -
return mapper.readValue(content, valueType); -
} -
}
编写一简单POJO测试类:
-
import java.util.Date; -
public class Hero { -
public static void main(String[] args) throws Exception { -
System.out.println(JsonUtil.generate(new Hero("Jason", new Date()))); -
} -
private String name; -
private Date birthday; -
public Hero() { -
} -
public Hero(String name, Date birthday) { -
this.name = name; -
this.birthday = birthday; -
} -
public String getName() { -
return name; -
} -
public Date getBirthday() { -
return birthday; -
} -
}
运行后输出结果如下:
{"name":"Jason","birthday":1540909420353}
可以看到日期转换为长整型。
ObjectMapper默认序列化配置启用了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,日期将转换为Timestamp。可查看如下源码:
-
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; -
}
默认情况下,Date类型序列化将调用DateSerializer的_timestamp 方法:
-
/** -
* For efficiency, we will serialize Dates as longs, instead of -
* potentially more readable Strings. -
*/ -
@JacksonStdImpl -
@SuppressWarnings("serial") -
public class DateSerializer extends DateTimeSerializerBase<Date> { -
... -
@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);
这时序列化将调用StdDateFormat的format()方法,使用ISO-8601兼容格式"yyyy-MM-dd'T'HH:mm:ss.SSSZ",输出内容如下:
{"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注解,代替全局设置,是一种更灵活的方法:
-
@JsonFormat(shape = JsonFormat.Shape.STRING) -
private Date birthday;
还可以定义pattern:
-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") -
private Date birthday;
当自定义pattern后,将创建新的SimpleDateFormat实例来序列化日期,参见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); -
} -
... -
}
Spring Boot与Jackson ObjectMapper
Spring Boot使用HttpMessageConverters处理HTTP交换中的内容转换。当classpath中存在Jackson时,Jackson2ObjectMapperBuilder将是默认的Converter,源码请查看HttpMessageConverters和WebMvcConfigurationSupport:
HttpMessageConverters
-
private List<HttpMessageConverter<?>> getDefaultConverters() { -
List<HttpMessageConverter<?>> converters = new ArrayList<>(); -
if (ClassUtils.isPresent("org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport", null)) { -
converters.addAll(new WebMvcConfigurationSupport() { -
public List<HttpMessageConverter<?>> defaultMessageConverters() { -
return super.getMessageConverters(); -
} -
}.defaultMessageConverters()); -
} -
else { -
converters.addAll(new RestTemplate().getMessageConverters()); -
} -
reorderXmlConvertersToEnd(converters); -
return converters; -
}
WebMvcConfigurationSupport
-
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> 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将创建ObjectMapper实例:
Jackson2ObjectMapperBuilder
-
public <T extends ObjectMapper> 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; -
}
ObjectMapper以下属性被禁用:
- MapperFeature.DEFAULT_VIEW_INCLUSION
- DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
- SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
Jackson2ObjectMapperBuilder
-
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); -
} -
}
JacksonAutoConfiguration
-
static { -
Map<Object, Boolean> featureDefaults = new HashMap<>(); -
featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); -
FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults); -
}
自定义Jackson ObjectMapper配置
针对ObjectMapper的六种Feature,Spring Boot都提供了相应的配置,列表如下:
| 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 |
例如,为启用美化打印,设置spring.jackson.serialization.indent_output=true,相当于启用SerializationFeature.INDENT_OUTPUT,配置中忽略feature_name大小写。
其他的Jackson配置属性:
- spring.jackson.date-format= # Date format string or a fully-qualified date format class name. For instance,
yyyy-MM-dd HH:mm:ss. - spring.jackson.joda-date-time-format= # Joda date time format string. If not configured, "date-format" is used as a fallback if it is configured with a format string.
- spring.jackson.locale= # Locale used for formatting.
- spring.jackson.property-naming-strategy= # One of the constants on Jackson's PropertyNamingStrategy. Can also be a fully-qualified class name of a PropertyNamingStrategy subclass.
- spring.jackson.time-zone= # Time zone used when formatting dates. For instance, "America/Los_Angeles" or "GMT+10".
其中spring.jackson.date-format默认值为com.fasterxml.jackson.databind.util.StdDateFormat。
@DateTimeFormat和@JsonFormat
在REST编程中,当提交application/json的POST/PUT请求时,JSON会通过Jackson进行转换。当提交GET请求时,如参数中包含日期,后台代码需要使用注解@DateTimeFormat:
-
@DateTimeFormat(pattern = "yyyy-MM-dd") -
private Date startDate;
两者可以同时使用:
-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") -
@DateTimeFormat(pattern = "yyyy-MM-dd") -
private Date startDate; -
参考: -
https://blog.csdn.net/weixin_44048532/article/details/86647880
Spring Boot默认与Jackson集成,ObjectMapper可进行对象和JSON转换。默认序列化日期为Timestamp,可禁用WRITE_DATES_AS_TIMESTAMPS将日期序列化为字符串,也可用@JsonFormat注解。Spring Boot使用Jackson2ObjectMapperBuilder处理内容转换,还能自定义ObjectMapper配置,REST编程中涉及日期处理可用@DateTimeFormat和@JsonFormat。

288

被折叠的 条评论
为什么被折叠?



