1.定义注解

创建Spring Boot项目添加以下依赖

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>5.7.22</version></dependency></dependencies>

然后定义Sensitive 注解,@JacksonAnnotationsInside的作用是将@JacksonAnnotation标注的注解作为一个组合注解,这里使用@JacksonAnnotationsInside在@Sensitive 注解中组合@JsonSerialize注解,这样就可以使用JsonSerialize的功能,并且可以拓展自定义属性和隐式得指定自定义序列化器SensitiveSerializer了。

@Target({ElementType.FIELD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveSerializer.class)
public @interface Sensitive {/*** 脱敏的类型,默认手机号* @return*/Type value();/*** CUSTOM_HIDE/CUSTOM_OVERLAY 时生效* 开始位置(包含)* @return*/int startInclude() default 0;/*** CUSTOM_HIDE/CUSTOM_OVERLAY 时生效* 结束位置(不包含)* @return*/int endExclude() default 0;/*** CUSTOM_OVERLAY 时生效,*重复的次数* @return*/int overlayRepeat() default 4;/*** Enumeration used with {@link Sensitive}*/public enum Type {/*** 手机号*/MOBILE,/*** 中文名*/CHINESE_NAME,/*** 身份证号*/ID_CARD,/*** 座机号*/FIXED_PHONE,/*** 地址*/ADDRESS,/*** 电子邮件*/EMAIL,/*** 银行卡*/BANK_CARD,/*** 自定义,有多少个字符替换成多少个** e.g: startInclude=3,endExclude=7,隐藏第3个到第7个的字符*/CUSTOM_HIDE,/***保留方式隐藏* e.g: startInclude=3,endExclude=4 ,保留前面3个和后面的4个*/CUSTOM_RETAIN_HIDE,/*** 自定义,只替换成指定个**/CUSTOM_OVERLAY,}}

2. 脱敏工具类

创建脱敏工具类SensitiveUtil ,统一封装数据脱敏的方法。

public class SensitiveUtil {/*** [手机号码] 前3位后4位明码,中间4位掩码用****显示,如138****0000* @param mobile 手机号码* @return*/public static String handlerMobile(String mobile) {if(StringUtil.isEmpty(mobile)){return null;}return hide(mobile,3,mobile.length() - 4);}/*** [手机号码] 只显示后四位, 如:*8856* @param phone 手机号码* @return*/public static String handlerPhone(String phone) {if(StringUtil.isEmpty(phone)){return null;}return overlay(phone,StringPool.ASTERISK,1,0,phone.length() - 4);}/*** [身份证号] 前6位后4位明码,中间掩码用***显示,如511623********0537* @param idNum* @return*/public static String handlerIdCard(String idNum) {if(StringUtil.isEmpty(idNum)){return null;}return hide(idNum,6,idNum.length() - 4);}/*** [银行卡] 前6位后4位明码,中间部分****代替,如622848*********5579* @param cardNum* @return*/public static String handlerBankCard(String cardNum) {if(StringUtil.isEmpty(cardNum)){return null;}return hide(cardNum,6,cardNum.length() - 4);}/*** [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:广东省广州市天河区****>* @param address*/public static String handlerAddress(String address) {if(StringUtil.isEmpty(address)){return null;}return overlay(address,StringPool.ASTERISK,4,9,address.length());}/*** [用户名] 只显示第一位 <例子:黄**>* @param username* @return*/public static String handlerUsername(String username) {if(StringUtil.isEmpty(username)){return null;}return hide(username,1,username.length());}/*** [固定电话] 后四位,其他隐藏<例子:****1234>*/public static String handlerFixedPhone(final String num) {if(StringUtil.isEmpty(num)){return null;}return overlay(num, StringPool.ASTERISK,4, 0,num.length()-4);}/*** [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>* @param email* @return*/public static String handlerEmail(final String email) {if(StringUtil.isEmpty(email)){return null;}final int index = StringUtil.indexOf(email, StringPool.AT_CHAR);if (index <= 1) {return email;} else {return hide(email, 1, index);}}/*** 用另一个字符串覆盖一个字符串的一部分* @param str  需要替换的字符串* @param overlay  将被替换成的字符串* @param overlayRepeat  overlay重复的次数* @param start  开始位置* @param end  结束位置* @return*/public static String overlay(String str, String overlay,int overlayRepeat, int start, int end) {if (StringUtil.isEmpty(str)) {return StringUtil.str(str);}if (StringUtil.isEmpty(overlay)) {overlay = StringPool.EMPTY;}final int len = str.length();if (start < 0) {start = 0;}if (start > len) {start = len;}if (end < 0) {end = 0;}if (end > len) {end = len;}if (start > end) {final int temp = start;start = end;end = temp;}return str.substring(0, start) + StringUtil.repeat(overlay, overlayRepeat) + str.substring(end);}/*** 替换指定字符串的指定区间内字符为"*"** @param str 字符串* @param startInclude 开始位置(包含)* @param endExclude 结束位置(不包含)* @return 替换后的字符串*/public static String hide(String str, int startInclude, int endExclude) {return hide(str, startInclude, endExclude,StringPool.ASTERISK_CHAR);}/*** 替换指定字符串的指定区间内字符为"*"** @param str 字符串* @param startInclude 开始位置(包含)* @param endExclude 结束位置(不包含)* @param replacedChar* @return 替换后的字符串*/public static String hide(String str, int startInclude, int endExclude, char replacedChar) {if (StringUtil.isEmpty(str)) {return StringUtil.str(str);}final int strLength = str.length();if (startInclude > strLength) {return StringUtil.str(str);}if (endExclude > strLength) {endExclude = strLength;}if (startInclude > endExclude) {// 如果起始位置大于结束位置,不替换return StringUtil.str(str);}final char[] chars = new char[strLength];for (int i = 0; i < strLength; i++) {if (i >= startInclude && i < endExclude) {chars[i] = replacedChar;} else {chars[i] = str.charAt(i);}}return new String(chars);}}

3. 自定义Jackson序列化器

参考Jackson自带的StringSerializer,继承JsonSerializer,重写serialize方法,自定义Jackson序列化器SensitiveSerializer针对String类型数据进行数据脱敏处理。

public class SensitiveSerializer extends JsonSerializer<String> implements ContextualSerializer {private Sensitive.Type type;private int startInclude;private int endExclude;private int overlayRepeat;public SensitiveSerializer() {}public SensitiveSerializer(final Sensitive sensitive) {this.type = sensitive.value();this.startInclude = sensitive.startInclude();this.endExclude = sensitive.endExclude();this.overlayRepeat = sensitive.overlayRepeat();}@Overridepublic void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {if(ObjectUtil.isEmpty(value)){gen.writeString(value);return;}else {switch (this.type) {case MOBILE:gen.writeString(SensitiveUtil.handlerMobile(value));break;case ID_CARD:gen.writeString(SensitiveUtil.handlerIdCard(value));break;case BANK_CARD:gen.writeString(SensitiveUtil.handlerBankCard(value));break;case CHINESE_NAME:gen.writeString(SensitiveUtil.handlerUsername(value));break;case FIXED_PHONE:gen.writeString(SensitiveUtil.handlerFixedPhone(value));break;case ADDRESS:gen.writeString(SensitiveUtil.handlerAddress(value));break;case EMAIL:gen.writeString(SensitiveUtil.handlerEmail(value));break;case CUSTOM_HIDE:gen.writeString(SensitiveUtil.hide(value,startInclude,endExclude));break;case CUSTOM_RETAIN_HIDE:gen.writeString(SensitiveUtil.hide(value,startInclude,(value.length()-endExclude)));break;case CUSTOM_OVERLAY:gen.writeString(SensitiveUtil.overlay(value, StringPool.ASTERISK,overlayRepeat,startInclude,endExclude));break;default:gen.writeString(value);}}}@Overridepublic JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {if(Objects.isNull(property)){return prov.getDefaultNullValueSerializer();}if(Objects.equals(property.getType().getRawClass(), String.class)){Sensitive sensitive = property.getAnnotation(Sensitive.class);if (Objects.isNull(sensitive)) {sensitive = property.getContextAnnotation(Sensitive.class);}if (Objects.nonNull(sensitive)) {return new SensitiveSerializer(sensitive);}}return prov.findValueSerializer(property.getType(), property);//Sensitive sensitive = property.getAnnotation(Sensitive.class);//type = sensitive.value();//return this;}
}

4. 测试使用

创建实体类Student

public class Student {@Sensitive(value = Sensitive.Type.CHINESE_NAME)private String name;@Sensitive(value = Sensitive.Type.ID_CARD)private String idCard;@Sensitive(value = Sensitive.Type.BANK_CARD)private String bankCard;@Sensitive(value = Sensitive.Type.FIXED_PHONE)private String fixedPhone;@Sensitive(value = Sensitive.Type.ADDRESS)private String address;@Sensitive(value = Sensitive.Type.EMAIL)private String email;@Sensitive(value = Sensitive.Type.CUSTOM_RETAIN_HIDE,startInclude = 3,endExclude = 10)private String remark;public Student() {}public String getBankCard() {return bankCard;}public void setBankCard(String bankCard) {this.bankCard = bankCard;}public String getFixedPhone() {return fixedPhone;}public void setFixedPhone(String fixedPhone) {this.fixedPhone = fixedPhone;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public Student(String name, String idCard, String bankCard, String fixedPhone, String address, String email, String remark) {this.name = name;this.idCard = idCard;this.bankCard = bankCard;this.fixedPhone = fixedPhone;this.address = address;this.email = email;this.remark = remark;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdCard() {return idCard;}public void setIdCard(String idCard) {this.idCard = idCard;}
}

定义接口/test/student

@RestController
@RequestMapping("/test")
public class TestController {@GetMapping("/student")public Student getStudent(){Student student = new Student();student.setName("张三三");student.setIdCard("44082199612054343");student.setBankCard("62173300255879654448");student.setFixedPhone("3110026");student.setAddress("广东省广州市天河区");student.setEmail("1258398545@qq.com");student.setRemark("sadhaonsdoasnodnaonodsn是大祭司大祭司你");return student;}
}

浏览器请求接口/test/student,查看接口返回的数据

Spring Boot基于注解方式处理接口数据脱敏相关推荐

  1. java datasource 配置_Spring boot 基于注解方式配置datasource

    Spring boot 基于注解方式配置datasource Xml配置 我们先来回顾下,使用xml配置数据源. 步骤: 先加载数据库相关配置文件; 配置数据源; 配置sqlSessionFactor ...

  2. Spring Boot 基于注解驱动源码分析--自动配置

    Spring作为Java开发最常用的容器管理框架,使用注解为我们提供很多便捷,下面通过源码分析Spring基于注解驱动自动配置的原理 首先介绍两个关键类: ConfigurationClassPost ...

  3. spring学习--基于注解方式创建对象AOP

    概念 下面四个注解功能是一样的,都可以用来创建 bean 实例 ​ (1)@Component ​ (2)@Service ​ (3)@Controller ​ (4)@Repository 1.引入 ...

  4. spring IOC容器 Bean 管理——基于注解方式

    IOC 操作 Bean 管理(基于注解方式) 1.什么是注解 ​ (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值-) ​ (2)使用注解,注解作用在类上面,方法上面, ...

  5. Spring 事务基于注解和xml方式

    文章目录 基于注解方式的Spring事务配置 1 创建表结构 2 创建实体类 3 创建Dao 4 创建DaoImpl 5 创建Service 6 创建SrviceImpl 7 创建TxConfig 8 ...

  6. 40 个 Spring Boot 常用注解

    以下文章来源方志朋的博客,回复"666"获面试宝典 作者 | 谭朝红 链接 | ramostear.com 一.Spring Web MVC 与 Spring Bean 注解 Sp ...

  7. 前端Vue+ElementUI的Pagination分页组件实现分页展示 后端Spring Boot +Mybatis Plus实现分页接口

    前端Vue+ElementUI的Pagination分页组件实现分页展示 & 后端Spring Boot +Mybatis Plus实现分页接口 很久没有更新博客了,主要原因是博主一直在补充自 ...

  8. 使用Spring Boot JPA Specification实现使用JSON数据来查询实体数据

    文章目录 使用Spring Boot JPA Specification实现使用JSON数据来查询实体数据 需求概要 JSON 结构的设计 使用策略模式执行不同的查询条件 构造查询条件 主逻辑具体的代 ...

  9. spring AOP自定义注解方式实现日志管理

    转:spring AOP自定义注解方式实现日志管理 今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接 ...

最新文章

  1. excel 解析 java_java解析Excel(xls、xlsx两种格式)
  2. 学习了哪些知识,计算机视觉才算入门?
  3. ps -aux|grep 详细信息
  4. php c扩展的方式,php中使用C语言写扩展的方法
  5. Python自动运维系列:每天凌晨定时执行特定任务
  6. java 中间件_从头到尾说一遍Java(中间件)垃圾回收
  7. Nand Flash驱动程序分析
  8. fm信号表达式_chirp信号表达式
  9. 云计算、大数据在农业信息化中的应用
  10. MT-考试座位-颜色排序
  11. js解决m3u8视频无法播放问题
  12. 大话设计模式之爱你一万年:第三章 创建型模式:工厂模式:我想让你坐在宝马里笑:5.工厂模式之抽象工厂模式
  13. abaqus编写本构方程vumat_基于ABAQUS的木材本构关系数值模拟方法与流程
  14. 重装win10系统 远程控制TeamViewer——深度学习菜鸡入门(2)
  15. java右移和无符号右移区别_Java 无符号右移与右移运算符的使用介绍
  16. foxmail皮肤_七大改变!Foxmail 6.5新功能体验
  17. vue+django实现一对一聊天功能
  18. 跟着大宇学MySQL------目录帖
  19. Wise Installation制作的安装包添加卸载快捷方式
  20. 软件项目中的决策分析_软件工程中的决策管理

热门文章

  1. 抖音不开直播的赚钱方式有哪些
  2. Shotcut for Mac(视频编辑器)
  3. 网上图书商城系统毕业设计,网上图书销售系统设计与实现,毕业设计论文毕设作品参考
  4. 金蝶云星空ERP附件上传接口开发思路
  5. Go 笔记之为什么要学 Go
  6. 依据银行卡号获取银行信息Java代码
  7. CINTA作业七:同态
  8. 如何使用Java对密码进行加密 Java Sah加密方式帮你实现加密
  9. IE11兼容IE8的设置
  10. vb中的clng函数