注解实现json序列化的时候自动进行数据脱敏

最近在进行开发的时候遇到一个问题,需要对用户信息进行脱敏处理,原有的方式是写一个util类,在需要脱敏的字段查出数据后,显示掉用方法处理后再set回去,觉得这种方式能实现功能,但是不是特别优雅,想找个比较优雅的实现 思考了一下,觉得数据只有在输出的时候进行脱敏处理即可,其它都是在内存阶段,相对来说都是比较安全的,输出阶段我想到了json序列化,因为我们用的restful接口输出json,于是去查询了一下相关的资源,jackson可以指定某个字段的自定义序列化类,那么还有一个问题,我指定了用某个类进行序列化,但是在序列化的时候如果判断脱敏的类型呢,翻看网上大神的文章得知,ContextualSerializer是 Jackson 提供的另一个序列化相关的接口,它的作用是通过字段已知的上下文信息定制JsonSerializer,只需要实现createContextual方法即可。废话少说,下面上代码:

用户信息实体:

@Data
public class UserDetailResponse {private Long useId;@ApiModelProperty(value = "用户编号")private String useNo;@ApiModelProperty(value = "用户姓名")private String useName;@SensitiveInfo(SensitiveType.MOBILE_PHONE)@ApiModelProperty(value = "用户手机号")private String mobile;@ApiModelProperty(value = "用户性别")private String sex;@ApiModelProperty(value = "用户年龄")private int age;@ApiModelProperty(value = "用户籍贯")private String nativePlace;@SensitiveInfo(SensitiveType.ID_CARD)@ApiModelProperty(value = "用户身份证号")private String idCard;@ApiModelProperty(value = "用户身份证号")private String borrowingLevel;
}

脱敏类型枚举类

public enum SensitiveType {/*** 中文名*/CHINESE_NAME,/*** 身份证号*/ID_CARD,/*** 座机号*/FIXED_PHONE,/*** 手机号*/MOBILE_PHONE,/*** 地址*/ADDRESS,/*** 电子邮件*/EMAIL,/*** 银行卡*/BANK_CARD,/*** 公司开户银行联号*/CNAPS_CODE
}


脱敏注解类

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveInfoSerialize.class)
public @interface SensitiveInfo {public SensitiveType value();
}

脱敏序列化类

public class SensitiveInfoSerialize extends JsonSerializer<String> implementsContextualSerializer {private SensitiveType type;public SensitiveInfoSerialize() {}public SensitiveInfoSerialize(final SensitiveType type) {this.type = type;}@Overridepublic void serialize(final String s, final JsonGenerator jsonGenerator,final SerializerProvider serializerProvider) throws IOException, JsonProcessingException {switch (this.type) {case CHINESE_NAME: {jsonGenerator.writeString(SensitiveInfoUtils.chineseName(s));break;}case ID_CARD: {jsonGenerator.writeString(SensitiveInfoUtils.idCardNum(s));break;}case FIXED_PHONE: {jsonGenerator.writeString(SensitiveInfoUtils.fixedPhone(s));break;}case MOBILE_PHONE: {jsonGenerator.writeString(SensitiveInfoUtils.mobilePhone(s));break;}case ADDRESS: {jsonGenerator.writeString(SensitiveInfoUtils.address(s, 4));break;}case EMAIL: {jsonGenerator.writeString(SensitiveInfoUtils.email(s));break;}case BANK_CARD: {jsonGenerator.writeString(SensitiveInfoUtils.bankCard(s));break;}case CNAPS_CODE: {jsonGenerator.writeString(SensitiveInfoUtils.cnapsCode(s));break;}}}@Overridepublic JsonSerializer<?> createContextual(final SerializerProvider serializerProvider,final BeanProperty beanProperty) throws JsonMappingException {if (beanProperty != null) { // 为空直接跳过if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) { // 非 String 类直接跳过SensitiveInfo sensitiveInfo = beanProperty.getAnnotation(SensitiveInfo.class);if (sensitiveInfo == null) {sensitiveInfo = beanProperty.getContextAnnotation(SensitiveInfo.class);}if (sensitiveInfo != null) { // 如果能得到注解,就将注解的 value 传入 SensitiveInfoSerializereturn new SensitiveInfoSerialize(sensitiveInfo.value());}}return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);}return serializerProvider.findNullValueSerializer(beanProperty);}
}


脱敏处理util类


public class SensitiveInfoUtils {/*** [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>*/public static String chineseName(final String fullName) {if (StringUtils.isBlank(fullName)) {return "";}final String name = StringUtils.left(fullName, 1);return StringUtils.rightPad(name, StringUtils.length(fullName), "*");}/*** [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>*/public static String chineseName(final String familyName, final String givenName) {if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {return "";}return chineseName(familyName + givenName);}/*** [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>*/public static String idCardNum(final String id) {if (StringUtils.isBlank(id)) {return "";}return StringUtils.left(id, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(id, 3), StringUtils.length(id), "*"),"***"));}/*** [固定电话] 后四位,其他隐藏<例子:****1234>*/public static String fixedPhone(final String num) {if (StringUtils.isBlank(num)) {return "";}return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");}/*** [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>*/public static String mobilePhone(final String num) {if (StringUtils.isBlank(num)) {return "";}return StringUtils.left(num, 2).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 2), StringUtils.length(num), "*"),"***"));}/*** [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>** @param sensitiveSize 敏感信息长度*/public static String address(final String address, final int sensitiveSize) {if (StringUtils.isBlank(address)) {return "";}final int length = StringUtils.length(address);return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");}/*** [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>*/public static String email(final String email) {if (StringUtils.isBlank(email)) {return "";}final int index = StringUtils.indexOf(email, "@");if (index <= 1) {return email;} else {return StringUtils.rightPad(StringUtils.left(email, 1), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));}}/*** [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>*/public static String bankCard(final String cardNum) {if (StringUtils.isBlank(cardNum)) {return "";}return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"),"******"));}/*** [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********>*/public static String cnapsCode(final String code) {if (StringUtils.isBlank(code)) {return "";}return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*");}}


效果图:


此文主要参考了下面几位大神的文章

http://www.scienjus.com/get-field-annotation-property-by-jackson-contextualserializer/

http://blog.csdn.net/liuc0317/article/details/48787793

http://www.voidcn.com/article/p-ezjgnfeh-bee.html

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

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

相关文章

PostgreSQL + PostGIS:空间数据存储及管理解决方案

在数据库领域&#xff0c;PostgreSQL 已成为最强大、最通用的选项之一。它管理大量数据的能力、对 SQL 标准的遵守以及可扩展的架构使其受到学术界和工业界的喜爱。然而&#xff0c;真正让 PostgreSQL 脱颖而出的原因之一是它与PostGIS的集成&#xff0c;这是一个允许您有效处理…

HTML 基础,尚优选网站设计开发(二)

最近在恶补HTML相关知识点&#xff0c;本人是后端程序员&#xff0c;看到周围很多人都被裁员了&#xff0c;突然想尽早转变成全栈程序员变成独立开发者&#xff0c;有空余接接私单、商单的 尚优选网站设计开发&#xff0c;HTMLCSSJavaScript实际使用 尚优选网站设计开发页面分析…

单元测试 Mock不Mock?

文章目录 前言单元测试没必要?Mock不Mock?什么是Mock?Mock的意义何在? 如何Mock&#xff1f;应该Mock什么&#xff1f;Mock 编写示例 总结 前言 前段时间&#xff0c;我们团队就单元测试是否采用 Mock 进行了一番交流&#xff0c;各有各的说法。本文就单元测试 Mock不Mock…

流媒体技术革新,EasyCVR视频汇聚平台赋能视频监控全面升级

随着科技的飞速发展&#xff0c;流媒体技术和视频监控正经历着前所未有的变革与融合。本文将从流媒体技术的新兴趋势出发&#xff0c;探讨其与视频监控领域的深度结合&#xff0c;以及这一融合所带来的创新与发展。 一、流媒体技术的新兴趋势 1、5G网络的广泛应用 5G网络以其…

Leetcode3258. 统计满足 K 约束的子字符串数量 I

Every day a Leetcode 题目来源&#xff1a;3258. 统计满足 K 约束的子字符串数量 I 解法1&#xff1a;暴力 暴力枚举每一个子字符串&#xff0c;看是否满足 k 约束。 代码&#xff1a; /** lc appleetcode.cn id3258 langcpp** [3258] 统计满足 K 约束的子字符串数量 I*/…

[米联客-XILINX-H3_CZ08_7100] FPGA程序设计基础实验连载-36高效的VIVADO BlockDesign设计方法

软件版本&#xff1a;VIVADO2021.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA 实验平台&#xff1a;米联客-MLK-H3-CZ08-7100开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http…

828华为云征文|华为云Flexus X实例docker部署MinIO对象存储系统obs

828华为云征文&#xff5c;华为云Flexus X实例docker部署MinIO对象存储系统obs 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求&#xff0c;一定…

单例模式的总结

常规模式:有属性/构造方法/普通方法&#xff0c;也可以在类中执行主方法&#xff0c;也可以在test类中执行主方法 单例模式是什么&#xff1f; 单例模式&#xff1a;类只有1个对象&#xff1b;保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。单例模式是在内…

【Python机器学习】词向量推理——词向量

目录 面向向量的推理 使用词向量的更多原因 如何计算Word2vec表示 skip-gram方法 什么是softmax 神经网络如何学习向量表示 用线性代数检索词向量 连续词袋方法 skip-gram和CBOW&#xff1a;什么时候用哪种方法 word2vec计算技巧 高频2-gram 高频词条降采样 负采样…

团队比赛活动如何记分?

团队比赛时如何记分&#xff1f; 在当今快节奏的社会中&#xff0c;团队合作和竞争已成为推动个人和集体发展的重要方式。无论是在学校的体育赛事、公司的团建活动&#xff0c;还是社区的娱乐竞赛中&#xff0c;团队比赛都扮演着不可或缺的角色。然而&#xff0c;组织一场成功的…

网络学习-eNSP配置路由器

#PC1网关&#xff1a;192.168.1.254 #PC3网关&#xff1a;192.168.3.254 #PC4网关&#xff1a;192.168.4.254# 注&#xff1a;路由器接口必须配置不同网段IP地址 <Huawei>system-view Enter system view, return user view with CtrlZ. #给路由器两个接口配置IP地址 [Hua…

黑马-Cloud21版-面试篇13:Sentinel源码分析

Sentinel源码分析 1.Sentinel的基本概念 Sentinel实现限流、隔离、降级、熔断等功能&#xff0c;本质要做的就是两件事情&#xff1a; 统计数据&#xff1a;统计某个资源的访问数据&#xff08;QPS、RT等信息&#xff09;规则判断&#xff1a;判断限流规则、隔离规则、降级规…

将用户证书导入到系统证书

现在大部分app已经不信任用户证书,通过传统charles安装证书抓包的方式已经不行,今天就来说一个将系统证书移动到系统目录的方法,系统证书的目录只有可读权限,有时候挂在目录会不成功 我们先下载如下模块 GitHub - ys1231/MoveCertificate: 支持Android7-14移动证书&#xff0…

WebAPI(四) BOM;延时函数;JS执行机制(同步异步);location对象;history对象;navigation对象

文章目录 BOM1. 定时器-延时函数2. JS执行机制(1)、同步与异步(2)、事件循环 3. location对象(1)、href属性获取完整的url地址(2)search属性获取地址中携带的参数(3) hash&#xff1a;获取地址中的#后边的部分(3) reload&#xff1a; 刷新当前页面&#xff0c;传入参数true表示…

2024年入职/转行网络安全,该如何规划?_网络安全职业规划

前言 前段时间&#xff0c;知名机构麦可思研究院发布了 《2022年中国本科生就业报告》&#xff0c;其中详细列出近五年的本科绿牌专业&#xff0c;其中&#xff0c;信息安全位列第一。 网络安全前景 对于网络安全的发展与就业前景&#xff0c;想必无需我多言&#xff0c;作为…

【每日刷题】Day112

【每日刷题】Day112 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 1137. 第 N 个泰波那契数 - 力扣&#xff08;LeetCode&#xff09; 2. 面试题 08.01. 三步问题 - …

没资料的屏幕怎么点亮?思路分享

这次尝试调通一个没资料的屏幕&#xff0c;型号是HYT13264&#xff0c;这个是淘宝上面的老王2.9元屏&#xff0c;成色很好但是长期库存没有资料和代码能点亮&#xff0c;仅仅只有一个引脚定义。这里我使用Arduino Nano作为控制器尝试点亮这个模块。 首先&#xff0c;已知别人找…

flink---window

Window介绍 DataStream: https://nightlies.apache.org/flink/flink-docs-release-1.17/zh/docs/dev/datastream/operators/windows/ SQL: https://nightlies.apache.org/flink/flink-docs-release-1.17/zh/docs/dev/table/sql/queries/window-tvf/ 1、为什么需要Window?…

【AI大模型】基于docker部署向量数据库Milvus和可视化工具Attu详解步骤

&#x1f680; 作者 &#xff1a;“大数据小禅” &#x1f680; 文章简介 &#xff1a;本专栏后续将持续更新大模型相关文章&#xff0c;从开发到微调到应用&#xff0c;需要下载好的模型包可私。 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 目…

项目7-音乐播放器7(测试报告)

1.项目背景 音乐播放器采用前后端分离的方法来实现&#xff0c;基于SSM框架构建&#xff0c;同时使用了数据库来存储相关的数据&#xff0c;同时将其部署到云服务器上。 用户可以轻松注册登录&#xff0c;浏览丰富的音乐库&#xff0c;搜索喜欢的歌曲。系统支持多种音频格式播…