SpringBoot自定义注解(AOP)
实例:做一个java后端限制重复提交的功能。
项目背景:SpringBoot Maven
思路:自定义标签,在接口(controller)加上注解@AccessLimit(参数:时间、最大次数)控制单位时间内的请求次数。redis 的hashMap中存某用户或者sessionId请求的次数,有值则比较,超出最大次数提交失败;其他情况正常提交
应用(TopicController.java)
@AccessLimit(seconds = 1,maxCount = 1) // 同一用户1秒内只允许一次请求
@ApiOperation(value = "专题列表", notes="专题列表")
@RequestMapping(value = "findTopics",method = RequestMethod.POST)
public RestResponse findTopics(@RequestBody TopicQto qto) throws RestException {
return RestResponse.success();
}
引入依赖(pom.xml)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
AOP实体
package com.xxx域名xxx.xxx项目名xx.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AccessLimit {
int seconds();
int maxCount();
}
AOP切面类(具体逻辑实现doAround方法)
package com.xxxxx.xxxxx.aspect;
import com.xxxxx.xxxxx.base.response.RestResponse;
import com.xxxxx.xxxxx.security.BdpSecurityManager;
import com.xxxxx.xxxxx.security.model.User;
import com.xxxxx.xxxxx.util.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Aspect
@Component
@SuppressWarnings({"unused"})
@Slf4j
public class AccessLimitAspect {
@Resource
private RedisUtil redisUtil;
@Pointcut("@annotation(com.xxxxx.xxxxx.annotation.AccessLimit)")
public void annotationPointcut() {
}
@Before("annotationPointcut()")
public void beforePointcut(JoinPoint joinPoint) {
// 此处进入到方法前 可以实现一些业务逻辑
}
@Around("annotationPointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) {
ServletRequestAttributes attributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//获取request
HttpServletRequest request = attributes.getRequest();
HttpSession session = request.getSession();
User user = BdpSecurityManager.getLoginedUser();
//组装redis key 从redis中获取对应的值
String key = "accessLimit";
String item = session.getId();
if(user != null){
item = user.getId();
}
Object flag = redisUtil.hget(key,item);
//如果redis中不存在对应的值,则执行原有的代码逻辑(插入文章操作)
if (flag == null) {
//redis设置key,value ,1秒有效
redisUtil.hset(key, item,"",5);
try {
return joinPoint.proceed();
} catch (Throwable throwable) {
redisUtil.hdel(key, item);
// RestResponse 为自定义的而返回对象
return RestResponse.valid("204", "系统错误,请联系管理员!");
}
} else {
//如果redis中存在对应的值,则证明重复提交,返回对应的信息
log.info("{}:重复提交", key+"_"+item);
return RestResponse.valid("204", "操作过于频繁,稍后请重新提交!");
}
}
/**
* 在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
* @param joinPoint
*/
@AfterReturning("annotationPointcut()")
public void doAfterReturning(JoinPoint joinPoint) {
}
}
如有错漏之处,敬请指正
——东东E