前后端数据传输格式(下)

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

上篇主要复习了HTTP以及POST相关的几种传参形式,这一篇来讲讲和实际开发更为紧密的内容:JSON。

初学者在需求分析阶段通常缺乏以下能力:

  • 无法通过看页面原型图分析出大致的请求格式和响应格式
  • 即使能分析出请求格式,却不知道用什么样的Java对象接收
  • 即使能分析出响应格式,却不知道用什么样的Java对象返回

这三个能力,其实都依赖于你对JSON的理解(本文主要讨论JSON,不涉及表单请求和文件上传类型)。

说得更具体些就是,初学者往往搞不清楚JSON与Java对象的转换关系(图片来自尚硅谷):

  • 请求:JSON转Java
  • 响应:Java转JSON

JSON

JSON的作用

在我刚入行时写过相关的博客,比较简单,感兴趣的同学可以看看:AJAX与JSON

JSON简单来说就是特定格式的字符串,注意,它的载体是字符串。很多人分不清JSON和JS对象,其实两者没有可比性。实在要说的话,JS对象和Java对象都是正儿八经的对象,存活于内存中(浏览器/服务器),而JSON只是字符串,往往承担的是网络传输的角色:

我们都知道,网页上的动态数据都是服务器那边组装后通过HTTP返回的,但很少有人会思考这样的一个问题:

服务器组装数据时用的是Java对象,比如user.setName("bravo"),但前端得到的却是JS对象,怎么做到的?

一般来说,浏览器被安装在我们的个人电脑中,而提供服务的Java应用则可能运行在阿里云服务器上,两者并不在同一片物理内存。由于对象存活必须依赖于内存(如果不做持久化,只要一断电,内存中的数据就没了),所以就上图而言,Java对象显然没法自己“跳出”服务器进入浏览器中,更别提Java对象如何变成JS对象。

要想完成跨内存的数据传输、对象转换,必须通过网络传输,而且需要一个传递信息的载体,过程中还涉及到序列化和反序列化。

实际上,整个请求响应的过程就是序列化和反序列化的过程:

  • 服务器端把Java对象序列化为JSON(中介,特定格式的字符串)
  • 网络不能直接传递对象,但可以传输字符串
  • 浏览器得到JSON后,反序列化为JS对象,然后设置到页面上

同理,不仅是浏览器和服务器,服务器和服务器之间也需要JSON作为数据交互的中介:

JSON的格式

使用Postman时,我们经常会发这样的请求:

Body就是请求体内容,一般都是字符串格式,所以这是一个JSON,而不是JS对象,尽管它们看起来很像。你可以理解为JSON是多种语言共同协定的一种数据交互格式:

  • "field":"xxx" 表示对象的字段,value如果是字符类型需要加"",数值可以不加
  • {} 表示对象或map或其他符合key-value格式的结构
  • [] 表示一组对象、一组字符串或一组数值

很简单吧?

然后各个语言都会遵守这个协定,转化为自己的对象结构,比如:

  • {}可以代表Java对象/Map,[]由于表示一组数据,刚好可以对应Java的数组、List或Set等单列集合
  • {}也可以代表Python对象/字典,[]对应Python的元组或list等
  • {}还可以代表PHP的对象,[]对应PHP中的Array
  • ...

当然,{}也可以代表JS对象,[]则可以转化为JS的数组。

为什么很多初学者会搞混JSON和JS对象呢?本质上还是因为:

  • 初学者都“见过”JS对象,而且它往往都是{}的形式出现
  • JS对象的格式和JSON确实比较像

但JSON本质是“干瘪瘪”的字符串,当各大语言需要进行反序列化时,就会按照上面的格式转为内存中“圆鼓鼓”的对象。应该把JS对象和Java对象看作一个梯队,而JSON则在另一个梯队,是一个特定格式的字符串。

常见JSON格式与Java对象的转换

这里只演示Java对象与JSON的转换:

如果不信的话,可以自己动手写一下接口,然后用Postman按照图中的格式发送JSON,看看接口能不能顺利接收参数。

上面说过,JSON的{}可以对应Java的对象或者Map,{}两个括号表示对象的边界,其实刚好对应类的{},里面的就是对象的字段。

我们来分析一下第一张图的结构。

接口返回的是一个HashMap,所以很容易想到最终JSON格式是:

{

...

}

接着往Map里put了一些value,我们先不管value是什么类型:

{

"1号男嘉宾" : xxx,

"2号男嘉宾" : xxx,

"3号男嘉宾" : xxx,

}

OK,JSON的大致结构出来了,再深入一层,看看xxx是什么。很明显,是一个Java的User对象,还是对应{}:

{

"1号男嘉宾" : {},

"2号男嘉宾" : {},

"3号男嘉宾" : {},

}

那么,这个User对象有哪些字段呢?填上即可:

{"1号男嘉宾": {"name": "雅木茶","age": 23},"2号男嘉宾": {"name": "卡卡罗特","age": 23},"3号男嘉宾": {"name": "贝吉塔","age": 22}
}

其他两个分析过程同理,就不演示了(思考一下,如果User里面有Department会是什么样)。

刚才是顺着来,现在我们玩一下“逆推”。假设现在前端跑过来告诉你

大佬,这个接口我到时候这样传参给你行吗?

[{"name": "张飞","age": 18,"tags": ["大眼睛","大胡子"]},{"name": "关羽","age": 19,"tags": ["万人敌","长胡子"]},{"name": "刘备","age": 20,"tags": ["刘皇叔","摔阿斗"]}
]

此时你应该如何设计入参才能接受前端这种格式的JSON呢?

jackson的一些操作

之前介绍过,服务器本身没有能力处理JSON和文件上传,都要靠第三方组件。SpringBoot则引入了jackson作为默认的JSON组件,其他常见的还有阿里的fastJson和谷歌的gson。

这里介绍一下jackson常见的几个注解。

@Slf4j
@RestController
public class UserController {@PostMapping("/addUser")public UserPOJO addUser(@RequestBody UserPOJO user) {user.setAge(null);return user;}}@Data
public class UserPOJO {/*** 姓名*/private String name;/*** 年龄*/private Integer age;/*** 用户类型*/private Integer userType;/*** 个人标签*/private List<String> tags;}

@JsonInclude

有时我们希望如果字段为null就不要返回给前端,可以使用@JsonInclude,它可以指定很多属性。

@JsonInclude还可以加在类上,那么该对象所有为null的字段都不会参与JSON序列化。

@JsonProperty

对于一些老项目或者其他什么原因,原本传参使用的是下划线,比如user_type,而后端用Java改写时又要符合驼峰命名,此时可以用@JsonProperty做一层“隔离”。

此时出入参都必须叫user_type:

@JsonFormat

有些同学容易把@JsonFormat和@DateTimeFormat搞混,我们单独开一个小节聊一聊。

时间格式

首先和大家说一下,数据库字段无论是datetime还是timestamp,其实都是可以自动对应Java的Date对象,一般讨论的所谓时间格式,都是指前端的显示格式:

刚才我们讨论为什么需要JSON时,提到一个观点:对象是在内存中存活的,无法直接进行网络传输。但是大家有没有想过:

class User {private String name;private Date birthday;
}

其实里面的字段也是对象,也要进行序列化。SpringBoot引入了jackson作为JSON序列化的组件,其中必然包括对Date进行序列化/反序列化的方案。

然而,SpringBoot1.x和2.x其实有较大的改动,其中就包括对Date格式化的改动。大家可以沿用刚才的项目,给UserPOJO加上birthday字段,然后在SpringBoot1.5.9和SpringBoot2.3.4环境下实验。

@Slf4j
@RestController
public class UserController {@PostMapping("/addUser")public UserPOJO addUser(@RequestBody UserPOJO user) {return user;}}

SpringBoot1.x

SpringBoot2.x

有两个细节:

  • SpringBoot1.x的返回值是毫秒数,SpringBoot2.x是另一种格式
  • 当入参和出参时间格式不同时,会发生转换,此时会出现时间差
    • SpringBoot1.x传递2020-12-07T22:58:11.000+00:00,返回1607381891000(+8)
    • SpringBoot2.x传递1607353091000,返回2020-12-07T14:58:11.000+00:00(-8)

可以通过时间戳转换验证一下(注意单位)。

时差的问题可以通过配置解决,比如:

spring.jackson.time-zone=GMT+8

总的来说就是:

如果希望更改出入参的时间格式,可以有局部和全局两种方式:

  • 局部:@JsonFormat / @DateTimeFormat
  • 全局
    • YAML
    • Config

@DateTimeFormat只适用于非JSON的POST请求,也就是说,如果项目本身都是JSON请求,你用@DateTimeFormat是无效的。你可以简单理解为:

  • @DateTimeFormat,走表单请求时间转换器(适用于GET、POST表单请求)
  • @JsonFormat,走JSON请求时间转换器(适用于POST JSON请求、JSON响应)

所以,你在这煞费苦心地调整表单请求的转换格式有啥用?

这里演示一下@JsonFormat的用法:

/*** 生日(时间格式很容易写错,可以抽取为常量或者使用第三方提供的,比如hutool就有)*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;

此时出入参都变为指定格式:

也可以在YAML中进行全局配置:

上面那个mvc:date-format是对表单请求的配置。

或者使用Config:

@Configuration
public class JacksonConfig {@Beanpublic ObjectMapper getObjectMapper() {ObjectMapper objectMapper = new ObjectMapper();// 全局配置objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));return objectMapper;}}

如果说@JsonInclude/@JsonFormat加到字段上、类上分别是字段级别、类级别,那么上面的配置就是整个项目级别,因为Spring的bean默认单例,而这个唯一的ObjectMapper已经被做了手脚,最终所有接口的序列化/反序列化行为都被改写。

这种全局和局部的思想,后面会很常见,这里先点一下。

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

进群,大家一起学习,一起进步,一起对抗互联网寒冬

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/197684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时间序列预测实战(二十三)进阶版LSTM多元和单元预测(课程设计毕业设计首选)

一、本文介绍 本篇文章给大家带来的是利用我个人编写的架构进行LSTM模型进行时间序列建模&#xff08;专门为了时间序列领域新人编写的架构&#xff0c;简单且不同于市面上大家用GPT写的代码&#xff09;&#xff0c;包括结果可视化、支持单元预测、多元预测、模型拟合效果检测…

文字处理工具Word mac软件特点

Microsoft Word mac是一款文字处理软件。它是 Microsoft office 套件的一部分&#xff0c;已广泛用于创建、编辑和格式化文本文档。 Word mac软件特点 改进的协作工具&#xff1a;使用 Microsoft Word 2021&#xff0c;多个用户可以同时处理一个文档&#xff0c;从而更轻松地与…

EasyRecovery2024免费永久版手机数据恢复软件

EasyRecovery2024是一款操作安全、用户可自主操作的数据恢复方案&#xff0c;它支持从各种各样的存储介质恢复删除或者丢失的文件&#xff0c;其支持的媒体介质包括&#xff1a;硬盘驱动器、光驱、闪存、硬盘、光盘、U盘/移动硬盘、数码相机、手机以及其它多媒体移动设备。能恢…

bad_python

攻防世界 (xctf.org.cn) 前戏 下载文件&#xff0c;解压完成后是这个 一个pyc文件 这里要用到python的反编译 要用到的工具有两个 1.python自带的uncompyle6 2.pycdc文件——比uncompyle6强大一点 我们一个一个来尝试一下 uncompyle6&#xff1a; 我是直接在pycharm里面…

Stm32 CubeIDE对RTC的日期、时间读写,后备存储的读写

Stm32 CubeIDE对RTC的日期、时间读写&#xff0c;后备存储的读写&#xff0c;一折腾又是好多的问题&#xff0c;现在梳理一下&#xff0c;后面的不要过多踩坑了。 用STM32CubeIDE生成代码 这里有时间和日期的设置&#xff0c;在代码中也会生成相应的代码&#xff0c;首次设置后…

文字识别(OCR)专题——基于NCNN轻量级PaddleOCRv4模型C++推理

前言 PaddleOCR 提供了基于深度学习的文本检测、识别和方向检测等功能。其主要推荐的 PP-OCR 算法在国内外的企业开发者中得到广泛应用。在短短的几年时间里&#xff0c;PP-OCR 的累计 Star 数已经超过了32.2k&#xff0c;常常出现在 GitHub Trending 和 Paperswithcode 的日榜…

第二节JavaScript 语法、语句、注释、变量、数据类型等

一、JavaScript语法 1、JavaScript字面量 数字&#xff08;Number&#xff09;字面量&#xff1a;可以是整数或者是小数、或者是科学计数。 如&#xff1a;3.14 、1001 、123e5 字符串&#xff08;String&#xff09;字面量&#xff1a;可以使用单引号或双引号。 例如&…

【算法】算法题-20231205

这里写目录标题 一、LCS 01. 下载插件二、已知一个由数字组成的列表&#xff0c;请将列表中的所有0移到右侧三、实现一个trim()函数&#xff0c;去除字符串首尾的空格&#xff08;不能使用strip()方法&#xff09; 一、LCS 01. 下载插件 简单 小扣打算给自己的 VS code 安装使…

全球与中国仿制药市场:增长趋势、竞争格局与前景展望

仿制药是指在剂型、功效、给药方法、品质、性能特征、用途等方面与原厂药相似并已获得原厂药上市许可的药品。仿制药的价格低于品牌药。糖尿病、癌症和心血管疾病等慢性疾病的快速成长推动了仿制药市场的成长。此外&#xff0c;仿制药的实惠价格以及最新产品的批准和推出也有助…

ViVo小游戏对接sdk

1.安装环境&#xff1a; 电脑环境&#xff1a;adb环境和oppo一样&#xff0c;npm环境和oppo一样 升级npm&#xff1a; npm install -g npm 清除npm缓存&#xff1a;npm cache clean -f 安装vivo初始化小游戏的工具&#xff1a; npm install -g vivo-minigame/cli 解决办法&…

[ 蓝桥杯Web真题 ]-外卖给好评

目录 介绍 准备 目标 效果 规定 思路 解答参考 介绍 外卖是现代生活中必备的一环。收到外卖后&#xff0c;各大平台软件常常会邀请用户在口味&#xff0c;配送速度等多个方面给与评分。在 element-ui 组件中&#xff0c;已经有相应的 Rate 组件&#xff0c;但是已有组件…

手搭手浅学状态管理VueX

https://vuex.vuejs.org/zh/guide/ 每一个 Vuex 应用的核心就是 store&#xff08;仓库&#xff09;。“store”基本上就是一个容器&#xff0c;它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同&#xff1a; Vuex 的状态存储是响应式的。当 Vu…

Oracle(2-9) Oracle Recovery Manager Overview and Configuration

文章目录 一、基础知识1、User Backup VS RMAN2、Restoring &Recovering DB 还原&恢复数据库3、Recovery Manager Features 管理恢复功能4、RMAN Components RMAN组件5、Repository1: Control File 存储库1:控制文件6、Channel Allocation 通道道分配7、Media Manageme…

[Azure]azure磁盘加密(Windows/Linux) ADE(Azure Disk Encryption)

Azure 磁盘加密用于保护数据&#xff0c;对于Windows使用BitLocker对磁盘进行加密&#xff0c;同时与Key Vault集成&#xff0c;控制和管理Key和Secret。 本文利用Potal对磁盘进行加密 注&#xff1a;Azure DIsk Encryption 可能会导致VM重启&#xff0c;对VM造成影响&#xff…

Linux下安装MySQL 5.7

1、下载安装包 wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm 2、安装MySQL包 yum -y install mysql57-community-release-el7-10.noarch.rpm 3、安装MySQL yum -y install mysql-community-server 如果出现下图失败情形&#xff0c;则…

基于Docker构建Python开发环境

1. Dockerfile dockerfile所在目录结构 FROM python:3.8 WORKDIR /leo RUN apt-get install -y wget RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai >/etc/timezone # ssh免密登录 COPY id_rsa.pub /leo RUN mkdir ~/.s…

[ROS2] --- ROS2安装

ROS2安装到Ubuntu2204系统中&#xff0c;安装步骤如下&#xff1a; 1 设置编码 $ sudo apt update && sudo apt install locales $ sudo locale-gen en_US en_US.UTF-8 $ sudo update-locale LC_ALLen_US.UTF-8 LANGen_US.UTF-8 $ export LANGen_US.UTF-82 添加源 $…

【开源】基于JAVA语言的天沐瑜伽馆管理系统

项目编号&#xff1a; S 039 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S039&#xff0c;文末获取源码。} 项目编号&#xff1a;S039&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 瑜伽课程模块2.3 课…

创建conan包-Understanding Packaging

创建conan包-Understanding Packaging 1 Understanding Packaging1.1 Creating and Testing Packages Manually1.2 Package Creation Process 本文是基于对conan官方文档Understanding Packaging翻译而来&#xff0c; 更详细的信息可以去查阅conan官方文档。 1 Understanding …

智能优化算法应用:基于适应度相关算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于适应度相关算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于适应度相关算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.适应度相关算法4.实验参数设定5.算法结果…