46. 从零开始学springboot: spel结合aop实现动态传参

SpringBoot SpEL表达式(五十二) 1. jep的使用 2. SpEL的各种用法 阅读详情

前言

基于SpingBoot框架中, 我们随处可以见的便是各种各样的功能注解, 注解的实现原理AOP之前有说过(翻看本系列的前面几章即可), 这里不过多赘述.

那么, 你有没有碰到这样一种场景: 需要动态的传参数进注解, 注意是动态的而不是写死在代码里的.

针对这种需求, 今天, 我们就来实现一个简单的案例.

SpEl表达式简介

正式撸代码之前, 先了解下SpEl (Spring Expression Language) 表达式, 这是Spring框架中的一个利器.

Spring通过SpEl能在运行时构建复杂表达式、存取对象属性、对象方法调用等等.

举个简单的例子方便理解, 如下

//定义了一个表达式
String expressionStr = "1+1";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(expressionStr);
Integer val = expression.getValue(Integer.class);
System.out.println(expressionStr + "的结果是:" + val);

通过以上案例, 不难理解, 所谓的SpEl, 本质上其实就是解析表达式,.

关于SpEl表达式感兴趣的可以自行查阅资料, 本篇不做细致的讨论.

实例: SpEl结合AOP动态传参

简单了解了SpEl表达式, 那么接下来我们就直接开始撸代码.

先引入必要的pom依赖, 其实只有aop依赖, SpEl本身就被Spring支持, 所以无需额外引入.

<dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

定义一个SpEl的工具类SpelUtil

public class SpelUtil {

    /**
     * 用于SpEL表达式解析.
     */
    private static final SpelExpressionParser parser = new SpelExpressionParser();

    /**
     * 用于获取方法参数定义名字.
     */
    private static final DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

    /**
     * 解析SpEL表达式
     *
     * @param spELStr
     * @param joinPoint
     * @return
     */
    public static String generateKeyBySpEL(String spELStr, ProceedingJoinPoint joinPoint) {
        // 通过joinPoint获取被注解方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 使用Spring的DefaultParameterNameDiscoverer获取方法形参名数组
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        // 解析过后的Spring表达式对象
        Expression expression = parser.parseExpression(spELStr);
        // Spring的表达式上下文对象
        EvaluationContext context = new StandardEvaluationContext();
        // 通过joinPoint获取被注解方法的形参
        Object[] args = joinPoint.getArgs();
        // 给上下文赋值
        for (int i = 0; i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        // 表达式从上下文中计算出实际参数值
        /*如:
            @annotation(key="#user.name")
            method(User user)
             那么就可以解析出方法形参的某属性值,return “xiaoming”;
          */
        return expression.getValue(context).toString();
    }
}

定义一个带参注解SpelGetParm

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SpelGetParm {

    String parm() default "";
    
}

定义带参注解SpelGetParmAop

@Aspect
@Slf4j
@Component
public class SpelGetParmAop {

    @PostConstruct
    public void init() {
        log.info("SpelGetParm init ......");
    }
    /**
     * 拦截加了SpelGetParm注解的方法请求
     *
     * @param joinPoint
     * @param spelGetParm
     * @return
     * @throws Throwable
     */
    @Around("@annotation(spelGetParm)")
    public Object beforeInvoce(ProceedingJoinPoint joinPoint, SpelGetParm spelGetParm) throws Throwable {
        Object result = null;
        // 方法名
        String methodName = joinPoint.getSignature().getName();
        //获取动态参数
        String parm = SpelUtil.generateKeyBySpEL(spelGetParm.parm(), joinPoint);
        log.info("spel获取动态aop参数: {}", parm);
        try {
            log.info("执行目标方法: {} ==>>开始......", methodName);
            result = joinPoint.proceed();
            log.info("执行目标方法: {} ==>>结束......", methodName);
            // 返回通知
            log.info("目标方法 " + methodName + " 执行结果 " + result);
        } finally {

        }
        // 后置通知
        log.info("目标方法 " + methodName + " 结束");
        return result;
    }

以上已经基本实现了案例的核心功能, 接下来我们使用该注解即可

定义一个实体User

@Getter
@Setter
@NoArgsConstructor
@JsonSerialize
@JsonInclude(Include.NON_NULL)
public class User implements Serializable {
    private static final long serialVersionUID = -7229987827039544092L;

    private String name;
    private Long id;

}

我们在UserController直接使用该带参注解即可

@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping("/param")
    @SpelGetParm(parm = "#user.name")
    public R repeat(@RequestBody User user) {
        return R.success(user);
    }
}

最后请求
image.png
image.png

可以看出, 切面成功获取到了实体的name值“张三”.

小结

结合SpEl表达式可以实现各种“骚操作”, 各位大佬可自由发挥, 下面一章我们准备结合SpEl来实现分布式锁的功能.

项目地址

https://github.com/MrCoderStack/SpringBootDemo/tree/master/sb-spel-annotations

请关注我的订阅号

订阅号.png

【SpringBoot3】SpEL表达式详细使用说明 SpEL(Spring Expression Language)是Spring框架提供的一种功能强大的表达式语言,用于在运行时查询和操作对象。 主要特点和用途包括: 1. 简洁性:SpEL表达式使用简洁的语法,使得在Spring配置和代码中能够更简洁地表达复杂的逻辑。 2. 动态性:SpEL表达式能够在运行时动态地解析和执行,从而提供了更大的灵活性。 3. 强大的功能:SpEL表达式支持各种功能,如方法调用、字符串模板、集合操作、逻辑运算等,使得在Spring配置和代码中能够完成复杂的逻辑处理。 阅读详情

相关推荐

Springboot - AOP 中使用spel 表达式解析

文章目录Springboot - AOP 中使用spel 表达式解析1、什么是SpEL2、引入依赖3、开启AOP ,注册组件4、构建一个切入注解5、编写切面5、简单示例使用 Springboot - AOP 中使用spel 表达式解析 1、什么是SpEL 参考: 2、引入依赖 <dependency> <groupId>org.sp...

简简单单Onlinezuozuo 7795

SpringBoot如何解析注解里的动态参数?

如果我们需要在注解中动态的传入参数,例如在加锁的操作中,需要根据方法的入参动态的传入userId作为lock的key,这个动态参数在aspect类中应该如何解析出来呢?答案是利用SpEL表达式实现。

weixin_45712835的博客 3474

Halcon Camera-calibration 相关算子(一)

Halcon Camera-calibration 相关算子介绍

qq_44744164的博客 1365

自定义注解中使用SpEL表达式,动态获取方法参数或执行方法

获取变量的功能,比较常见的用法是spring中缓存注解的功能。可以动态获取方法中参数的值。如下: 1.2 执行方法 这个例子用过spring security的或者类似的授权框架的可能比较熟悉。如下 这里其实就是通过表达式去执行某个类的hasRole方法,参数为’ROLE_ADMIN’,然后获得返回值再进行后续操作。表达式不仅支持获取属性和执行方法,还支持各种运算符操作,能查到很多其他大神写的。这里就不写了写demo之前先简单介绍一下执行表达式时比较重要的几个类 最后获得的value就是传入的值,这个dem

weixin_42645678的博客 1万+

ST7102驱动移植与调试实战

本文详细介绍了在君正T40平台上移植和调试ST7102 LCD驱动芯片的实战经验。内容涵盖硬件接口配置、时序参数调整、寄存器初始化序列编写及常见问题解决,重点解析了ST7102单芯片集成显示与触控功能的特性,为嵌入式设备显示驱动开发提供实用指南。

k6l7m8n9的博客 1406

【护网行动-红蓝攻防】第一章-红蓝对抗基础 认识红蓝紫

军事上的演练,是除了实战以外最能检验军队战斗力的一种考核方式,他可以模拟面对外部势力的攻击时候,如何更好的去维护国家和主权的安全。同样的,在网络上面,真实环境下的网络攻防演练也是检验一个单位,企业网络防御能力,发现潜在危险最好的方法。1.政策要求2安全威胁驱动当前,我国关键信息基础设施面临的网络安全形势严峻复杂,网站平台大规模数据泄露事件频发,生产业务系统安全隐患突出,甚至有的系统长期被控面对高级持续性的网络攻击,防护能力十分欠缺。目前,我国面临的网络安全威胁主要有以下几点。

wxh的博客 1571

自定义注解使用SPEL表达式来动态获取方法传参

如果是对象参数,@DataAuth(spaceName = "#graphShowAttribute.space")要实现的是 动态入参,也就是在使用自定义注解的时候 ,写入的是字符串,并非一个传入参数值。如果是单个参数,@DataAuth(spaceName = "#space"),每次接口参数变化,我都想将这个参数传入自定义的注解中用以校验;这里的spaceName 并非一个固定字符串,而是一个路径参数。

奋斗男孩的博客 3754

ray.tune调参学习笔记0:调参基本流程

本篇总结python中使用tune调参的整体流程

Mr_111000的专栏 2621

【SpringBoot应用篇】【AOP+注解】SpringBoot+SpEL表达式基于注解实现权限控制

Spring 表达式语言最初是为 Spring 社区创建的,它拥有一种受良好支持的表达式语言,可用于 Spring 产品组合中的所有产品。虽然 SpEL 是 Spring 产品组合中表达式评估的基础,但它不直接与 Spring 绑定,可以独立使用。Spring 表达式语言 SpEL 是一种非常强大的表达式语言,它支持在运行时查询和操作对象图。它提供了许多高级功能,例如方法调用和基本的字符串模板功能。注解的支持就是使用SpEL表达式实现的权限控制。Spring Security框架中启用。

输入技术、输出想法 4140

FUXA实战:5步搞定基于Web的SCADA系统搭建(含Node.js版本避坑指南)

本文提供了一份基于开源工具FUXA搭建Web版SCADA系统的实战指南。文章重点解析了从环境准备到生产部署的五个核心步骤,并特别强调了Node.js版本选择对西门子S7 PLC通信兼容性的关键影响,帮助开发者避开常见陷阱,快速构建工业监控界面。

weixin_29172963的博客 138

拆解一个800G光模块:手把手带你认识里面的MT插芯和光纤阵列(FA)

本文详细拆解了800G光模块中的关键组件MT插芯和光纤阵列(FA),揭示了并行光学技术如何实现高速数据传输。通过显微镜下的精密观察,展示了MT插芯的高精度构造和光纤阵列的连接奥秘,同时解析了高精度研磨工艺对光信号传输的重要性。这些微型组件是高速收发模块实现800Gbps带宽的核心技术。

weixin_30839881的博客 1540

基于AOP+SPEL 自定义日志组件

基于AOP,SPEL,实现注解日志组件

谭宁邦 4257

夏令营纪实——东南大学计科院&PALM实验室面试全解析

本文详细解析了东南大学计科院与PALM实验室夏令营的面试全流程,包括前期准备、技术考察、项目经验深挖等关键环节。特别针对自然语言处理(NLP)和机器学习(ML)领域的高频问题提供应对策略,帮助申请者提升面试表现。文章还分享了实用的准备技巧和面试经验,为有意向参加该夏令营的学生提供宝贵参考。

convnet3designer的博客 459

AOP支持spEL表达式

aop支持spel表达式

dark 1033

Ubuntu20.04安装Eigen3.3.7、模板类Sophus和Ceres

Sophus的使用必须依赖3.3以上的Eigen版本。如果版本太低,Sophus库将无法安装使用。

qq_62964142的博客 3422

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Spring Spel表达式动态计算

假如数据库查询出来的结果保存在Map中 如微博账号的查询结果 Map<String,Integer> map = new HashMap<>(); map.put("reposts_count",10); map.put("comments_count",12); map.put("praises_count",3); map.put("post_count",5); ...

hello_v_world的博客 3123

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

AOP+SpEL实现日志记录

大家先思考一个问题,缓存注解和日志注解上#后面跟的动态参数是怎么解析出来的 方法上缓存注解 @Cached(name = "cktest", key = "#sjzxDbname + #sjzxTable", cacheType = CacheType.LOCAL, expire = Integer.MAX_VALUE, localLimit = 1500) 方法上日志注解 @CkOperatedLog(module = "test", operation = "find", description =

ke7025的博客 987

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Springboot 实现注解的参数值可以动态设置

一般来说,注解只能配置常量,在一些构架的开发中,有时候我们需要给注解动态配置一些值,或者想从配置文件中读取配置。直接在注解上配置是无法实现的,但是我们可以在拿到注解的值之后,再对这些值进行...

qq_18244417的博客 2万+

springBoot,AOP切面实现日志记录,自定义注解,注解属性动态传参

SpringBoot,AOP切面实现日志记录,自定义注解,注解属性动态传参 项目需求: 需要记录用户的操作具体的方法,记录当前具体操作的是哪一条数据信息,作为参数也一并保存起来。 如:更新数据,IP,电脑号,调用方法,类型为修改,及这条更新的数据具体信息。 用SpringAOP + Annotation来实现 自定义aop注解类,通用日志文件 import java.lang.annotation.*; /****************************** * 用途说明: 通用日志文件

weixin_43931918的博客 3753

自定义注解支持SpEL表达式(动态参数)

实际生产中一个案例:利用AOP生成用户操作日志代码直接复制过去就可以测试,亲测可用 2.定义spel解析工具类 3.定义切面类 4.方法上使用日志注解

zhangkaixuan456的博客 3394

SpringBoot 自定义注解 + AOP 实现日志保存&使用SPEL表达式绑定动态变量参数值实现自定义注解动态参数传递

SpringBoot 自定义注解 + AOP 实现日志保存& 使用SPEL表达式绑定动态变量参数值实现自定义注解动态参数传递目标,创建一个方法注解,我们在执行方法时,并可以给该方法的参数值动态传递给注解。 由于业务需要,需要在自定义注解中将参数中的值传入到注解的指定属性中,这很容易让我联想到 Spring 的 SpEL. 虽然根据反射也能得到相同结果,但是有更好的工具为什么不用呢?因此根据网上大神的攻略,整合出自定义注解伪动态传递参数的 SpEL 使用.

无间行者 3118

Spring(SpringBoot) SpEl介绍

EL表达式大家也许都听说过,但是用Spring作为脚手架的我们,经常在用SpEl表达式,但你真的了解SpEl吗?本文将带你分析学习SpEl表达式

杨海吉 3710

Spel实现自定义注解获取动态入参

开给c端的接口需要鉴权,这里入参的格式种类繁多,但是最终需要的是拿到一个id,当然只有封装入参VO的人才知道哪个字段对应id。所以需要实现的功能就是在切面上由对应的方法传入不同的VO里命名不一样的 “id”。如果是固定字段直接在注解上给固定值就好,这里针对那种需要从入参VO对象进行取值的情况。tips:这里同时定义了一个字段,用于后续传参。同时需要定一个advice类,来对切面进行增强。注意这里的spel表达式要跟入参的参数名相同。这样就可以在注解里动态读取到对应的入参啦。

技术杂货铺 2363

Spring Boot集成SpEL快速入门demo

Spring Expression Language(简称 SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于 Unified EL,但提供了额外的特性,最显著的是方法调用和基本的字符串模板功能。下面是一些常见的例子,更多的可以去官网看详细的文档,这里只给一个基本的入门。访问 properties, arrays, lists, maps。实验目标:实现属性注入文件,lis和进行逻辑运算。以上只是一些关键代码,所有代码请参见下面代码仓库。读取属性文件,然后表达式注入list。

HBLOG 802

Spring Aop中解析spel表达式,实现更灵活的功能

前言 在Spring Aop中,我们可以拿到拦截方法的参数,如果能结合spel表达式,就能实现更加灵活的功能。典型的实现有Spring的缓存注解: @Cacheable(value = "user", key = "#id", condition = "#id lt 10") public User conditionFindById(final Long id) { } 复制代码@Caching...

weixin_34377065的博客 4432

基于SpEL的SpringBoot含有动态参数的日志记录与管理的实现

一、功能介绍 在SpringBoot的项目应用中,常常需要记录日志到数据库中,例如系统访问日志(登录日志)、用户操作日志等,日志文本中需要含有动态的参数(发送http请求的请求参数),此情景下,可基于Spring Expression Language的动态日志信息记录功能。 二、需求场景 场景需求如下: package com.tang.demo.controller; import javax.validation.Valid; import org.springframework.validati

IT- 研究者 1290
上一篇: 摸鱼JVM -运行时数据区
下一篇: 47. 从零开始学springboot: spel结合redisson实现动态参数分布式锁
码哥说
博客等级 码龄8年 5645粉丝 172原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

码哥说

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值