AOP+Token防止表單重復提交


表單重復提交:

由於用戶誤操作,多次點擊表單提交按鈕

由於網速等原因造成頁面卡頓,用戶重復刷新提交頁面

 

避免表單重復提交的方式:

1.頁面上的按鈕做防重復點擊操作

2.在數據庫中可以做唯一約束

3.利用token校驗重復提交

 

如何利用token校驗表單重復提交

思路:在表單提交前先請求后台獲取token,后台隨機生成token保存在session中,提交表單時在請求參數中帶上獲取的token即可,后台校驗token是否匹配。

token的獲取和校驗可以統一寫在AOP切面類中。

 

自定義注解

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

 

切面類

@Aspect
@Component
public class TokenAspect {

    @SuppressWarnings("unused")
    @Before("within(@org.springframework.stereotype.Controller *) && @annotation(token)")
    public void testToken(final JoinPoint joinPoint, Token token){
        try {
            if (token != null) {
                //獲取 joinPoint 的全部參數
                Object[] args = joinPoint.getArgs();
                HttpServletRequest request = null;
                HttpServletResponse response = null;
                for (int i = 0; i < args.length; i++) {
                    //獲得參數中的 request && response
                    if (args[i] instanceof HttpServletRequest) {
                        request = (HttpServletRequest) args[i];
                    }
                    if (args[i] instanceof HttpServletResponse) {
                        response = (HttpServletResponse) args[i];
                    }
                }

                boolean needSaveSession = token.save();
                if (needSaveSession){
                    String uuid = UUID.randomUUID().toString();
                    request.getSession().setAttribute( "token" , uuid);
                    System.out.println("進入表單頁面,Token值為:"+uuid);
                }

                boolean needRemoveSession = token.remove();
                if (needRemoveSession) {
                    if (isRepeatSubmit(request)) {
                        System.out.println("表單重復提交");
                        throw new FormRepeatException("表單重復提交");
                    }
                    request.getSession(false).removeAttribute( "token" );
                }
            }

        } catch (FormRepeatException e){
            throw e;
        } catch (Exception e){
            e.printStackTrace();
            throw e;
        }
    }

    private boolean isRepeatSubmit(HttpServletRequest request) throws FormRepeatException {
        String serverToken = (String) request.getSession( false ).getAttribute( "token" );
        if (serverToken == null ) {
            return true;
        }
        String clinetToken = request.getParameter( "token" );
        if (clinetToken == null || clinetToken.equals("")) {
            return true;
        }
        if (!serverToken.equals(clinetToken)) {
            return true ;
        }
        System.out.println("校驗是否重復提交:表單頁面Token值為:"+clinetToken + ",Session中的Token值為:"+serverToken);
        return false ;
    }
}

 

全局異常處理

@ControllerAdvice
public class ControllerAdviceHandler {
    
    @ResponseBody
    @ExceptionHandler(value={com.irish.exception.FormRepeatException.class})
    public String arithmeticExceptionHandler(Exception e){
           return "您重復提交表單了!";
    }

}

 

自定義異常

public class FormRepeatException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public FormRepeatException(String message){ super(message);}
    
    
}

 

controller層

@Controller
public class URLController {

    
    /**
     * 獲取token,並將token保存在session中
     * @return
     */
    @Token(save = true)
    @RequestMapping("/queryToken")
    @ResponseBody
    public String getToken(HttpServletRequest request, HttpServletResponse response){
        return (String) request.getSession().getAttribute("token");
    }

    /**
     * 提交表單的地址,在AOP中檢查表單是否重復提交,將token刪除
     * @param request
     * @param response
     * @return
     */
    @Token(remove = true)
    @RequestMapping("/submitFrom")
    @ResponseBody
    public String removeToken(HttpServletRequest request, HttpServletResponse response){
        return "success";
    }
}

 

項目結構:

 github下載地址:https://github.com/jake1263/form-repeat-submit


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM