1. Spel 简单使用
package com.example.demo;
import lombok.Builder;
import lombok.Data;
import org.assertj.core.util.Lists;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.util.Date;
import java.util.List;
/**
* https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/expressions.html
*/
public class SpelTest {
public static void main(String[] args) {
UserWrapper zs = UserWrapper.builder()
.age(22).birthDay(new Date()).username("zs")
.likes(Lists.newArrayList("篮球", "羽毛球"))
.build();
System.out.println(zs);
// 1. 创建解析器
ExpressionParser parser = new SpelExpressionParser();
// 2. 设置上下文
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("zs", zs);
context.setVariable("zs2", null);
// 3. 创建表达式并且解析
// 3.1 解析username
System.out.println("========0");
Expression expression = parser.parseExpression("#zs.username");
String name = (String) expression.getValue(context);
System.out.println(name);
String value = parser.parseExpression("#zs.username + '111222'").getValue(context, String.class);
System.out.println(value);
// 3.2 解析likes 爱好
System.out.println("========1");
System.out.println(parser.parseExpression("#zs.likes").getValue(context));
System.out.println(parser.parseExpression("#zs.likes").getValueType(context));
// spel 调用方法
System.out.println(parser.parseExpression("#zs.likes.size()").getValue(context));
System.out.println(parser.parseExpression("#zs.likes.size() == 2").getValue(context));
System.out.println(parser.parseExpression("#zs.likes.get(1)").getValue(context));
// spel 调用方法添加元素
System.out.println(parser.parseExpression("#zs.likes.add('新爱好')").getValue(context));
System.out.println(zs.getLikes());
// 3. 解析age 年龄
System.out.println("========1");
Integer age = parser.parseExpression("#zs.age").getValue(context, int.class);
System.out.println(age);
// 4. 解析在上下文环境中,值为null的获取的值为null; 不存在上下文中、或者解析值为null的对象的属性会报 SpelEvaluationException 错误
// Object value1 = parser.parseExpression("#zs2.age").getValue(context);
// Object value2 = parser.parseExpression("#zs.age2").getValue(context);
// System.out.println(value1);
/**
* UserWrapper(username=zs, age=22, birthDay=Fri Feb 10 11:01:56 CST 2023, likes=[篮球, 羽毛球])
* ========0
* zs
* zs111222
* ========1
* [篮球, 羽毛球]
* class java.util.ArrayList
* 2
* true
* 羽毛球
* true
* [篮球, 羽毛球, 新爱好]
* ========1
* 22
*/
}
}
@Data
@Builder
class UserWrapper {
private String username;
private int age;
private Date birthDay;
private List<String> likes;
}
2. AOP基于Spel 获取参数值
1. 注解
package com.example.demo.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AopAnnotation {
/**
* id 表达式
* @return
*/
String idSpel() default "";
/**
* 值
* @return
*/
String value();
}
2. 切面Aspect
package com.example.demo.aop;
import cn.hutool.core.util.ArrayUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
@Component
@Aspect
public class AopAspect {
// 定义一个空方法,借用其注解抽取切点表达式
@Pointcut("@annotation(com.example.demo.aop.AopAnnotation)")
public void pc() {
}
// 环绕通知
@Around("AopAspect.pc()")
public Object around(ProceedingJoinPoint pjp) {
System.out.println("----------------环绕通知之前 的部分(相当于前置通知)----------------");
// 获取到类名
String targetName = pjp.getTarget().getClass().getName();
System.out.println("代理的类是:" + targetName);
// 获取到参数
Object[] parameter = pjp.getArgs();
System.out.println("传入的参数是:" + Arrays.toString(parameter));
// 获取到方法签名,进而获得方法
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
System.out.println("增强的方法名字是:" + method.getName());
// 处理一些业务逻辑
// 模拟简单的获取参数
AopAnnotation annotation = method.getAnnotation(AopAnnotation.class);
String value = annotation.value();
System.out.println("注解参数值: value\t" + value);
// spel 解析参数
Parameter[] parameters = method.getParameters();
String idSpel = annotation.idSpel();
if (ArrayUtil.isNotEmpty(parameters)) {
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
for (int index = 0, length_1 = parameters.length; index < length_1; index++) {
String paramterName = parameters[index].getName();
Object paramterValue = parameter[index];
context.setVariable(paramterName, paramterValue);
}
String value1 = parser.parseExpression(idSpel).getValue(context, String.class);
System.out.println(String.format("idSpel: %s, value: %s", idSpel, value1));
} else {
System.out.println("idSpel 参数获取不到上下文环境, idSpel: " + idSpel);
}
// 让方法执行
Object proceed = null;
try {
proceed = pjp.proceed();
// 环绕通知之后的业务逻辑部分
System.out.println("----------------环绕通知之后的部分(相当于后置通知AfterReturning)-----------------");
} catch (Throwable e) {
System.out.println("-------------环绕通知的异常部分(相当于异常通知AfterThrowing)--------------------------");
e.printStackTrace();
} finally {
System.out.println("-------------环绕通知的最终部分部分(相当于最终通知After)--------------------------");
}
return proceed;
}
}
3. 测试Controller
package com.example.demo.aop;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/aop")
public class AopTestController {
@GetMapping("/")
@AopAnnotation(idSpel = "#id", value = "test")
public String test(String id) {
return "111222";
}
}
4. 访问: http://localhost:8088/aop/?id=3
5. 控制台
----------------环绕通知之前 的部分(相当于前置通知)----------------
代理的类是:com.example.demo.aop.AopTestController
传入的参数是:[3]
增强的方法名字是:test
注解参数值: value test
idSpel: #id, value: 3
----------------环绕通知之后的部分(相当于后置通知AfterReturning)-----------------
-------------环绕通知的最终部分部分(相当于最终通知After)--------------------------
【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】