1.简述
2.返回为空的场景及其处理方案
2.1返回空对象或是空集合处理方案 2.2对于返回data为集合类型,data中有对象为空的处理方案
2.2.1更改序列化规则(三种方式)
2.2.2指定空对象上添加注解
1.简述
springMVC返回前端数据格式应该想到HttpMessageConverter,简单来讲就是将http请求的请求内容和响应内容转化为对应格式.常见的http消息转化器有很多,现在大部分前后端数据通用格式为json,和json处理相关内的消息转化器是
MappingJacksonHttpMessageConverter
: 负责读取和写入json格式的数据;具体实现方式本文以 jackson进行说明,也是springMVC默认支持的处理json的方式.里面涉及几个类(下面处理会用到简单提一下):
ObjectMapper,支持json格式信息读取;
SerializationFeature:序列化规定的特性或是叫做规则更容易理解,不同规则会有相应的处理.
案例场景用到的响应封装参数:
public class ResultVo<T> {
private int code;
// 是否成功标识.true表示成功,false表示失败
private boolean success;
// 操作成功时需要响应给客户端的响应数据
private String msg;
private T data;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date time;
// 省略get/set
}
以下所有的返回信息均以data为目标进行处理
2.返回为空的场景及其处理方案
2.1返回空对象或是空集合处理方案
直接new HashMap<>()或是ArrayList<>(),适用于前端接仅接收一个空对象或是空集合场景.
相关代码如下:
@RequestMapping("/test")
@RestController
public class TestJsonkon {
@GetMapping("/test")
public ResultVo commonDdos(){
return ResultVoUtil.success(new HashMap<>());
}
}
返回信息:
2.2对于返回data为集合类型,data中有对象为空的处理方案
这里创建两个对象,业务场景是要求返回的集合中有数据的要返回具体的数据信息,没有数据的要返回空对象.不理解业务场景没关系,可以直接关注空对象CommonDto2 即可.
前后端返回协议:
相关代码:
公共父类
public class CommonDdo {
}
返回子对象1
public class CommonDto1 extends CommonDdo {
private String name;
private int age;
// 省略get/set
}
返回子对象2
public class CommonDto2 extends CommonDdo {
}
测试代码:
@RequestMapping("/test")
@RestController
public class TestJsonkon {
@GetMapping("/test")
public ResultVo<ArrayList<CommonDdo>> commonDdos(){
ArrayList<CommonDdo> commonDdos = new ArrayList<>();
commonDdos.add(new CommonDto1("jack",18));
commonDdos.add(new CommonDto2());
commonDdos.add(new CommonDto2());
return ResultVoUtil.success(commonDdos);
}
进行测试发现:
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.chenghao.program.chenghaoprogram.jacksonHandle.CommonDto2]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.chenghao.program.chenghaoprogram.jacksonHandle.CommonDto2 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.chenghao.program.chenghaoprogram.interceptorHanle.ResultVo["data"]->java.util.ArrayList[1])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:460) ~[spring-web-5.3.8.jar:5.3.8]
// 省略部分异常...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.chenghao.program.chenghaoprogram.jacksonHandle.CommonDto2 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.chenghao.program.chenghaoprogram.interceptorHanle.ResultVo["data"]->java.util.ArrayList[1])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1276) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:71) ~[jackson-databind-2.12.3.jar:2.12.3]
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:33) ~[jackson-databind-2.12.3.jar:2.12.3]
// 省略部分异常
... 48 common frames omitted
最根本的异常信息:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.chenghao.program.chenghaoprogram.jacksonHandle.CommonDto2 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.chenghao.program.chenghaoprogram.interceptorHanle.ResultVo["data"]->java.util.ArrayList[1])
关键原因分析:SerializationFeature.FAIL_ON_EMPTY_BEANS
,这是序列化规则中的一种,具体实现:
/**
确定在找不到类型的访问器时会发生什么的功能(并且没有注释表明它是要序列化的)。如果启用(默认),则抛出异常以指示这些为不可序列化的类型;如果禁用,它们将被序列化为空对象,即没有任何属性。
请注意,此功能仅对那些没有任何可识别注释(如@JsonSerialize)的“空”bean 起作用的空类型:具有注释的那些不会导致抛出异常。
默认情况下启用该功能。
*/
FAIL_ON_EMPTY_BEANS(true),
也就是说对于默认空对象,序列化特性(规则)中是不支持序列化,代码中体现就是抛出异常.解决问题的方式有两种,更改枚举属性为false;另一中是按照注释上所讲,在指定对象上添加可识别’'空对象"的注解.
2.2.1更改序列化规则(三种方式)
1.通过自定义创建objectMapper,设置FAIL_ON_EMPTY_BEANS,相当于是覆盖默认配置.
@Bean
public ObjectMapper getObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
return objectMapper;
}
2.通过Jackson2ObjectMapperFactoryBean设置
@Bean
public Jackson2ObjectMapperFactoryBean getJackson2ObjectMapperFactoryBean(){
Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();
jackson2ObjectMapperFactoryBean.setFailOnEmptyBeans(false);
return jackson2ObjectMapperFactoryBean;
}
3.通过配置文件
spring:
jackson:
serialization:
FAIL_ON_EMPTY_BEANS: false
2.2.2指定空对象上添加注解
自定义定义空对象类上添加注解:@JsonInclude(JsonInclude.Include.NON_EMPTY)
该注解可以作用于类上表示为空对象对象时不参与序列化.平常常用的方式是作用于实体类字段属性上,当为空时不返回前端数据.
以上处理均自测完成,如有问题欢迎评论区留言讨论!