SpringMVC JSON使用

SpringMVC JSON使用

现如今前后端分离,传输数据离不开 JSON。在对 SpringMVC 进一步使用前,先来了解一下 JSON!本节新建 SpringMVC-06-JSON 项目学习 JSON 的基本使用。

1. JSON简介

JSON( JavaScript Object Notation,JS 对象简谱)是一种轻量级的数据交换格式,目前使用广泛。

JSON 的特点有

  • 采用完全独立于编程语言的文本格式来存储和表示数据;
  • 层次结构简单清晰,方便数据交换;
  • 易于程序员阅读和编写,也易于机器解析和生成。

在 JavaScript 中,一切都是对象。因此,任何 JavaScript 支持的类型都可以通过 JSON 来表示,如字符串、数字、对象、数组等。

JSON 的语法格式为

  • 方括号 [ ] 表示数组
  • 花括号 { } 表示对象
  • 对象中的属性用键值对表示,冒号 : 表示属性,对象间由逗号 , 分割
{"name": "Qiyuan", "age": 18, "address": {"country" : "CHINA", "city": "NJ"}}
[1, 2, 3, 4, 5, 6, 7, 8] // 数组中当然也可以保存上面的对象

JSON 和 JavaScript 对象的区别

JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串

// 这是一个对象,注意键名也是可以使用引号包裹的
var obj = {a: ‘Hello‘, b: ‘World‘}; 
// 这是一个 JSON 字符串,本质是一个字符串
var json = ‘{"a": "Hello", "b": "World"}‘; 

JSON 和 JavaScript 对象之间的转换

从 JSON 字符串转换为 JavaScript 对象,使用 JSON.parse() 方法

var obj = JSON.parse(‘{"a": "Hello", "b": "World"}‘);
//结果为 {a: ‘Hello‘, b: ‘World‘}

从 JavaScript 对象转换为 JSON 字符串,使用 JSON.stringify() 方法

var json = JSON.stringify({a: ‘Hello‘, b: ‘World‘});
//结果是 ‘{"a": "Hello", "b": "World"}‘

基本的使用就这么多,还是来试试吧!

2. 前端转换

创建一个 JSONTest.html 文件,用代码测试一下 JSON 和 JS 对象之间的转换

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JSONTest</title>
</head>
<body>
    <script>
        // 创建一个 JS 对象
        var user = { name:"祈鸢", age:18, id:7 }
        console.log(user)
    </script>
</body>
</html>

打开这个 html 文件,检查控制台输出,可以看到

Object
age: 18
id: 7
name: "祈鸢"

这就输出了一个 JS 对象了(怎么在学 JS 了,不过也挺好)!

然后通过 JSON.stringify 把对象转换成 JSON 字符串输出,在通过 JSON.parse 把 JSON 字符串解析成对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JSONTest</title>
</head>
<body>
    <script>
        // 创建一个 JS 对象
        var user = { name:"祈鸢", age:18, id:7 }
        // console.log(user)
        var json = JSON.stringify(user)
        console.log(json)
        console.log("==========")
        var obj = JSON.parse(json)
        console.log(obj)
    </script>
</body>
</html>

检查控制台输出

{"name":"祈鸢","age":18,"id":7}
==========
Object
age: 18
id: 7
name: "祈鸢"

很简单啦,没什么问题。

3. Jackson使用

在前端测试完了,就要回到后端了。那么现在的问题是:如何在后端( Controller )把对象的信息转换为 JSON?

说到底,就是按照特定的格式把对象的信息转换为字符串,这种事情写个(亿个)工具类当然也能做到。不过这种事情肯定是有人已经做过了,所以只需要站在巨人的肩膀上,导入 Jackson 的依赖

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>

接下来就可以使用一下了,配置 web.xml 和 springmvc-servlet.xml 的步骤就不多说了。

3.1 返回JSON

首先创建一个实体类 User,就是我们要传输的对象( Lombok,行!)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private String name;
    private int age;
    private String gender;

}

然后添加 UserController 类,先写个方法直接返回一个字符串试试

@Controller
public class UserController {

    @RequestMapping("/json1")
    // 使用这个注解,返回的结果就不会去视图解析器,还是一个字符串
    @ResponseBody
    public String JSONTest1() throws JsonProcessingException {
        // 创建对象
        User user = new User("祈鸢", 18, "男");
        // 因为 @ResponseBody,返回的就是一个普通字符串
        return user.toString();
    }
}
// 网页输出
// User(name=??, age=18, gender=?)

乱码了,要在 @RequestMapping 中设置返回类型和编码才行!

	@RequestMapping(value = "/json", produces = "application/json;charset=utf-8")
// 再次请求
// User(name=祈鸢, age=18, gender=男)

这样返回的字符串就正常啦。

既然能正常返回字符串,JSON 也是字符串,所以能返回 JSON(完美论证)!

再写一个方法,通过对象解析器 ObjectMapper 的方法,把对象转换为 JSON 字符串返回!

@Controller
public class UserController {
    
    @RequestMapping(value = "/json2", produces = "application/json;charset=utf-8")
    // 使用这个注解,返回的结果就不会去视图解析器,还是一个字符串
    @ResponseBody
    public String JSONTest2() throws JsonProcessingException {
        //创建 jackson 的对象映射器以解析数据
        ObjectMapper mapper = new ObjectMapper();
        // 创建对象
        User user = new User("祈鸢", 18, "男");
        // 把对象转换为 json 字符串
        String str = mapper.writeValueAsString(user);
        // 因为 @ResponseBody,返回的就是一个普通字符串
        return str;
    }
}
// 网页输出
// {"name":"祈鸢","age":18,"gender":"男"}

看这输出,花括号表示对象,冒号表示属性,标准的 JSON!

前后端分离:前端接收 JSON 格式的数据,解析后渲染到页面上;而后端只要提供接口给前端,返回 JSON 格式的数据就行了!

3.2 乱码统一解决

上面的乱码虽然解决了,不过每有一个方法,就要设置一下 produces,太麻烦了。SpringMVC 当然也想到了这点,所以可以在配置文件中统一配置!

在配置文件 springmvc-servlet.xml 中添加(扩展了开启注解的标签)

<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>

真好使啊,设置完后字体都变好看了??。

总之用到了 Jakson 把它配置上去准没错!

3.3 返回JSON统一解决

和乱码一样啦,要是有很多方法,每个方法都是返回 JSON 的,每个都添加 @ResponseBody 不也很麻烦?SpringMVC 又想到了(太牛了),可以在控制器类中统一配置!

把控制器类的 @Controller 注解换成 @RestController 即可

@RestController
//@Controller
public class UserController {
    // 所有方法都不需要 @ResponseBody 了
    ...
}

就是这么简单,都没什么好说的了。

3.4 集合对象输出

该解决的问题都解决了,上面测试的是一个对象的输出,没有问题,那么对象集合呢?再来试试。

再写一个方法,将集合转换为 JSON 字符串返回

@RestController
//@Controller
public class UserController {
    
    @RequestMapping("/json3")
    public String JSONTest3() throws JsonProcessingException {

        //创建 jackson 的对象映射器以解析数据
        ObjectMapper mapper = new ObjectMapper();
        // 创建好多对象
        User user1 = new User("祈鸢A", 18, "男");
        User user2 = new User("祈鸢B", 18, "男");
        User user3 = new User("祈鸢C", 18, "男");
        User user4 = new User("祈鸢D", 18, "男");
        List<User> list = new ArrayList<User>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);

        // 将对象解析成为 JSON 字符串
        String str = mapper.writeValueAsString(list);
        return str;
    }
}
// 网页输出
/*
[{"name":"祈鸢A","age":18,"gender":"男"},
 {"name":"祈鸢B","age":18,"gender":"男"},
 {"name":"祈鸢C","age":18,"gender":"男"},
 {"name":"祈鸢D","age":18,"gender":"男"}]
*/

看这方括号,是 JSON 数组()!

3.5 时间对象输出

基本的对象返回单个或集合都没有问题了,不过还有一种特殊的对象:时间对象,年月日横线分割乱七八糟的能不能输出呢?再来试试。

再增加一个方法,返回时间对象转换后的 JSON 字符串

@RestController
//@Controller
public class UserController {
    
    @RequestMapping("/json4")
    public String JSONTest4() throws JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();
        //创建时间对象 注意是 java.util.Date
        Date date = new Date();
        // 将对象解析成为 JSON 字符串
        String str = mapper.writeValueAsString(date);
        return str;
    }
}
// 网页输出
// 1630573794971

直接输出了一串好像毫无意义的数字,不过其实这是时间戳,之前也遇到过(还研究了一下时区的问题),得转换成看得懂的日期

@RestController
//@Controller
public class UserController {
    
    @RequestMapping("/json5")
    public String JSONTest5() throws JsonProcessingException {

        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();
        String str = mapper.writeValueAsString(date);

        return str;
    }
}
// 网页输出
// "2021-09-02 17:14:12"

这样输出的就是正常的日期了!注意还有双引号哦,这还是一个 JSON 字符串!

如果经常使用到时间戳与正常日期的转换,可以直接提取为工具类 JsonUtil

public class JsonUtil {

    public static String getJson(Object object) {
        // 调用带格式的方法
        return getJson(object,"yyyy-MM-dd HH:mm:ss");
    }

    public static String getJson(Object object,String dateFormat) {
        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;
    }
}

使用的时候直接调用工具类的方法,更加简便了!

@RestController
//@Controller
public class UserController {
    
	@RequestMapping("/json6")
    public String JSONTest6() throws JsonProcessingException {

        //创建时间对象 注意是 java.util.Date
        Date date = new Date();
        // 将对象解析成为 JSON 字符串
        String str = JsonUtil.getJson(date);
        return str;
    }
}

当然,ObjectMapper 会自己判断转换的对象是否是日期,是日期则应用设置的日期格式,若不是则会正常转换对象。所以这个工具类在什么地方都是能用的,省去了创建 ObjectMapper 对象的步骤!

4. 总结

本节了解了什么是 JSON 以及 Jackson 的使用,总而言之,JSON 就是一种前端和后端约定好的,传输数据的格式。后端提供接口执行业务返回 JSON 数据(不像之前直接返回前端页面了),前端通过接口获取 JSON 数据去渲染页面,就是前后端分离了!

除了 Jackson,Fastjson 也可以做到对象和 JSON 之间的转换,不过就先不实践了,迟早得忘的东西用到再说吧??!

SpringMVC JSON使用

上一篇:数组的运算


下一篇:04_Go语言( 运算符)