springboot 自定义注解实现数据脱敏

2023-04-10 20:47:40

本文为springboot + mybatis + swagger2 为基础框架用户实现自定义接口脱敏

项目结构

        

1.定义自定义接口注解

package com.wll.desen.densenInter;

import java.lang.annotation.*;

/**
 * @author wll
 * data 2021-09-13
 */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Desensitized {
    // 脱敏类型
    SensitiveTypeEnum typ();
}

        

2.自定义注解脱敏类型

package com.wll.desen.densenInter;

/**
 * @author wll
 * data 2021-09-13
 */
public enum SensitiveTypeEnum {
    /**
     * 中文名
     */
    CHINESE_NAME,
    /**
     * 身份证号
     */
    ID_CARD,
    /**
     * 座机号
     */
    FIXED_PHONE,
    /**
     * 手机号
     */
    MOBILE_PHONE,
    /**
     * 地址
     */
    ADDRESS,
    /**
     * 电子邮件
     */
    EMAIL,
    /**
     * 银行卡
     */
    BANK_CARD,
    /**
     * 密码
     */
    PASSWORD,
    /**
     * 车牌号
     */
    CARNUMBER;
}

3.数据处理工具

package com.wll.desen.densenInter;

import org.apache.commons.lang3.StringUtils;

/**
 * @author wll
 * data 2021-09-13
 */
public class DesensitizedUtils {


    /**
     * <<中文姓名>>只显示第一个汉字,其他隐藏为2个星号,比如:李**
     *
     * @param fullName
     * @return
     */
    public static String chineseName(String fullName) {
        if (StringUtils.isBlank(fullName)) {
            return "";
        }
        String name = StringUtils.left(fullName, 1);
        return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
    }

    /**
     * <<身份证号>> 显示最后四位,其他隐藏。共计18位或者15位,比如:412**********1234
     *
     * @param id
     * @return
     */
    public static String idCardNum(String id) {
        if (StringUtils.isBlank(id)) {
            return "";
        }
        return StringUtils.left(id, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(id, 4), StringUtils.length(id), "*"), "***"));
    }

    /**
     * <<固定电话>> 后四位,其他隐藏,比如1234
     *
     * @param num
     * @return
     */
    public static String fixedPhone(String num) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");
    }

    /**
     * <<手机号码>>前三位,后四位,其他隐藏,比如135******10
     *
     * @param num
     * @return
     */
    public static String mobilePhone(String num) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 2), StringUtils.length(num), "*"), "***"));
    }

    /**
     * <<地址>>只显示到地区,不显示详细地址,比如:北京市海淀区****
     *
     * @param address
     * @param sensitiveSize 敏感信息长度
     * @return
     */
    public static String address(String address, int sensitiveSize) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        int length = StringUtils.length(address);
        return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");
    }

    /**
     * <<电子邮箱>> 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示,比如:d**@126.com>
     *
     * @param email
     * @return
     */
    public static String email(String email) {
        if (StringUtils.isBlank(email)) {
            return "";
        }
        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>
     *
     * @param cardNum
     * @return
     */
    public static String bankCard(String cardNum) {
        if (StringUtils.isBlank(cardNum)) {
            return "";
        }
        return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******"));
    }

    /**
     * <<密码>>密码的全部字符都用*代替,比如:******
     *
     * @param password
     * @return
     */
    public static String password(String password) {
        if (StringUtils.isBlank(password)) {
            return "";
        }
        String pwd = StringUtils.left(password, 0);
        return StringUtils.rightPad(pwd, StringUtils.length(password), "*");
    }

    /**
     * <<车牌号>>前两位后一位,比如:苏M****5
     *
     * @param carNumber
     * @return
     */
    public static String carNumber(String carNumber) {
        if (StringUtils.isBlank(carNumber)) {
            return "";
        }
        return StringUtils.left(carNumber, 2).
                concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(carNumber, 1), StringUtils.length(carNumber), "*"), "**"));

    }
}

4.数据处理方法

package com.wll.desen.densenInter;

import com.alibaba.fastjson.serializer.ValueFilter;

import java.lang.reflect.Field;

/**
 * @author wll
 * data 2021-09-13
 */
public class ValueDesensitizeFilter implements ValueFilter {

    @Override
    public Object process(Object object, String name, Object value) {

        if (null == value || !(value instanceof String) || ((String) value).length() == 0) {
            return value;
        }
        try {
            Field field = object.getClass().getDeclaredField(name);
            Desensitized desensitization;
            if (String.class != field.getType() || (desensitization = field.getAnnotation(Desensitized.class)) == null) {
                return value;
            }
            String valueStr = (String) value;
            SensitiveTypeEnum type = desensitization.typ();
            switch (type) {
                case CHINESE_NAME:
                    return DesensitizedUtils.chineseName(valueStr);
                case ID_CARD:
                    return DesensitizedUtils.idCardNum(valueStr);
                case FIXED_PHONE:
                    return DesensitizedUtils.fixedPhone(valueStr);
                case MOBILE_PHONE:
                    return DesensitizedUtils.mobilePhone(valueStr);
                case ADDRESS:
                    return DesensitizedUtils.address(valueStr, 8);
                case EMAIL:
                    return DesensitizedUtils.email(valueStr);
                case BANK_CARD:
                    return DesensitizedUtils.bankCard(valueStr);
                case PASSWORD:
                    return DesensitizedUtils.password(valueStr);
                case CARNUMBER:
                    return DesensitizedUtils.carNumber(valueStr);
                default:
            }
        } catch (NoSuchFieldException e) {
            return value;
        }
        return value;
    }
}

5.自定义拦截器

package com.wll.desen.densenInter;

import com.alibaba.fastjson.serializer.ValueFilter;

import java.lang.reflect.Field;

/**
 * @author wll
 * data 2021-09-13
 */
public class ValueDesensitizeFilter implements ValueFilter {

    @Override
    public Object process(Object object, String name, Object value) {

        if (null == value || !(value instanceof String) || ((String) value).length() == 0) {
            return value;
        }
        try {
            Field field = object.getClass().getDeclaredField(name);
            Desensitized desensitization;
            if (String.class != field.getType() || (desensitization = field.getAnnotation(Desensitized.class)) == null) {
                return value;
            }
            String valueStr = (String) value;
            SensitiveTypeEnum type = desensitization.typ();
            switch (type) {
                case CHINESE_NAME:
                    return DesensitizedUtils.chineseName(valueStr);
                case ID_CARD:
                    return DesensitizedUtils.idCardNum(valueStr);
                case FIXED_PHONE:
                    return DesensitizedUtils.fixedPhone(valueStr);
                case MOBILE_PHONE:
                    return DesensitizedUtils.mobilePhone(valueStr);
                case ADDRESS:
                    return DesensitizedUtils.address(valueStr, 8);
                case EMAIL:
                    return DesensitizedUtils.email(valueStr);
                case BANK_CARD:
                    return DesensitizedUtils.bankCard(valueStr);
                case PASSWORD:
                    return DesensitizedUtils.password(valueStr);
                case CARNUMBER:
                    return DesensitizedUtils.carNumber(valueStr);
                default:
            }
        } catch (NoSuchFieldException e) {
            return value;
        }
        return value;
    }
}

6.配置类

package com.wll.desen.filter;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.wll.desen.densenInter.ValueDesensitizeFilter;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author wll
 * data 2021-09-13
 */
@Configuration
public class WebConfigurer implements WebMvcConfigurer {

    /**
     * 配置fastjson为默认JSON转换
     *
     * @return
     */
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        // fastConverter.setDefaultCharset(StandardCharsets.UTF_8); // 测试乱码定义下类型
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        fastJsonConfig.setSerializeFilters(new ValueDesensitizeFilter());//添加自己写的拦截器
        fastConverter.setFastJsonConfig(fastJsonConfig);
        HttpMessageConverter<?> converter = fastConverter;
        return new HttpMessageConverters(converter);
    }

}

7.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.15.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wll</groupId>
    <artifactId>desen</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>desen</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.21</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-core-asl</artifactId>
            <version>1.9.13</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
            <exclusions>
                <exclusion>
                    <groupId>io.swagger</groupId>
                    <artifactId>swagger-models</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

8.实体对象

package com.wll.desen.bean;

import com.wll.desen.densenInter.Desensitized;
import com.wll.desen.densenInter.SensitiveTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;

import java.lang.reflect.Type;
import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;

/**
 * user
 *
 * @author wll
 * @date 2021-09-13
 */
@ApiModel(value = "用户基本信息")
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键", required = false)
    private String userId;
    @ApiModelProperty(value = "昵称", required = false)
    private String userName;
    @Desensitized(typ = SensitiveTypeEnum.CHINESE_NAME)
    @ApiModelProperty(value = "真实姓名", required = false)
    private String relaName;
    @Desensitized(typ = SensitiveTypeEnum.MOBILE_PHONE)
    @ApiModelProperty(value = "手机号", required = false)
    private String phone;
    @Desensitized(typ = SensitiveTypeEnum.CARNUMBER)
    @ApiModelProperty(value = "车牌号", required = false)
    private String carNumber;
    @Desensitized(typ = SensitiveTypeEnum.ID_CARD)
    @ApiModelProperty(value = "身份证号", required = false)
    private String idCart;
    @ApiModelProperty(value = "创建时间", required = false)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date created;
    @ApiModelProperty(value = "修改时间", required = false)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updated;
    @ApiModelProperty(value = "同步标志  0 无需同步/已同步1 新增 2修改 3 删除", required = false)
    private Integer synch;


    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserName() {
        return userName;
    }

    public void setRelaName(String relaName) {
        this.relaName = relaName;
    }

    public String getRelaName() {
        return relaName;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getPhone() {
        return phone;
    }

    public void setCarNumber(String carNumber) {
        this.carNumber = carNumber;
    }

    public String getCarNumber() {
        return carNumber;
    }

    public void setIdCart(String idCart) {
        this.idCart = idCart;
    }

    public String getIdCart() {
        return idCart;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    public Date getCreated() {
        return created;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    public Date getUpdated() {
        return updated;
    }

    public void setSynch(Integer synch) {
        this.synch = synch;
    }

    public Integer getSynch() {
        return synch;
    }

    @Override
    public String toString() {
        return "User{" +
                "			userId:'" + userId + '\'' +
                ", 			userName:'" + userName + '\'' +
                ", 			relaName:'" + relaName + '\'' +
                ", 			phone:'" + phone + '\'' +
                ", 			carNumber:'" + carNumber + '\'' +
                ", 			idCart:'" + idCart + '\'' +
                ", 			created:" + created +
                ", 			updated:" + updated +
                ", 			synch:" + synch +
                '}';
    }

}

9.yml文件

server:
  port: 8098
  tomcat:
    uri-encoding: UTF-8
  servlet:
    context-path: /desen
    session:
      timeout: 36000s #1小时,这里不设置太长,防止未登录session占用大量资源
spring:
  datasource:
    username: root
    password: 13811920289
    url: jdbc:mysql://****:3306/hxgj_product?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: swagger

mybatis:
  mapper-locations: classpath*:mapper/**/*Mapper.xml
  type-aliases-package: com.wll.desen.bean
  #configuration:
  # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

swagger:
  #swagger接口扫描范围
  scan: com.wll
  #标题
  title: 接口文档
  #描述
  description: 相关接口
  # 版本
  version: 0.0.1

效果图

如若有疑问可私信:共同进步

  • 作者:wll_cxy1
  • 原文链接:https://blog.csdn.net/a2365900668/article/details/120306728
    更新时间:2023-04-10 20:47:40