Java 如何通过注解实现接口输出时数据脱敏

目录
  • Java注解实现接口输出数据脱敏
    • 先声明了一个注解
    • 我们目前只支持对手机号
    • 然后我们需要实现注解的拦截功能
    • 我对默认声明和脱敏名称和手机号进行了测试
  • Java注解的字段脱敏处理
    • 定义需要脱敏的字段规则
    • 声明注解
    • 测试

Java注解实现接口输出数据脱敏

在后台管理中,对于手机号,身份证,姓名这些数据不允许所有人都能看,这时候我们要对相对数据进行脱敏.

先声明了一个注解

通过对相关接口函数进行声明,以及配置需要脱敏的参数类型SecretTypeEnum,默认脱敏手机号

/**
 * 脱敏声明
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SecretManage {

    SecretTypeEnum[] value() default {SecretTypeEnum.MOBILE};

}

我们目前只支持对手机号

身份证,用户姓名三个字段进行脱敏, 字段名称必须符合枚举的desc值

package com.test.base.enums;

import com.fasterxml.jackson.annotation.JsonValue;

/**
 * @author fyf
 * @date 2021/2/26
 */
public enum SecretTypeEnum implements BaseEnum {
    MOBILE(0, "mobile"),
    NAME(1, "name"),
    ID(2, "identity")
    ;

    @JsonValue
    private int code;
    private String desc;

    public String getDesc() {
        return desc;
    }

    SecretTypeEnum(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    @Override
    public int code() {
        return code;
    }

    public static SecretTypeEnum checkParam(String paramName) {
        SecretTypeEnum[] values = values();
        for (int i = 0; i < values.length; i++) {
            if (paramName.equals(values[i].getDesc())) {
                return values[i];
            }
        }
        return null;
    }
}

然后我们需要实现注解的拦截功能

/**
 * 对字段进行脱敏管理
 * @author: fyf
 * @date: 2021/02/23
 */
@Order(1)
@Aspect
@Component
public class SecretManageAspect {

    @Pointcut("@annotation(com.test.base.annotations.SecretManage)")
    public void pointCut() {
    }

    @Around("pointCut() && @annotation(secretManage)")
    public Object secretManageAround(ProceedingJoinPoint joinPoint, SecretManage secretManage) throws Throwable {
        Class returnType = ((MethodSignature) joinPoint.getSignature()).getReturnType();
        Object invokeResult = joinPoint.proceed();
        if (returnType.isInstance(invokeResult)) {
            returnType.cast(invokeResult);
        }
        Field[] fields = returnType.getDeclaredFields();
        List<SecretTypeEnum> annotationSecretTypeEnums = Arrays.asList(secretManage.value());
        for (Field field : fields) {
            String fieldName = field.getName();
            Class<?> paramType = field.getType();
            System.out.println("字段名称:" + fieldName);
            SecretTypeEnum secretTypeEnum = SecretTypeEnum.checkParam(fieldName);
            long count = annotationSecretTypeEnums.stream().filter(item -> item.equals(secretTypeEnum)).count();
            if (secretTypeEnum != null && count > 0) {
                fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                // 获取到setter方法
                Method setMethod = returnType.getMethod("set" + fieldName, new Class[]{paramType});
                // 获取到getter方法
                Method getMethod = returnType.getMethod("get" + fieldName);
                // 执行getter方法
                Object value = getMethod.invoke(invokeResult);
                this.invokeSetter(setMethod, invokeResult, secretTypeEnum, value);
            }
        }
        return invokeResult;
    }

    /**
     * 封装执行setter函数
     */
    private void invokeSetter(Method setterMethod, Object invokeResult, SecretTypeEnum secretTypeEnum, Object value)
        throws InvocationTargetException, IllegalAccessException {
        switch (secretTypeEnum) {
            case NAME:
                setterMethod.invoke(invokeResult, SecretUtil.nameSecret(value.toString()));
                break;
            case MOBILE:
                setterMethod.invoke(invokeResult, SecretUtil.mobileSecret(value.toString()));
                break;
            case ID:
                setterMethod.invoke(invokeResult, SecretUtil.idNoSecret(value.toString()));
                break;
        }
    }
}

上面我们就是实现了脱敏的功能,现在我们可以mock接口看看结果了,

我对默认声明和脱敏名称和手机号进行了测试

	/**
	 *  curl localhost:9999/user/test-secret
	 */
	@GetMapping("/test-secret")
//	@SecretManage(value = {SecretTypeEnum.NAME, SecretTypeEnum.MOBILE})
	@SecretManage
	public User getSecretUser() {
		User user = new User();
		user.setId(1);
		user.setMobile("13715166409");
		user.setName("张志新");
		user.setIdentity("370283790911703");
		return user;
	}

下面是测试结果

Java注解的字段脱敏处理

有这样一个场景,系统中可以出现敏感的数据,在打印日志的时候,我们并不希望打印出现,这样,我们使用自己定义注解,来解决这个问题。

定义需要脱敏的字段规则

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.gson.Gson;
import com.ucf.platform.framework.core.annotation.SensitiveInfo;
import com.ucf.platform.framework.core.log.UcfLogger;
import com.ucf.platform.framework.core.log.UcfLoggerFactory;

/**
 * @Title: SensitiveInfoUtils.java
 * @Copyright: Copyright (c) 2011
 * @Description: <br>
 *               敏感信息屏蔽工具<br>
  */
public final class SensitiveInfoUtils {

    private final static UcfLogger logger = UcfLoggerFactory.getLogger(SensitiveInfoUtils.class);

    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
     *
     * @param name
     * @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), "*");
    }

    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
     *
     * @param familyName
     * @param givenName
     * @return
     */
    public static String chineseName(String familyName, String givenName) {
        if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {
            return "";
        }
        return chineseName(familyName + givenName);
    }

    /**
     * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>
     *
     * @param id
     * @return
     */
    public static String idCardNum(String id) {
        if (StringUtils.isBlank(id)) {
            return "";
        }
        String num = StringUtils.right(id, 4);
        return StringUtils.leftPad(num, 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), "*");
    }

    /**
     * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>
     *
     * @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, 4), 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, "*");
    }

    /**
     * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.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), "*"), "******"));
    }

    /**
     * [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********>
     *
     * @param code
     * @return
     */
    public static String cnapsCode(String code) {
        if (StringUtils.isBlank(code)) {
            return "";
        }
        return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*");
    }

    /**
     * 获取脱敏json串 <注意:递归引用会导致java.lang.StackOverflowError>
     *
     * @param javaBean
     * @return
     */
    public static String getJson(Object javaBean) {
        String json = null;
        if (null != javaBean) {
            Class<? extends Object> raw = javaBean.getClass();
            try {
                if (raw.isInterface())
                    return json;
                Gson g = new Gson();
                Object clone = g.fromJson(g.toJson(javaBean, javaBean.getClass()), javaBean.getClass());
                Set<Integer> referenceCounter = new HashSet<Integer>();
                SensitiveInfoUtils.replace(SensitiveInfoUtils.findAllField(raw), clone, referenceCounter);
                json = JSON.toJSONString(clone, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);
                referenceCounter.clear();
                referenceCounter = null;
            } catch (Throwable e) {
                logger.error("SensitiveInfoUtils.getJson() ERROR", e);
            }
        }
        return json;
    }

    private static Field[] findAllField(Class<?> clazz) {
        Field[] fileds = clazz.getDeclaredFields();
        while (null != clazz.getSuperclass() && !Object.class.equals(clazz.getSuperclass())) {
            fileds = (Field[]) ArrayUtils.addAll(fileds, clazz.getSuperclass().getDeclaredFields());
            clazz = clazz.getSuperclass();
        }
        return fileds;
    }
    private static void replace(Field[] fields, Object javaBean, Set<Integer> referenceCounter) throws IllegalArgumentException, IllegalAccessException {
        if (null != fields && fields.length > 0) {
            for (Field field : fields) {
                field.setAccessible(true);
                if (null != field && null != javaBean) {
                    Object value = field.get(javaBean);
                    if (null != value) {
                        Class<?> type = value.getClass();
                        // 1.处理子属性,包括集合中的
                        if (type.isArray()) {
                            int len = Array.getLength(value);
                            for (int i = 0; i < len; i++) {
                                Object arrayObject = Array.get(value, i);
                                SensitiveInfoUtils.replace(SensitiveInfoUtils.findAllField(arrayObject.getClass()), arrayObject, referenceCounter);
                            }
                        } else if (value instanceof Collection<?>) {
                            Collection<?> c = (Collection<?>) value;
                            Iterator<?> it = c.iterator();
                            while (it.hasNext()) {
                                Object collectionObj = it.next();
                                SensitiveInfoUtils.replace(SensitiveInfoUtils.findAllField(collectionObj.getClass()), collectionObj, referenceCounter);
                            }
                        } else if (value instanceof Map<?, ?>) {
                            Map<?, ?> m = (Map<?, ?>) value;
                            Set<?> set = m.entrySet();
                            for (Object o : set) {
                                Entry<?, ?> entry = (Entry<?, ?>) o;
                                Object mapVal = entry.getValue();
                                SensitiveInfoUtils.replace(SensitiveInfoUtils.findAllField(mapVal.getClass()), mapVal, referenceCounter);
                            }
                        } else if (!type.isPrimitive()
                                   && !StringUtils.startsWith(type.getPackage().getName(), "javax.")
                                   && !StringUtils.startsWith(type.getPackage().getName(), "java.")
                                   && !StringUtils.startsWith(field.getType().getName(), "javax.")
                                   && !StringUtils.startsWith(field.getName(), "java.")
                                   && referenceCounter.add(value.hashCode())) {
                            SensitiveInfoUtils.replace(SensitiveInfoUtils.findAllField(type), value, referenceCounter);
                        }
                    }
                    // 2. 处理自身的属性
                    SensitiveInfo annotation = field.getAnnotation(SensitiveInfo.class);
                    if (field.getType().equals(String.class) && null != annotation) {
                        String valueStr = (String) value;
                        if (StringUtils.isNotBlank(valueStr)) {
                            switch (annotation.type()) {
                                case CHINESE_NAME: {
                                    field.set(javaBean, SensitiveInfoUtils.chineseName(valueStr));
                                    break;
                                }
                                case ID_CARD: {
                                    field.set(javaBean, SensitiveInfoUtils.idCardNum(valueStr));
                                    break;
                                }
                                case FIXED_PHONE: {
                                    field.set(javaBean, SensitiveInfoUtils.fixedPhone(valueStr));
                                    break;
                                }
                                case MOBILE_PHONE: {
                                    field.set(javaBean, SensitiveInfoUtils.mobilePhone(valueStr));
                                    break;
                                }
                                case ADDRESS: {
                                    field.set(javaBean, SensitiveInfoUtils.address(valueStr, 4));
                                    break;
                                }
                                case EMAIL: {
                                    field.set(javaBean, SensitiveInfoUtils.email(valueStr));
                                    break;
                                }
                                case BANK_CARD: {
                                    field.set(javaBean, SensitiveInfoUtils.bankCard(valueStr));
                                    break;
                                }
                                case CNAPS_CODE: {
                                    field.set(javaBean, SensitiveInfoUtils.cnapsCode(valueStr));
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

//----------------------------------------------------------------------------------------------
    public static Method [] findAllMethod(Class<?> clazz){
        Method [] methods= clazz.getMethods();
        return methods;
    }

  //----------------------------------------------------------------------------------------------
    public static enum SensitiveType {
        /**
         * 中文名
         */
        CHINESE_NAME,

        /**
         * 身份证号
         */
        ID_CARD,
        /**
         * 座机号
         */
        FIXED_PHONE,
        /**
         * 手机号
         */
        MOBILE_PHONE,
        /**
         * 地址
         */
        ADDRESS,
        /**
         * 电子邮件
         */
        EMAIL,
        /**
         * 银行卡
         */
        BANK_CARD,
        /**
         * 公司开户银行联号
         */
        CNAPS_CODE;
    }
}

声明注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.ucf.platform.framework.core.util.SensitiveInfoUtils;

/**
 * @Title: SensitiveInfo.java
 * @Copyright: Copyright (c) 2015
 * @Description: <br>
 *               敏感信息注解标记 <br>
 */
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SensitiveInfo {

    public SensitiveInfoUtils.SensitiveType type() ;
}

测试

public class JavaBeanA {

    public JavaBeanA(String name,String id){

    }

    @SensitiveInfo(type=SensitiveType.CHINESE_NAME)
    private String name = "A先生";

    private JavaBeanB b;

    private Date date;

    private List<JavaBeanB> list;

    private Map<String,JavaBeanB> map;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public JavaBeanB getB() {
        return b;
    }

    public void setB(JavaBeanB b) {
        this.b = b;
    }

    public List<JavaBeanB> getList() {
        return list;
    }

    public void setList(List<JavaBeanB> list) {
        this.list = list;
    }

    public Map<String, JavaBeanB> getMap() {
        return map;
    }

    public void setMap(Map<String, JavaBeanB> map) {
        this.map = map;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

}
public class JavaBeanB {
    @SensitiveInfo(type=SensitiveType.CHINESE_NAME)
    private String name = "B先生";

    private JavaBeanA a;

    private Set<JavaBeanA> list;

    private Map<String,JavaBeanA> map;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public JavaBeanA getA() {
        return a;
    }

    public void setA(JavaBeanA a) {
        this.a = a;
    }

    public Set<JavaBeanA> getList() {
        return list;
    }

    public void setList(Set<JavaBeanA> list) {
        this.list = list;
    }

    public Map<String, JavaBeanA> getMap() {
        return map;
    }

    public void setMap(Map<String, JavaBeanA> map) {
        this.map = map;
    }
}
public class SensitiveInfoUtilsTest {

    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
     */
    @Test
    public void testChineseNameString() {
        System.out.println(SensitiveInfoUtils.chineseName("李先生"));
    }

    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
     */
    @Test
    public void testChineseNameStringString() {
        System.out.println(SensitiveInfoUtils.chineseName("李","雷"));
    }

    /**
     * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>
     */
    @Test
    public void testIdCardNum() {
        System.out.println(SensitiveInfoUtils.idCardNum("1103541983073188711"));
    }

    /**
     * [固定电话] 后四位,其他隐藏<例子:****1234>
     */
    @Test
    public void testFixedPhone() {
        System.out.println(SensitiveInfoUtils.fixedPhone("01077482277"));
    }

    /**
     * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>
     */
    @Test
    public void testMobilePhone() {
        System.out.println(SensitiveInfoUtils.mobilePhone("13777446578"));
    }

    /**
     * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
     */
    @Test
    public void testAddress() {
        System.out.println(SensitiveInfoUtils.address("北京朝阳区酒仙桥中路26号院4号楼人人大厦",8));
    }

    /**
     * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>
     */
    @Test
    public void testEmail() {
        System.out.println(SensitiveInfoUtils.email("66374777@qq.com"));
    }

    /**
     * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>
     */
    @Test
    public void testBankCard() {
        System.out.println(SensitiveInfoUtils.bankCard("6228480402565890018"));
    }

    /**
     *  [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********>
     */
    @Test
    public void testCnapsCode() {
        System.out.println(SensitiveInfoUtils.cnapsCode("102100029679"));
    }

    /**
     * 获取脱敏json串 <注意:递归引用会导致java.lang.StackOverflowError>
     */
    @Test
    public void testGetJson() {
//        ThreadPoolExecutor consumeExecutor = new ThreadPoolExecutor(30, 30 + 10, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(30 + 10), new ThreadFactory() {
//            @Override
//            public Thread newThread(Runnable r) {
//                Thread myThread = new Thread(r);
//                myThread.setName("TT");
//                return myThread;
//            }
//        }, new ThreadPoolExecutor.CallerRunsPolicy());
//        while (true) {
//            consumeExecutor.execute(new Runnable() {
//                @Override
//                public void run() {}
//            });
//        }

        JavaBeanA a1 = new JavaBeanA("","");
        JavaBeanA a2 = new JavaBeanA("","");
        JavaBeanB b1 = new JavaBeanB();
        a1.setB(b1);
//        a1.setDate(new Date());

        List<JavaBeanB> a1l = new ArrayList<JavaBeanB>();
        a1l.add(b1);
        a1.setList(a1l);
        Map<String, JavaBeanB> a1m = new HashMap<String, JavaBeanB>();
        a1m.put("b1", b1);
        a1.setMap(a1m);

        b1.setA(a2);
        Set<JavaBeanA> b1l = new HashSet<JavaBeanA>();
        b1.setList(b1l);
        Map<String, JavaBeanA> b1m = new HashMap<String, JavaBeanA>();
        b1m.put("a2", a2);
        b1.setMap(b1m);
        long t = System.currentTimeMillis();
        System.out.println(t);
        System.out.println(SensitiveInfoUtils.getJson(a1));
        System.out.println(System.currentTimeMillis()-t);
        System.out.println(JSON.toJSON(a1));
        System.out.println(System.currentTimeMillis()-t);

    }
}

测试结果:

李**
李*
***************8711
*******2277
137****6578
北京朝阳区酒仙桥中路26号********
6*******@qq.com
622848*********0018
10**********
1443435915750
{"b":{"a":{"b":null,"date":null,"list":[],"map":null,"name":"A**"},"list":[],"map":{"a2":{"b":null,"date":null,"list":[],"map":null,"name":"A**"}},"name":"B**"},"date":null,"list":[{"a":{"b":null,"date":null,"list":[],"map":null,"name":"A**"},"list":[],"map":{"a2":{"b":null,"date":null,"list":[],"map":null,"name":"A**"}},"name":"B**"}],"map":{"b1":{"a":{"b":null,"date":null,"list":[],"map":null,"name":"A**"},"list":[],"map":{"a2":{"b":null,"date":null,"list":[],"map":null,"name":"A**"}},"name":"B**"}},"name":"A**"}
289
{"b":{"a":{"name":"A先生"},"list":[],"map":{"a2":{"name":"A先生"}},"name":"B先生"},"list":[{"a":{"name":"A先生"},"list":[],"map":{"a2":{"name":"A先生"}},"name":"B先生"}],"map":{"b1":{"a":{"name":"A先生"},"list":[],"map":{"a2":{"name":"A先生"}},"name":"B先生"}},"name":"A先生"}
300

使用了google 的API,可以使用maven在添加,配置如下:

<!-- gson -->
  <dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
  </dependency>

说明:在需要脱敏的字段上使用定义好的注解,在具体的使用时用SensitiveInfoUtils.getJson(a1),如果不需要脱敏的输出,尽量不要打印JSON,使用对象的toString()输出。效率更高。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Springboot之日志、配置文件、接口数据如何脱敏

    目录 一.前言 二.配置文件如何脱敏? 1. 添加依赖 2. 配置秘钥 3. 生成加密后的数据 4. 将加密后的密文写入配置 5. 总结 三.接口返回数据如何脱敏? 1. 自定义一个Jackson注解 2. 定制脱敏策略 3. 定制JSON序列化实现 4. 定义Person类,对其数据脱敏 5. 模拟接口测试 6. 总结 四.日志文件如何数据脱敏? 1. 添加log4j2日志依赖 2. 在/resource目录下新建log4j2.xml配置 3. 自定义PatternLayout实现数据脱敏 4

  • Java利用Jackson序列化实现数据脱敏

    几天前使用了Jackson对数据的自定义序列化.突发灵感,利用此方法来简单实现接口返回数据脱敏,故写此文记录. 核心思想是利用Jackson的StdSerializer,@JsonSerialize,以及自己实现的数据脱敏过程. 使用效果如下: 首先在需要进行脱敏的VO字段上面标注相关脱敏注解 调用接口即可看到脱敏效果 实现过程如下: 1. 定义脱敏的过程实现 /** * Created by EalenXie on 2021/9/24 15:52 * 顶级的脱敏器 */ public inte

  • java 日志的数据脱敏的实现方法

    数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护.在涉及客户安全数据或者一些商业性敏感数据的情况下,在不违反系统规则条件下,对真实数据进行改造并提供测试使用,如身份证号.手机号.卡号.客户号等个人信息都需要进行数据脱敏,数据库安全技术之一. 比如我们现在有个user表,含有名字,性别,邮箱,电话号码等字段,但是当查看这些数据时,我们又不希望这些数据被暴露,这时可以对这些数据进行脱敏处理,当然可以根据需要选择哪些字段需要脱敏,然后再输出,至于怎么选择的,是另外一回事

  • Java 如何通过注解实现接口输出时数据脱敏

    目录 Java注解实现接口输出数据脱敏 先声明了一个注解 我们目前只支持对手机号 然后我们需要实现注解的拦截功能 我对默认声明和脱敏名称和手机号进行了测试 Java注解的字段脱敏处理 定义需要脱敏的字段规则 声明注解 测试 Java注解实现接口输出数据脱敏 在后台管理中,对于手机号,身份证,姓名这些数据不允许所有人都能看,这时候我们要对相对数据进行脱敏. 先声明了一个注解 通过对相关接口函数进行声明,以及配置需要脱敏的参数类型SecretTypeEnum,默认脱敏手机号 /** * 脱敏声明 *

  • java开发之基于Validator接口的SpringMVC数据校验方式

    Spring MVC 提供了两种数据校验的方式: 1.基于 Validator 接口. 2.使用 Annotation JSR - 303 标准进行校验. 基于 Validator 接口的⽅式需要自定义 Validator 验证器,每⼀条数据的验证规则需要开发者⼿动完成, 使⽤ Annotation JSR - 303 标准则不需要⾃定义验证器,通过注解的方式可以直接在实体类中添加每个属性的验证规则,这种方式更加方便,实际开发中推荐使用. 1.定义实体类Account package entit

  • Java实现调用对方http接口得到返回数据

    目录 Java 用对方http接口得到返回数据 java后台工具类调用api接口,解析数据 一 . 引入jar包 二. httpclient请求接口工具类 Java 用对方http接口得到返回数据 如图所示我们这里自己写一个接口作为访问地址,返回的是json字符串 首先我们在浏览器访问这个接口的地址,会在浏览器打印出如图所示的内容, 然后我们写一个方法访问刚刚的接口地址,使用HttpURLConnextion进行访问,通过BufferedReader获取流,已得到返回的值 运行这个方法,会在控制

  • Java的接口调用时的权限验证功能的实现

    提示:这里可以添加本文要记录的大概内容: 例如:一般系统前端调用后台相关功能接口时,需要验证此时用户的权限是否满足调用该接口的条件,因此我们需要配置相应的验证权限的功能. 提示:以下是本篇文章正文内容,下面案例可供参考 一.编写的环境 工具:IDEA 框架:GUNS框架(自带后台权限验证配置,我们这里需要编写前端权限验证配置) 二.使用步骤 1.配置前端调用的接口 代码如下(示例): 在WebSecurityConfig中: // 登录接口放开过滤 .antMatchers("/login&qu

  • 全面解析Java中的注解与注释

    注解 一.什么是 Annotation? (注解 or 注释) Annotation, 准确的翻译应该是 -- 注解. 和注释的作用完全不一样. Annotation 是JDK5.0及以后版本引入的一个特性. 与类.接口.枚举是在同一个层次,可以成为java 的一个类型. 语法是以@ 开头 简单来说, 注释是程序员对源代码的类,方法,属性等做的一些记忆或提示性描述(比如这个方法是做什么用的),是给人来看的. 注解则是Java 编译器可以理解的部分,是给编译器看的. 举个简单的例子来看一下注解的使

  • 全面剖析java中的注解(Annotation)

    1.什么是注解 用一个词就可以描述注解,那就是元数据,即一种描述数据的数据.所以,可以说注解就是源代码的元数据.比如,下面这段代码: @Override public String toString() { return "This is String Representation of current object."; } 上面的代码中,我重写了toString()方法并使用了@Override注解.但是,即使我不使用@Override注解标记代码,程序也能够正常执行.那么,该注解

  • Java中的注解和反射实例详解

    一.注解 注解(Annotation): 从jdk5.0开始引进,可以对程序进行解释或被其他程序读取. 注解格式:"@注释名",并可以添加一些参数. 例:@MyAnnotation(value='value') 1.内置注解 @override: 用于修饰方法,表示该方法声明是重写或实现一个父类的方法 @Deprecated: 用于修饰方法.属性.类,表示已过时不建议使用的 @SuppressWarnings: 用于抑制编译时的警告信息 2.元注解 作用:用于注解其他注解 @Targe

  • SpringBoot如何使用自定义注解实现接口限流

    目录 使用自定义注解实现接口限流 1.自定义限流注解 2.限流类型枚举类 3.限流 Lua 脚本 4.限流切面处理类 5.使用与测试 SpringBoot工程中限流方式 1.google的guava,令牌桶算法实现限流 2.interceptor+redis根据注解限流 使用自定义注解实现接口限流 在高并发系统中,保护系统的三种方式分别为:缓存,降级和限流. 限流的目的是通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统,一旦达到限制速率则可以拒绝服务.排队或等待. 1.

  • Java特性之注解和异常 Throwable

    目录 注解 作用 注解的常见分类 异常 Java异常类层次结构 可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)区别 throw和throws的区别? Java 7 的 try-with-resource? 异常的底层? 反射 什么是反射? 反射的使用 getName.getCanonicalName与getSimpleName的区别? 注解 作用 注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包.类.接口.字段.

  • 详解Java中自定义注解的使用

    目录 什么是注解 注解的注意事项 注解的本质 自定义注解使用 使用方式 1 使用方式 2 什么是注解 在早期的工作的时候 ,自定义注解写的比较多,可大多都只是因为 这样看起来 不会存在一堆代码耦合在一起的情况,所以使用了自定义注解,这样看起来清晰些, Annontation是Java5开始引入的新特征,中文名称叫注解. 它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类.方法.成员变量等)进行关联.为程序的元素(类.方法.成员变量)加上更直观.更明了的说

随机推荐