Jackson-自定义注解及实现数据脱敏、枚举转换

Hi,大家好,我是抢老婆酸奶的小肥仔。

上一章,我们介绍了下Jackson及相关的注解,其实我们可以通过仿照一些注解来实现自定义以满足我们自己的业务需求,这一章,我们来说说jackson提供的自定义注解及一些应用吧。

废话不多说,撸起来。

1、自定义注解

在Jackson中使用 @JacksonAnnotationsInside来标注当前定义的注解为jackson注解。我们通过一个简单例子来看下。

1.1 自定义注解

/*** @author: jiangjs* @description:* @date: 2023/6/15 10:07**/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"id","nickName","password","name"})
public @interface DataOrderAndFilter {
}

上述注解实现了序列化时排列的顺序,以及不显示数值为null的字段。

1.2 创建实体

/*** @author: jiangjs* @description:* @date: 2023/6/15 10:11**/
@Data
@AllArgsConstructor
@DataOrderAndFilter
public class CustomDataEnter {private Integer id;private String name;private String nickName;private String password;
}

1.3 测试

@Test
public void useJacksonAnnotationsInside() throws JsonProcessingException {CustomDataEnter dataEnter = new CustomDataEnter(1, "zhangsan", null, "123456");String json = new ObjectMapper().writeValueAsString(dataEnter);log.info("使用@JacksonAnnotationsInside实现自定义注解序列化json:" + json);
}

输出:

上述代码通过简单的例子说明了@JacksonAnnotationsInside可以自定义注解。下面我们来看看在我们日常工作中在哪些地方可以使用。

2、自定义注解应用

2.1 实现数据脱敏

结合@JsonSerialize在数据进行序列化时,进行数据的脱敏。

需求:用户信息在返回到前端时,对用户名,身份证号,手机号等进行数据脱敏。

  1. 用户名:如果两个字时,只保留姓,后面为*,例如:张三,脱敏后:张*,超过三个字时,则保留前后两个字,中间使用*,例如:张小四,脱敏后:张*四
  2. 身份证号:前后各保留四位,中间用四个连接,例如:450218199103458901,脱敏后:4501***8901
  3. 手机号:保留前三位和后四位,中间四位用连接,例如:13456789012,脱敏后:134***9012

根据上述需求,我们先建一个枚举,实现不同类型数据脱敏,也方便后期实现其他字段脱敏时,只要在这个枚举类中加入就行。

2.1.1 创建脱敏枚举
/*** @author: jiangjs* @description: 脱敏策略* @date: 2022/4/15 16:23**/
public enum DesensitizedStrategy {/*** 用户信息脱敏*/USER_NAME(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"));private final Desensitized desensitized;DesensitizedStrategy(Desensitized desensitized){this.desensitized = desensitized;}public Desensitized getDesensitize() {return desensitized;}
}

定义的脱敏字段中采用了Function函数来实现。

/*** @author: jiangjs* @description: 脱敏接口* @date: 2022/4/15 16:22**/
public interface Desensitized extends Function<String,String> {
}
2.1.2 创建注解
/*** @author: jiangjs* @description: 使用jackson进行数据脱敏* @date: 2023/6/1 15:50**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = JacksonDataDesensitized.class)
public @interface JsonSensitive {DesensitizedStrategy strategy();
}

@JsonSerialize:实现数据的序列化,using则是实现序列化的具体类

2.1.3 创建序列化类
/*** @author: jiangjs* @description: 通过jackson数据序列化来实现脱敏* @date: 2023/6/1 15:54**/
@NoArgsConstructor
@AllArgsConstructor
public class JacksonDataDesensitized extends JsonSerializer<String> implements ContextualSerializer {/*** 脱敏数据*/private DesensitizedStrategy strategy;@Overridepublic void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {gen.writeString(strategy.getDesensitize().apply(value));}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {if (Objects.isNull(property)){return prov.findNullValueSerializer(null);}//校验当前bean是否为Stringif (Objects.equals(property.getType().getRawClass(),String.class)){JsonSensitive sensitive = property.getAnnotation(JsonSensitive.class);if (Objects.isNull(sensitive)){sensitive = property.getContextAnnotation(JsonSensitive.class);}if (Objects.nonNull(sensitive)){return new JacksonDataDesensitized(sensitive.strategy());}}return prov.findValueSerializer(property.getType(), property);}
}

创建的序列化类继承了JsonSerializer类,指定了数据的类型,实现了ContextualSerializer上下文序列化来保证JsonSerializer不为空。

JsonGenerator:用来生成Json格式的内容,可以使用JsonFactory来生成一个实例。

2.1.4 使用注解
/*** @author: jiangjs* @description:* @date: 2022/4/15 11:33**/
@Data
@Accessors(chain = true)
@EqualsAndHashCode
public class UserInfo implements Serializable{/*** 主键*/private Integer id;/*** 用户名*/private String userName;/*** 昵称*/@JsonSensitive(strategy = DesensitizedStrategy.USER_NAME)private String nickName;/*** 手机号*/@JsonSensitive(strategy = DesensitizedStrategy.PHONE)private String phone;/*** 身份证号*/@JsonSensitive(strategy = DesensitizedStrategy.ID_CARD)private String idCard;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss",timezone = "GTM+8")private Date createTime;private static final long serialVersionUID = 1L;
}

在实体中通过注解来指定各字段脱敏的类型。

2.1.4 测试
/*** @author: jiangjs* @description:* @date: 2023/6/15 11:31**/
@RestController
@RequestMapping("/desensitized")
public class DesensitizedController {@GetMapping("/getUserInfo.do")public UserInfo getUserInfo(){UserInfo userInfo = new UserInfo();userInfo.setId(1).setUserName("zhangsan").setNickName("张三").setIdCard("450218199103458901").setPhone("13456789012");return userInfo;}
}

输出:

从输出结果中,我们可以看到使用注解的字段已经实现数据脱敏。

2.2 通用枚举转换

需求:在实体中有时候会用到枚举,前端往往会传递一个值保存到数据,但是查询返回时往往又是对应的另外的值。因此做一个通用的枚举类型转换,查询数据时进行赋值。

2.2.1 创建注解
/*** @author: jiangjs* @description:* @date: 2023/6/15 16:08**/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = TypeChangeSerialize.class)
public @interface TypeChange {//值得替换 导出是{a_id,b_id} 导入反过来,所以只用写一个String[] replace() default {};
}

replace():仿照Easypoi中@Excel注解中的replace。

2.2.1 创建序列化实现类
/*** @author: jiangjs* @description:* @date: 2023/6/15 16:21**/
@AllArgsConstructor
public class TypeChangeSerialize extends JsonSerializer<Object> implements ContextualSerializer {private final String[] annotationValues;@Overridepublic void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {String[] types = this.annotationValues;Map<String, String> typeMap = new ConcurrentHashMap<>();if (Objects.nonNull(types) && types.length > 0) {for (String type : types) {String[] s = type.split("_");typeMap.put(s[0],s[1]);}}gen.writeString(typeMap.get(String.valueOf(value)));}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException {if (Objects.isNull(property)){return provider.findNullValueSerializer(null);}//校验当前bean是否为String或Integerif (Objects.equals(property.getType().getRawClass(),String.class) ||Objects.equals(property.getType().getRawClass(),Integer.class)){TypeChange typeChange = property.getAnnotation(TypeChange.class);if (Objects.isNull(typeChange)){typeChange = property.getContextAnnotation(TypeChange.class);}if (Objects.nonNull(typeChange)){return new TypeChangeSerialize(typeChange.replace());}}return provider.findValueSerializer(property.getType(), property);}
}

annotationValues:定义接受注解replace的值。

new TypeChangeSerialize(typeChange.replace()):初始化序列化处理类,将获取到的replace()值赋值给annotationValues。

2.2.3 使用注解
/*** @author: jiangjs* @description:* @date: 2022/4/15 11:33**/
@Data
@Accessors(chain = true)
@EqualsAndHashCode
public class UserInfo implements Serializable{/*** 主键*/private Integer id;@TypeChange(replace = {"1_男","2_女"})private Integer gender;private static final long serialVersionUID = 1L;
}

@TypeChange(replace = {“1_男”,“2_女”}):按照注解的规则,赋值replace。

2.2.4 测试
/*** @author: jiangjs* @description:* @date: 2023/6/15 11:31**/
@RestController
@RequestMapping("/desensitized")
public class DesensitizedController {@GetMapping("/getUserInfo.do")public UserInfo getUserInfo(){UserInfo userInfo = new UserInfo();userInfo.setId(1).setGender(1);return userInfo;}
}

输出:

从输出结果来看,gender赋值为1,序列化后返回的是对应的中文:男。也就是说,这个实现了我们需求,即字段进行了替换。

上述就是我在工作中使用jackson的一些应用,大家可以举一反三来实现自己的需求,例如:自定义时间格式化等等。

源码:https://github.com/lovejiashn/use_jackson.git

工欲善其事,必先利其器,小伙伴们撸起来吧。

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

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

相关文章

Virtualbox7.0.10--创建虚拟机

前言 下载Virtualbox7.0.10&#xff0c;可参考《Virtualbox–下载指定版本》 Virtualbox7.0.10具体安装步骤&#xff0c;可参考《Virtualbox7.0.10的安装步骤》 Virtualbox7.0.10创建虚拟机&#xff0c;可参考《Virtualbox7.0.10–创建虚拟机》 Virtualbox7.0.10安装Ubuntu20.0…

H.265码流解析

这一篇内容旨在对H.265码流中的一些概念做简单了解,部分概念与H.264相同,本篇中将不再重复。 1、NALU H.265(HEVC)码流的NALU结构和AVC有一些不同,属于增强版,HEVC NALU结构如下: NALU Header: Forbidden_zero_bit:1位,必须为0,如果不是则表示NALU非法;Nal_unit_t…

后端如何处理接口的重复调用

首先是&#xff0c;原理在请求接口之前&#xff0c;使用过滤器拦截数据&#xff0c;来进行判断两次数据是否一致。 1.自定义注解 2.创建一个Handler处理器 3.RepeatSubmitInterceptor的实现类 4.过滤器的配置

大型企业总分支多区域数据传输,效率为先还是安全为先?

大型企业为了业务拓展需要&#xff0c;会在全国乃至全球各地设立分公司和办事机构&#xff0c;以便更好地处理当地事务&#xff0c;并进行市场的开拓和客户维护&#xff0c;此时&#xff0c;企业内部就衍生出了新的业务需求&#xff0c;即多区域数据传输。 多区域很难准确定义&…

云容器与云中间件

云容器与中间件是两种不同的技术和服务类别&#xff0c;它们分别在云计算环境中扮演着不同的角色&#xff0c;旨在帮助企业构建、部署、管理应用程序并确保其高效、可靠地运行。下面分别介绍两者的基本概念、包含的内容以及各自的用途。 容器 基本概念&#xff1a; 在腾讯云中…

[C++][算法基础]最大不相交区间数量(贪心 + 区间问题2)

给定 &#x1d441; 个闭区间 [&#x1d44e;&#x1d456;,&#x1d44f;&#x1d456;]&#xff0c;请你在数轴上选择若干区间&#xff0c;使得选中的区间之间互不相交&#xff08;包括端点&#xff09;。 输出可选取区间的最大数量。 输入格式 第一行包含整数 &#x1d4…

Aiseesoft Data Recovery for Mac:专业数据恢复软件

Aiseesoft Data Recovery for Mac是一款高效且专业的数据恢复软件&#xff0c;专为Mac用户量身打造。 Aiseesoft Data Recovery for Mac v1.8.22激活版下载 无论是由于误删、格式化还是系统崩溃等原因导致的数据丢失&#xff0c;Aiseesoft都能帮助您快速找回。 它采用先进的扫描…

使用命令删除zip中的文件

要删除zip文件中的某个文件&#xff0c;可以使用zip工具的-d&#xff08;delete&#xff09;选项。 首先需要确保系统已安装zip程序&#xff0c;通常会预装在Linux与macOS上。在Windows系统上&#xff0c;可能要安装额外的压缩工具如7-zip&#xff0c;才能在命令行中执行这类操…

IDEA插件-通义灵码 VS ChatGPT-EasyCode

智能编码助手新时代&#xff1a;通义灵码 vs ChatGPT-EasyCode 随着人工智能技术的飞速发展&#xff0c;智能编码助手逐渐成为程序员的必备工具。它们可以帮助程序员提高编码效率&#xff0c;降低代码缺陷率&#xff0c;并解放创造力。 目前市场上涌现出了众多智能编码助手&a…

Golang | Leetcode Golang题解之第60题排列序列

题目&#xff1a; 题解&#xff1a; func getPermutation(n int, k int) string {factorial : make([]int, n)factorial[0] 1for i : 1; i < n; i {factorial[i] factorial[i - 1] * i}k--ans : ""valid : make([]int, n 1)for i : 0; i < len(valid); i {…

【哈希】Leetcode 217. 存在重复元素

题目讲解 217. 存在重复元素 算法讲解 使用set集合完成元素的存储&#xff0c;当我们将当前元素插入到集合单中&#xff0c;如果insert的返回值的pair.second等于false说明当前元素已经存在&#xff0c;反之元素在集合中存在 class Solution { public:bool containsDuplica…

开放式耳机哪个牌子好?五大爆款机型大盘点

开放式耳机采用挂耳设计&#xff0c;体积小巧&#xff0c;携带方便&#xff0c;并且更加通风透气&#xff0c;避免了耳朵过热和出汗导致的问题&#xff1b;更轻的重量能有效减少长期佩戴对耳朵带来的压力&#xff0c;佩戴时舒适度直接爆表&#xff0c;在跑步、爬山、打球等户外…

ip ssl证书无限端口

IP SSL证书是由CA认证机构颁发的一种特殊数字证书。大部分SSL数字证书都需要用户使用域名进行申请&#xff0c;想要对公网IP地址加密实现https访问就需要申请IP SSL证书。IP SSL证书采用了强大的加密算法&#xff0c;可以有效地防止数据在传输过程中被窃取或篡改&#xff0c;具…

Linux系统ipv4参数解析

ipv4参数解析 不要在任何事物面前迷失掉自我&#xff0c;哪怕是教条&#xff0c;哪怕是别人的眼光&#xff0c;哪怕是爱情 ——《成为简-奥斯汀》 1.参数简介 /proc/sys/net/ipv4目录下这些参数都是 Linux 内核中的网络相关参数&#xff0c;通过修改这些参数可以调整系统的网络…

Copilot Workspace是GitHub对人工智能驱动的软件工程的诠释

软件开发的未来是人工智能驱动的集成开发环境吗&#xff1f;至少GitHub 是这样想的。 在今年初秋于旧金山举行的 GitHub Universe 年度大会之前&#xff0c;GitHub 发布了 Copilot Workspace&#xff0c;这是一种开发环境&#xff0c;利用 GitHub 所称的 “Copilot 驱动的代理…

基于SpringBoot的在线拍卖系统 - 源码免费(私信领取)

1. 研究目的 本项目旨在设计并实现一个基于Spring Boot的在线拍卖系统&#xff0c;提供一个安全、高效的平台&#xff0c;供用户进行拍卖活动&#xff0c;实现商品的快速交易。 2. 研究要求 a. 需求分析 通过市场调研和用户需求分析&#xff0c;了解在线拍卖市场的特点和用…

Pytest自动化测试框架详解

今日之失&#xff0c;未必不为后日之得。大家好&#xff0c;刚才在翻看之前整理的一些关于自动化测试的文档&#xff0c;突然发现一个比较详细的关于pytest框架的介绍和使用文章&#xff0c;对于打算使用python进行自动化测试编写的小伙伴&#xff0c;还是很值得一看的&#xf…

力扣爆刷第129天之动态规划五连刷(完全平方数、单词拆分、打劫劫舍)

力扣爆刷第129天之动态规划五连刷&#xff08;完全平方数、单词拆分、打劫劫舍&#xff09; 文章目录 力扣爆刷第129天之动态规划五连刷&#xff08;完全平方数、单词拆分、打劫劫舍&#xff09;一、279. 完全平方数二、139. 单词拆分三、198.打家劫舍四、213. 打家劫舍 II五、…

K8S - 各节点的kube-flannel-ds-amd64-xxxxx不能正常启动的问题

- kubectl get pods -A -o wide - 查看日志发现 - pods "kube-flannel-ds-amd64-xxxxx" is forbidden: User "system:serviceaccount:kube-system:flannel" cannot get resource "pods" in API group "" in the namespace "kube-…

深度学习之基于YOLOv5烟花燃放智能检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着科技的进步和人们对环保、安全意识的提高&#xff0c;传统的烟花燃放监管方式已逐渐不能满足现代…