java反射高级用列(脱敏+aop)

ClassUtils 、FieldUtils、MethodUtils、ReflectionUtils高级

List<String> list = new ArrayList<>();
Class<?> userClass = ClassUtils.getUserClass(list.getClass());
System.out.println(Collection.class.isAssignableFrom(userClass));
Class<?> clazz = Class.forName("com.sd.entity.User");
Object instance = clazz.getDeclaredConstructor().newInstance();
BeanUtils.populate(clazz, map);
instanceof

ReflectionUtils.doWithFields(MyClass.class, field -> {
    // 对每个字段执行操作
});

ReflectionUtils.doWithMethods(MyClass.class, method -> {
    // 对每个方法执行操作
});

ReflectionUtils.doWithFields(MyClass.class, field -> {
    // 对每个带有特定注解的字段执行操作
}, field -> field.isAnnotationPresent(MyAnnotation.class));

ReflectionUtils.doWithMethods(MyClass.class, method -> {
    // 对每个带有特定注解的方法执行操作
}, method -> method.isAnnotationPresent(MyAnnotation.class));

   //获取类的所有带有特定注解的字段
List<Field> fields = FieldUtils.getFieldsListWithAnnotation(MyClass.class, MyAnnotation.class);

    //获取字段值
Field field = ReflectionUtils.findField(MyClass.class, "myField");
Object fieldValue = ReflectionUtils.getField(field, myClassInstance);
    //读取字段值(忽略访问修饰符)
Object fieldValue = FieldUtils.readField(field, myClassInstance, true);//readStaticField读取静态值

   //设置字段值
Field field = ReflectionUtils.findField(MyClass.class, "myField");//字段名称
ReflectionUtils.setField(field, myClassInstance, "newValue");
FieldUtils.writeField(field, myClassInstance, "newValue", true);

实列

作用域方法上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveData {
}
作用域字段
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveInfo {
    Type value() default Type.DEFAULT;

    enum Type {
        PHONE_NUMBER,
        ID_CARD,
        DEFAULT
    }
}



package com.sd.config;

import java.lang.reflect.Field;
import java.util.Collection;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import com.sd.annotation.SensitiveInfo;

@Aspect
@Component
public class SensitiveInfoAOP {

    //针对所有controller不能够限制方法行为。包含以下注解进行脱敏@ResponseBody/@RestController
	//第一种
	//@Around("execution(* com.sd.controller.*.*(..)) && (@annotation(org.springframework.web.bind.annotation.ResponseBody) || @within(org.springframework.web.bind.annotation.RestController))")
    //第二种
    //灵活限制脱敏行为
    @Around("execution(* com.sd.controller.*.*(..)) && @annotation(com.sd.annotation.SensitiveData)")
    public Object processSensitiveInfo(ProceedingJoinPoint pjp) throws Throwable {
        Object result = pjp.proceed();

        handleSensitiveFields(result);

        return result;
    }

    private void handleSensitiveFields(Object target) {
        if (target instanceof Collection) {
            for (Object item : (Collection<?>) target) {
                handleSingleSensitiveItem(item);
            }
        } else if (target instanceof Map) {
            handleSensitiveMap((Map<?, ?>) target);
        //针对对象    
        } else {
            handleSingleSensitiveFields(target);
        }
    }

    private void handleSensitiveMap(Map<?, ?> mapTarget) {
        for (Map.Entry<?, ?> entry : mapTarget.entrySet()) {
            handleSensitiveField(entry,entry.getValue());
        }
    }
                 
    private void handleSensitiveField(Entry<?, ?> entry,Object value) {
        if (value instanceof String) {
            maskSensitiveString((String) value);
        } else if (value instanceof Map) {
            handleSensitiveMap((Map<?, ?>) value);
        } else if (value instanceof Collection) {
            handleSensitiveFields(value);
        } else if (value != null) {
            Class<?> clazz = value.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                SensitiveInfo annotation = field.getAnnotation(SensitiveInfo.class);
                if(annotation!=null) {
                	maskSensitiveField(field, value);
                }
            }
        }
    }


    private void maskSensitiveField(Field field, Object target) {
        try {
            Object fieldValue = ReflectionUtils.getField(field, target);
            if (fieldValue instanceof String) {
                String originalValue = (String) fieldValue;
                String maskedValue = maskSensitiveString(originalValue);
                ReflectionUtils.setField(field, target, maskedValue);
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to mask sensitive data", e);
        }
    }

    private void handleSingleSensitiveFields(Object target) {
        ReflectionUtils.doWithFields(target.getClass(), field -> {
            if (!"serialVersionUID".equals(field.getName())) { // 跳过 serialVersionUID 字段
                field.setAccessible(true);
                SensitiveInfo annotation = field.getAnnotation(SensitiveInfo.class);
                if(annotation!=null) {
                switch (annotation.value()) {
                     case PHONE_NUMBER: 
                         maskPhoneNumber(field, target);
                         break;
                     case ID_CARD:
                         break;
                 }	
                //Object fieldValue = ReflectionUtils.getField(field, target);
                maskSensitiveField(field, target);
                }
            }
        });
    }

    private void handleSingleSensitiveItem(Object item) {
        handleSensitiveFields(item);
    }

    // 脱敏逻辑(例如手机号和身份证号)
    private void maskPhoneNumber(Field field, Object target) throws IllegalAccessException {
        // 实现手机号脱敏逻辑
    	Object fieldValue = FieldUtils.readField(field, target, true);
        ReflectionUtils.setField(field, target, fieldValue+"_"+0123);
    }
    
    // 脱敏逻辑(例如手机号和身份证号)
    private String maskSensitiveString(String sensitiveStr) {
        // 这里实现具体的字符串脱敏逻辑
        // ...
        return sensitiveStr; // 返回脱敏后的字符串
    }
    
}


实体
@SensitiveInfo(Type.PHONE_NUMBER)
private String phone; 

controller
@GetMapping("/test")
//@SensitiveData此注解是灵活脱敏部分controller类中的方法。上述aop中有两种方式不加就是第一种
//脱敏的过程是针对返回对象,Aop进行反射得到详细类进行特定注解字段进行脱敏
public Object getDataSend(){
	User i=new User();
	i.setPhone(password);
	return i;
}

@GetMapping("/test")
@SensitiveData
public Object getDataSend(){
	List<Object> l=new ArrayList<>();
	User i=new User();
	i.setPhone(password);
	l.add(i);
	return l;
}

FastJson消息转换脱敏配置

@SensitiveInfo(Type.PHONE_NUMBER)
private String phone;
package com.sd.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    // 创建一个用于脱敏的ValueFilter
    public static class SensitiveInfoValueFilter implements ValueFilter {
        @Override
        public Object process(Object obj, String s, Object value) {
            try {
				Field field = obj.getClass().getDeclaredField(name);
				SensitiveInfo desensitization;
	            if (String.class != field.getType() || (desensitization = field.getAnnotation(SensitiveInfo.class)) == null) {
	                return value;
	            }
	            String valueStr = (String) value;
	            Type type = desensitization.value();
	            switch (type) {
	            case PHONE_NUMBER:
	            	String encrypted = Base64.getEncoder().encodeToString(valueStr.getBytes(StandardCharsets.UTF_8));
	                return encrypted;
	            default:
	            }
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			}
			return value;
        }

        private boolean isPhoneNumber(String str) {
            // 校验手机号码规则...
            return true; // 示例返回true,实际应替换为正则匹配或其他验证逻辑
        }

        private String desensitizePhone(String phone) {
            // 脱敏处理手机号码...
            return phone.substring(0, 3) + "****" + phone.substring(7);
        }

        private boolean isIdCardNumber(String str) {
            // 校验身份证号码规则...
            return true; // 示例返回true,实际应替换为正则匹配或其他验证逻辑
        }

        private String desensitizeIdCard(String idCard) {
            // 脱敏处理身份证号码...
            return idCard.replaceAll("(?<=\\d{4})\\d(?=\\d{10})", "*");
        }
    }

    //以下是全局配置只要响应为JSON如@GetMapping它会进入SensitiveInfoValueFilter
    //也可以把下列全部注释在controller中配置需要进行转换脱敏的方法即可
    //使用参考controller
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();

        // 设置全局配置,例如:序列化特性、日期格式等
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue);
        
        // 添加自定义脱敏过滤器
        fastJsonConfig.setSerializeFilters(new SensitiveInfoValueFilter());

        List<MediaType> supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        fastJsonConverter.setSupportedMediaTypes(supportedMediaTypes);

        fastJsonConverter.setFastJsonConfig(fastJsonConfig);

        // 将FastJson转换器添加到消息转换器列表的最前面
        converters.add(0, fastJsonConverter);
    }

    // 或者通过@Bean的方式注册FastJsonHttpMessageConverter
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        FastJsonConfig fastJsonConfig = getFastJsonConfig();
        FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
        fastJsonConverter.setFastJsonConfig(fastJsonConfig);
        return new HttpMessageConverters(fastJsonConverter);
    }

    private FastJsonConfig getFastJsonConfig() {
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue);
        config.setSerializeFilters(new SensitiveInfoValueFilter());
        return config;
    }
}

controller不注释全局使用如下

@GetMapping

@RequestMapping
@ResponseBody

注释局部定义使用

@RequestMapping("/test")
@ResponseBody
SerializeConfig serializeConfig = new SerializeConfig();
serializeConfig.addFilter(User.class, new SensitiveInfoValueFilter());
Map<String, Object> userMap = JSON.parseObject(JSON.toJSONString(user, serializeConfig), Map.class);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有知识的山巅

文章对你有用,学到了知识。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值