Java对JSON的操作方式
发表于:2020-09-11 | 分类: 后端

第1章 注意事项

JDK里面默认是不带对JSON的支持的, 所以要使用JSON需要引入其他第三方依赖

目前市面上常见的JSON框架有: fastjson(阿里出品) gson(谷歌出品) jackson(推荐使用)

第2章 JSON格式

1.1 普通JSON

格式: 键使用双引号引起来, 值如果是字符串也需要使用双引号引起来, 如果是数字则可以直接写

{ "name”:”parkour”, “age”:28 }

JSON里面嵌套JSON

{ "name”:”parkour”, “age”:28, “hobby”: {“java”:”like”,“basketball”:”unlike”} }

1.2 JSON数组

格式

[ { "name”:”parkour”, “age”:28 },{ "name”:”xiaoqinyun”, “age”:18 } ]

1.3 前端中JSON和JavaScript对象的区分

很多人搞不清楚 JSON 和 JavaScript 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:

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

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

1.4 前端中JSON和JavaScript对象互转

let obj = JSON.parse('{"a": "Hello", "b": "World"}'); // JSON字符串转换为JavaScript 对象
//结果是 {a: 'Hello', b: 'World'}
let json = JSON.stringify({a: 'Hello', b: 'World'}); // JavaScript 对象转换为JSON字符串
//结果是 '{"a": "Hello", "b": "World"}'

第3章jackson框架的使用(推荐使用)

为什么推荐使用:

1.fastjson经常被爆出有漏洞使用jackson更安全

2.Spring Boot 默认的json解析器就是Jackson

3.1 导入依赖

注意: 不要导错导入jackson-databind了

因为 jackson-databind不支持java8的日期时间格式如: localdatetime, 只有jackson-datatype-jsr310才支持

<!--导入jackson依赖(支持java8日期格式的)-->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.13.4</version>
</dependency>

3.2 jackson中对日期的特殊处理

private static ObjectMapper getObjectMapper() {
    ObjectMapper mapper = new ObjectMapper();

    // 注入java时间模块, 指定日期的序列化与反序列化格式
    JavaTimeModule javaTimeModule = new JavaTimeModule();
    
    javaTimeModule.addSerializer(LocalDateTime.class, 
                                 new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                                 
    javaTimeModule.addDeserializer(LocalDateTime.class, 
                                 new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                                 
    mapper.registerModule(javaTimeModule);
    
    return mapper;
}

3.3 json与对象之间的相互转换

抽取JacksonUtil工具类

public class JacksonUtil {

    /**
     * 将对象转换成JSON数据
     *
     * @param data 对象
     * @return JSON数据
     */
    public static String beanToJson(Object data) {
        try {
            return getObjectMapper().writeValueAsString(data);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将JSON数据转换成对象
     *
     * @param jsonData JSON数据
     * @param beanType 对象类型
     * @return 对象
     */
    public static <T> T jsonToBean(String jsonData, Class<T> beanType) {
        try {
            return getObjectMapper().readValue(jsonData, beanType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 将JSON数据转换成列表
     *
     * @param jsonData JSON数据
     * @param beanType 对象类型
     * @return 列表
     */
    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
        try {
            ObjectMapper mapper = getObjectMapper();
            JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, beanType);
            return mapper.readValue(jsonData, javaType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将JSON数据转换成Set集合
     *
     * @param jsonData    JSON数据
     * @param elementType 元素类型
     * @return Set集合
     */
    public static <E> Set<E> jsonToSet(String jsonData, Class<E> elementType) {
        try {
            ObjectMapper mapper = getObjectMapper();
            JavaType javaType = mapper.getTypeFactory().constructCollectionType(Set.class, elementType);
            return mapper.readValue(jsonData, javaType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将JSON数据转换成Map集合
     *
     * @param jsonData  JSON数据
     * @param keyType   键类型
     * @param valueType 值类型
     * @return Map集合
     */
    public static <K, V> Map<K, V> jsonToMap(String jsonData, Class<K> keyType, Class<V> valueType) {
        try {
            ObjectMapper mapper = getObjectMapper();
            JavaType javaType = mapper.getTypeFactory().constructMapType(Map.class, keyType, valueType);
            return mapper.readValue(jsonData, javaType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 获取一个ObjectMapper对象
     *
     * @return 一个初始化后的ObjectMapper对象
     */
    private static ObjectMapper getObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();

        // 注入java时间模块, 指定日期的序列化与反序列化格式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, 
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDateTime.class, 
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        mapper.registerModule(javaTimeModule);
        return mapper;
    }
}

测试

public class JacksonDemo {
    public static void main(String[] args) throws Exception {
        testBeanToJson();
        testJsonToBean();
        testJsonToList();
        testJsonToSet();
        testJsonToMap();
    }


    /**
     * 测试将bean对象转换成json
     */
    public static void testBeanToJson(){
        //1.准备数据
        Student student1 = new Student();
        student1.setId("110");
        student1.setName("狗娃");
        student1.setBirthday(LocalDateTime.now());
        student1.setAddress(new Address("家庭地址:四川","学习地址:北京"));

        Student student2 = new Student();
        student2.setId("120");
        student2.setName("狗剩");
        student2.setBirthday(LocalDateTime.now());
        student2.setAddress(new Address("家庭地址:湖南","学习地址:上海"));

        List<Student> list = new ArrayList<>();
        list.add(student1);
        list.add(student2);

        // 2.转换
        String jsonStr = JacksonUtil.beanToJson(student1);
        String jsonListStr = JacksonUtil.beanToJson(list);
        System.out.println(jsonStr);
        System.out.println(jsonListStr);
    }

    /**
     * 测试将json转换成普通的javabean对象(非集合类对象)
     */
    public static void testJsonToBean(){
        //1.准备数据
        String jsonStr = "{\"id\":\"110\",\"name\":\"狗娃\",\"birthday\":\"2022-10-22 19:13:20\",\"address\":{\"homeAddress\":\"家庭地址:四川\",\"schoolAddress\":\"学习地址:北京\"}}";

        // 2.转换
        Student student = JacksonUtil.jsonToBean(jsonStr, Student.class);
        System.out.println(student);
    }


    /**
     * 测试将json list字符串 转换成对应的List集合
     */
    public static void testJsonToList(){
        //1.准备数据
        String jsonListStr = "[{\"id\":\"110\",\"name\":\"狗娃\",\"birthday\":\"2022-10-22 19:13:56\",\"address\":{\"homeAddress\":\"家庭地址:四川\",\"schoolAddress\":\"学习地址:北京\"}},{\"id\":\"120\",\"name\":\"狗剩\",\"birthday\":\"2022-10-22 19:13:56\",\"address\":{\"homeAddress\":\"家庭地址:湖南\",\"schoolAddress\":\"学习地址:上海\"}}]";

        // 2.转换
        List<Student> list = JacksonUtil.jsonToList(jsonListStr, Student.class);
        System.out.println(list);
    }

    /**
     * 测试将json set字符串 转换成对应的set集合
     */
    public static void testJsonToSet(){
        //1.准备数据 (这里面有两个一模一样的狗剩对象)
        String jsonSetStr = "[{\"id\":\"110\",\"name\":\"狗娃\",\"birthday\":\"2022-10-22 20:03:42\",\"address\":{\"homeAddress\":\"家庭地址:四川\",\"schoolAddress\":\"学习地址:北京\"}},{\"id\":\"120\",\"name\":\"狗剩\",\"birthday\":\"2022-10-22 20:03:42\",\"address\":{\"homeAddress\":\"家庭地址:湖南\",\"schoolAddress\":\"学习地址:上海\"}},{\"id\":\"120\",\"name\":\"狗剩\",\"birthday\":\"2022-10-22 20:03:42\",\"address\":{\"homeAddress\":\"家庭地址:湖南\",\"schoolAddress\":\"学习地址:上海\"}}]";

        // 2.转换 (转换后只打印了一次狗剩对象)
        Set<Student> set = JacksonUtil.jsonToSet(jsonSetStr, Student.class);
        System.out.println(set);
    }


    /**
     * 测试json字符串 转换成map对象
     */
    public static void testJsonToMap(){
        //1.准备数据
        String jsonMapStr = "{\"id\":\"110\",\"name\":\"狗娃\",\"birthday\":\"2022-10-22 20:08:46\",\"address\":{\"homeAddress\":\"家庭地址:四川\",\"schoolAddress\":\"学习地址:北京\"}}";

        // 2.转换
        Map<String, Object> map = JacksonUtil.jsonToMap(jsonMapStr, String.class, Object.class);
        Objects.requireNonNull(map).forEach((k, v)-> System.out.println(k + "===>" + v));
    }
}

3.4 jackson常用注解

@JsonFormat(pattern=”yyyy-MM-dd HH:mm:ss”)   // 定义日期时间格式
@JsonProperty(“alia”) // 指定字段转换成json时使用的别名
@JsonIgnore // 放到某个字段上后, 转换成json时会忽略这个字段

3.5 解决json响应前台中文乱码的问题

我们随便编写一个User的实体类,然后我们去编写我们的测试Controller;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
   private String name;
   private int age;
   private String sex;
}

编写一个Controller

@RestController
public class UserController {
   //produces:指定响应体返回类型和编码
   @RequestMapping(value = "/json1")
   public String json1() throws JsonProcessingException {
       //创建一个jackson的对象映射器,用来解析数据
       ObjectMapper mapper = new ObjectMapper();
       //创建一个对象
       User user = new User("秦疆1号", 3, "男");
       //将我们的对象解析成为json格式
       String str = mapper.writeValueAsString(user);
       //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
       return str;
  }
}

配置Tomcat,启动测试一下!

http://localhost:8080/json1

JSON1

发现出现了乱码问题,我们需要设置一下他的编码格式为utf-8,以及它返回的类型;

通过@RequestMaping的produces属性来实现,修改下代码

//produces:指定响应体返回类型和编码
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")

再次测试, http://localhost:8080/json1 , 乱码问题OK!
JSON2

【注意:使用json记得处理乱码问题】

乱码统一解决

上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!

我们可以在springmvc的配置文件上添加一段消息StringHttpMessageConverter转换配置!

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

3.6 SpringBoot整合jackson

3.6.1 SpringBoot中配置jackson日期格式

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss

3.6.2 SpringBoot中解决json响应中文乱码的问题

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {

    @Bean
    public HttpMessageConverter responseBodyConverter(){
        //解决返回值中文乱码
        StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        return converter;
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(responseBodyConverter());
    }
}

第4章fastjson框架的使用

4.1 注意最好不要用这个框架

fastjson经常爆安全漏洞, 另外现在fastjson已经改名升级为fastjson2了

4.2 将json转成java对象

String str = "{'name':'parkour'}"  
Student s = JSON.parseObject(str,Student.class)

4.3 将java对象转成json格式字符串

Student student = new Student("110","狗娃");
String jsonstring = JSON.toJSONString(student);

4.4 将json数组转成java对象的List结合

String jsonArrayString = "[{'name':'狗娃'},{'name':'狗剩'}]"
List<Student> list = JSON.parseArray(jsonArrayString,Student.class);

4.5 将java对象的List集合转成json数组格式字符串

Student student1 = new Student("110","狗娃");
Student student2 = new Student("120","狗剩");
List<Student> list = new ArrayList<>();
list.add(student1);
list.add(student2);
String jsonArrayString = JSON.toJSONString(list);
上一篇:
MongoDB
下一篇:
MySQL