一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - springmvc 防止表單重復(fù)提交的兩種方法

springmvc 防止表單重復(fù)提交的兩種方法

2021-11-03 12:08阿豪_mike Java教程

最近在本地開發(fā)測試的時(shí)候,遇到一個(gè)表單重復(fù)提交的現(xiàn)象。本文主要介紹了springmvc 防止表單重復(fù)提交的兩種方法,感興趣的可以了解一下

最近在本地開發(fā)測試的時(shí)候,遇到一個(gè)表單重復(fù)提交的現(xiàn)象。 因?yàn)榫W(wǎng)絡(luò)延遲的問題,我點(diǎn)擊了兩次提交按鈕,數(shù)據(jù)庫里生成了兩條記錄。其實(shí)這種現(xiàn)象以前也有遇到過,一般都是提交后把按鈕置灰,無法再次提交,這是很常見的客戶端處理的方式。 但是這不是從根本上解決問題,雖然客戶端解決了多次提交的問題,但是接口中依舊存在著問題。假設(shè)我們不是從客戶端提交,而是被其他的系統(tǒng)調(diào)用,當(dāng)遇到網(wǎng)絡(luò)延遲,系統(tǒng)補(bǔ)償?shù)臅r(shí)候,還會(huì)遇到這種問題

1、通過session中的token驗(yàn)證

  • 初始化頁面時(shí)生成一個(gè)唯一token,將其放在頁面隱藏域和session中
  • 攔截器攔截請求,校驗(yàn)來自頁面請求中的token與session中的token是否一致
  • 判斷,如果一致則提交成功并移除session中的token,不一致則說明重復(fù)提交并記錄日志

步驟1:創(chuàng)建自定義注解

?
1
2
3
4
5
6
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
    boolean save() default false;
    boolean remove() default false;
}

步驟2:創(chuàng)建自定義攔截器(@slf4j是lombok的注解)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Slf4j
public class RepeatSubmitInterceptor extends HandlerInterceptorAdapter {
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        HandlerMethod handlerMethod = null;
        try {
            handlerMethod = (HandlerMethod)handler;
        } catch (Exception e) {
            return true;
        }
        Method method = handlerMethod.getMethod();
 
        Token token = method.getAnnotation(Token.class);
        if(token != null ){
            boolean saveSession = token.save();
            if(saveSession){
                request.getSession(true).setAttribute("token", UUID.randomUUID());
            }
 
            boolean removeSession = token.remove();
            if(removeSession){
                if(isRepeatSubmitSession(request)){
                    log.info("repeat submit session :" + request.getServletPath());
                    response.sendRedirect("/error/409");
                    return false;
                }
                request.getSession(true).removeAttribute("token");
            }
        }
        return true;
    }
 
    private boolean isRepeatSubmitSession(HttpServletRequest request){
        String sessionToken = String.valueOf(request.getSession(true).getAttribute("token") == null ? "" : request.getSession(true).getAttribute("token"));
        String clientToken =  String.valueOf(request.getParameter("token") == null ? "" : request.getParameter("token"));
        if(sessionToken == null || sessionToken.equals("")){
            return true;
        }
        if(clientToken == null || clientToken.equals("")){
            return true;
        }
        if(!sessionToken.equals(clientToken)){
            return true;
        }
        return false;
    }
 
}

步驟3:將自定義攔截器添加到配置文件

?
1
2
3
4
<mvc:interceptor>
 <mvc:mapping path="/**"/>
 <bean class="com.chinagdn.base.common.interceptor.RepeatSubmitInterceptor"/>
</mvc:interceptor>

使用案例

?
1
2
3
4
5
6
7
8
9
10
11
12
//save = true 用于生成token
@Token(save = true)
   @RequestMapping(value = "save", method = RequestMethod.GET)
   public String save(LoginUser loginUser, Model model) throws Exception {
       return "sys/user/edit";
   }
//remove = true 用于驗(yàn)證token
@Token(remove = true)
   @RequestMapping(value = "save", method = RequestMethod.POST)
   public String save(@Valid LoginUser loginUser, Errors errors, RedirectAttributes redirectAttributes, Model model) throws Exception {
    //.....
   }

jsp頁面隱藏域添加token

?
1
<input type="hidden" name="token" value="${sessionScope.token}">

2、通過當(dāng)前用戶上一次請求的url和參數(shù)驗(yàn)證重復(fù)提交

攔截器攔截請求,將上一次請求的url和參數(shù)和這次的對(duì)比
判斷,是否一致說明重復(fù)提交并記錄日志

步驟1:創(chuàng)建自定義注解

?
1
2
3
4
5
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SameUrlData {
 
}

步驟2:創(chuàng)建自定義攔截器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class SameUrlDataInterceptor 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();
            //是否有 SameUrlData 注解
            SameUrlData annotation = method.getAnnotation(SameUrlData.class);
            if (annotation != null) {
                if (repeatDataValidator(request)) {//如果重復(fù)相同數(shù)據(jù)
                    response.sendRedirect("/error/409");
                    return false;
                } else {
                    return true;
                }
            }
            return true;
        } else {
            return super.preHandle(request, response, handler);
        }
    }
 
    /**
     * 驗(yàn)證同一個(gè)url數(shù)據(jù)是否相同提交  ,相同返回true
     * @param httpServletRequest
     * @return
     */
    private boolean repeatDataValidator(HttpServletRequest httpServletRequest) {
        String params = JsonMapper.toJsonString(httpServletRequest.getParameterMap());
        String url = httpServletRequest.getRequestURI();
        Map<String, String> map = new HashMap<>();
        map.put(url, params);
        String nowUrlParams = map.toString();//
 
        Object preUrlParams = httpServletRequest.getSession().getAttribute("repeatData");
        if (preUrlParams == null) { //如果上一個(gè)數(shù)據(jù)為null,表示還沒有訪問頁面
            httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
            return false;
        } else { //否則,已經(jīng)訪問過頁面
            if (preUrlParams.toString().equals(nowUrlParams)) { //如果上次url+數(shù)據(jù)和本次url+數(shù)據(jù)相同,則表示城府添加數(shù)據(jù)
                return true;
            } else { //如果上次 url+數(shù)據(jù) 和本次url加數(shù)據(jù)不同,則不是重復(fù)提交
                httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
                return false;
            }
        }
    }
}

步驟3:將自定義攔截器添加到配置文件

?
1
2
3
4
<mvc:interceptor>
 <mvc:mapping path="/**"/>
 <bean class="com.chinagdn.base.common.interceptor.SameUrlDataInterceptor"/>
</mvc:interceptor>

使用案例

?
1
2
3
4
5
6
//在controller層使用  @SameUrlData 注解即可
@SameUrlData
   @RequestMapping(value = "save", method = RequestMethod.POST)
   public String save(@Valid LoginUser loginUser, Errors errors, RedirectAttributes redirectAttributes, Model model) throws Exception {
    //.....
   }

到此這篇關(guān)于springmvc 防止表單重復(fù)提交的兩種方法的文章就介紹到這了,更多相關(guān)springmvc 防止表單重復(fù)提交內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://juejin.cn/post/6990963223486791688

延伸 · 閱讀

精彩推薦
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程xml與Java對(duì)象的轉(zhuǎn)換詳解

    xml與Java對(duì)象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對(duì)象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程20個(gè)非常實(shí)用的Java程序代碼片段

    20個(gè)非常實(shí)用的Java程序代碼片段

    這篇文章主要為大家分享了20個(gè)非常實(shí)用的Java程序片段,對(duì)java開發(fā)項(xiàng)目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java實(shí)現(xiàn)搶紅包功能

    Java實(shí)現(xiàn)搶紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)搶紅包功能,采用多線程模擬多人同時(shí)搶紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程升級(jí)IDEA后Lombok不能使用的解決方法

    升級(jí)IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級(jí),尋思已經(jīng)有好久沒有升過級(jí)了。升級(jí)完畢重啟之后,突然發(fā)現(xiàn)好多錯(cuò)誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java8中Stream使用的一個(gè)注意事項(xiàng)

    Java8中Stream使用的一個(gè)注意事項(xiàng)

    最近在工作中發(fā)現(xiàn)了對(duì)于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個(gè)非常重要的注意點(diǎn),所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7482021-02-04
主站蜘蛛池模板: 天天狠天天透天干天天怕处 | 校园全黄h全肉细节文 | 天莱男模gary | 日韩精品久久不卡中文字幕 | 2019理论韩国理论中文 | beeg日本高清xxxx18 | 成年视频在线播放 | 青青青手机在线观看 | 国产99热99| 欧美日韩一区二区三区久久 | 亚洲精品一区二区久久这里 | 99ri在线精品视频在线播放 | 国产成人精品福利色多多 | 精品一区二区免费视频蜜桃网 | 免费在线公开视频 | 四虎影院免费在线播放 | gay男男白袜chinese | 亚洲精品国产一区二区在线 | 99热久久这里只精品国产www | 好大好硬好紧太深了受不了 | 免费观看成年肉动漫网站 | 日本免费三区 | 日韩在线免费看 | 91精品综合久久久久久五月天 | 高清视频在线播放 | 欧美人与禽交片在线播放 | 非洲一级毛片又粗又长aaaa | 国产亚洲精品一区二区在线播放 | 2019亚洲男人天堂 | 日韩特级片 | 亚洲欧美在线免费观看 | 韩国甜性涩爱在线播放 | 男人捅女人漫画 | 9久热久爱免费精品视频在线观看 | 亚洲福利视频在线观看 | 美女扒开腿让男生桶爽漫画 | 亚洲精品国产综合久久一线 | 校园刺激全黄H全肉细节文 校草让我脱了内裤给全班看 | 四虎1515hh.com| 亚洲精品乱码久久久久久蜜桃图片 | 青青草国产青春综合久久 |