Spring Boot中的JSON技术

2023-11-19

Spring Boot中的JSON技术

SpringBoot在处理对象的序列化和反序列的时候,底层用的是Jackson。来完成数据到实体类,实体类集合的映射。我们开发会指定 @RequestBody @ResponseBody 这样的注解。而了解Jackson框架,就显得很有必要了!

1、序列化

  • Jackson通过使用mapper的writeValueAsString()方法,将Java对象序列化为JSON格式字符串。
    /**
     *底层通过objectMapper把JAVA对象变成JSON字符串输出给前端
     * @param id
     * @return
     * @throws JsonProcessingException
     */
    @GetMapping("findById2/{id}")
    public void findById2(@PathVariable(name = "id")Long id, HttpServletResponse response) throws IOException {
        UmsAdmin umsAdmin = adminService.findById(id);
        String str = objectMapper.writeValueAsString(umsAdmin);
        response.getWriter().println(str);

    }

  • 使用@ResponseBody注解可以使对象序列化为JSON格式字符串
    @GetMapping("findById/{id}")
    @ResponseBody
    public UmsAdmin findById(@PathVariable(name = "id")Long id) {
       UmsAdmin umsAdmin = adminService.findById(id);
        System.out.println(umsAdmin);
        return umsAdmin;
    }

2、反序列化

  • Jackson通过使用readValue()将Java对象和JSON数据进行绑定
@Autowired
ObjectMapper mapper;

@RequestMapping("readjsonasobject")
@ResponseBody
public String readJsonAsObject() {
    try {
        String json = "{\"name\":\"mrbird\",\"age\":26}";
        User user = mapper.readValue(json, User.class);
        String name = user.getUserName();
        int age = user.getAge();
        return name + " " + age;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
  • 使用@ResponseBody注解可以使JSON格式字符串反序列化为JSON格式的对象

    @GetMapping("/save")
    public UmsAdmin save(@RequestBody UmsAdmin umsAdmin){
        System.out.println(umsAdmin);
        return umsAdmin;
    }

3、他的注解

3.1、@JsonProperty

@JsonProperty,作用在属性上,用来为JSON Key指定一个别名。

@JsonProperty("bth")
private Date birthday;
{"userName":"mrbird","age":0,"password":null,"bth":"2018-04-02 10:38:37"}

3.2、@Jsonlgnore

@Jsonlgnore,作用在属性上,用来忽略此属性。

@JsonIgnore
private String password;
{"userName":"mrbird","age":0,"bth":"2018-04-02 10:40:45"}

password属性已被忽略。

3.3、@JsonIgnoreProperties

@JsonIgnoreProperties,忽略一组属性,作用于类上,比如JsonIgnoreProperties({ "password", "age" })

@JsonIgnoreProperties({ "password", "age" })
public class User implements Serializable {
    ...
}
{"userName":"mrbird","bth":"2018-04-02 10:45:34"}

3.3、@JsonFormat

@JsonFormat,用于日期格式化,如:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;

3.4、@JsonNaming

@JsonNaming,用于指定一个命名策略,作用于类或者属性上。Jackson自带了多种命名策略,你可以实现自己的命名策略,比如输出的key 由Java命名方式转为驼峰命名方式 —— userName转化为user-name。

@JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)
public class User implements Serializable {
    ...
{"user_name":"mrbird","bth":"2018-04-02 10:52:12"}

3.5、@JsonSerialize

@JsonSerialize,指定一个实现类来自定义序列化的方式。类必须实现JsonSerializer接口,代码如下:

import java.io.IOException;

import com.example.pojo.User;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class UserSerializer extends JsonSerializer<User> {

    @Override
    public void serialize(User user, JsonGenerator generator, SerializerProvider provider)
            throws IOException, JsonProcessingException {
        generator.writeStartObject();
        generator.writeStringField("user-name", user.getUserName());
        generator.writeEndObject();
    }
}

上面的代码中我们仅仅序列化userName属性,且输出的key是user-name。 使用注解@JsonSerialize来指定User对象的序列化方式:

@JsonSerialize(using = UserSerializer.class)
public class User implements Serializable {
    ...
}
{"user-name":"mrbird"}

3.6、@JsonDeserialize

import java.io.IOException;

import com.example.pojo.User;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;

public class UserDeserializer extends JsonDeserializer<User> {

    @Override
    public User deserialize(JsonParser parser, DeserializationContext context)
            throws IOException, JsonProcessingException {
        JsonNode node = parser.getCodec().readTree(parser);
        String userName = node.get("user-name").asText();
        User user = new User();
        user.setUserName(userName);
        return user;
    }
}

使用注解@JsonDeserialize来指定User对象的序列化方式:

@JsonDeserialize (using = UserDeserializer.class)
public class User implements Serializable {
    ...
}
@Autowired
ObjectMapper mapper;

@RequestMapping("readjsonasobject")
@ResponseBody
public String readJsonAsObject() {
    try {
        String json = "{\"user-name\":\"wangnaixing\"}";
        User user = mapper.readValue(json, User.class);
        String name = user.getUserName();
        return name; //输出 wngnaixing
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

3.7、@JsonView

@JsonView,作用在类或者属性上,用来定义一个序列化组。 比如对于User对象,某些情况下只返回userName属性就行,而某些情况下需要返回全部属性。 因此User对象可以定义成如下:

public class User implements Serializable {
    private static final long serialVersionUID = 6222176558369919436L;
    
    public interface UserNameView {};
    public interface AllUserFieldView extends UserNameView {};
    
    @JsonView(UserNameView.class)
    private String userName;
    
    @JsonView(AllUserFieldView.class)
    private int age;
    
    @JsonView(AllUserFieldView.class)
    private String password;
    
    @JsonView(AllUserFieldView.class)
    private Date birthday;
    ...	
}

User定义了两个接口类,一个为userNameView,另外一个为AllUserFieldView继承了userNameView接口。这两个接口代表了两个序列化组的名称。属性userName使用了@JsonView(UserNameView.class),而剩下属性使用了@JsonView(AllUserFieldView.class)

@JsonView(User.UserNameView.class)
@RequestMapping("getuser")
@ResponseBody
public User getUser() {
    User user = new User();
    user.setUserName("mrbird");
    user.setAge(26);
    user.setPassword("123456");
    user.setBirthday(new Date());
    return user;
}
{"userName":"mrbird"}

如果将@JsonView(User.UserNameView.class)替换为@JsonView(User.AllUserFieldView.class),输出:

{"userName":"mrbird","age":26,"password":"123456","birthday":"2018-04-02 11:24:00"}

因为接口AllUserFieldView继承了接口UserNameView所以userName也会被输出。

4、集合的反序列化

在Controller方法中,可以使用@RequestBody将提交的JSON自动映射到方法参数上,比如:

@RequestMapping("updateuser")
@ResponseBody
public int updateUser(@RequestBody List<User> list){
    return list.size();
}

上面方法可以接受如下一个JSON请求,并自动映射到User对象上:

[{"userName":"mrbird","age":26},{"userName":"scott","age":27}]

有些情况下,集合对象并没有包含泛型定义,如下代码所示,反序列化并不能得到期望的结果

@Autowired
ObjectMapper mapper;

@RequestMapping("customize")
@ResponseBody
public String customize() throws JsonParseException, JsonMappingException, IOException {
    String jsonStr = "[{\"userName\":\"mrbird\",\"age\":26},{\"userName\":\"scott\",\"age\":27}]";
    List<User> list = mapper.readValue(jsonStr, List.class);
    String msg = "";
    for (User user : list) {
        msg += user.getUserName();
    }
    return msg;
}

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.example.pojo.User

这是因为在运行时刻,泛型己经被擦除了(不同于方法参数定义的泛型,不会被擦除)。为了提供泛型信息,Jackson提供了JavaType ,用来指明集合类型,将上述方法改为:

@Autowired
ObjectMapper mapper;

@RequestMapping("customize")
@ResponseBody
public String customize() throws JsonParseException, JsonMappingException, IOException {
    String jsonStr = "[{\"userName\":\"mrbird\",\"age\":26},{\"userName\":\"scott\",\"age\":27}]";
    JavaType type = mapper.getTypeFactory().constructParametricType(List.class, User.class);
    List<User> list = mapper.readValue(jsonStr, type);
    String msg = "";
    for (User user : list) {
        msg += user.getUserName();
    }
    return msg;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot中的JSON技术 的相关文章

随机推荐

  • python3 爬取36氪新闻网页

    一个做了反爬的36氪 返回数据恶心 感觉是一堆垃圾 这里只是记录一下爬取过程 一 爬取环境 win10 python3 scrapy 二 爬取过程 1 入口 搜索 2 动态js数据加载 查看下一页操作 3 返回数据 4 请求链接 http
  • Jmeter 数据库压力测试

    一 jmeter本地数据库压力测试 1 将JMeterPlugins Extras jar和JMeterPlugins Standard jar放到apache jmeter 3 0 lib ext目录下 2 在本地打开ServerAgen
  • 操作系统学习(九)进程通信

    一 知识总览 二 定义 进程通信是指进程之间的信息交换 每个进程都拥有自己的内存空间 是相互独立的 这样在每个进程执行时 才不会被其他进程所干扰 三 进程通信的方式 1 共享存储 1 两个进程对共享区的访问必须是互斥的 即在同一时间内 只允
  • C语言实现kafka多线程,【转】c++(11)使用librdkafka库实现kafka的消费实例

    版权声明 本文为博主原创文章 遵循 CC 4 0 by sa 版权协议 转载请附上原文出处链接和本声明 本文链接 https blog csdn net lijinqi1987 article details 76691170 librdk
  • AspectJ使用

    一 AOP介绍 AOP Aspect Oriented Programming 面向切面编程 是一种新的方法论 编程范式 是对传统 OOP Object Oriented Programming 面向对象编程 的补充 旨在通过允许横切关注点
  • 2022 React 面试题(50道)

    什么是同源 如果两个页面 接口 的协议 域名 端口号都相同 我们认为他们具6511有相同的源 UmiJs和dva roadhog是什么关系 roadhog 是基于 webpack 的封装工具 目的是简化 webpack 的配置 umi 可以
  • 初学Linux基本的命令操作应当记牢

    Linux管理文件和目录的命令 命令 功能 命令 功能 pwd 显示当前目录 ls 查看目录下的内容 cd 改变所在目录 cat 显示文件的内容 grep 在文件中查找某字符 cp 复制文件 touch 创建文件 mv 移动文件 rm 删除
  • 7.Closing non transactional SqlSession 导致事务失败问题

    博主在研究Spring事务源码 编写测试代码时 出现了Closing non transactional SqlSession 导致事务失败的问题 于是写下这篇文章 记录一下这个问题 前提 已经通过配置方式 开启了 Spring 声明式事务
  • JS练习_九九乘法表

    效果图 分析 1 先使用基本的for循环嵌套 展示乘法表 2 完
  • Qt使用https

    Qt貌似默认是不支持SSl认证的 可以这样操作 将 libeay32 dll和ssleay32 dll这两个库文件拷贝到程序生成目录下 即生成exe的同级目录 或者拷贝到QtNetwork模块的库文件目录中 路径示例 E Qt Qt5 12
  • qt orm 基于Qt的ORM框架QyOrm,类似peewee,最简单的语法,最高效的使用

    QyOrm Gitee传送门 支持功能 AutoGenerate根据数据库表自动生成类的定义代码 外键 实例化 联合查询 特殊查询 Json的读取和保存 QT GUI常见input widget 的双向绑定 以下是使用的例子 手动 类的定义
  • 第一篇:PyGame小游戏——2D迷宫游戏(16W字详解)

    目录 在开头的开场白 在CSDN看到一篇 利用深度优先算法自动生成随机迷宫 的blog 突发灵感 就想做这个迷宫游戏 本文大部分讲的意思 而非代码 文章最后会展示最终代码和图片的 读者不用过多地注意那些 本文是作者第一次写blog 难免有些
  • 【Java编程】关于Java的几个基础问题

    关于Java的几个基础问题 String 和 StringBuffer 和 StringBuilder 的异同 相同点 三者在 Java 中都是用来处理字符串的 三个类都被 final 修饰 因此都是不可继承的 StringBuilder
  • 超级等级福利礼包

    文章目录 一 介绍 二 设计等级礼包的目的 1 提升游戏玩家活跃度 2 提升游戏用户吸引力 3 提高游戏用户留存率 4 实现间接收入 5 持续营收 三 玩家心理总结 四 总结该模式的赢利点 五 该模式的应用场景举例 一 介绍 超级等级福利礼
  • 二分查找(C语言版)

    刚刚学到到的知识 掌握的不怎么好 如有不足麻烦留言 第一步 先理清你要查找的数组 最好是有序排序的数组 本人还没学到数组的排序就只能用有序的数组来 int arr 10 1 2 3 4 5 6 7 8 9 10 第二步 计算出该数组的长度
  • MATLAB(1)MATLAB工作环境

    目录 工具栏 当前文件夹窗口 命令行窗口 工作区 文件编辑窗口 图形 Figure x 窗口 本文基于MATLAB R2020b MATLAB刚打开时 一般如下图所示 包括上方的工具栏 左侧的当前文件夹窗口 中间的命令行窗口以及最右侧的工作
  • 考研机试题 -- 字符串、背包、枚举

    目录 首字母大写 字符串 日志排序 字符串 双关键字排序 字符串转换整数 字符串 点菜问题 01背包 神奇的口袋 01背包 计数 整数拆分 完全背包 计数 CCF201512 2 消除类游戏 枚举 首字母大写 字符串 https www n
  • 全球排名第一的免费开源ERP Odoo替代料管理应用解决方案

    本文节选自Odoo亚太金牌服务机构 开源智造 所编写的 ERP真的免费不花钱 Odoo应用指南 如需获取完整的知识内容 请至开源智造官网免费获取 感谢网友一键三连 点赞 转发 收藏 您的支持是我们最大的前进动力 电子行业产品竞争激烈 升级换
  • 【QT学习】实现MVC框架的简易封装(一文读懂)

    文章目录 前言 一 MVC框架简介 1 核心部件 2 使用目的 3 MVC优点 二 具体封装步骤 1 文件管理 2 创建模型 3 创建控制器 4 MVC实现 用户登录验证为例 总结 前言 MVC Model View Controller
  • Spring Boot中的JSON技术

    Spring Boot中的JSON技术 SpringBoot在处理对象的序列化和反序列的时候 底层用的是Jackson 来完成数据到实体类 实体类集合的映射 我们开发会指定 RequestBody ResponseBody 这样的注解 而了