Spring Boot:SpringBoot 如何优雅地定制JSON响应数据返回

一、前言

**  目前微服务项目中RESTful API已经是前后端对接数据格式的标配模式了,RESTful API是一种基于REST(Representational State Transfer,表述性状态转移)原则的应用程序编程接口(Application Programming Interface),它主要用于Web服务之间的数据交互。RESTful API的设计遵循一些核心原则,这些原则使得API更加简洁、灵活和可扩展。**

**  在构建这些API时,我们往往需要根据不同的客户端、用户角色或业务需求,灵活地控制返回的数据结构和内容。Jackson库的@JsonView注解为我们提供了一种优雅且高效的方式来实现这一目标。**

二、问题场景

**  @JsonView 是 Jackson 库中的一个注解,它允许你定义哪些属性应该被序列化到 JSON 中,基于不同的"视图"或"配置"。这在某些情况下非常有用,特别是当你想要为不同的用户或API端点返回不同级别的详细信息时。**

例如,你可能有一个User对象,其中包含多个属性,如id、name、email和password。当你为外部API或网站前端返回用户数据时,你可能不希望包含password字段。但是,在内部API或某些特定的情况下,你可能想要返回包含password的完整用户对象。

**  这就是@JsonView可以帮助你的地方。你可以定义一个或多个"视图"类,并为你的属性指定应该出现在哪些视图中。**

在本文中,通过了解@JsonView,你将能够更好地掌握如何在Spring Boot应用中定制JSON数据的输出,从而提供更加灵活、安全且高效的RESTful API服务。

三、@JsonView主要应用场景

主要应用场景包括:

1.数据脱敏:在某些情况下,你可能不希望将数据库中的某些敏感信息(如密码、密钥等)暴露给客户端。通过使用 @JsonView,你可以定义哪些字段应该被包含在特定的视图中,并在返回数据时仅包含这些字段。

2.自定义数据输出:你可以根据客户端的需求或权限级别,定义不同的视图,并在返回数据时根据当前视图的配置来输出不同的字段组合。

四、代码实战

1. 定义实体类

java 复制代码
package com.example.yddemo.JSONView;

import com.fasterxml.jackson.annotation.JsonView;

public class User {

    @JsonView(Views.Public.class)
    private Long id;

    @JsonView(Views.Public.class)
    private String name;

    @JsonView(Views.Internal.class)
    private String email;

    @JsonView(Views.Internal.class)
    private String password;

    public User(Long id, String name, String email, String password) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.password = password;
    }

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getEmail() {
        return email;
    }

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

    public String getPassword() {
        return password;
    }

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

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

2. 定义视图控制器

java 复制代码
public class Views {
    public static class Public { }
    public static class Internal extends Public { }
}

3. 在代码中使用,添加@JsonView注解

java 复制代码
package com.example.yddemo.JSONView;

import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestDemoController {

    @GetMapping("/user/Public")
    @JsonView(Views.Public.class)
    public User userPublic() {
        User user = new User(1L, "Tom", "123123@163.com", "123456") ;
        return user  ;
    }

    @GetMapping("/user/Internal")
    @JsonView(Views.Internal.class)
    public User userInternal() {
        User user = new User(1L, "Tom", "123123@163.com", "123456") ;
        return user;
    }
}

输出结果


**  不想使用在Controller接口上使用@JsonView注解方式,你还可以通过编程的方式控制,通过ObjectMapper类也能方便的控制json输出。**

java 复制代码
  @GetMapping("/user/all/public")
    public String userAllPublic() {
        ObjectMapper mapper = new ObjectMapper();
        User user = new User(1L, "Tom", "123123@163.com", "123456") ;
        String publicJson;
        try {
            publicJson = mapper.writerWithView(Views.Public.class).writeValueAsString(user);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return publicJson;
    }

    @GetMapping("/user/all/internal")
    public String userAllInternal() {
        ObjectMapper mapper = new ObjectMapper();
        User user = new User(1L, "Tom", "123123@163.com", "123456") ;
        String internalJson;
        try {
            internalJson = mapper.writerWithView(Views.Internal.class).writeValueAsString(user);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return internalJson;
    }

输出结果

通过@JsonView的代码展示思考一个问题?

如果没有该注解你会通过什么方式实现?针对不同的场景定义不同的DTO?通过@JsonIgnore注解?

**  定义不同的DTO太麻烦,代码大量冗余。使用@JsonIgnore注解所有的接口都将会忽略该字段,不能精准控制单个API接口。所以整体上看还是使用@JsonView更加的灵活。**

四、总结

**  @JsonView 与 @JsonIgnore 区别**

①. @JsonView 用于控制序列化时的字段组合,允许你根据不同的视图返回不同的字段集合。

②. @JsonIgnore 则简单地忽略某个字段,使其在序列化时不会被包含在 JSON 中。

**  最后@JsonView 提供了一种灵活且强大的方式来控制序列化的 JSON 数据。通过定义视图和将它们应用到属性和控制器方法上,你可以根据需要暴露不同级别的数据,实现 API 的数据定制化。**

相关推荐
亲爱的非洲野猪10 分钟前
Kafka “假死“现象深度解析与解决方案
分布式·kafka
虾条_花吹雪16 分钟前
2、Connecting to Kafka
分布式·ai·kafka
考虑考虑1 小时前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying1 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·2 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
春生野草2 小时前
关于SpringMVC的整理
spring
Edingbrugh.南空2 小时前
Hadoop高可用集群搭建
大数据·hadoop·分布式
martinzh2 小时前
Spring AI 项目介绍
后端
Bug退退退1233 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq