首先要说明一点,SpringMVC进行JSON序列化处理时,使用的工具包是Jackson。
与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。
Jackson 的 1.x 版本的包名是 org.codehaus.jackson ,当升级到 2.x 版本时,包名变为 com.fasterxml.jackson,本文讨论的内容是基于最新的 Jackson 的 2.9.1 版本。
Jackson 的核心模块由三部分组成。
jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
jackson-annotations,注解包,提供标准注解功能;
jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。

当我们开发一个RestController接口时,如果返回的是对象,那么SpringMVC会进行JSON处理
表:
CREATE TABLE `sp_boot_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`u_name` varchar(255) CHARACTER SET latin1 DEFAULT '',
`create_time` datetime DEFAULT NULL,
`balance_point` decimal(10,0) DEFAULT NULL,
`total_point` decimal(10,0) DEFAULT NULL,
`address` varchar(255) CHARACTER SET latin1 DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `sp_boot_user` VALUES ('1', '1', '2023-04-19 22:02:02', '100', '100', '1');
INSERT INTO `sp_boot_user` VALUES ('2', '2', '2023-04-06 00:00:00', '50', '80', '2');实体:
package com.example.springboot.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("sp_boot_user")
public class User {
@TableId(value = "id", type = IdType.AUTO)
@JsonSerialize(using = ToStringSerializer.class)
private Integer id;
@TableField(exist = false)
private String ids;
@TableField(value = "u_name")
private String name;
@TableField("create_time")
private Date createTime;
@TableField("balance_point")
private Long balancePoint;
@TableField("total_point")
private Long totalPoint;
@TableField(value = "address")
private String address;
}接口:
package com.example.springboot.controller;
import com.example.springboot.constant.DataResult;
import com.example.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test/mybatis")
public class MyBatisController {
@Autowired
private UserService userService;
@RequestMapping("/user")
public DataResult getUser(){
return DataResult.success(userService.getById(1));
}
}请求:http://localhost:1088/test/mybatis/user 返回:
{
"code": 0,
"msg": "success",
"data": {
"id": "1",
"ids": null,
"name": "1",
"createTime": "2023-04-19T14:02:02.000+00:00",
"balancePoint": 100,
"totalPoint": 100,
"address": "1"
},
"success": true
}我们看到返回的时间,格式不太友好,而且,显示的时间,不准确。
所以这里要说明一下的是,Jackson使用的时区,不是中国时区,因此需要手动指定下其使用的时区。
Spring配置文件增加:
spring: jackson: default-property-inclusion: non_null # JSON处理时忽略非空字段 time-zone: Asia/Shanghai # 指定上海时区 serialization: write-dates-as-timestamps: true
返回:
{
"code": 0,
"msg": "success",
"data": {
"id": "1",
"name": "1",
"createTime": 1681912922000,
"balancePoint": 100,
"totalPoint": 100,
"address": "1"
},
"success": true
}这个时间戳就是中国时间,但是有个问题,上面配置了写时间为时间戳,并没有格式化,修改Spring配置
spring: jackson: default-property-inclusion: non_null # JSON处理时忽略非空字段 time-zone: Asia/Shanghai # 指定上海时区 date-format: yyyy-MM-dd HH:mm:ss serialization: write-dates-as-timestamps: false
返回:
{
"code": 0,
"msg": "success",
"data": {
"id": "1",
"name": "1",
"createTime": "2023-04-19 22:02:02",
"balancePoint": 100,
"totalPoint": 100,
"address": "1"
},
"success": true
}上面是一个全局配置,我们用可以单独配置某个字段的序列化方式
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("sp_boot_user")
public class User {
@TableField("create_time")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}如果我们要动态指定时区时,必须手动编码。
这里我们需要手动指定格式和时区,数据库默认是GMT+8,这里我们指定一个GMT+9来看效果。
@RequestMapping("/userStr")
public String getUserStr() throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.setTimeZone(TimeZone.getTimeZone("GMT+9"));
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
return mapper.writeValueAsString(userService.getById(1));
}返回
{
"id": "1",
"ids": null,
"name": "1",
"createTime": "2023-04-19 23:02:02",
"balancePoint": 100,
"totalPoint": 100,
"address": "1"
}我们看到格式是对的,时间也加了一个小时。
END
当我们返回的是字符串,不是对象时,Spring的视图不会做任何处理。