动态切面

简介: `AdviceConfiguration` 类用于动态注册一个基于 AspectJ 的切面顾问,该顾问通过 `@ConditionalOnExpression` 注解控制是否生效。配置中包含一个从 Apollo 获取的 JSON 值,用于构建方法拦截器的切入点表达式,涉及特定包和类。拦截器 `ControllerAdvice` 实现了 `MethodInterceptor`,用于记录请求日志,包括 URL、参数和执行时间,同时根据配置决定是否对返回结果进行加密。
package integration.configuration;

import cn.hutool.core.collection.CollUtil;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import integration.advice.ControllerAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 动态注入需要切面的类
 * 没什么卵用
 */
@Configuration
public class AdviceConfiguration {

    private String expression;

    [
        {
            "package": "com.xx.xx.xxxxxx.xxxxxxx.controller",
            "class": [
                "XXXXXXXController",
                "XXXXXXXXController"
            ]
        }
    ]
    
    @ApolloJsonValue("${advice.expression:}")
    private void setExpression(List<Map<String, Object>> value) {
        if (CollUtil.isEmpty(value)) return;
        StringBuilder sb = new StringBuilder();
        for (Map<String, Object> item : value) {
            List<String> clazz = (List<String>) item.get("class");
            for (String s : clazz) {
                sb.append("execution(* ");
                sb.append(item.get("package")).append(".");
                sb.append(s);
                sb.append(".*(..)) || ");
            }
        }
        expression = sb.substring(0, sb.length() - 4);
    }

    private final Map<String, Boolean> aa = new HashMap<>();

    @Bean
    @ConditionalOnExpression("${advice.switch:false}")
    public AspectJExpressionPointcutAdvisor config() {
        AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
        advisor.setExpression(expression);
        advisor.setAdvice(new ControllerAdvice());
        return advisor;
    }

}

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import integration.util.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 这俩配合着用
*/
public class ControllerAdvice implements MethodInterceptor {
    
    @Value("${isPrd:false}")
    private boolean isEncryption;

    private final ObjectMapper objectMapper = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        long start = System.currentTimeMillis();
        String requestUrl = getRequestUrl();
        Map<String, String> headers = LoginUtil.getHeaders();
        Object[] args = invocation.getArguments();
        log.info("Controller.LogAspect url:{} headers:{}, param:{} ", requestUrl, headers, printObj(args));
        Object result = invocation.proceed();
        log.info("Controller.LogAspect url:{} cost:{}ms result:{} ", requestUrl, System.currentTimeMillis() - start, printObj(result));
        return result;
    }

    private String getRequestUrl(){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes == null ? "" : attributes.getRequest().getRequestURI();
    }

    private Object printObj(Object o){
        try {
            return isEncryption ? Base64.getEncoder().encodeToString(objectMapper.writeValueAsBytes(o)) : o;
        } catch (JsonProcessingException e) {
            return e.getMessage();
        }
    }
}
相关文章
|
NoSQL Redis Docker
Mac下Docker安装Redis
Mac下Docker安装Redis
1258 0
|
域名解析 安全 应用服务中间件
手把手教你安装WordPress详细教程(图文)
如果还有不了解宝塔面板怎么使用的小伙伴,可以看下我总结的系列教程,保证从新手变老鸟:
1735 0
手把手教你安装WordPress详细教程(图文)
|
12月前
|
JavaScript 前端开发 物联网
Node.js
Node.js:将JavaScript从浏览器带入服务端的革命性运行时,凭借事件驱动、非阻塞I/O模型,重塑高性能服务器开发。它打破全栈壁垒,催生庞大生态,推动实时应用与微服务发展,成为连接过去与未来的技术桥梁。(238字)
954 137
|
12月前
|
监控 安全 算法
137_安全强化:输入过滤与水印 - 实现输出水印的检测算法与LLM安全防护最佳实践
随着大语言模型(LLM)在各行业的广泛应用,安全问题日益凸显。从提示注入攻击到恶意输出生成,从知识产权保护到内容溯源,LLM安全已成为部署和应用过程中不可忽视的关键环节。在2025年的LLM技术生态中,输入过滤和输出水印已成为两大核心安全技术,它们共同构建了LLM服务的安全防护体系。
965 148
|
存储 人工智能 自然语言处理
RAG:为大语言模型注入知识的力量
RAG:为大语言模型注入知识的力量
765 100
|
机器学习/深度学习 存储 人工智能
AI职场突围战:夸克应用+生成式人工智能认证,驱动“打工人”核心竞争力!
在AI浪潮推动下,生成式人工智能(GAI)成为职场必备工具。文中对比了夸克、豆包、DeepSeek和元宝四大AI应用,夸克以“超级入口”定位脱颖而出。同时,GAI认证为职场人士提供系统学习平台,与夸克结合助力职业发展。文章还探讨了职场人士如何通过加强学习、关注技术趋势及培养合规意识,在AI时代把握机遇。
|
人工智能 算法 架构师
GEO技术讲师哪个靠谱?谁有实力?
AI推荐常陷“声量陷阱”,难辨真伪专家。识别靠谱技术讲师需三重考验:深研认知逻辑、构建系统架构、通过商业实战。
|
IDE API 开发工具
Gleam
Gleam 是面向 Erlang 虚拟机的类型化语言,Gleam 的语法对于类型化语言来说非常优雅和简单。如果能看到 Gleam 像 Elixir 一样成功,那就太酷了。
1175 4
|
安全 程序员 云计算
程序员知识体系探索:点、线、面、体(上)
程序员知识体系探索:点、线、面、体(上)
835 0
程序员知识体系探索:点、线、面、体(上)
|
测试技术 数据库 Android开发
深入解析Android架构组件——Jetpack的使用与实践
本文旨在探讨谷歌推出的Android架构组件——Jetpack,在现代Android开发中的应用。Jetpack作为一系列库和工具的集合,旨在帮助开发者更轻松地编写出健壮、可维护且性能优异的应用。通过详细解析各个组件如Lifecycle、ViewModel、LiveData等,我们将了解其原理和使用场景,并结合实例展示如何在实际项目中应用这些组件,提升开发效率和应用质量。
743 6

热门文章

最新文章