首先要说明一点,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
Java小强
未曾清贫难成人,不经打击老天真。
自古英雄出炼狱,从来富贵入凡尘。
发表评论: