Spring AOP使用案例

Spring AOP使用案例,第1张

Spring AOP使用案例 AOP 原理

代理模式。

需求背景

返回前端的用户信息包含手机号等敏感内容,并在系统上已经有大量接口。现拿到需求,需要在返回前端的对象中,找到手机号的属性并将手机号加密
现状:
分散在各处的接口中都有手机号需要加密。
不同对象里对手机号命名可能不同,如 String number ; String phone。
思路:
按接口逐个添加加密逻辑过于繁琐,不利后续维护。
考虑创建一个Util类但不好兼容不同用户信息对象的类型,且属性名称也不统一。
考虑使用自定义注解+代理模式,即AOP思想

伪代码 创建自定义注解
@Target(ElementType.METHOD) // 定义注解的作用目标**作用范围字段、枚举的常量/方法
@Retention(RetentionPolicy.RUNTIME) // RUNTIME:运行时可以获取相关属性。
@documented // 说明该注解将被包含在javadoc中
public @interface PhoneAccess {

    
    String phoneFiled() default "phone";

    
    String phoneResource() default "phoneAccessBtn";
}

自定义注解创建后,虽然可以在系统任意方法上使用@PhoneAccess,但没有具体意义。

创建Aspect
  • 使用@Aspect标记这是一个Aspect类
  • 使用@Around("@annotation(pa)") 对注解刚刚创建的自定义注解:@PhoneAccess 环绕通知
  • 方法需要传入 ProceedingJoinPoint point, PhoneAccess pa 。
  1. 利用 point.proceed(); 先执行被代理的目标函数
  2. PhoneAccess pa 将被代理的目标函数上的对象信息传入,再做加密
@Aspect // 使用@Aspect标记这是一个Aspect
@Component
public class PhoneAspect {
    private final Logger logger = LoggerFactory.getLogger(PhoneAspect.class);

    private static ObjectMapper mapper = new ObjectMapper();
    
    @Around("@annotation(pa)") // 对注解:@PhoneAccess 环绕通知
    public Object serviceLog(ProceedingJoinPoint point, PhoneAccess pa) throws Throwable {
        Object result = point.proceed(); // 执行目标函数
        // 代理的内容
        if(ObjectUtils.isEmpty(result)){
            return result;
        }
        if(ObjectUtils.isEmpty(pa)){
            return result;
        }
        Map map = mapper.readValue(mapper.writevalueAsString(result), Map.class);

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession s = request.getSession();
        if(ObjectUtils.isEmpty(s)){
            return result;
        }
        Object o = s.getAttribute(UnifiedProfileConstants.UNIFIED_PROFILE);
        UnifiedProfile unifiedProfile = (UnifiedProfile)o;
        List buttonResourceList = unifiedProfile.getButtonList();
        if(ObjectUtils.isEmpty(buttonResourceList)){
            return result;
        }

        //判断是否资源权限
        Boolean hasAccess = hasPhoneAccess(buttonResourceList, pa.phoneResource());
        if(hasAccess){
            return result;
        }

        //遮盖电话号码
        recursiveAnalysis(map, pa.phoneFiled(), hasAccess);
        Object newResult = null;
        try {
            newResult = mapper.readValue(mapper.writevalueAsString(map), result.getClass());
        } catch (Exception e) {
            e.printStackTrace();
            return result;
        }
        return newResult;
    }

   


 private Boolean hasPhoneAccess(List buttonResources, String phoneResource) {
        Boolean hasAccess = Boolean.FALSE;
        if(!ObjectUtils.isEmpty(buttonResources)){
            for(ButtonResource br: buttonResources){
                if(br.getKey().equals(phoneResource)){
                    hasAccess = br.getHasAccess();
                }
            }
        }
        return hasAccess;
    }

    public static void recursiveAnalysis(Object m, String fieldName, Boolean hasAccess){
        Map mp = null;
        if(m instanceof Map || m instanceof linkedHashMap){
            mp = (linkedHashMap)m;
            for(Iterator ite = mp.entrySet().iterator(); ite.hasNext();){
                Map.Entry e = (Map.Entry) ite.next();

                if(e.getValue() instanceof String){
                    if(!ObjectUtils.isEmpty(e.getValue()) && e.getValue().toString().length() == 11){
                        if(!hasAccess && e.getKey().equals(fieldName)){
                            String str = "****";
                            StringBuilder sb = new StringBuilder(e.getValue().toString());
                            sb.replace(3, 7, str);
                            e.setValue(sb.toString());
                        }
                    }
                }else if(e.getValue() instanceof linkedHashMap){
                    recursiveAnalysis((linkedHashMap)e.getValue(), fieldName, hasAccess);
                }else if(e.getValue() instanceof ArrayList){
                    recursiveAnalysis((ArrayList)e.getValue(), fieldName, hasAccess);
                }
            }
        }

        List ls = null;
        if(m instanceof List || m instanceof ArrayList){
            ls = (ArrayList)m;
            for(int i=0;i 
自此 

可以在任意需要加密处理的接口打上注解@PhoneAccess,指定当前返回值中存放手机号的属性名,就能完成加密。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5661439.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存