当前位置: 首页 > news >正文

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

作者简介:大家好,我是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

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

相关文章:

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

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 上篇主要复习了HTTP以及…...

mysql pxc高可用离线部署(三)

pxc学习流程 mysql pxc高可用 单主机 多主机部署&#xff08;一&#xff09; mysql pxc 高可用多主机离线部署&#xff08;二&#xff09; mysql pxc高可用离线部署&#xff08;三&#xff09; mysql pxc高可用 跨主机部署pxc 本文使用docker进行安装&#xff0c;主机间通过…...

XXL-JOB 日志表和日志文件自动清理

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…...

常用sql记录

备份一张表 PostgreSQL CREATE TABLE new_table AS SELECT * FROM old_table;-- 下面这个比上面好&#xff0c;这个复制表结构时&#xff0c;会把默认值、约束、注释都复制 CREATE TABLE new_table (LIKE old_table INCLUDING ALL) WITHOUT OIDS; INSERT INTO new_table SELE…...

设备温度和振动综合监测:温振一体式传感器的优点和应用

随着工业设备的复杂性和自动化程度的提高&#xff0c;对设备状态监测的需求也日益增加。温振一体式传感器作为一种集振动和温度监测于一体的传感器&#xff0c;具备多项优势&#xff0c;因此在工业设备状态监测领域得到广泛应用。 温振一体式传感器基于振动传感器和温度传感器的…...

彻底解决ModuleNotFoundError: No module named ‘exceptions‘【Bug完美解决】

文章目录 项目场景:问题描述原因分析:解决方案:此Bug解决方案总结心得项目场景: 根据本文可找到bug原因并彻底解决**ModuleNotFoundError: No module named ‘exceptions‘**Bug 报错: E:\Anconda\python.exe c:\Users\24190\PycharmProjects\pythonProject4py尝试 gong…...

yarn和npm的区别

2023-12-8 yarn和npm的区别 是常用的包管理工具&#xff0c;用于node.js项目中安装、管理、和更新依赖项 有以下几个区别&#xff1a; 性能和速度&#xff1a;在包的安装和下载方面&#xff0c;yarn比npm更快速&#xff0c;yarn通过并行下载和缓存等优化策略&#xff0c;可以…...

设计图中时序图

设计图中的时序图通常用于展示两个或多个对象之间的交互和消息传递的顺序。它是一种用于描述软件或系统中的并发性和时序行为的工具。 以下是一个简单的时序图的示例&#xff1a; 首先&#xff0c;在时序图中创建两个对象&#xff0c;例如"对象A"和"对象B&quo…...

反射实现tomcat

获取类信息的方法 1.通过类对象 x.getClass() 2.通过class.forname方法 Class.forname(className);这里className是存储类名的字符串 3.通过类名.class 类名.class 通过类名创建对象 类名.newInstance&#xff08;&#xff09;&#xff1b; 反射可以看到类的一切信息&#xff1…...

Ubuntu 安装 CUDA 和 cuDNN 详细步骤

我的Linux系统背景&#xff1a; 系统和驱动都已安装。 系统是centos 8。查看自己操作系统的版本信息&#xff1a;cat /etc/issue或者是 cat /etc/lsb-release 用nvidia-smi可以看到显卡驱动和可支持的最高cuda版本&#xff0c;我的是12.2。驱动版本是535.129.03 首先&#…...

ArkTS快速入门

一、概述 ArkTS是鸿蒙生态的应用开发语言。它在保持TypeScript&#xff08;简称TS&#xff09;基本语法风格的基础上&#xff0c;对TS的动态类型特性施加更严格的约束&#xff0c;引入静态类型。同时&#xff0c;提供了声明式UI、状态管理等相应的能力&#xff0c;让开发者可以…...

HTTP不同场景下的通信过程和用户上网认证过程分析

目录 HTTP不同场景的通信过程 HTTP正常交互过程 HTTP透明加速传输过程 HTTP代理服务器场景下交互过程 通过AC对上网用户不同场景的认证过程 AC上网认证正常交互过程 通过Cookie实现免认证交互过程 代理服务器场景下HTTP密码认证交互过程 HTTP不同场景的通信过程 HTTP、…...

VR 实现 Splash Screen 效果

文章目录 背景官方实现逆向分析 背景 手机 App 在实现 Splash Screen 的时候&#xff0c;目前都有成熟的方案可以参考&#xff0c;但是在做 VR 开发时&#xff0c;要如何实现一个 App 自己的 Splash Screen &#xff0c;下面是我们基于 PICO & OCULUS 进行业务开发时经过探…...

HarmonyOS学习--TypeScript语言学习(一)

注意&#xff1a;这只是我学习的笔记&#xff01;&#xff01;&#xff01; 注意&#xff1a;这只是我学习的笔记&#xff01;&#xff01;&#xff01; 注意&#xff1a;这只是我学习的笔记&#xff01;&#xff01;&#xff01; 本章目录如下&#xff1a; 一、TypeScript语言…...

【C语言】函数递归详解(一)

目录 1.什么是递归&#xff1a; 1.1递归的思想&#xff1a; 1.2递归的限制条件&#xff1a; 2.递归举例&#xff1a; 2.1举例1&#xff1a;求n的阶乘&#xff1a; 2.1.1 分析和代码实现&#xff1a; 2.1.2图示递归过程&#xff1a; 2.2举例2&#xff1a;顺序打印一个整数的…...

WT588F02B-8S语音芯片助力破壁机:智能声音播放提示IC引领健康生活新潮流

在追求健康饮食的时代潮流中&#xff0c;破壁机作为榨汁、搅拌的重要厨房电器&#xff0c;融入智能技术的趋势不断加强。唯创知音的WT588F02B-8S语音芯片作为声音播放提示IC&#xff0c;为破壁机注入了更智能、便捷的声音提示功能&#xff0c;引领用户迈入健康生活的新潮流。 …...

NXP iMX8M Plus Qt5 双屏显示

By Toradex胡珊逢 简介 双屏显示在显示设备中有着广泛的应用&#xff0c;可以面向不同群体展示特定内容。文章接下来将使用 Verdin iMX8M Plus 的 Arm 计算机模块演示如何方便地在 Toradex 的 Linux BSP 上实现在两个屏幕上显示独立的 Qt 应用。 硬件介绍 Verdin iMX8M Plu…...

RepidJson中Writer类、FilewriteStream类、 PrettyWriter类的区别

rapidjson是一个C的JSON解析库&#xff0c;可以用于解析和序列化JSON数据。 Writer是rapidjson中一种基本的输出流&#xff0c;用于将JSON数据输出到字符串或文件中。 FileWriteStream是一个Writer的子类&#xff0c;它专门用于将JSON数据输出到文件中。相比于普通的Writer&a…...

IntelliJ idea卡顿解决,我遇到的比较管用的方案

Setttings> Build, Execution,Deployment>Debugger> Data Views> Java 取消 Enable "toString()" object view; Speed up debugging in IntelliJ Yesterday, I observed painfully slow debugging in IntelliJ. Every step over or step in took almost…...

Fabric.js 实战开发使用介绍

原生canvas用的多的有哪些槽点就不用我多说了&#xff1b;fabric 作为一个canvas库&#xff0c;提供了非常高效、直观的API操作&#xff0c;使我们对涉及canvas相关的功能开发效率大幅提升~~~~ 简单记录下自己的心得&#xff1b;以下是对比canvas来说的优势&#xff1a; 1.简…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...