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@componentpublic 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); }}
最后请求
可以看出, 切面成功获取到了实体的name值“张三”.
以上就是springboot通过spel结合aop实现动态传参的方法的详细内容。