SpringBoot,Java使用AOP统一处理请求

711 阅读2分钟

AOP:面向切面编程;公共行为从业务逻辑分离进行统一处理;

1. 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. new Aspect类

IDE是idea的话,不是右键后的那个选项,是class 添加注解和逻辑代码

@Aspect
@Component
public class ***Aspect{
	@Before("execution()")//接触到业务代码之前处理
	public void doBefore(){
	}

	@After("execution()")//接触到业务代码之后处理
	public void doAfter(){
	}
}

execution()的使用参考博客Spring-AOP @AspectJ切点函数之execution()

当存在公用切点时,可采用@Pointcut进行处理

@Aspect
@Component
public class ***Aspect{
	@Pointcut("execution()")//统一公用代码
	public void common(){
	}

	@Before("common()")//接触到业务代码之前处理
	public void doBefore(){
	}

	@After("common()")//接触到业务代码之后处理
	public void doAfter(){
	}

	@AfterReturning(returning="obj",pointcut="common()")//方法返回后处理
	public void doAfterReturning(Object obj){
	}
}

3. 其他

public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //url
        logger.info("url={}", request.getRequestURL());

        //method
        logger.info("method={}", request.getMethod());

        //ip
        logger.info("ip={}", request.getRemoteAddr());

        //类方法
        logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());

        //参数
        logger.info("args={}", joinPoint.getArgs());
    }

4.实例

下面这个例子是最近在公司用到的,做请求拦截 首先是注解代码

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimit {
    /**
     * 返回redis的key
     * 默认类名+方法名
     *
     * @return redis的key
     */
    String key() default "";

    /**
     * 请求限制后的提示语
     *
     * @return 提示语
     */
    String msg() default "操作频繁";

    /**
     * redis超时时间
     *
     * @return 超时时间
     */
    long timeout() default 1000L;
}

然后是切面的代码,只针对注解拦截,没有对方法做切入点。另外不提供userUtil和redisUtil,根据自己用到的替换这部分代码就好啦,不影响大局

@Aspect
@Component
@Slf4j
public class RequestLimitAspect {
    @Resource
    private UserUtil userUtil;
    @Resource
    private RedisUtils redisUtils;

    @Pointcut("@annotation(cn.xxx.web.config.aspect.annotation.RequestLimit)")
    public void executeService() {
    }

    @Around("executeService()&&@annotation(requestLimit)")
    public Object around(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {
        String errorMsg = requestLimit.msg();
        String redisKey = requestLimit.key();
        long timeout = requestLimit.timeout();
        if (StringUtils.isBlank(redisKey)) {
            redisKey = joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName();
        }
        redisKey = redisKey + userUtil.getOpenId();
        if (redisUtils.exists(redisKey)) {
            return MessageBean.fail(errorMsg);
        }
        try {
            redisUtils.set(redisKey, userUtil.getSessionId(), timeout, TimeUnit.MILLISECONDS);
            return joinPoint.proceed();
        } finally {
            redisUtils.delete(redisKey);
        }
    }
}

使用

    @RequestLimit(key = WHEELING_REQUEST_PREFIX, msg = "正在抽奖,请稍后...", timeout = 4 * 1000L)
    public MessageBean wheelPay() {
        String sessionId = userUtil.getSessionId();
        if (StringUtils.isBlank(sessionId)) {
            return new MessageBean(ErrorCodeEnum.WEB_NOT_AUTHED);
        }
        return orderService.wheelPay(userUtil.getOpenId(), sessionId);
    }

阿豆的闲暇时光 www.ibean.top/archives/20…