关于Blade框架对数字类型的null值转为-1问题

关于Blade框架对数字类型的null值转为-1问题

问题:最近项目遇到了一个问题,SpringBoot项目后端Long类型的数据,如果是NULL的话,返回给前端的时候是-1。如下图:

分析

是由于使用了 blade 框架,项目启动的时候会执行MessageConfiguration类的代码:

MappingApiJackson2HttpMessageConverter这个类会执行:

BladeBeanSerializerModifier类对于 Number 类型会执行下面:


可以看到设置为 -1了。

解决办法

从上面我们可以看出主要是由于BladeBeanSerializerModifier类里面的方法,如果 Number 类型就会 NUMBER_JSON_SERIALIZER ,这个里面设为了 -1,那么我们只需要修改这里为 我们想返回的值就好。

但是这是源码,我们不能直接修改,所以就要"围魏救赵"。我们可以采用下面的方法

1、添加三个类:

  • MessageConfiguration :
java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springblade.core.tool.jackson.BladeJacksonProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
@Order(value = (Integer.MIN_VALUE + 1))
public class MessageConfiguration implements WebMvcConfigurer {

	private final ObjectMapper objectMapper;
	private final BladeJacksonProperties properties;

	public MessageConfiguration(final ObjectMapper objectMapper, final BladeJacksonProperties properties) {
		this.objectMapper = objectMapper;
		this.properties = properties;
	}

	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		converters.removeIf((x) -> {
			return x instanceof AbstractJackson2HttpMessageConverter;
		});
		converters.add(new MappingApiJackson2HttpMessageConverter(this.objectMapper, this.properties));
	}
}

注意:Order 设置为 Integer.MIN_VALUE + 1,让我们写的这个类的 configureMessageConverters 方法,执行顺序在 原本MessageConfiguration类的configureMessageConverters方法之后,在我们的方法移出他们框架的MappingApiJackson2HttpMessageConverter,添加我们自己的 MappingApiJackson2HttpMessageConverter 类(后面代码有提供)。

  • MappingApiJackson2HttpMessageConverter :
java 复制代码
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.springblade.core.tool.jackson.AbstractReadWriteJackson2HttpMessageConverter;
import org.springblade.core.tool.jackson.BladeJacksonProperties;
import org.springblade.core.tool.jackson.BladeNumberModule;
import org.springblade.core.tool.utils.Charsets;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;

public class MappingApiJackson2HttpMessageConverter extends AbstractReadWriteJackson2HttpMessageConverter {
    @Nullable
    private String jsonPrefix;

    public MappingApiJackson2HttpMessageConverter(ObjectMapper objectMapper, BladeJacksonProperties properties) {
        super(objectMapper, initWriteObjectMapper(objectMapper, properties), initMediaType(properties));
    }

    private static List<MediaType> initMediaType(BladeJacksonProperties properties) {
        List<MediaType> supportedMediaTypes = new ArrayList();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        supportedMediaTypes.add(new MediaType("application", "*+json"));
        if (Boolean.TRUE.equals(properties.getSupportTextPlain())) {
            supportedMediaTypes.add(MediaType.TEXT_PLAIN);
        }

        return supportedMediaTypes;
    }

    private static ObjectMapper initWriteObjectMapper(ObjectMapper readObjectMapper, BladeJacksonProperties properties) {
        ObjectMapper writeObjectMapper = readObjectMapper.copy();
        if (Boolean.TRUE.equals(properties.getBigNumToString())) {
            writeObjectMapper.registerModules(new Module[]{BladeNumberModule.INSTANCE});
        }

        if (Boolean.TRUE.equals(properties.getNullToEmpty())) {
            writeObjectMapper.setSerializerFactory(writeObjectMapper.getSerializerFactory().withSerializerModifier(new BladeBeanSerializerModifier()));
            writeObjectMapper.getSerializerProvider().setNullValueSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
        }

        return writeObjectMapper;
    }

    protected void writeInternal(@NonNull Object object, @Nullable Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        if (object instanceof String) {
            Charset defaultCharset = this.getDefaultCharset();
            Charset charset = defaultCharset == null ? Charsets.UTF_8 : defaultCharset;
            StreamUtils.copy((String)object, charset, outputMessage.getBody());
        } else {
            super.writeInternal(object, type, outputMessage);
        }

    }

    public void setJsonPrefix(@Nullable String jsonPrefix) {
        this.jsonPrefix = jsonPrefix;
    }

    public void setPrefixJson(boolean prefixJson) {
        this.jsonPrefix = prefixJson ? ")]}', " : null;
    }

    protected void writePrefix(@NonNull JsonGenerator generator, @NonNull Object object) throws IOException {
        if (this.jsonPrefix != null) {
            generator.writeRaw(this.jsonPrefix);
        }

    }
}
  • BladeBeanSerializerModifier:
java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
/

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;

import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.Date;
import java.util.List;

public class BladeBeanSerializerModifier extends BeanSerializerModifier {
    public BladeBeanSerializerModifier() {
    }

    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
        beanProperties.forEach((writer) -> {
            if (!writer.hasNullSerializer()) {
                JavaType type = writer.getType();
                Class<?> clazz = type.getRawClass();
				if (type.isTypeOrSubTypeOf(Number.class)) {
					writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.NUMBER_JSON_SERIALIZER);
				} else if (type.isTypeOrSubTypeOf(Boolean.class)) {
					writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.BOOLEAN_JSON_SERIALIZER);
                } else if (type.isTypeOrSubTypeOf(Character.class)) {
                    writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
                } else if (type.isTypeOrSubTypeOf(String.class)) {
                    writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
                } else if (!type.isArrayType() && !clazz.isArray() && !type.isTypeOrSubTypeOf(Collection.class)) {
                    if (type.isTypeOrSubTypeOf(OffsetDateTime.class)) {
                        writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
                    } else if (!type.isTypeOrSubTypeOf(Date.class) && !type.isTypeOrSubTypeOf(TemporalAccessor.class)) {
                        writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.OBJECT_JSON_SERIALIZER);
                    } else {
                        writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.STRING_JSON_SERIALIZER);
                    }
                } else {
                    writer.assignNullSerializer(BladeBeanSerializerModifier.NullJsonSerializers.ARRAY_JSON_SERIALIZER);
                }

            }
        });
        return super.changeProperties(config, beanDesc, beanProperties);
    }

    public interface NullJsonSerializers {
        JsonSerializer<Object> STRING_JSON_SERIALIZER = new JsonSerializer<Object>() {
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            
		// 这里是关键:你要是想返回 NULL,这样写:gen.writeNull()
		// 返回空字符串按照下面写:
                gen.writeString("");
            }
        };
        JsonSerializer<Object> NUMBER_JSON_SERIALIZER = new JsonSerializer<Object>() {
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
				gen.writeString("");
            }
        };
        JsonSerializer<Object> BOOLEAN_JSON_SERIALIZER = new JsonSerializer<Object>() {
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeObject(Boolean.FALSE);
            }
        };
        JsonSerializer<Object> ARRAY_JSON_SERIALIZER = new JsonSerializer<Object>() {
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeStartArray();
                gen.writeEndArray();
            }
        };
        JsonSerializer<Object> OBJECT_JSON_SERIALIZER = new JsonSerializer<Object>() {
            public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeStartObject();
                gen.writeEndObject();
            }
        };
    }
}

注意:上面三个类导入的都是我们重写的类,不要导入 blade 框架原有的了哦~。

测试

启动项目,进行测试:

相关推荐
小杜-coding27 分钟前
黑马头条day02
java·spring boot·spring·spring cloud·java-ee·maven·mybatis
谦行28 分钟前
前端视角 Java Web 入门手册 5.5:真实世界 Web 开发——控制反转与 @Autowired
java·后端
qw94931 分钟前
JVM:JVM与Java体系结构
java·开发语言·jvm
啊QQQQQ37 分钟前
设计模式-原型模式
java·设计模式·原型模式
jstart千语38 分钟前
【版本控制】git命令使用大全
java·git
李白的粉43 分钟前
基于ssm的航空售票系统
java·毕业设计·ssm·课程设计·源代码·航空售票系统
小万编程1 小时前
基于SpringBoot+Vue的汽车展销平台【提供源码+论文1.5W字+答辩PPT+项目部署】
vue.js·spring boot·汽车
cg50171 小时前
Spring Boot 使用 SMB 协议
java·前端·spring boot·smb
SnXJi_1 小时前
开源技术如何助力中小企业实现财务管理自主化?
java·gitee·开源·开源软件
2401_845417452 小时前
C++ string类
java·开发语言·c++