1、前言
关于 AOP 与 SpEL 的知识点 可以结合 SpringBoot中的AOP使用 和 spring boot spel 基本使用
2、实战
1、自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DemoLog {
String name() default "demo";
String el();
}
2、Aop 实现
@Slf4j
@Aspect
@Component
public class LogAspect implements ApplicationContextAware {
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 定义拦截点,拦截添加了注解DemoLog的方法
*
*/
@Pointcut(value = "@annotation(com.example.learn.annotaion.DemoLog)")
public void logAspect() {
}
/**
* 定义环绕拦截
* @param joinPoint 切点
* @return
* @throws Throwable
*/
@Around(value = "logAspect()")
public Object getAroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
Object proceed;
try {
//前置处理
saveLogAspect(joinPoint, null);
// 调用业务代码
proceed = joinPoint.proceed();
return proceed;
} catch (Throwable throwable) {
saveLogAspect(joinPoint, throwable);
throw new RuntimeException(throwable.getMessage());
}
}
private void saveLogAspect(JoinPoint joinPoint, Throwable throwable) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
try {
// 获取自定义注解
DemoLog demoLog = methodSignature.getMethod().getAnnotation(DemoLog.class);
if (Objects.nonNull(demoLog)) {
String logData = getLogData(joinPoint, methodSignature, demoLog);
log.info("logData = {}",logData);
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
/**
* 获取日志信息
* @param joinPoint 连接点
* @param methodSignature 拦截的函数签名
* @param demoLog 注解信息
* @return
*/
private String getLogData(JoinPoint joinPoint, MethodSignature methodSignature, DemoLog demoLog) {
// 创建 context 对象
StandardEvaluationContext context = new StandardEvaluationContext();
// 设置bean的根对象
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
// 获取被拦截方法的参数信息
String[] params = parameterNameDiscoverer.getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());
// 把参数配置到上下文中
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
context.setVariable(params[i], args[i]);
}
// 创建spel的解析对象
SpelExpressionParser parser = new SpelExpressionParser();
// 解析el 表达式
String strElData = parser.parseExpression(demoLog.el()).getValue(context, String.class);
return "操作:" + demoLog.name() + ",详细内容:" + strElData;
}
}
3、测试
创建控制器
@Component
@RestController
public class SpelController {
/**
* 只获取请求的参数信息
* @param id
* @return
*/
@DemoLog(name="获取用户订单信息",el = "'订单id:'.concat(#id)")
@GetMapping(value = "spel/demo/{id}")
public String get(@PathVariable("id") Integer id){
return String.valueOf(id);
}
/**
* 只获取请求的参数信息
* @param id
* @return
*/
@DemoLog(name="获取用户订单信息",el = "'用户:'.concat(@userBean).concat(',获取订单,订单id:'.concat(#id))")
@GetMapping(value = "spel/demo02/{id}")
public String getDetil(@PathVariable("id") Integer id){
return String.valueOf(id);
}
@Bean("userBean")
public String userBean() {
return"一辉";
}
}
访问 http://localhost:8080/spel/demo/565
输出如下:
logData = 操作:获取用户订单信息,详细内容:订单id:565
访问 http://localhost:8080/spel/demo02/565 输出如下:
logData = 操作:获取用户订单信息,详细内容:用户:一辉,获取订单,订单id:565
4、总结
上述只是实现了基本的操作日志的处理业务,对于更新详细的处理流程可以参照