一般而言,如果后端返回的属性值为 null,最好的处理办法就是连属性名也删掉,因为 iOS 没有 null,前端字典遍历有值但又展示 null,是比较尴尬的时候,然后万事都说不准,这不,PHP 又来捣乱了,要求属性值为 null 也要展示属性名,同时还要求 string 的 null 用 "" 代替。
spring 中 json 工具类是 JackSon,以此为例。
1. 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GamePHPBody {
}
2. 核心类
static class PHPMessageConverter extends MappingJackson2HttpMessageConverter {
/**
* 处理数组类型的null值
*/
public class NullArrayJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
if (value == null) {
jgen.writeStartArray();
jgen.writeEndArray();
}
}
}
/**
* 处理字符串类型的null值
*/
public class NullStringJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
jsonGenerator.writeString(StringUtils.EMPTY);
}
}
/**
* 处理数字类型的null值
*/
public class NullNumberJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
jsonGenerator.writeNumber(0);
}
}
/**
* 处理布尔类型的null值
*/
public class NullBooleanJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
jsonGenerator.writeBoolean(false);
}
}
public class MyBeanSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
//循环所有的beanPropertyWriter
for (Object beanProperty : beanProperties) {
BeanPropertyWriter writer = (BeanPropertyWriter) beanProperty;
//判断字段的类型,如果是array,list,set则注册nullSerializer
if (isArrayType(writer)) {
//给writer注册一个自己的nullSerializer
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());
}
}
return beanProperties;
}
/**
* 是否是数组
*/
private boolean isArrayType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return clazz.isArray() || Collection.class.isAssignableFrom(clazz);
}
/**
* 是否是string
*/
private boolean isStringType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
}
/**
* 是否是int
*/
private boolean isNumberType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return Number.class.isAssignableFrom(clazz);
}
/**
* 是否是boolean
*/
private boolean isBooleanType(BeanPropertyWriter writer) {
Class<?> clazz = writer.getType().getRawClass();
return clazz.equals(Boolean.class);
}
}
PHPMessageConverter() {
getObjectMapper().setSerializerFactory(getObjectMapper().getSerializerFactory().withSerializerModifier(new MyBeanSerializerModifier()));
}
}
3. 加入 spring 配置
public class GamePHPMethodProcessor implements HandlerMethodReturnValueHandler {
private GameFormMethodArgumentResolver formResolver;
private GameJsonMethodArgumentResolver jsonResolver;
public GamePHPMethodProcessor() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
PHPMessageConverter PHPMessageConverter = new PHPMessageConverter();
messageConverters.add(PHPMessageConverter);
jsonResolver = new GameJsonMethodArgumentResolver(messageConverters);
formResolver = new GameFormMethodArgumentResolver();
}
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return returnType.hasMethodAnnotation(GamePHPBody.class);
}
@Override
public void handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest) throws Exception {
jsonResolver.handleReturnValue(o, methodParameter, modelAndViewContainer, nativeWebRequest);
}
}
public static class MyMvcConfigurer implements WebMvcConfigurer {
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers){
handlers.add(new GamePHPMethodProcessor());
}
}