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

springMVC-12 处理json和HttpMessageConverter<T>

Json拾遗

         JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式

1.回顾json语法

JSON的格式主要有两种结构:

1) 对象(Object):表示为键值对(key: value)的无序集合,使用花括号{}包围。键值对之间用逗号分隔,键和值之间用冒号分隔。

        键必须是字符串,用双引号括起来。

        值可以是字符串、数字、布尔值、数组、对象或null。

2)数组(Array):表示值的有序集合,使用方括号[]包围。值之间用逗号分隔。

        数组中的值可以是字符串、数字、布尔值、数组、对象或null。

注意:JSON中不允许有注释,且字符串必须使用双引号(不能使用单引号)。

下面是一个JSON对象的例子:

{

        "name": "张三",

        "age": 30,

        "isStudent": false,

        "hobbies": ["篮球", "阅读", "旅游"],

        "address": {

                "city": "北京",

                "street": "朝阳路"

        },

        "nullValue": null

}

在这个例子中:

- "name"是 字符串

- "age"是 数字

- "isStudent"是 布尔值

- "hobbies"是一个 字符串数组

- "address"是一个 嵌套的对象

- "nullValue"是 null

接下来的是困扰我多年来的疑惑,感谢DeepSeek

2.JavaScript对象字面量的写法

提问:下面这个语句,和json有什么关系?为什么name、age不用双引号括起来

let obj = { name: "张三", age: 30 }

解释:

它们是javascript对象字面量的写法

需要明确区分:JSON是一种数据格式,而JavaScript对象是JavaScript语言中的一种数据结构。

        在JavaScript中,对象字面量的键可以不用引号(当键是有效的标识符时),也可以使用单引号或双引号。以下写法在JavaScript中都是合法的:

        let obj1 = { name: "张三" };

        let obj2 = { "name": "张三" };

        let obj3 = { 'name': "张三" };

3.ES6 属性简写 (Property Shorthand)

当对象属性名与变量名相同时,可省略键值对中的值声明:

// 传统写法{ userName: userName, salary: salary } // ES6 简写(完全等效){ userName, salary }

所以在接下来的示例中,你会它们三个的混合,代码如下:

                var userName = $("#username").val();
                var salary = $("#salary").val();


                //简化写法
                var args=JSON.stringify({
                    userName,
                    salary
                })


                //完整写法
                // var args=JSON.stringify({
                //     "userName":userName,
                //     "salary":salary
                // })

本质上,进行了如下的转换:
    JSON.stringify() 会自动处理为合法 JSON:

小结

        综上,一个是json,一个是javascript,然后通过JSON字符串工具,进行了转换。格式上有相似的地方,注意区分。

处理JSON-@ResponseBody

说明

        项目开发中,我们往往需要服务器返回的数据格式是按照json来返回的,我们看一下SpringMVC是如何处理的,项目效果示意图

1.请求一个json数据

2.响应json数据

应用案例

1.引入处理json需要的jar包,注意spring5.x需要使用jackson-2.9.x.jar的包。

2.创建web/json.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>请求json</title><%--引入jquery--%><%--编写jquery代码--%></head>
<body>
<h1>请求一个json数据</h1><a href="?" id="getJson">点击获取json数据</a>
</body>
</html>

3.创建com/stein/springMVC/json/entity/Dog.java

public class Dog {private String name;private int age;//有参,无参构造器,getter and setter,toString
}

4.com/stein/springMVC/json/handler/JsonHandler.java

@Controller
public class DogHandler {@RequestMapping("/json/dog")@ResponseBodypublic Dog getDog() {return new Dog("小花",3);}
}

5.修改web/json.jsp

        1)完善href链接;
        2)使用jquery 发送ajax请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>请求json</title><%--引入jquery--%><script type="text/javascript" src="script/jquery-3.6.0.min.js"></script><%--编写jquery代码--%><script type="text/javascript">$(function () {$("#getJson").click(function () {var url = this.href;var args = {"age":8,//每次发送的时间都是新的,避免浏览器使用缓存"time":new Date()}$.post(url,args,function (data) {console.log("data=",data)console.log("name=",data.name)console.log("age=",data.age)},"json")//避免页面跳转return false;})})</script></head>
<body>
<h1>请求一个json数据</h1><%--相对路径写法--%>
<%--  <a href="json/dog" id="getJson">点击获取json数据</a> <br>--%><%--绝对路径写法--%><a href="<%=request.getContextPath()%>/json/dog" id="getJson">点击获取json数据-by full path</a></body>
</html>

6.测试

使用Postman测试

处理JSON-@RequestBody

说明

- 前面是通过表单,或者url请求携带 参数名=参数值 把数据提交给目标方法
1)给大家举例客户端发送json字符串数据,
2)使用SpringMVC的@RequestBody将客户端提交的json数据,封装成JavaBean对象
3)再把这个javabean以json对象形式返回
4)完成效果示意图

应用案例

1.添加新的json请求,修改web/json.jsp

        以前是通过表单form标签的形式提交的,现在是通过ajax来提交数据

username:<input type="text" id="username"/> <br>
salary:  <input type="text" id="salary"/> <br>
<button  name="submit" >提交</button>

2.创建com/stein/springMVC/json/entity/User.java

public class User {private String userName;private int salary;Constract,setter,getter,toString

3.添加方法,com/stein/springMVC/json/handler/JsonHandler.java

@Controller
@RequestMapping("/json")
public class JsonHandler {@RequestMapping("/dog")@ResponseBodypublic Dog getDog() {//System.out.println("age=" + age);return new Dog("小花",3);}@RequestMapping("/user")@ResponseBody //返回的数据是jsonpublic User saveUser(@RequestBody User user) {//接受的实参是json,然后转换成javabean对应的userSystem.out.println("user="+user);return user;}
}

4.web/json.jsp中编写ajax代码

    <%--编写jquery代码--%><script type="text/javascript">$(function () {$("button[name=submit]").click(function () {var url="json/user";var userName = $("#username").val();var salary = $("#salary").val();//简化写法var args=JSON.stringify({userName,salary})//完整写法// var args=JSON.stringify({//     "userName":userName,//     "salary":salary// })$.ajax({url,data:args,type:"post",success:function (data,state,xhr) {console.log("data=",data)console.log("state=",state)console.log("xhr",xhr)},// 表示提交的数据是json格式的contentType:"application/json;charset=uft-8"})return false;})})</script>

5.测试

postman再次测试

注意事项和细节

1.目标方法正常返回JSON需要的数据,可以是一个对象,也可以是一个集合。区别于之前只返回一个Dog对象->转成Json数据格式返回
2.@ResponseBody可以直接写在controller上,这样对所有方法生效
3.@ResponseBody+@Controller可以直接写成@RestController,我们看一下源码!

梳理数据传输格式

1.客户端ajax的设置数据格式的两种方式

contentType:用于设置发送数据到服务器时所使用的内容类型

dataType: 设置预期服务器返回的数据类型

2.后端设置数据格式的方式

//设置请求的字符编码
request.setCharacterEncoding("uft-8");

//设置响应的字符编码
response.setContentType("text/html;charset=utf-8");

3.混乱的来源

        理解字面上,客户端发送请求的contentType和后端响应的contentType是同一个字段,然而一个用在请求上,一个用在响应上,给人使用不一致的感觉。

        应当站在各方角度上来理解,客户端用contentType设置了前端发送的格式,后端用contentType设置了后端的发送格式,这儿后端面的发送就是响应Response。

总结规律:

  1. 数据发送方负责声明格式

    • 客户端发请求 → 用contentType

    • 服务器返响应 → 用response.setContentType()

  2. 数据接收方负责配置解析方式

    • 服务器收请求 → 用request.setCharacterEncoding()

    • 客户端收响应 → 用dataType(可选) + 自动按Content-Type解析

HttpMessageConverter<T>

● 基本说明

        SpringMVC处理JSON-底层实现是依靠HttpMessageConverter<T>来进行转换的

● 工作机制简图

●处理JSON-底层实现(HttpMessageConverter<T>)

1.使用HttpMessageConverter<T>将请求信息转化并绑定到处理方法的入参中,或将响应结果转为对应类型的响应信息,Spring提供了两种途径:
√使用@RequestBody/@ResponseBody对目标方法进行标注
√使用HttpEntity<T>/ResponseEntity<T>作为目标方法的入参或返回值

2.当控制器处理方法使用到@RequestBody,/@ResponseBody或
HttpEntity<T>/ResponseEntity<T>时,Spring首先根据请求头或响应头的Accept属性选择匹配的
HttpMessageConverter,进而根据参数类型或泛型类型的过滤得到匹配的HttpMessageConverter,若找不到可用的HttpMessageConverter将报错

Dubug源码-梳理一下

1.从请求报文 ->springMVC方向

先 ctrl+n 找到HttpMessageConverter接口

再在该接口上 Ctrl+Alt+B 找到实现类列表,找到AbstractJackson2HttpMessageConverter这个实现类,找到下图方法打断点

以debug方式运行项目,提交数据

1)请求报文->HttpInputMessage

        此时运行到打断点的位置,对参数inputmessage估值可以看到,将请求报文封装到了HttpInputMessage中。headers是表头,body是传输的数据内容

2)HttpInputMessage -> HttpMessageConverter

        通过对contentType的获取,得到要转换的类型

从而选择对应的转换器

3. HttpMessageConverter -> SpringMVC的javabean

从inputMessage的body中获取信息,封装到对应javaType中

下断点到JsonHandler的方法上

此时可以看到,数据已经成功封装到javabean上

2.springMVC->输出报文方向

1)springMVC->HttpMessageConverter

        断点到writeInternal方法上,继续执行,可以执行到该处,此时,依然通过contentType获取要返回的类型

        

得到要进行转换的转换器

2)HttpMessageConverter->HttpOutputMessage的封装

3)回写报文

相关文章:

  • 《第二章-内功筑基》 C++修炼生涯笔记(基础篇)数据类型与运算符
  • DAY 53 对抗生成网络
  • 每日算法刷题Day30 6.13:leetcode二分答案2道题,用时1h10min
  • 玩转计算机视觉——按照配置部署paddleOCR(英伟达环境与昇腾300IDUO环境)
  • java爬虫框架,简单高效,易用,附带可运行案例
  • 基于 Spring Cloud Gateway + Sentinel 实现高并发限流保护机制
  • 流数据机器学习框架 CapyMOA
  • Spring Boot常用依赖大全:从入门到精通
  • Java求职者面试指南:Spring, Spring Boot, Spring MVC, MyBatis技术深度解析
  • MySQL(多表设计、多表查询)
  • keil下载安装
  • 【写实交互数字人】实时数字人助力政务变革:技术、产品与应用价值的全景剖析
  • Handler消息机制
  • 【压缩中断数目--二级中断查找】
  • 深入理解Python协程:asyncio、异步并发、事件循环
  • 三格电子——Profinet 协议 IO-Link 主站网关IO-Link 系列集线器如何组网使用
  • 解决 Git 错误:error: src refspec master does not match any
  • 看PDF文献用什么软件比较好?高效文献阅读工具推荐
  • k8s从入门到放弃之k3s轻量级
  • 多重根号表达式及其MATLAB实现
  • HTML可以做彩票网站吗/百度竞价多少钱一个点击
  • 网站基础建设一般多少钱/二级域名查询网站
  • 网站为什么被降权/慧聪网
  • 企业网站设计过程中/网页制作公司
  • wordpress插件的使用方法/宁波网络推广优化公司
  • 网站做打鱼游戏挣钱吗/自己怎么做网站