-
一.@Response使用条件
-
二. @Response在最小配置、jackson的jar包情况下,json中包含的日期类型字段都是以时间戳long类型返回
-
三. Jack序列化对象转为JSON的限制条件
-
四. @ResponseBody如何工作的
-
五. Spring偏底层记录.
-
六.参考文章
一. @Response使用条件
1.引入依赖jackson-databind 或者其他类型的json转换,比如gson、fastjson
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
</dependency>
2.最小配置,<mvc:annotation-driven/>
最低满足上面两个条件,即可在@RequestMapping的方法上添加注解@ResponseBody,将结果用JSON直接返回给客户端.
二. @Response在最小配置、jackson的jar包情况下,json中包含的日期类型字段都是以时间戳long类型返回
直接说结论,各位可以尽管测试,使用jackson的情况下,转换的json日期类型字段都会以时间戳long类型展示;
jackson最简单的API使用方式普及下,当然你也可以倒数第二行调用 writeValueAsString这样更加简单:
public static void main(String[] args) throws IOException {
JsonEncoding encoding = JsonEncoding.UTF8;
ObjectMapper mapper = new ObjectMapper();
JsonGenerator generator =mapper.getFactory().createGenerator(new File("E:\\home\\1.txt"),encoding);
ObjectWriter writer = mapper.writer();
Date date = new Date();
writer.writeValue(generator,date);
generator.flush();
}
查看输出文件的信息: Spring底层就是按照这个API 调用方式来生成JSON ,我们没有对ObjectMapper做任何配置,所以生成日期类型都是返回其时间戳;
SpringMvc 4.3中@ResponseBody时间类型是返回时间戳类型,至于其他版本测试就可以知道是否直接返回时间戳类型;
二.1 Jackson Api层面记录如何取消这种时间类型生成方式
下面用mapper代替你的new ObjectMapper()
方式一. mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
说明:mapper configure设置需要在 createGenerator 以及 获取writer之前才有效!
方式二. mapper.setDateFormat(new SimpleDateFormat("yyyy--MM--dd HH:mm:ss"));
说明:这种方式扩展性更好,可以日期自定义格式化,相比较方式一更符合开发需求;
方式三. 实体属性上标注注解 @JsonFormat
public static void main(String[] args) throws IOException {
JsonEncoding encoding = JsonEncoding.UTF8;
ObjectMapper mapper = new ObjectMapper();
JsonGenerator generator =mapper.getFactory().createGenerator(new File("E:\\home\\1.txt"),encoding);
ObjectWriter writer = mapper.writer();
PrivateMyDate date = new PrivateMyDate();
writer.writeValue(generator,date);
generator.flush();
}
static class PrivateMyDate{
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public Date now=new Date();
}
效果图如下:@JsonFormat是Jackson的,而不是Spring的!
说明:方式三应该是日常开发中最方便的,只需要在实体类上添加@JsonFormat,可以满足各种类型的日期格式
三. Jack序列化对象转为JSON的限制条件
三.1 Jackson API使用注意事项点:
之前偷懒, 属性修饰符、getter方法都没有写 , 误打误撞发现Jackson抛出异常
com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class xxx and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
当结合Spring @ResponseBody一起使用,那异常可能就是另外一种表现形式(当然下面这种异常不仅仅可能是这个Jackson Api使用注意事项引起的)
java.lang.IllegalArgumentException: No converter found for return value of type: class demo2.MyDate
三.1.1异常引起原因:比如尝试序列化Json这样一个实体类,就会抛出第一种异常,在Spring就会抛出第二种异常
public class PrivateMyDate {
String name="123";
int age=18;
}
三.1.2 异常原因说明: Jackson2默认地序列化成JSON,实体类属性或者对应属性getter方法为 public类型,才能够将该属性成功转为Json ; 如果只是少数字段不为public类型,那这些少数字段就不会出现在转换后的Json中;如果所有字段都不是public且没有public的getter方法,就会抛出上面第一种异常 ;
三.1.3 异常解决方案:
方案一.最直接的方案
如果有权操作实体类,给对应实体类添加标准的getter方法(public类型,jackson默认是标准的)
方案二.全局级别方案
obejctMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
说明:ANY 代表转换成JSON时候 FIELD即属性可以为任意类型,public、protected、default、private类型都可以
方案三.实体级别方案
实体类上标注 @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)即可
三.1.4 Jackson2结合Spring4.x实现全局级别的@JsonFormat以及 @JsonAutoDetect
自己修改了下原来<mvc:annotation-driven/>达到了全局级别的效果,不用再在实体类上添加@JsonFormat以及@JsonAutoDetect; 简单说明下原理:新增了MappingJackson2HttpMessageConverter,自己配置了一个ObjectMapper,其中visibility属性篇幅较长,如果遇到第一种异常的话可以加上;
<mvc:annotation-driven>
<mvc:message-converters>
<bean id="mappingJackson" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
&l