我是跟着b站狂神说的SpringMVC来进行学习的。这是我的笔记。www.bilibili.com/video/BV1aE…
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
JSON
在前后端分离时代:
后端部署后端,提供接口:
JOSN 是一个数据交换格式,是前后端数据交换格式。用来将数据传输
前端部署前端,负责渲染后端的数据
我理解的 JSON 是,前端只接收这种格式的数据,前端返回的格式也只有 JSON。所以后端需要有将数据变成 JSON 格式的方法和将 JSON 格式数据变成普通数据的方法。
JSON 的格式
我们可以通过 js 自带的 JSON 类来观察一下 JSON 的格式
【xml】
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>通过控制台看json格式</title>
<script type="text/javascript">
// 编写一个 js 对象
let user = {
name: "何鸭子",
age: 21,
sex: "男"
};
// 将对象之间送到前端
console.log(user);
console.log("=================================")
// 将 js 对象转换为 json 对象
let json = JSON.stringify(user);
console.log(json);
console.log("=================================")
// 将 json 对象转换为 js 对象
let parse = JSON.parse(json);
console.log(parse)
</script>
</head>
<body>
</body>
</html>
- 我们可以看出,直接的对象传输和 JSON 格式传输是有不同的。现在是通过 js 自带的方法对数据进行转换。后端也有类似的方法对数据进行转换。就是下面的 Jackson 和 fastjson 了。
Jackson 对象传输
我们可以通过 Jackson 来将后端的数据转换成 JSON 格式的对象。下面是我们将数据转换的操作步骤
-
第一步我们需要先导入依赖
<!-- jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.2.2</version> </dependency>我们需要将依赖导入 lib 包中
-
创建一个 Controller 类。我们需要在类上添加
@RestController注解。@RestController写在类上,这个类的所有方法返回的字符串都不会经过视图解析器,而是变成普通字符串。如果前后端分离,我们的方法都不会走视图解析器了,只会返回 json 字符串到前端。让前端去对数据进行渲染。
直接在类上写
@RestController等同于 类上写@Controller+ 方法@ResponseBody的操作(表示这个方法是只返回字符串不走视图解析器)。一般都是使用前者。 -
在类中创建方法,通过Jackson 的 ObjectMapper 对象的 writeValueAsString 方法将转化成 json 格式的字符串
@RequestMapping("/j2") public String json2() throws JsonProcessingException { // 1. 创建 Jackson 的 ObjectMapper 对象 ObjectMapper mapper = new ObjectMapper(); // 2. 创建对象 User user = new User(1, "何鸭子", 21); // 3. 将对象转换成 json 格式,会抛出异常提示 String s = mapper.writeValueAsString(user); return s; }如果以后熟练掌握了,想要传输 JSON 字符串,可以用
return new ObjectMapper().writeValueAsString(数据);就可以了new ObjectMapper().writeValueAsString(user)
【结果】
可以看到 JSON 中也有中文乱码的问题,我们接下来就两种方法来解决。
Jackson 乱码解决方法
方法一
方法一是直接使用 springmvc 注解来解决
@RequestMapping(value = "/j2", produces = "application/json;charset=utf-8")
public String json2() throws JsonProcessingException {
// 1. 创建 Jackson 的 ObjectMapper 对象
ObjectMapper mapper = new ObjectMapper();
// 2. 创建对象
User user = new User(1, "何鸭子", 21);
// 3. 将对象转换成 json 格式,会抛出异常提示
String s = mapper.writeValueAsString(user);
return s;
}
添加了 produces属性指定 JSON 的编码格式用 utf-8。
【结果】
可以看到对象的所有属性和属性值都变成了 utf-8 的格式,就连双引号也变了。
方法二
我们可以在 springmvc 的配置文件上添加一段消息 StringHttpMessageConverter 转换配置
将下面的代码放入 springmvc 的配置文件
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
这是固定配置,可以写在模板里面。我们可以通过代码来测试一下
@RequestMapping("/j3")
public String json3() throws JsonProcessingException {
// 1. 创建 Jackson 的 ObjectMapper 对象
ObjectMapper mapper = new ObjectMapper();
// 2. 创建对象
User user = new User(1, "何鸭子", 21);
// 3. 将对象转换成 json 格式,会抛出异常提示
String s = mapper.writeValueAsString(user);
return s;
}
【结果】
【总结】
这个方法只会对中文部分进行指定 utf-8 编码格式,方便前端接收;而不是像方法一一样将将整个 JSON 字符串都变成了 utf-8 的格式。我认为这个方法更好。
Jackson 集合传递
我们后端将数据传到前端一般都是以对象的方式传输。当多个对象的时候我们会使用集合。下面就来展示一下集合转化成 JSON 字符串之后是怎么样的。
@RequestMapping("/j4")
public String json4() throws JsonProcessingException {
// 创建多个对象放在一个 json 字符串中传到前端去
User user1 = new User(1, "何鸭子", 21);
User user2 = new User(1, "何鸭子", 21);
User user3 = new User(1, "何鸭子", 21);
User user4 = new User(1, "何鸭子", 21);
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
return new ObjectMapper().writeValueAsString(list);
}
【结果】
【总结】
我们可以看到用一个 '[ ]' 来表示集合。集合中不同的对象用 ',' 来间隔,用 '{ }' 来表示一个对象。对象里 用 " ":" " 来表示属性和属性值之间的关系。
Jackson 时间显示
我们将时间字符串变成 JSON 格式传到前端有两种方法
无论如何我们都是通过时间戳来将时间输出
@RequestMapping("/j5")
public String json5() throws JsonProcessingException {
// 将 Date 类型的对象放在一个 json 字符串中传到前端去
Date date = new Date();
// 传到前端的是一个时间戳 Timestamp 1970.01.01到现在的毫秒数
return new ObjectMapper().writeValueAsString(date);
}
【结果】
方法一:使用 java 传统方法将时间输出
@RequestMapping("/j6")
public String json6() throws JsonProcessingException {
// 使用 java 传统方法将时间输出
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
// 传到前端的是一个按照一定格式的时间
return new ObjectMapper().writeValueAsString(sdf.format(date));
}
【结果】
这个方法是用了 java 的传统方法将时间输出,算是复习了一下。
方法二:使用 Jackson 的 ObjectMapper 方法将时间输出
@RequestMapping("/j7")
public String json7() throws JsonProcessingException {
// 使用 ObjectMapper 方法将时间输出
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//指定日期格式
mapper.setDateFormat(sdf);
Date date = new Date();
return mapper.writeValueAsString(date);
}
【结果】
这个方法调用了 Jackson 的方法,但是可以看出实现的步骤要比普通 java 方法要多,但是有许多步骤是和 Jackson 对象传输以及集合传递是相同的。所以我们可以通过写一个 Jackson 的方法类来将相同的步骤集合到一起。
自定义 JacksonUtils
可以看出红色框和黄色框的操作都是相同的,而蓝色框是仅在时间输出的时候才需要执行。所以我们可以写一个工具类将重复的动作封装
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
/**
* @author workplace
* @date 2022/4/14 22:49
*/
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object, "YYYY-MM-DD hh:mm:ss");
}
public static String getJson(Object object, String dateFormat) {
// 使用 ObjectMapper 方法将时间输出
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
//指定日期格式
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
【测试】
@RequestMapping("/j8")
public String json8() throws JsonProcessingException {
// 使用 JsonUtils 方法将时间输出
Date date = new Date();
return JsonUtils.getJson(date);
}
【测试】
@RequestMapping("/j9")
public String json9() throws JsonProcessingException {
// 创建多个对象放在一个 json 字符串中传到前端去
User user1 = new User(1, "何鸭子", 21);
User user2 = new User(1, "何鸭子", 21);
User user3 = new User(1, "何鸭子", 21);
User user4 = new User(1, "何鸭子", 21);
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
return JsonUtils.getJson(list);
}
【总结】
创建了 JsonUtils 工具类,对于需要重写的方法可以通过互相调用来减少代码的冗余。
我的理解:对于方法类重载,我们可以先写参数多的,再用参数少的去调用,将多余的参数定死。必须注意,所有的重载的方法的最终目的都是一样的,不能改变!
使用 fastjson
【导入依赖】
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.80</version>
</dependency>
【代码测试】
@RequestMapping("/j10")
public void json10() throws JsonProcessingException {
// 创建多个对象通过 fastjson 创建一个 json 字符串中传到前端去
// 写代码的时候一定要认真。如果出现问题必然不是代码出问题,而是环境没配置好。以后运维背锅就对了嘿嘿嘿
//创建一个对象
User user1 = new User(1, "何鸭子", 21);
User user2 = new User(1, "何鸭子", 21);
User user3 = new User(1, "何鸭子", 21);
User user4 = new User(1, "何鸭子", 21);
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
System.out.println("*******Java对象 转 JSON字符串*******");
String str1 = JSON.toJSONString(list);
System.out.println("JSON.toJSONString(list)==>" + str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1)==>" + str2);
System.out.println("\n****** JSON字符串 转 Java对象*******");
User jp_user1 = JSON.parseObject(str2, User.class);
System.out.println("JSON.parseObject(str2,User.class)==>" + jp_user1);
System.out.println("\n****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>" + jsonObject1.getString("name"));
System.out.println("\n****** JSON对象 转 Java对象 ******");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>" + to_java_user);
}
【结果】
可以尝试自己去写一下,继续完善自己的 JacksonUtils