SpringBoot 切面通知

SpringBoot 切面通知

  • maven依赖
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • yaml配置不需要开启aop
  #################################   ---   spring - aop   ---   #################################
spring:
  aop:
    auto: true
    proxy-target-class: true
  • 也不需要在启动类开启注解
  • 因为SpringBootApplication会自动装配

  • @Order(2) 权重 , 数字越小, 权重越高
  • @Aspect 切面注解,表示这是一个aop切面类
  • @Component Spring组件,被Spring所管理
  • @Pointcut 切入点,这里配置监听规则
  • @Before 前置通知,执行切入点之前执行
  • @After 后置通知,执行切入点之后通知
  • @Around 环绕通知 , 切入点执行前后都通知
  • @AfterReturning @BeforeThrowing 都属于异常通知, 这里只写了两个

  • 切面类;
  • 这里只监听了两个方法登录和登出,只是记录用户登录有效时间;
  •  joinPoint.getSignature().getName(); 获取方法名;
  • joinPoint.getSignature();获取签名;
  • joinPoint.getArgs();
  • 获取所有参数;
  • RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();获取RequestAttributes ;
  • HttpServletRequest request=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);运用requestAttributes对象,获取HttpServletRequest;
import com.richfit.user.domain.AuthUser;
import com.richfit.user.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 *  Login&Logout log print By CHENYB date 2019-09-03
 */
@Order(2)
@Aspect
@Component
public class LoginAdvice{

    private final Logger logger = LoggerFactory.getLogger(LoginAdvice.class);

    @Autowired
    private UserService userService;
    /**
     * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码.
     * 使用 @Pointcut 来声明切入点表达式.
     * 后面的其他通知直接使用方法名来引用当前的切入点表达式.
     * (..)表示任意参数
     * 这里路径尽量精准,减少资源浪费,或是错过写什么.
     */
    @Pointcut("execution(public String com.richfit.user.controller.UserInfoController.*(..))")
    public void declareJointPointExpression() {
    }

    @After("declareJointPointExpression()")
    public void afterMethod(JoinPoint joinPoint) {

        String loginInfoText = "";
        //获取被调用的方法名
        String methodName = joinPoint.getSignature().getName();

        // 获取签名
        //Signature signature = joinPoint.getSignature();

        //  获取RequestAttributes
        RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
        //  从requestAttributes中获取HttpServletRequest信息 ,如果参数中有, 在参数中提取也可以
        HttpServletRequest request=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

        //获取参数
        Object[] args = joinPoint.getArgs();

        if ("login".equals( methodName )){
            String loninId = (String) args[1];
            String clientIp = getClientIp( request );
            loginInfoText = "系统提示 ######### " + new Date(  ) + ", 帐号:"+loninId+",正在使用:"+clientIp+" -> 登录服务器 #########";
        }

        if ("logOut".equals( methodName )){
            String userId = (String) args[1];
            AuthUser authInfo = userService.getAuthInfo( userId );
            String clientIp = getClientIp( request );
            loginInfoText = "系统提示 ######### " + new Date(  ) + ", 帐号:"+authInfo.getLoginId()+",正在使用:"+clientIp+" -> 已退出登录 #########";
        }

        logger.info(loginInfoText);
    }

    //获取用户ip
    private String getClientIp(HttpServletRequest request) {
        //X-Forwarded-For,不区分大小写
        String possibleIpStr = request.getHeader("X-Forwarded-For");
        String remoteIp = request.getRemoteAddr();
        String clientIp;
        if (StringUtils.isNotBlank(possibleIpStr) && !"unknown".equalsIgnoreCase(possibleIpStr)) {
            //可能经过好几个转发流程,第一个是用户的真实ip,后面的是转发服务器的ip
            clientIp = possibleIpStr.split(",")[0].trim();
        } else {
            //如果转发头ip为空,说明是直接访问的,没有经过转发
            clientIp = remoteIp;
        }
        return clientIp;
    }

}
  • 注:想要开启多个通知配置,通知方法的返回值、方法名、参数
  • 注:只有环绕通知(@Around)可以使用这个参数“ProceedingJoinPoint”,前、后通知不可以
2021-07-04 20:50:15 ERROR SpringApplication:858 - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'objectMapperConfigurer' defined in class path resource [springfox/documentation/spring/web/SpringfoxWebMvcConfiguration.class]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': BeanPostProcessor before instantiation of bean failed; nested exception is java.lang.IllegalArgumentException: ProceedingJoinPoint is only supported for around advice
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:510)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:240)
	at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:721)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:534)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)

chenyb 随笔记录,只为方便自己学习

2019-09-04

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值