麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > Java > 正文

Spring注解方式防止重復提交原理詳解

2024-07-14 08:42:58
字體:
來源:轉載
供稿:網友

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 {@Overridepublic 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的配置文件里加入:

<mvc:interceptors>  <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 -->     <mvc:interceptor>       <mvc:mapping path="/**"/>       <!-- 定義在mvc:interceptor下面的表示是對特定的請求才進行攔截的 -->       <bean class="****包名****.TokenInterceptor"/>     </mvc:interceptor> </mvc:interceptors>@RequestMapping("/add.jspf")@Token(save=true)public String add() {  //省略  return TPL_BASE + "index";} @RequestMapping("/save.jspf")@Token(remove=true)public void save() { //省略}

用法:

在Controller類的用于定向到添加/修改操作的方法上增加自定義的注解類 @Token(save=true)

在Controller類的用于表單提交保存的的方法上增加@Token(remove=true)

在表單中增加 用于存儲token,每次需要報token值傳入到后臺類,用于從緩存對比是否是重復提交操作

方法二:springboot中用注解方式

每次操作,生成的key存放于緩存中,比如用google的Gruava或者Redis做緩存

定義Annotation類

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface LocalLock {  /**   * @author fly   */  String key() default "";  /**   * 過期時間 TODO 由于用的 guava 暫時就忽略這屬性吧 集成 redis 需要用到   *   * @author fly   */  int expire() default 5;}

設置攔截類

@Aspect@Configurationpublic class LockMethodInterceptor {  private static final Cache<String, Object> 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); 代碼了    }  }  /**   * key 的生成策略,如果想靈活可以寫成接口與實現類的方式(TODO 后續講解)   *   * @param keyExpress 表達式   * @param args    參數   * @return 生成的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; }}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 最新中文字幕第一页视频 | 一级免费看片 | 亚洲欧美成aⅴ人在线观看 av免费在线播放 | 中文字幕精品在线观看 | 亚洲一区二区三区四区精品 | 日韩视频一区二区 | 久久精品99久久久久久2456 | 一级成人毛片 | 12av毛片| 羞羞视频免费网站 | 九九视频精品在线 | chinesexxxx极品少妇 | 欧美精品久久久久久久久久 | 特片网久久 | 欧美一级一区二区三区 | 欧美视频国产 | 免费黄色在线观看网站 | www亚洲| 成年人高清视频在线观看 | 久久综合久久综合久久综合 | 久草在线视频网 | 国产美女视频一区二区三区 | 美女视频黄a视频免费全过程 | 九九精品在线观看视频 | 中国女人内谢69xxxx天美 | 欧美日韩亚洲一区二区三区 | 久草在线手机视频 | 一级片免费在线 | 亚洲国产精久久久久久久 | 鲁丝一区二区三区不属 | 精品亚洲视频在线观看 | 色羞羞| 国产精品视频专区 | 毛片视频网站 | 巨根插入 | 爱视频福利 | 国产精品视频在线观看免费 | 夜夜夜操操操 | 成人男男视频拍拍拍在线观看 | 成人片免费视频 | 精品国产91久久久久 |