一.Json参数

1.1 json 分类详解

  • JACKSON,官方,SpringBoot默认
  • 本身框架提供了依赖
  • Json 处理的核心工具:HttpMessageConverter
  • gson, Google, 安卓上使用较多
  • fastjson,Alibaba提供,但是安全漏洞和其他问题多。。

1.2 Spring中使用json分类

详解:Springmvc 中使用json分两个方面

  • 返回值 :返回JSON
  • 如果是返回值,接口定义的时候,直接返回的是对象,所以需要有一个工具,把我们返回的对象转为JSON,这个工具就是HttpMessageConverter
  • 请求的参数是一个JSON
  • 如果是请求参数,那么JSON一般是放在请求体中,我们需要一个工具,将请求体中的JSON字符串转为一个对象

1.3 HttpMessageConverter

  • HttpMessageConverter本身是一个接口,是一个规范。具体怎么做,看不同JSON处理工具提供不同依赖去实HttpMessageConverter这个接口。
  • 只需要一段Json请求下:
  • 如果使用的是Jackson或者gson,那么默认情况下,SpringMVC会自动帮我们配置对应的HttpMessageConverter
  • 需要的别的功能
  • 如果使用的是fastjson,需要你自己手动配置

二.Json 的实际使用

2.1 添加json的依赖

依赖添加成功后,凡是在接口中直接返回的对象,集合等等,都会自动转为 JSON。

<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.3</version>
        </dependency>

2.2 没有特殊需求的时候

没有特殊需求的时候我们只需要1.加一个依赖2.正常返回对象,其他的事情idear会帮你做(大部分时候我们都不会有特殊的需求)

/**
     * SpringMVC 会自动通过 HttpMessageConverter 将 User 对象转为 JSON 字符串
     * @param id
     * @return
     */
    @GetMapping("/user")
    @ResponseBody
    public User getUserById(Integer id) {
        User user = new User();
        user.setId(id);
        user.setUsername("张三");
        user.setAddress("广州");
        user.setPassword("123");
        user.setBirthday(new Date());
        return user;
    }

返回的json的样式

{"id":null,"address":"广州","birthday":1656905389231,"name":"张三"}

2.3 特殊需求的时候

2.3.1 对于属性的特殊需求

user类

package com.huang.demo.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Date;

public class User {
    private Integer id;
    //@JsonProperty("name") 表示 username 这个属性将来生成的 json 的 key 为 name
    @JsonProperty("name")
    private String username;
    private String address;
    //生成 JSON 的时候,忽略该字段
    @JsonIgnore
    private String password;

    //注意,日期格式化的时候,需要指定时区
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "Asia/Shanghai")
    private Date birthday;

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
三种特殊的使用
  • 1.更改属性的key命名
  • @JsonProperty(“name”)
    private String username;
  • 2.生成Json的时候,忽略不想要的字段
  • //生成 JSON 的时候,忽略该字段
    @JsonIgnore
    private String password;
  • 3.容器格式化的时候要指定时区,不然会增减八个小时
  • @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”,timezone = “Asia/Shanghai”)
    private Date birthday;

UserController

  • 这里返回一个对象,但是在前端接收到的则是一个 JSON 字符串,这个对象会通过 HttpMessageConverter 自动转为 JSON 字符串。
package com.huang.demo.controller;


import com.huang.demo.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

@Controller
public class UserController {

    /**
     * SpringMVC 会自动通过 HttpMessageConverter 将 User 对象转为 JSON 字符串
     * @param id
     * @return
     */
    @GetMapping("/user")
    @ResponseBody
    public User getUserById(Integer id) {
        User user = new User();
        user.setId(id);
        user.setUsername("张三");
        user.setAddress("广州");
        user.setPassword("123");
        user.setBirthday(new Date());
        return user;
    }
}

如果想返回一个 JSON 数组,写法如下:

UserController

@RequestMapping("/user")
@ResponseBody
public List<Book> getAllUsers() {
    List<User> list = new ArrayList<User>();
    for (int i = 0; i < 10; i++) {
        User user = new User();
        user.setId(i);
        user.setUsername("黄黄:" + i);
        user.setAddress("上海路:" + i);
        user.setPassword(":" + i);
        list.add(book);
    }
    return list;
}

2.3.2 HttpMessageConverter 在Json中的作用

它的作用是 Http 消息转换器,既然是消息转换器,它提供了两方面的功能:

  • 将返回的对象转为 JSON
  • 将前端提交上来的 JSON 转为对象

ttpMessageConverter 只是一个接口,由各个 JSON 工具提供相应的实现,在 jackson 中,实现的名字叫做 MappingJackson2HttpMessageConverter,而这个东西的初始化,则由 SpringMVC 来完成。除非自己有一些自定义配置的需求,否则一般来说不需要自己提供 MappingJackson2HttpMessageConverter。

2.3.3 如何使用定制返回日期的格式

2.3.3.1 第一种,User类上面配置局部的

实体类上加注解 如下

User 类

package com.huang.demo.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Date;

public class User {
    private Integer id;
    //@JsonProperty("name") 表示 username 这个属性将来生成的 json 的 key 为 name
    @JsonProperty("name")
    private String username;
    private String address;
    //生成 JSON 的时候,忽略该字段
    @JsonIgnore
    private String password;

    //注意,日期格式化的时候,需要指定时区
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "Asia/Shanghai")
    private Date birthday;



    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
  • 弊端:这种方式有一个弊端,这个注解可以加在属性上,也可以加在类上,也就说,最大可以作用到一个类中的所有日期属性上。如果项目中有很多实体类都需要做日期格式化,使用这种方式就比较麻烦了
2.3.3.2 第二种,xml中配置全局的时间配置
  • 解决方法: 自己提供一个 jackson 的 HttpMesageConverter 实例,在这个实例中,自己去配置相关属性,这里的配置将是一个全局配置
<mvc:annotation-driven>
    <mvc:message-converters>
        <ref bean="httpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" id="httpMessageConverter">
    <property name="objectMapper">
        <bean class="com.fasterxml.jackson.databind.ObjectMapper">
            <property name="dateFormat">
                <bean class="java.text.SimpleDateFormat">
                    <constructor-arg name="pattern" value="yyyy-MM-dd HH:mm:ss"/>
                </bean>
            </property>
            <property name="timeZone" value="Asia/Shanghai"/>
        </bean>
    </property>
</bean>
2.3.3.3 第三种,配置一个日期类型转换器

DateConverter 类 即 我们的日期类型转换器

package com.huang.demo.converter;


import org.springframework.core.convert.converter.Converter;
import org.springframework.expression.ParseException;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 日期类型转换器
 *
 * 直接将当前类注入到 Spring 容器中
 * 默认情况下,bean 的名字就是类名首字母小写
 *
 * 如果想要自定义 bean 的名称
 * @Component("dc")
 */

@Component("dc")
public class DateConverter implements Converter<String, Date> {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    @Override
    public Date convert(String source) {
        try {
            return sdf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (java.text.ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • 日期类型转换器有两种配置方法:第一种跟上面一样就是加上一个@Component(“dc”)注解,注解里面给注入到bean的转换器命名

第二种如下,在springMVC的配置文件spring-servlet.xml里配置

<!--第二种 xml配置方法
bean叫做dateConverter,-->
    <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" id="serviceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="dateConverter"/>
            </set>
        </property>
    </bean>

注意

  • 1.xml中配置了,期类型转换器DateConverter 类中依旧要加注解,但是不需要给他加名字
@Component("")
  • 2.xml中全局的自己配置相关属性的全局配置依旧是要存在的,即 jackson 的 HttpMesageConverter 实例依旧要存在

三. gson是实际使用

3.1 概念:

  • gson 是 Google 推出的一个 JSON 解析器,主要在 Android 开发中使用较多,不过,Web 开发中也是支持这个的,而且 SpringMVC 还针对 Gson 提供了相关的自动化配置,以致我们在项目中只要添加 gson 依赖,就可以直接使用 gson 来做 JSON 解析了。

3.2 实际的使用

第一步: 添加gson的依赖

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>
  • 注意
  • 项目中,同时存在 jackson 和 gson 的话,那么默认使用的是 jackson
  • 原因
  • 在 org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter 类的构造方法中,加载顺序就是先加载 jackson 的 HttpMessageConverter,后加载 gson 的 HttpMessageConverter

在springMVC的配置文件spring-servlet.xml里配置

<mvc:annotation-driven>
    <mvc:message-converters>
        <ref bean="httpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter" id="httpMessageConverter">
    <property name="gson">
        <bean class="com.google.gson.Gson" factory-bean="gsonBuilder" factory-method="create"/>
    </property>
</bean>
<bean class="com.google.gson.GsonBuilder" id="gsonBuilder">
    <property name="dateFormat" value="yyyy-MM-dd"/>
</bean>

四. fastjson的实际使用

4.1 概念

  • 最快的 JSON 解析器,但是也是这三个中 BUG 最多的一个。在 SpringMVC 并没针对 fastjson 提供相应的 HttpMessageConverter,所以,fastjson 在使用时,一定要自己手动配置 HttpMessageConverter(前面两个如果没有特殊需要,直接添加依赖就可以了)

有一说一这玩意快是真的快,但是bug是真多,就像1.2.83版本,都不知道为什么就是解析不了中文

第一步: 添加fastjson依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.60</version>
</dependency>

第二步: SpringMVC 的配置文件中配置 HttpMessageConverter:

<mvc:annotation-driven>
    <mvc:message-converters>
        <ref bean="httpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" id="httpMessageConverter">
    <property name="fastJsonConfig">
        <bean class="com.alibaba.fastjson.support.config.FastJsonConfig">
            <property name="dateFormat" value="yyyy-MM-dd"/>
        </bean>
    </property>
</bean>

第三步 : astjson 默认中文乱码,添加如下配置解决:(即实际开发中要在第二步上加东西)

<mvc:annotation-driven>
    <mvc:message-converters>
        <ref bean="httpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" id="httpMessageConverter">
    <property name="fastJsonConfig">
        <bean class="com.alibaba.fastjson.support.config.FastJsonConfig">
            <property name="dateFormat" value="yyyy-MM-dd"/>
        </bean>
    </property>
    <property name="supportedMediaTypes">
        <list>
            <value>application/json;charset=utf-8</value>
        </list>
    </property>
</bean>