前后端交互时将返回值中的null置为空字符串的8种方式(亲测有效)

博客主要围绕后端回传JSON数据时处理空值问题展开。介绍了通过继承WebMvcConfigurationSupport、实现WebMvcConfigurer等八种处理方式,还给出了选择建议,如全局生效选前四种,特定接口用方式五和六等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

返回给前端的Json对象中有很多字段没有值,就会有很多的null值(如下图)

 前端判断处理会比较麻烦,所以打算在后端回传数据时做一下处理:

1、字符串null值置为空字符串

2、空List转为[]

3、封装数字类型null转为0

4、Boolean类型null转为false

先看想要达到的效果:

 一、通过继承WebMvcConfigurationSupport,重写configureMessageConverters方法实现

@Configuration
public class MyJsonConfig extends WebMvcConfigurationSupport {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
                //json格式输出
                SerializerFeature.PrettyFormat,
                // 保留map为空的字段
                SerializerFeature.WriteMapNullValue,
                // 将String类型的null转成""形式
                SerializerFeature.WriteNullStringAsEmpty,
                // 将Number类型的null转成0
                SerializerFeature.WriteNullNumberAsZero,
                // 将List类型的null转成[],而不是""
                SerializerFeature.WriteNullListAsEmpty,
                // Boolean类型的null转成false
                SerializerFeature.WriteNullBooleanAsFalse,
                // 处理可能循环引用的问题
                SerializerFeature.DisableCircularReferenceDetect);
        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        List<MediaType> mediaTypeList = new ArrayList<>();
        mediaTypeList.add(MediaType.APPLICATION_JSON);
        converter.setSupportedMediaTypes(mediaTypeList);
        converters.add(converter);
    }
}

二、通过实现WebMvcConfigurer,重写configureMessageConverters方法实现

@Configuration
public class BaseMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        /**
         * 序列换成Json时,将所有的Long变成String
         * 因为js中得数字类型不能包括所有的java Long值
         */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);

        // 所有的double类型返回保留三位小数
        simpleModule.addSerializer(Double.class, CustomerDoubleSerialize.instance);
        simpleModule.addSerializer(Double.TYPE, CustomerDoubleSerialize.instance);

        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(jackson2HttpMessageConverter);
    }
}

三、在Springboot启动类中注入Bean---FastJson

@Bean
public HttpMessageConverters fastJsonConverters() {
	FastJsonHttpMessageConverter4 fastConverter = new FastJsonHttpMessageConverter4();
	FastJsonConfig fastJsonConfig = new FastJsonConfig();
	fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, SerializerFeature.IgnoreNonFieldGetter,
			SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty);
	fastConverter.setFastJsonConfig(fastJsonConfig);
	List supportedMediaTypes = new ArrayList();
	supportedMediaTypes.add(new MediaType("text", "json", Charset.forName("utf8")));
	supportedMediaTypes.add(new MediaType("application", "json", Charset.forName("utf8")));
	fastConverter.setSupportedMediaTypes(supportedMediaTypes);
	HttpMessageConverter<?> converter = fastConverter;
	return new HttpMessageConverters(converter);
}

四、在Springboot启动类中注入Bean---Jackson

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
	MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
	List<MediaType> supported = new ArrayList<>();
	supported.add(MediaType.APPLICATION_JSON_UTF8);
	mappingJackson2HttpMessageConverter.setSupportedMediaTypes(supported);

	// JsonMapper
	ObjectMapper objectMapper = new ObjectMapper();

	// null值的处理,必须要放在第一步,否则会将下面的日期格式化覆盖掉  null ==> ""
	objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
		@Override
		public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
			gen.writeString("");
		}
	});

	// 处理默认日期格式化:yyyy-MM-dd HH:mm:ss
	objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
	objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

	mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
	return mappingJackson2HttpMessageConverter;
}

五、使用fastjson的toJSONString方式

/**
 * @Description: 将java对象的null值置空,转成JSON对象
 * @Parameters: Object 任意java对象
 * @Return: JSONObject 返回fastjson的JSON对象
 * @Auther: WZH
 * @Date: 2021/1/15 9:54
 */
public static JSONObject nullToEmptyJson(Object object){
	String returnString = JSONObject.toJSONString(object,
			//json格式输出
			SerializerFeature.PrettyFormat,
			// 保留map为空的字段
			SerializerFeature.WriteMapNullValue,
			// 将String类型的null转成""形式
			SerializerFeature.WriteNullStringAsEmpty,
			// 将Number类型的null转成0
			SerializerFeature.WriteNullNumberAsZero,
			// 将List类型的null转成[],而不是""
			SerializerFeature.WriteNullListAsEmpty,
			// Boolean类型的null转成false
			SerializerFeature.WriteNullBooleanAsFalse,
			// 处理可能循环引用的问题
			SerializerFeature.DisableCircularReferenceDetect);
	return JSONObject.parseObject(returnString);
}

六、通过反射判断修改(可根据需要补全其他类型)

public static <T> void  nullToEmpty(T bean){
	Field[] field = bean.getClass().getDeclaredFields();
	//遍历所有属性
	for (Field item : field) {
		//获取属性的名字
		String name = item.getName();
		//将属性的首字符大写,方便构造get,set方法
		name = name.substring(0, 1).toUpperCase() + name.substring(1);
		//获取属性的类型
		String type = item.getGenericType().toString();
		//如果type是类类型,则前面包含"class ",后面跟类名
		if ("class java.lang.String".equals(type)) {
			try {
				Method mGet = bean.getClass().getMethod("get" + name);
				//调用getter方法获取属性值
				String value = (String) mGet.invoke(bean);
				if (value == null || "".equals(value)) {
					Method mSet = bean.getClass().getMethod("set" + name, String.class);
					mSet.invoke(bean, new String(""));
				}
			} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}
}

七、在entity实体类或者字段上面加JsonInclude注解,过滤掉NULL值的属性

@JsonInclude(JsonInclude.Include.NON_NULL)

八、直接在entity字段上加JSONField注解,转Json时不返回当前字段

@JSONField(serialize = false)

如何选择:

1、全局生效,添加之后该服务下的所有接口都会生效,选择前四种;

2、针对特定接口使用,作为静态方法根据自己需要加在接口返回前,方式五和六;

3、针对特定实体类或者字段不传null值属性,使用方式七;

4、直接在Json序列化时不传某个字段,使用方式八。

 

<think>我收到了用户的查询,他问的是“null字符串的区别在编程中”。我之前的回答引用了站内资料,涵盖了不同编程语言中的区别和判断方法。用户现在需要更深入的理解。用户可能正在学习编程基础知识,或者在调试代码遇到了相关困惑。需要重点区分“字符串是存在的对象”和“null是不存在的引用”这一核心概念。根据引用[1],字符串是长度为0的字符串对象,而null表示不存在的对象引用。这点在几乎所有编程语言中都通用。引用[2][3][4]补充了实际编程中的判断技巧,比如Java用StringUtils.hasText()检查null字符串,Python用`notsors.isspace()`处理含格的情况。用户可能隐含的真实需求是:如何在实际编码中正确使用两者避免bug?在面向对象语言里,对null操作会引发NullPointerException,而操作字符串是安全的。在数据库领域,null表示缺失字符串则被视为有效。我可以从内存角度解释:字符串在堆中有对象地址,null是未初始化的指针。需要补充SQL中的NULL处理差异,以及前端JS里null和''在类型转换中的不同表现。另外说明类型语言(C#)Nullable类型的特殊处理会很有帮助。用户可能还需要知道常见误区,比如认为null字符串在条件判断中行为相同。实际上if("")可能成立而if(null)不成立。后续可以建议生成关于“如何选择使用场景”或“各语言最佳实践”的延伸问题。</think> 在编程中,`null` 和字符串 `""` 的根本区别在于**对象的存在性**和**内存表示**,以下是核心区别和典型应用场景: --- ### 一、本质区别 1. **字符串 `""`** - **存在对象**:它是一个有效字符串对象,占用内存间。 - **内容为**:长度固定为0(例如 Java 中 `"".length()` 返回 `0`)。 - **可调用方法**:可安全调用字符串方法(如 `isEmpty()`、`trim()`)。 ```java String s = ""; System.out.println(s.length()); // 输出 0(合法操作) ``` 2. **`null`** - **不存在对象**:表示变量未引用任何对象(栈内存有指针但指向)。 - **无内容无长度**:没有底层对象,无法调用任何方法。 - **操作触发异常**:尝试操作会抛出 `NullPointerException`(Java)或类似错误。 ```java String s = null; System.out.println(s.length()); // 抛出 NullPointerException ``` --- ### 二、内存模型对比(以 Java 为例) | **变量状态** | 栈内存 | 堆内存 | |---------------------|---------------|------------------| | `String s = "";` | 指针 → | 存储长度为0的字符串对象 | | `String s = null;` | 指针 → `null` | 无对象 | --- ### 三、实际编程中的关键差异 1. **条件判断** - **字符串**:显式检查长度或内容(如 `str.isEmpty()`)。 - **null**:需优先检查引用存在性(如 `str == null`)。 ```java // 安全判断示例(Java) if (str != null && !str.trim().isEmpty()) { // 处理非且非纯格的字符串 } ``` 2. **数据库交互** - **字符串 `""`**:表示字段有但内容为(如用户未填写姓名)。 - **`NULL`**:表示字段缺失或未定义(如未收集该信息)。 3. **函数返回值语义** - 返回 `""`:明确表示“结果为”。 - 返回 `null`:常表示“无有效结果”或“发生错误”。 --- ### 四、不同编程语言的实现差异 1. **Python** - `None` 等效于 `null`,`""` 是字符串。 - 检查方法:`if not s:` 会同捕获 `None` 和 `""`。 ```python s = "" print(s is None) # False print(len(s)) # 0(合法) ``` 2. **JavaScript** - `null` 与 `undefined` 表示引用,`""` 是字符串。 - 宽松相等(`==`)下 `null == undefined` 为 `true`,但 `null !== ""`。 --- ### 五、常见误区与陷阱 1. **未初始化变量**: ```java String uninitialized; // 默认为 null(未分配对象) String empty = ""; // 已分配对象 ``` 2. **方法链调用风险**: ```java // 错误示例:可能因 null 抛出异常 user.getAddress().getCity().trim(); // 正确:逐层判 if (user != null && user.getAddress() != null) { ... } ``` 3. **含字符串**: - `" "`(字符串)长度 >0,需用 `trim()` 处理: ```java String s = " "; boolean isBlank = s.trim().isEmpty(); // true ``` --- ### 总结对比表 | **特性** | 字符串 `""` | `null` | |------------------|------------------------|----------------------| | 对象是否存在 | 是(有效对象) | 否(无对象引用) | | 内存占用 | 是(对象头 + 长度信息) | 仅栈指针(无堆分配) | | 调用方法 | 安全 | 抛出异常 | | 语义 | “有但内容为” | “无或未定义” | | 数据库含义 | 存储了字符串 | 字段缺失 | | 类型检查 | `String` 类型 | 无类型 | > 引用说明:字符串表示存在的对象,而 null 表示不存在的对象引用[^1]。在条件判断需区分 null以避免错误[^2],对于含字符串需用 `trim()` 处理[^3],工具类如 `StringUtils.hasText()` 可简化检查逻辑[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值