SpringBoot中使用Jackson序列化返回

SpringBoot中使用Jackson序列化返回

在Spring Boot应用中,使用Jackson库来处理JSON的序列化和反序列化是一种常见的做法。Jackson是一个高效的JSON处理器,广泛用于Java环境中,尤其是在与Spring框架集成时。本文将详细介绍如何在Spring Boot中配置和使用Jackson,以实现复杂对象的序列化。

基本配置

在Spring Boot项目中,默认已经集成了Jackson,因此你不需要手动引入Jackson库。Spring Boot会自动配置Jackson,并将其用作默认的JSON转换库。以下是一个简单的示例,展示了如何在Spring Boot应用中使用Jackson来序列化一个对象。

实体类定义

假设我们有一个名为User的实体类,包含几个属性:姓名、年龄和邮箱。

import com.fasterxml.jackson.annotation.JsonProperty;

public class User {
    private String name;
    private int age;
    private String email;

    // 标准的getter和setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

控制器层

在Spring Boot控制器中,你可以直接返回一个对象,Spring MVC会自动使用Jackson将对象序列化为JSON格式。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/user")
    public User getUser() {
        User user = new User();
        user.setName("张三");
        user.setAge(30);
        user.setEmail("zhangsan@example.com");
        return user;
    }
}

自定义序列化,JsonSerializer

尽管Spring Boot的默认配置通常足够使用,但在某些情况下,你可能需要对Jackson的行为进行定制。以下是一些常见的自定义配置方法。

简单使用

如果你想要自定义某个类的序列化方式,可以通过实现JsonSerializer来实现。例如,如果你想在序列化User类时隐藏邮箱信息,可以创建一个自定义的序列化器。

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.IOException;

public class UserSerializer extends StdSerializer<User> {

    public UserSerializer() {
        this(null);
    }

    public UserSerializer(Class<User> t) {
        super(t);
    }

    @Override
    public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("name", user.getName());
        jsonGenerator.writeNumberField("age", user.getAge());
        // 不序列化email字段
        jsonGenerator.writeEndObject();
    }
}

整数格式化为千分位

在使用 Jackson 进行序列化时,如果需要将整数(例如 Integer 类型)格式化为带有千分位的字符串(如 “100,000”),可以通过自定义序列化器来实现。这里我将演示如何创建一个自定义的序列化器,并应用在一个实体类的字段上。

步骤 1: 创建自定义序列化器

首先,我们需要创建一个扩展自 JsonSerializer<T> 的类,专门用于序列化 Integer 字段。

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.text.DecimalFormat;

public class ThousandsFormatterSerializer extends JsonSerializer<Integer> {
    private static final DecimalFormat formatter = new DecimalFormat("#,###");

    @Override
    public void serialize(Integer value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
        } else {
            gen.writeString(formatter.format(value));
        }
    }
}

这个自定义的序列化器使用 DecimalFormat 将整数格式化为千分位字符串。

步骤 2: 应用注解到实体类

现在,你可以使用 @JsonSerialize 注解来指定使用这个自定义序列化器。将此注解添加到实体类的相应字段上:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

public class DataModel {
    private String name;

    @JsonSerialize(using = ThousandsFormatterSerializer.class)
    private Integer amount;

    // 构造函数、getter 和 setter 省略
}

在这个例子中,amount 字段将被格式化为千分位字符串,当 Jackson 序列化这个 DataModel 类的实例时。

步骤 3: 使用和测试

最后,在你的应用程序中创建 DataModel 的实例,并通过 Spring Boot 的 REST 控制器返回它,Jackson 会自动应用这个自定义的序列化器来格式化 amount 字段。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DataController {

    @GetMapping("/formatted-data")
    public DataModel getFormattedData() {
        DataModel data = new DataModel();
        data.setName("Example");
        data.setAmount(100000);
        return data;
    }
}

当你访问这个控制器方法时,你应该会看到如下格式的 JSON 响应:

{
    "name": "Example",
    "amount": "100,000"
}

几个常用的注解

指定序列化和反序列化时JSON对象的属性名。@JsonProperty

  • 指定序列化和反序列化时JSON对象的属性名。
  • 例如,可以将Java字段名从 firstName 映射到 JSON 属性 first_name
public class User {
    @JsonProperty("first_name")
    private String firstName;
}

在序列化和反序列化过程中忽略该属性。@JsonIgnore

在序列化和反序列化过程中忽略该属性。

public class User {
    private String firstName;
    
    @JsonIgnore
    private String password;
}

用于格式化字段,如日期格式。 @JsonFormat

用于格式化字段,如日期格式。

public class User {
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private Date birthDate;
}

下面有详细讲

使用@JsonView控制输出

@JsonView 是Jackson提供的一种方式,允许你在同一个类中定义多个视图,根据上下文来序列化不同的属性集合。这个功能在你需要根据用户的不同权限展示不同级别的数据时特别有用。

定义视图

首先,你需要定义一些视图接口。这些接口不包含任何方法,它们的目的是为不同的序列化视图提供标记。

public class Views {
    public static class Public {}
    public static class Internal extends Public {}
}

应用视图到实体类

然后,使用@JsonView注解来标注User实体类中的不同字段,这些字段将根据视图的不同而序列化。

public class User {
    @JsonView(Views.Public.class)
    private String name;
    
    @JsonView(Views.Public.class)
    private int age;
    
    @JsonView(Views.Internal.class)
    private String email;

    // getters 和 setters
}

控制器中使用视图

在Spring MVC控制器中,你可以通过@JsonView注解来指定哪个视图应该被用于序列化。

@RestController
public class UserController {

    @GetMapping("/user/public")
    @JsonView(Views.Public.class)
    public User getPublicUser() {
        return createUser();
    }

    @GetMapping("/user/internal")
    @JsonView(Views.Internal.class)
    public User getInternalUser() {
        return createUser();
    }

    private User createUser() {
        User user = new User();
        user.setName("张三");
        user.setAge(30);
        user.setEmail("zhangsan@example.com");
        return user;
    }
}

@JsonViewJsonSerializer 混合使用

在Jackson中,@JsonViewJsonSerializer 是可以组合使用的,但这样做可能会导致一些复杂性和冗余。这两种机制都用于控制JSON序列化的行为,但它们各自适用于不同的场景。

使用场景

  1. @JsonView:这是一种较为简洁的方法,用于在不同的上下文中控制哪些属性被包含在JSON中。它适用于简单的情况,比如当同一个对象在不同的API端点返回不同字段时。

  2. JsonSerializer:这是一个更为强大和灵活的工具,允许你完全控制一个对象的序列化过程。当你需要对序列化进行详细控制,如改变输出的结构或添加复杂的条件逻辑时,这是一个更好的选择。

组合使用

当你同时使用@JsonViewJsonSerializer时,通常是因为你需要处理非常具体的序列化需求,如下面的示例所示:

public class CustomUserSerializer extends StdSerializer<User> {
    public CustomUserSerializer() {
        super(User.class);
    }

    @Override
    public void serialize(User user, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        if (provider.getActiveView() != null && provider.getActiveView().equals(Views.Public.class)) {
            gen.writeStringField("name", user.getName());
        }
        if (provider.getActiveView() != null && provider.getActiveView().equals(Views.Internal.class)) {
            gen.writeStringField("email", user.getEmail());
            gen.writeNumberField("age", user.getAge());
        }
        gen.writeEndObject();
    }
}

在这个例子中,CustomUserSerializer 判断当前激活的视图,并根据视图决定序列化哪些字段。这样做虽然增加了灵活性,但也增加了代码的复杂性和维护难度。

处理日期和枚举

处理日期和枚举类型时,可能需要特别注意。Jackson提供了多种方式来定制日期和枚举的序列化方式。

日期格式化

如果你需要自定义日期的格式,可以使用@JsonFormat注解来指定日期字段的格式。

import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;

public class Event {
    private String name;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    private Date eventDate;

    // getters 和 setters
}

枚举的自定义序列化

对于枚举类型,你可能想要序列化为不同于默认的名字。使用@JsonValue注解可以指定一个枚举的方法来返回想要序列化的值。

public enum Type {
    FULL_TIME("Full time"),
    PART_TIME("Part time");

    private String value;

    Type(String value) {
        this.value = value;
    }

    @JsonValue
    public String getValue() {
        return value;
    }
}

### 返回结果示例

假设你有一个Java类`Employee`,其中包含一个`Type`枚举字段,如下所示:

```java
public class Employee {
    private String name;
    private Type employmentType;

    public Employee(String name, Type employmentType) {
        this.name = name;
        this.employmentType = employmentType;
    }

    // Getters and Setters
}

在Spring Boot应用中,当你返回一个包含枚举字段的Employee对象时,由于Type枚举使用了@JsonValue,序列化的JSON将反映getValue()方法提供的字符串,而不是枚举的名字。例如:

@RestController
public class EmployeeController {

    @GetMapping("/employee")
    public Employee getEmployee() {
        return new Employee("张三", Type.FULL_TIME);
    }
}

该端点返回的JSON可能如下所示:

{
    "name": "张三",
    "employmentType": "Full time"
}

这里,employmentType字段显示为"Full time",这是FULL_TIME枚举值的自定义序列化输出。

参考链接

  • 官方Spring文档关于JSON处理:https://spring.io/projects/spring-framework#overview
  • Jackson项目主页:https://github.com/FasterXML/jackson
  • 关于Jackson注解的详细使用:https://www.baeldung.com/jackson
  • 更多关于@JsonView的用法:https://www.baeldung.com/jackson-json-view-annotation

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/551623.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

预付费电表管理系统

预付费电表管理系统是一种现代化的电力管理系统&#xff0c;它将信息化技术和电力系统紧密结合&#xff0c;旨在提供更加高效、便捷的电力使用与管理方式。该系统能够有效地解决传统计费方法中存在的延迟计费、欠费风险等问题&#xff0c;通过预付费的方式&#xff0c;既保证了…

【动态规划】【01背包 尽量装满背包】Leetcode 1049. 最后一块石头的重量 II

【动态规划】【01背包 尽量装满背包】Leetcode 1049. 最后一块石头的重量 II 解法 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法 &#x1f612;: 我的代码实现> 动规五部曲 ✒️确定dp数组以及下标的含义 d…

[数据结构]——二叉树链式结构的实现

目录 1. 前置说明 2. 二叉树的遍历 1. 前序、中序以及后序遍历 1.前序遍历递归 1.图解&#xff1a;​编辑 2.代码 2.中序遍历递归 3.后序遍历递归 3. 节点个数以及高度等 1.二叉树节点个数 2.叶子节点个数 3.树的高度 4.K层节点个数 5.二叉树查找值为x的节点是否存在…

【考研数学】跟张宇,刷《660》正确率惨不忍睹,怎么办?

接下来要先改错 50%的正确率 &#xff0c;说明一半的题目都有一些问题导致了结果错误。 做题不是检查完结果&#xff0c;得到一个正确率就完事了。 核心是把错题的原因找到&#xff0c;计算出问题&#xff1f;有思路把公式忘了&#xff1f;或是根本没解题思路&#xff1f;还…

《深入Linux内核架构》第3章 内存管理(1)

目录 3.1 概述 3.2 NUMA模型的内存组织 3.2.1 概述 3.2.2 三个数据结构 3.2.2.1 node 3.2.2.2 zone 3.2.2.3 page 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;订阅后续文章。 本章讲物理内存的管理&#xff0c;而不是虚拟内存地址空间。 3.1 概述 页帧&a…

DC/DC电源模块直流升压变换器电压控制输出5V12V24V转0-50V80V110V150V180V200V250V300V500V800V1000V

特点 效率高达 75%以上1*2英寸标准封装单电压输出可直接焊在PCB 上工作温度: -40℃~75℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好电压控制输出,输出电压随控制电压线性变化 应用 GRB 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#xff1a;4.5~9V、…

记录Python的pandas库详解

如何生成一个pd import pandas as pd df pd.DataFrame([[1,2,3],[4,5,6]],index[A,B],columns[C1,C2,C3])df ---------------------------------------------------------------------------C1 C2 C3 A 1 2 3 B 4 5 6df.T -------------------------------------------------…

字节8年经验之谈 —— 接口测试框架接入性能测试实践分享!

1. 前言 现如今接口测试在软件质量行业中的地位&#xff0c;已经越来越重要&#xff0c;相对于上层的UI自动化测试和下层的单元测试&#xff0c;接口测试的“低”投入、“高”回报&#xff0c;也成了绝大多数质量保障实践的首选。 在开展接口测试时&#xff0c;往往很多时候都…

python使用redis存储时序数据

import redisdef ts_demo():"""时序数据存储RedisTimeSeries测试"""# 连接到Redisr redis.Redis(hostlocalhost, password"xxxx", port63790, db0)r1 r.ts()# print(r1.get("ts_key"))# print(r.exists(ts_key))# # 清空键…

PyQt5 快速入门

PyQt5 简介和开发环境搭建 简介 PyQt是一个GUI小部件工具包。 它是Qt的Python接口&#xff0c; Qt是最强大&#xff0c;最受欢迎的跨平台GUI库之一。 PyQt由RiverBank Computing Ltd.开发。最新版本的PyQt可从其官方网站下载 - riverbankcomputing.com PyQt API是一组包含大…

【leetcode】双指针算法技巧——滑动窗口

标题&#xff1a;【leetcode】双指针算法技巧——滑动窗口 水墨不写bug 正文开始&#xff1a; 滑动窗口介绍 滑动窗口是一种常用的算法技巧&#xff0c;用于解决一些涉及 连续子数组或子串 的问题。它的基本思想是 维护一个窗口&#xff0c;通过 在窗口内移动 来寻找满…

SD-WAN为什么能让网络运维更简单

在数字化浪潮席卷的今天&#xff0c;企业面临着网络规模的不断扩大、分支机构的广泛分布以及云服务需求的日益增长。企业目前的网络不足以达到这些要求&#xff0c;因而出现网络性能下降、运维复杂度剧增、成本攀升的问题。而SD-WAN&#xff08;软件定义广域网&#xff09;作为…

SASE:打造数据安全保障新模式

在企业纷纷拥抱数字业务的过程中&#xff0c;由于边缘计算、云服务、混合网络的逐渐兴起&#xff0c;使得本就漏洞百出的传统网络安全架构更加岌岌可危&#xff0c;而且远远无法满足企业数字业务的需要。 伴随企业全球化发展&#xff0c;企业的数据中心不再是用户与设备访问需…

socket编程——tcp

在我这篇博客&#xff1a;网络——socket编程中介绍了关于socket编程的一些必要的知识&#xff0c;以及介绍了使用套接字在udp协议下如何通信&#xff0c;这篇博客中&#xff0c;我将会介绍如何使用套接字以及tcp协议进行网络通信。 1. 前置准备 在进行编写代码之前&#xff…

Docker部署Prometheus+AlertManager实现邮件告警

文章目录 一、环境准备1、硬件准备&#xff08;虚拟机&#xff09;2、关闭防火墙&#xff0c;selinux3、所有主机安装docker 二、配置Prometheus1、docker启动Prometheus 三、添加监控节点1、docker启动node-exporter 四、Prometheus配置node-exporter1、修改prometheus.yml配置…

Docker构建Golang项目常见问题

Docker构建Golang项目常见问题 1 dockerfile报错&#xff1a;failed to read expected number of bytes: unexpected EOF2 go mod tidy: go.mod file indicates go 1.21, but maximum supported version is 1.17 1 dockerfile报错&#xff1a;failed to read expected number o…

鸿蒙语言TypeScript学习第18天:【泛型】

1、TypeScript 泛型 泛型&#xff08;Generics&#xff09;是一种编程语言特性&#xff0c;允许在定义函数、类、接口等时使用占位符来表示类型&#xff0c;而不是具体的类型。 泛型是一种在编写可重用、灵活且类型安全的代码时非常有用的功能。 使用泛型的主要目的是为了处…

【Linux】详解如何利用共享内存实现进程间通信

一、共享内存&#xff08;Shared Memory&#xff09;的认识 共享内存&#xff08;Shared Memory&#xff09;是多进程间共享的一部分物理内存。它允许多个进程访问同一块内存空间&#xff0c;从而在不同进程之间共享和传递数据。这种方式常常用于加速进程间的通信&#xff0c;因…

JS打包工具 Vite

Vite是 JS 新一代的打包的工具&#xff0c;它所解决的问题&#xff0c;是前端打包慢的问题&#xff0c;随着前端应用复杂度越来越大&#xff0c;项目文件越来越多&#xff0c;通常项目中都是使用 Webpack 进行打包&#xff0c;Webpack是个静态的打包工具&#xff0c;每次改动都…

9.Jetson AGX Orin protobuf验证

Jetson AGX Orin protobuf验证 前提已经安装好grpc 1&#xff1a;进入目录grpc/examples/cpp/helloworld下编译 make如果出现错误&#xff0c;protoc: Command not found。 进入/usr/local/bin与/usr/local/lib 均没发现protoc与libprotobuf。原来/grpc/third_party/protob…