栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring注解方式防止重复提交原理详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring注解方式防止重复提交原理详解

Srping注解方式防止重复提交原理分析,供大家参考,具体内容如下

方法一: Springmvc使用Token

使用token的逻辑是,给所有的url加一个拦截器,在拦截器里面用java的UUID生成一个随机的UUID并把这个UUID放到session里面,然后在浏览器做数据提交的时候将此UUID提交到服务器。服务器在接收到此UUID后,检查一下该UUID是否已经被提交,如果已经被提交,则不让逻辑继续执行下去…**

1 首先要定义一个annotation: 用@Retention 和 @Target 标注接口

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
  boolean save() default false;
  boolean remove() default false;
}

2 定义拦截器TokenInterceptor:

public class TokenInterceptor extends HandlerInterceptorAdapter {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  if (handler instanceof HandlerMethod) {
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Method method = handlerMethod.getMethod();
    Token annotation = method.getAnnotation(Token.class);
    if (annotation != null) {
      boolean needSaveSession = annotation.save();
      if (needSaveSession) {
 request.getSession(false).setAttribute("token", UUID.randomUUID().toString());
      }
      boolean needRemoveSession = annotation.remove();
      if (needRemoveSession) {
 if (isRepeatSubmit(request)) {
   return false;
 }
 request.getSession(false).removeAttribute("token");
      }
    }
    return true;
  } else {
    return super.preHandle(request, response, handler);
  }
}

private boolean isRepeatSubmit(HttpServletRequest request) {
  String serverToken = (String) request.getSession(false).getAttribute("token");
  if (serverToken == null) {
    return true;
  }
  String clinetToken = request.getParameter("token");
  if (clinetToken == null) {
    return true;
  }
  if (!serverToken.equals(clinetToken)) {
    return true;
  }
  return false;
}
}

Spring MVC的配置文件里加入:

 
  
     
      

设置拦截类

@Aspect
@Configuration
public class LockMethodInterceptor {

  private static final Cache CACHES = CacheBuilder.newBuilder()
      // 最大缓存 100 个
      .maximumSize(1000)
      // 设置写缓存后 5 秒钟过期
      .expireAfterWrite(5, TimeUnit.SECONDS)
      .build();

  @Around("execution(public * *(..)) && @annotation(com.demo.testduplicate.Test1.LocalLock)")
  public Object interceptor(ProceedingJoinPoint pjp) {
    MethodSignature signature = (MethodSignature) pjp.getSignature();
    Method method = signature.getMethod();
    LocalLock localLock = method.getAnnotation(LocalLock.class);
    String key = getKey(localLock.key(), pjp.getArgs());
    if (!StringUtils.isEmpty(key)) {
      if (CACHES.getIfPresent(key) != null) {
 throw new RuntimeException("请勿重复请求");
      }
      // 如果是第一次请求,就将 key 当前对象压入缓存中
      CACHES.put(key, key);
    }
    try {
      return pjp.proceed();
    } catch (Throwable throwable) {
      throw new RuntimeException("服务器异常");
    } finally {
      // TODO 为了演示效果,这里就不调用 CACHES.invalidate(key); 代码了
    }
  }

  
  private String getKey(String keyExpress, Object[] args) {
    for (int i = 0; i < args.length; i++) {
      keyExpress = keyExpress.replace("arg[" + i + "]", args[i].toString());
    }
    return keyExpress;
  }
}

Controller类引用

@RestController
@RequestMapping("/books")
public class BookController {

 @LocalLock(key = "book:arg[0]")
 @GetMapping
 public String save(@RequestParam String token) {
  return "success - " + token;
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/139603.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号