婚纱设计网站首页,客户网站留言,安徽黄山网站建设,网站广告怎么赚钱目录
#x1f378;前言
#x1f37b;一、Jackson 序列化库
#x1f37a;二、方案实践 2.1 环境准备 2.2 依赖引入 2.3 代码编写 #x1f49e;️三、接口测试
#x1f379;四、章末 #x1f378;前言 小伙伴们大家好#xff0c;最近也是很忙啊#xff0c;上次的文章…
目录
前言
一、Jackson 序列化库
二、方案实践 2.1 环境准备 2.2 依赖引入 2.3 代码编写 ️三、接口测试
四、章末 前言 小伙伴们大家好最近也是很忙啊上次的文章分享了 Caffeine 本地缓存文章链接如下
【Caffeine】⭐️SpringBoot 项目整合 Caffeine 实现本地缓存_springboot caffeine-CSDN博客 最近在别的技术分享上看到了数据脱敏的介绍感觉平时接触的挺多的比如个人私密信息在页面上显示的时候需要对部分信息加密就像手机号中间几个位置用 “*” 代替如下图具体的实现也有很多方式比如单独某一个接口需要加密那么可以在接口返回值时处理下数据即可但是如果过多的接口有此需求挨个处理显然费时费力并且增加代码冗余这个时候就可以选用全局处理的解决方案实现一次编写到处实现具体的方案就是可以在序列化时处理数据 序列化工具常用的 Jackson 日常接触也很多 一、Jackson 序列化库 Jackson 是一个流行的 Java 序列化/反序列化库专门用于处理 JSON 数据。它提供了一组功能强大且灵活的 API可以帮助开发者在 Java 对象和 JSON 数据之间进行转换。有以下几个特性灵活、高效、应用广泛整合各种框架比如我们经常接触的 web 系统就是将后端的数据 Json 序列化后传递给前端实现的
二、方案实践 2.1 环境准备 测试项目是基于 SpringBoot 框架的项目实现另外接口测试使用 Apipost 实现模拟请求 2.2 依赖引入 因为使用的 SpringBoot 框架所以在创建项目的时候就已经勾选了 web 模块而这些模块已经集成了相关的 Jackson 包依赖如下 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency 如果项目中没有的话也可以手动引入依赖如下 注手动引入的时候需要注意下版本问题项目启动的时候可能会遇到如下情况这种情况我在博客上搜索了相关的文章有讲解的不是很多但是可行的一种方案就是自己不要指定版本使用父依赖的即可解决 Error starting Tomcat context. Exception: org.springframework.beans.factory.BeanCreationException. Message: Error creating bean with name formContentFilter defined in class path resource dependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-core/artifactId
!-- version2.9.8/version--/dependencydependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-annotations/artifactId
!-- version2.9.8/version--/dependencydependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactId
!-- version2.9.8/version--/dependencydependencygroupIdcom.fasterxml.jackson.datatype/groupIdartifactIdjackson-datatype-jsr310/artifactId
!-- version2.13.0/version lt;!ndash; 替换为与你的Spring Boot兼容的版本 ndash;gt;--/dependency 2.3 代码编写 2.3.1 脱敏数据类型枚举 指定哪些类型的数据需要脱敏命名为枚举类方便后续调用
/*** author HuangBen */
public enum SensitiveEnum {/*** 中文名*/CHINESE_NAME,/*** 身份证号*/ID_CARD,/*** 手机号*/MOBILE_PHONE,/*** 地址*/ADDRESS,/*** 电子邮件*/EMAIL,/*** 银行卡*/BANK_CARD,
} 2.3.2 处理隐私数据工具类 这里将已有的处理工具封装为一个工具类方便设置参数以及调用这里导入的工具类如果报错说明并没有引入依赖依赖如下 dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactIdversion3.12.0/version/dependency
import org.apache.commons.lang3.StringUtils;/*** author HuangBen */
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位。例子420**********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, 4), StringUtils.length(id), *),***));}/*** [手机号码] 前三位后四位其他隐藏例子:138******1234*/public static String mobilePhone(final String num) {if (StringUtils.isBlank(num)) {return ;}return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 4), 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), *),******));}} 2.3.3 编写脱敏序列化实现类 这里就是先用刚才工具类处理数据再进行序列化
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import java.io.IOException;
import java.util.Objects;/*** author HuangBen*/
public class SensitiveSerialize extends JsonSerializerString implements ContextualSerializer {/*** 脱敏类型*/private SensitiveEnum type;Overridepublic void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {switch (this.type) {case CHINESE_NAME: {jsonGenerator.writeString(SensitiveInfoUtils.chineseName(s));break;}case ID_CARD: {jsonGenerator.writeString(SensitiveInfoUtils.idCardNum(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;}}}Overridepublic JsonSerializer? createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {// 为空直接跳过if (beanProperty ! null) {// 非 String 类直接跳过if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {SensitiveWrapped sensitiveWrapped beanProperty.getAnnotation(SensitiveWrapped.class);if (sensitiveWrapped null) {sensitiveWrapped beanProperty.getContextAnnotation(SensitiveWrapped.class);}if (sensitiveWrapped ! null) {// 如果能得到注解就将注解的 value 传入 SensitiveSerializereturn new SensitiveSerialize(sensitiveWrapped.value());}}return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);}return serializerProvider.findNullValueSerializer(beanProperty);}public SensitiveSerialize() {}public SensitiveSerialize(final SensitiveEnum type) {this.type type;}
} 2.3.4 编写脱敏注解类 通过此注解可以灵活标注哪些数据需要脱敏处理并且标注对应的枚举类型注意这里指定了序列化的实现类为我们自己刚定义的具体实现的功能就是遇到此注解标注的字段序列化的时候使用我们指定的序列化器我们自定义的序列化器中对每种类型的字段都有相应的处理逻辑
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;/*** author HuangBen */
Retention(RetentionPolicy.RUNTIME)
JacksonAnnotationsInside
JsonSerialize(using SensitiveSerialize.class)
public interface SensitiveWrapped {/*** 脱敏类型* return*/SensitiveEnum value();
} 2.3.5 编写测试实体类 这里指定了 mobile , idcard 两个字段需要脱敏并且指明了按照哪一种数据类型脱敏处理
import lombok.Data;/*** author HuangBen */
Data
public class UserEntity {/*** 用户ID*/private Long userId;/*** 用户姓名*/private String name;/*** 手机号*/SensitiveWrapped(SensitiveEnum.MOBILE_PHONE)private String mobile;/*** 身份证号码*/SensitiveWrapped(SensitiveEnum.ID_CARD)private String idCard;/*** 年龄*/private String sex;/*** 性别*/private int age;} ️三、接口测试 简单用一个 restful 接口测试下处理后的数据是否脱敏接口如下 利用接口请求工具确实按照我们指定的字段以及类型进行脱敏处理了测试成功结果如下 四、章末 通过这种方式实现的数据脱敏处理后续在使用的时候也很方便有哪些需要处理的字段只需要在实体类的字段上方添加注解并且指定脱敏类型即可符合开闭原则并且遵循很少改动原有代码的规则 文章到这里就结束了~