说明
接口返回的json对象内的字段可能包含null值,前端可能还需要再对null做处理,判断、显示等
方案
除对象外,字段不会再返回null值
全局对返回null的处理
后端可使用注解@JacksonAllowNull允许字段返回null
类型 | 默认返回值 | 默认处理 |
---|---|---|
String | "" | 无 |
Boolean | false | 无 |
Integer,Float,Double,BigDecimal | 0 | 无 |
Long | 0 | 无 |
Array,List,Set | [] | 无 |
Date | null | FORMAT('yyyy-MM-dd HH:mm:ss'), timeZone(GMT+8) |
内容
JacksonAllowNull
<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n60" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit; background-repeat: inherit;">/**
- <p>
- 不处理null的数据
- </p>
- @author miaoyj
- @version 1.0.0-SNAPSHOT
- @since 2020-07-09
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JacksonAllowNull {
}</pre>
JacksonHttpMessageConverter
<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="java" cid="n65" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; caret-color: rgb(51, 51, 51); color: rgb(51, 51, 51); font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; background-position: inherit; background-repeat: inherit;">@Component
public class JacksonHttpMessageConverter extends MappingJackson2HttpMessageConverter {
/**
- <p>
- 构造函数
- </p>
- @author miaoyj
- @since 2020-09-09
*/
public JacksonHttpMessageConverter() {
ObjectMapper objectMapper = getObjectMapper();
// 日期格式化
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 时区设置
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
objectMapper.setSerializerFactory(objectMapper.getSerializerFactory()
.withSerializerModifier(new MyBeanSerializerModifier()));
//解决 /instances/%5Bobject%20Object%5D/actuator/metrics
//https://github.com/codecentric/spring-boot-admin/issues/1517
objectMapper.addMixIn(InstanceId.class, InstanceIdMixin.class);
String[] pwdConstructor = new String[]{".*password$"};
objectMapper.registerModule(new AdminServerModule(pwdConstructor));
//解决domain.values.Registration cannot deserialize from Object
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Registration.class, ToStringSerializer.instance);
simpleModule.addDeserializer(Registration.class, new RegistrationDeserializer());
objectMapper.registerModule(simpleModule);
}
/**
- {@inheritDoc}
- <p>
- 类型只支持application/json
- </p>
- @author miaoyj
- @since 2020-09-09
*/
@Override
public List<MediaType> getSupportedMediaTypes() {
return CollUtil.newArrayList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN);
}
/**
- {@inheritDoc}
- <p>
- JSON输出只处理Wrapper的包装类
- </p>
- <p>
- 不注释会导致springBootAdmin显示失败
- </p>
- @author miaoyj
- @since 2020-09-09
*/
// @Override
// public boolean canWrite(Class<?> clazz, MediaType mediaType) {
// return ResultWrapper.class.isAssignableFrom(clazz);
// }
private class MyBeanSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
for (Object beanProperty : beanProperties) {
BeanPropertyWriter writer = (BeanPropertyWriter) beanProperty;
/过滤允许为null的注解/
if (ObjectUtil.isNull(writer.getAnnotation(JacksonAllowNull.class))) {
if (isArrayType(writer)) {
writer.assignNullSerializer(new NullArrayJsonSerializer());
} else if (isNumberType(writer)) {
writer.assignNullSerializer(new NullNumberJsonSerializer());
} else if (isBooleanType(writer)) {
writer.assignNullSerializer(new NullBooleanJsonSerializer());
} else if (isStringType(writer)) {
writer.assignNullSerializer(new NullStringJsonSerializer());
}
}
/* 防止Long精度丢失 */
// if(isLongType(writer)){
// writer.assignSerializer(new ToStringSerializer());
// }
}
return beanProperties;
}
private boolean isArrayType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return clazz.isArray() || Collection.class.isAssignableFrom(clazz);
}
private boolean isStringType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
}
private boolean isNumberType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return Number.class.isAssignableFrom(clazz);
}
private boolean isLongType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return Long.class.isAssignableFrom(clazz);
}
private boolean isBooleanType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return clazz.equals(Boolean.class);
}
}
private class NullArrayJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException {
if (o == null) {
jsonGenerator.writeStartArray();
jsonGenerator.writeEndArray();
}
}
}
private class NullStringJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(StringUtils.EMPTY);
}
}
private class NullNumberJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeNumber(0);
}
}
private class NullBooleanJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeBoolean(false);
}
}
}</pre>