1. 定义注解

  1. @Inherited
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.METHOD)
  4. public @interface CheckAuth {
  5. /**
  6. * 使用SpEL表达式标识需要需要检查的房间id
  7. */
  8. String roomId();
  9. /**
  10. * SpEL表达式标识需要被检查的用户userId
  11. */
  12. String userId();
  13. }

2. 解析SpEL表达式的工具方法

  1. public class SpelExpressionUtil {
  2. private static final ExpressionParser parser = new SpelExpressionParser();
  3. private static final LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
  4. public static <T> T parseSpel(Method targetMethod, Object[] args, String spel, Class<T> paramType) {
  5. EvaluationContext context = new StandardEvaluationContext();
  6. String[] params = discoverer.getParameterNames(targetMethod);
  7. for (int len = 0; len < params.length; len++) {
  8. context.setVariable(params[len], args[len]);
  9. }
  10. Expression expression = parser.parseExpression(spel);
  11. return expression.getValue(context, paramType);
  12. }
  13. }

3. 编写切面

  1. @Slf4j
  2. @Component
  3. @Aspect
  4. public class CheckResourceAuthProcessor {
  5. @Before(value = "@annotation(com.xxx.yyy.aspect.CheckAuth) && @annotation(c)")
  6. public void check(JoinPoint joinPoint, CheckAuth c) {
  7. // 获取方法参数值
  8. Object[] arguments = joinPoint.getArgs();
  9. // 获取method
  10. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  11. Method method = signature.getMethod();
  12. // 获取spel表达式
  13. String roomIdSpEL = c.roomId();
  14. String userIdSpEL = c.userId();
  15. // 根据spel表达式获取真正的入参中 需要检查的变量
  16. Long roomId = SpelExpressionUtil.parseSpel(method, arguments, roomIdSpEL, Long.class);
  17. String userId = SpelExpressionUtil.parseSpel(method, arguments, userIdSpEL, String.class);
  18. ///...对用户操作是否有权限进行校验
  19. }
  20. }

4. 使用注解

  1. @CheckAuth(roomId = "#req.roomId", userId = "#operator")
  2. public void doSomething(KickOutReq req, String operator) {
  3. ///...其他业务逻辑
  4. }

5. IDEA配置

在IDEA中Spring自带的SpEL表达式显示是有提示的
类似于这种
image.png

但是我们自定义的是没有提示的
我们可以加一下IDEA的提示

光标放到SpEL表达式上, Alt+Enter ,弹出, 选择 Inject language
image.png
查询spel, 选择
image.png

这下我们的IDEA就能够把这个字符串当做SpEL正常的显示了
image.png

6. @Language(“SpEL”)

IDEA的配置只能配置自己电脑, 如果你经常换电脑, 那么这个spel的语法由无法正确显示了
如果团队中所有人都使用IDEA进行开发, 这里提供一个方法, 让团队中的所有人都能自动以spel的方式查看

  1. 添加依赖

    1. <dependency>
    2. <groupId>org.jetbrains</groupId>
    3. <artifactId>annotations</artifactId> <version>13.0</version>
    4. <scope>provided</scope>
    5. </dependency>
  2. 使用@Language 注解

    1. @Inherited
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Target(ElementType.METHOD)
    4. public @interface CheckResourceAuth {
    5. /**
    6. * 使用SpEL表达式标识需要需要检查的房间id
    7. */
    8. @Language("SpEL")
    9. String roomId();
    10. /**
    11. * SpEL表达式标识需要被检查的用户userId
    12. */
    13. @Language("SpEL")
    14. String userId();
    15. }

    这时候idea不需要做任何配置, 自动就能正常显示spel语法了
    image.png