Jackson 库简介--以及数据脱敏

Jackson 是一个流行的 Java JSON 处理库,它提供了将 Java 对象与 JSON 数据相互转换的功能。Jackson 的主要功能包括:

  1. 序列化将 Java 对象转换为 JSON 字符串。
  2. 反序列化将 JSON 字符串转换为 Java 对象。

Jackson 提供了以下几个核心组件:

  • jackson-core:核心库,提供 JSON 的解析和生成。
  • jackson-databind:数据绑定库,负责将 JSON 数据绑定到 Java 对象。
  • jackson-annotations:包含用于 JSON 处理的注解,如 @JsonProperty@JsonIgnore 等。

基本使用

在使用 Jackson 之前,你需要在 pom.xml 中添加 Jackson 的依赖:

<dependencies><!-- Jackson 核心库 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.13.3</version></dependency><!-- Jackson 数据绑定库 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.3</version></dependency><!-- Jackson 注解库 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.13.3</version></dependency>
</dependencies>

序列化示例

import com.fasterxml.jackson.databind.ObjectMapper;public class Example {public static void main(String[] args) throws Exception {ObjectMapper objectMapper = new ObjectMapper();// 创建一个示例对象User user = new User();user.setName("John");user.setAge(30);// 将对象转换为 JSON 字符串String json = objectMapper.writeValueAsString(user);System.out.println(json); // 输出: {"name":"John","age":30}}
}class User {private String name;private int age;// Getter 和 Setter
}

反序列化示例

import com.fasterxml.jackson.databind.ObjectMapper;public class Example {public static void main(String[] args) throws Exception {ObjectMapper objectMapper = new ObjectMapper();// JSON 字符串String json = "{\"name\":\"John\",\"age\":30}";// 将 JSON 字符串转换为 Java 对象User user = objectMapper.readValue(json, User.class);System.out.println(user.getName()); // 输出: John}
}class User {private String name;private int age;// Getter 和 Setter
}

实现自定义注解

如果你需要自定义序列化或反序列化逻辑,你可以创建自定义注解和序列化器。以下是详细步骤:

1. 定义自定义注解

创建一个自定义注解,用于标记需要特殊处理的字段。例如,我们可以创建一个 @Sensitive 注解,用于标记需要脱敏处理的字段。

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JsonSerialize(using = SensitiveJsonSerializer.class) // 指定自定义序列化器
public @interface Sensitive {SensitiveStrategy strategy(); // 指定脱敏策略
}

理解 SensitiveJsonSerializer 类的代码时,可以将其分为几个部分来讲解。这个类实现了 JsonSerializer,用于自定义序列化过程,特别是处理带有 @Sensitive 注解的字段。下面详细解释代码的每个部分:

1. JsonSerializer<String>

SensitiveJsonSerializer 类继承自 Jackson 的 JsonSerializer<String>。这是一个泛型类,用于自定义如何将 String 类型的对象序列化为 JSON。

2. serialize 方法

serialize 方法是 JsonSerializer 类的抽象方法,必须实现。它的作用是定义如何将 Java 对象(在这个例子中是 String)转换为 JSON 字符串。

 

2. 定义脱敏策略

创建一个枚举 SensitiveStrategy,定义不同的脱敏策略。

import java.util.function.Function;public enum SensitiveStrategy {USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));private final Function<String, String> desensitizer;SensitiveStrategy(Function<String, String> desensitizer) {this.desensitizer = desensitizer;}public Function<String, String> desensitizer() {return desensitizer;}
}

理解 strategy.desensitizer().apply(value) 是如何工作的,我们需要详细了解 Function<String, String> 这个接口,以及 SensitiveStrategy 枚举类是如何定义和使用这个接口的。

Function 接口

Function 是 Java 8 引入的一个函数式接口,它位于 java.util.function 包中。这个接口定义了一个方法 apply,用于将一个输入值转换成一个输出值:

@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}
  • T 是输入类型
  • R 是输出类型
  • apply 方法接受一个 T 类型的参数,并返回一个 R 类型的结果
SensitiveStrategy 枚举

SensitiveStrategy 枚举中,每个枚举实例都被赋予了一个 Function<String, String> 类型的对象。这个对象用于定义字符串脱敏的具体实现。

public enum SensitiveStrategy {USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),ADDRESS(s -> s.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));private final Function<String, String> desensitizer;SensitiveStrategy(Function<String, String> desensitizer) {this.desensitizer = desensitizer;}public Function<String, String> desensitizer() {return desensitizer;}
}

每个枚举实例都使用一个 Function<String, String> 对象来定义如何进行字符串替换:

  • USERNAME 实例的 Function 对象:s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")
    • 这个函数会将用户名的第二个字符替换为 *
  • ID_CARD 实例的 Function 对象:s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")
    • 这个函数会将身份证号码的中间部分替换为 ****
  • 其他实例类似。

这些 Function 对象都实现了 apply 方法,用于对输入的字符串进行处理。

调用 desensitizer.apply(value)

当你调用 strategy.desensitizer().apply(value) 时,实际上执行了以下步骤:

  1. strategy.desensitizer() 返回 Function<String, String> 类型的 desensitizer 对象。
  2. desensitizer.apply(value) 调用 Function 对象的 apply 方法,对输入的 value 进行处理并返回处理后的结果。
 总结
  • 在序列化过程中,调用 strategy.desensitizer().apply(value) 对字符串进行脱敏处理。
  • 将处理后的字符串写入 JsonGenerator 以生成最终的 JSON 输出。
3. 实现自定义序列化器

创建一个自定义的 JsonSerializer 类,用于处理带有 @Sensitive 注解的字段。

public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {private SensitiveStrategy strategy;@Overridepublic void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {gen.writeString(strategy.desensitizer().apply(value));}/*** 获取属性上的注解属性*/@Overridepublic JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {Sensitive annotation = property.getAnnotation(Sensitive.class);System.out.println(annotation);if (Objects.nonNull(annotation)&& Objects.equals(String.class, property.getType().getRawClass())) {this.strategy = annotation.strategy();return this;}return prov.findValueSerializer(property.getType(), property);}
}

这段代码是一个自定义的 Jackson 序列化器,它实现了 JsonSerializer<String>ContextualSerializer 接口,用于在序列化过程中对特定类型的字段进行脱敏处理。让我们逐行解释代码的含义和作用。

  • SensitiveJsonSerializer 继承了 JsonSerializer<String>,表示这是一个自定义的序列化器,专门用于序列化 String 类型的字段。
  • 它还实现了 ContextualSerializer 接口,这使得序列化器能够访问字段的上下文(如注解)并根据上下文进行调整。
  • strategy 是一个 SensitiveStrategy 类型的字段,用于存储从注解中提取的脱敏策略。
 serialize 方法
  • serialize 方法用于序列化对象。
  • value 是需要序列化的字段值。
  • genJsonGenerator,用于将序列化的内容写入输出。
  • serializersSerializerProvider,提供了其他序列化器。
  • 在方法内部,使用脱敏策略 (strategy.desensitizer()) 对字段值 (value) 进行脱敏处理,并将处理后的值写入输出 (gen.writeString)。
createContextual 方法
  • createContextual 方法用于在序列化过程中根据上下文(即字段的注解)配置序列化器。
  • provSerializerProvider,提供了其他序列化器。
  • propertyBeanProperty,表示当前正在序列化的字段。

方法内部,首先获取字段上的 Sensitive 注解(如果有) 

Sensitive annotation = property.getAnnotation(Sensitive.class);

然后,检查注解是否存在且字段类型是否为 String

if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {this.strategy = annotation.strategy();return this;
}
    • 如果注解存在并且字段类型是 String,则从注解中提取脱敏策略 (annotation.strategy()) 并赋值给 this.strategy
    • 返回当前的序列化器 (return this;)。
  • 如果没有注解或字段类型不是 String,则使用默认的序列化器 (prov.findValueSerializer(property.getType(), property))。
4. 使用自定义注解

在你的类中使用 @Sensitive 注解来标记需要脱敏处理的字段。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {/*** 真实姓名*/@Sensitive(strategy = SensitiveStrategy.USERNAME)private String realName;/*** 地址*/@Sensitive(strategy = SensitiveStrategy.ADDRESS)private String address;/*** 电话号码*/@Sensitive(strategy = SensitiveStrategy.PHONE)private String phoneNumber;/*** 身份证号码*/@Sensitive(strategy = SensitiveStrategy.ID_CARD)private String idCard;}
5.测试 
@RestController
public class TestController {@GetMapping("/test")public Person test(){Person user = new Person();user.setRealName("xxxx");user.setPhoneNumber(" 15242554546");user.setAddress("天津市河西区....");user.setIdCard("111111111111111");return user;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C2W2.Assignment.Parts-of-Speech Tagging (POS).Part2

理论课&#xff1a;C2W2.Part-of-Speech (POS) Tagging and Hidden Markov Models 文章目录 2 Hidden Markov Models2.1 Generating MatricesCreating the A transition probabilities matrixExercise 03Create the B emission probabilities matrixExercise 04 理论课&#x…

FastAPI 学习之路(五十六)将token缓存到redis

在之前的文章中&#xff0c;FastAPI 学习之路&#xff08;二十九&#xff09;使用&#xff08;哈希&#xff09;密码和 JWT Bearer 令牌的 OAuth2&#xff0c;FastAPI 学习之路&#xff08;二十八&#xff09;使用密码和 Bearer 的简单 OAuth2&#xff0c;FastAPI 学习之路&…

Kubernetes 之 Ingress

Kubernetes 之 Ingress 定义 Ingress 可以把外部需要进入到集群内部的请求转发到集群中的一些服务上&#xff0c;从而实现把服务映射到集群外部的需要。Ingress 能把集群内 Service 配置成外网能够访问的 URL&#xff0c;流量负载均衡&#xff0c;提供基于域名访问的虚拟主机…

RabbitMQ 和 RocketMQ 的区别

RabbitMQ 和 RocketMQ 都是流行的开源消息中间件&#xff0c;它们用于在分布式系统中异步传输消息。尽管它们都实现了核心的消息队列功能&#xff0c;但它们在设计、性能、特性和使用场景上有一些关键的区别&#xff1a; 基础架构: RabbitMQ: 基于AMQP&#xff08;高级消息队列…

阵列信号处理学习笔记(二)--空域滤波基本原理

阵列信号 阵列信号处理学习笔记&#xff08;一&#xff09;–阵列信号处理定义 阵列信号处理学习笔记&#xff08;二&#xff09;–空域滤波基本原理 文章目录 阵列信号前言一、阵列信号模型1.1 信号的基本模型1.2 阵列的几何构型1.3 均匀直线阵的阵列信号基本模型 总结 前言…

HOW - React 处理不紧急的更新和渲染

目录 useDeferredValueuseTransitionuseIdleCallback 在 React 中&#xff0c;有一些钩子函数可以帮助你处理不紧急的更新或渲染&#xff0c;从而优化性能和用户体验。 以下是一些常用的相关钩子及其应用场景&#xff1a; useDeferredValue 用途&#xff1a;用于处理高优先级…

嵌入式面试总结

C语言中struct和union的区别 struct和union都是常见的复合结构。 结构体和联合体虽然都是由多个不同的数据类型成员组成的&#xff0c;但不同之处在于联合体中所有成员共用一块地址空间&#xff0c;即联合体只存放了一个被选中的成员&#xff0c;结构体中所有成员占用空间是累…

【网络】windows和linux互通收发

windows和linux互通收发 一、windows的udp客户端代码1、代码剖析2、总体代码 二、linux服务器代码三、成果展示 一、windows的udp客户端代码 1、代码剖析 首先我们需要包含头文件以及lib的一个库&#xff1a; #include <iostream> #include <WinSock2.h> #inclu…

前端页面是如何禁止被查看源码、被下载,被爬取,以及破解方法

文章目录 1.了解禁止查看,爬取原理1.1.JS代码,屏蔽屏蔽键盘和鼠标右键1.2.查看源码时,通过JS控制浏览器窗口变化2.百度文库是如何防止抓包2.1.HTPPS2.2. 动态加载为什么看不到?如何查看动态加载的内容?3.禁止复制,如果解决3.1.禁止复制原理3.2.如何破解1.了解禁止查看,爬…

使用scikit-learn进行机器学习:基础教程

使用scikit-learn进行机器学习&#xff1a;基础教程 Scikit-learn是Python中最流行的机器学习库之一。它提供了简单易用的工具&#xff0c;帮助我们进行数据预处理、模型训练、评估和预测。本文将带你通过一个基础教程&#xff0c;了解如何使用scikit-learn进行机器学习。 1.…

【模板代码】用于编写Threejs Demo的模板代码

基础模板代码 使用须知常规模板代码常规Shader模板代码 使用须知 本模板代码&#xff0c;主要用于编写Threejs的Demo&#xff0c;因为本人在早期学习的过程中&#xff0c;大量抄写Threejs/examples下的代码以及各个demo站的代码&#xff0c;所以养成了编写Threejs的demo的习惯…

SAP 采购订单 Adobe 消息输出

目录 1 简介 2 业务数据例子 3 选择增强 & 代码 1&#xff09;BADI: MM_PUR_S4_PO_MODIFY_HEADER 2&#xff09;BADI: MM_PUR_S4_PO_MODIFY_ITEM 4 自定义 Adobe form 1&#xff09;PO Master form 2&#xff09;PO form 5 前台主数据配置 6 后台配置 1&#xf…

昇思22天

CycleGAN图像风格迁移互换 CycleGAN&#xff08;循环生成对抗网络&#xff09;是一种用于在没有成对训练数据的情况下学习将图像从源域 X 转换到目标域 Y 的方法。该技术的一个重要应用是域迁移&#xff0c;即图像风格迁移。 模型介绍 模型简介: CycleGAN 来自于论文 Unpair…

掌握Rust:函数、闭包与迭代器的综合运用

掌握Rust&#xff1a;函数、闭包与迭代器的综合运用 引言&#xff1a;解锁 Rust 高效编程的钥匙函数定义与模式匹配&#xff1a;构建逻辑的基石高阶函数与闭包&#xff1a;代码复用的艺术迭代器与 for 循环&#xff1a;高效数据处理的引擎综合应用案例&#xff1a;构建一个简易…

Mybatis——一对多处理

环境搭建 与多对一相似&#xff0c;有一些地方需要改动&#xff1a; 实体类&#xff1a; Data public class Student {private int id;private String name;private int tid;} Data public class Teacher {private int id;private String name;// 一个老师拥有多个学生priv…

【LeetCode】day15:110 - 平衡二叉树, 257 - 二叉树的所有路径, 404 - 左叶子之和, 222 - 完全二叉树的节点个数

LeetCode 代码随想录跟练 Day15 110.平衡二叉树257.二叉树的所有路径404.左叶子之和222.完全二叉树的节点个数 110.平衡二叉树 题目描述&#xff1a; 给定一个二叉树&#xff0c;判断它是否是 平衡二叉树 平衡二叉树的定义是&#xff0c;对于树中的每个节点&#xff0c;其左右…

qt自定义控件(QLabel)

先创建自定义控件类painter_label 1.自定义类必须给基类传入父窗口指针 2.重写控件中的方法 3.在UI中创建一个QLabel,右键“提升为”&#xff0c;输入类名

动画革命:Lottie如何改变我们对移动应用交互的认知

在数字世界的浩瀚星空中&#xff0c;每一个像素都跃动着无限创意与想象的火花。当静态的界面遇上动态的魔法&#xff0c;一场视觉盛宴便悄然开启。今天&#xff0c;让我们一同揭开一位幕后英雄的神秘面纱——Lottie&#xff0c;这个在UI/UX设计界掀起波澜的动画利器&#xff0c…

掌握构建自动化:如何在Gradle中使用Init脚本进行构建初始化

掌握构建自动化&#xff1a;如何在Gradle中使用Init脚本进行构建初始化 在现代软件开发中&#xff0c;自动化构建是提高效率和一致性的关键。Gradle&#xff0c;作为一个功能强大的构建工具&#xff0c;提供了丰富的自动化支持。其中&#xff0c;Init脚本是Gradle中用于初始化…

SVN与Git功能差异对比分析

最近在调研学习Git管理和分支模型相关内容&#xff0c;外延到了SVN和Git差异、工作原理等相关细节&#xff0c;学习整理如下。 SVN&#xff08;Subversion&#xff09;与 Git 的最大不同&#xff0c;主要包括以下几个方面&#xff1a; 交流探讨&#xff0c;加入群聊【Java学习…