Spring Boot切面获取PathVariable及自定义注解传参问题
问题分析与解决方案
嘿,这个问题我之前也碰到过,其实核心原因很简单:你自定义的注解切面并没有自动解析SpEL表达式的能力,而@PreAuthorize是Spring Security专门实现了这部分逻辑的。
为什么会拿到"#id"字符串?
Spring Security的@PreAuthorize注解内部集成了SpEL表达式解析器,它会自动识别并解析#id这种占位符,将其替换为方法的实际参数值。但你自己定义的@HasZone注解只是一个普通的自定义注解,Spring AOP在切面中默认只会把注解里的原始字符串值(也就是"#id")传递给你,不会帮你做表达式解析。
解决办法:手动解析SpEL表达式
要拿到实际的路径变量值,你需要在切面中手动解析注解里的SpEL表达式,步骤如下:
1. 修改切面方法,获取方法上下文
首先,切面方法需要加入JoinPoint参数,通过它可以拿到当前被拦截方法的签名、参数名和参数值。
2. 构建SpEL解析上下文
使用Spring的StandardEvaluationContext把方法的参数名和对应的参数值绑定进去,这样SpEL表达式就能找到对应的变量。
3. 解析注解中的表达式
用SpelExpressionParser解析注解里的#id表达式,从上下文中获取实际值。
完整的切面代码示例(Kotlin):
import org.aspectj.lang.JoinPoint import org.aspectj.lang.annotation.Before import org.aspectj.lang.reflect.MethodSignature import org.springframework.expression.spel.standard.SpelExpressionParser import org.springframework.expression.spel.support.StandardEvaluationContext @Before("@annotation(hasZone)") fun checkZonePermissions(joinPoint: JoinPoint, hasZone: HasZone) { // 获取方法签名和参数信息 val methodSignature = joinPoint.signature as MethodSignature val parameterNames = methodSignature.parameterNames val args = joinPoint.args // 构建SpEL评估上下文,绑定参数名与参数值 val evaluationContext = StandardEvaluationContext() parameterNames?.forEachIndexed { index, paramName -> evaluationContext.setVariable(paramName, args[index]) } // 解析每个id表达式 val spelParser = SpelExpressionParser() hasZone.id.forEach { spelExpr -> val actualId = spelParser.parseExpression(spelExpr).getValue(evaluationContext, String::class.java) println("实际路径变量id值:$actualId") // 这里可以加入你的权限校验逻辑,比如用actualId去检查权限 } }
额外注意:确保参数名能被正确获取
如果你的项目编译时没有保留方法参数名,methodSignature.parameterNames可能会返回null或者类似arg0、arg1的默认名称,导致SpEL解析失败。你需要在构建工具中开启保留参数名的配置:
- Gradle:在
build.gradle.kts中添加tasks.withType<JavaCompile> { options.compilerArgs.add("-parameters") } - Maven:在
pom.xml的maven-compiler-plugin中配置<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <parameters>true</parameters> </configuration> </plugin>
这样修改后,你的切面就能正确拿到@PathVariable的实际值啦~
内容的提问来源于stack exchange,提问作者mgh
相关产品推荐
相关产品推荐

