使用aop注解实现表单防重复提交功能
1.这里采用的方法是:使用get请求进入表单页面时,后台会生成一个tokrn_flag分别放到session和request中,表单页面用一个隐藏域储存该token_flag,在提交表单时,将该token_flag一并提交到后台,后台将该token_flag和session中对比,只要比对通过就立即删除session中的token_flag,这样就能保证表单最多只有一次成功提交的机会。
2.表单防重复提交一般前后端都会做,前端比较简单,点击过一次就将提交按钮置灰或disabled。
3.因为生成和验证token_flag具有通用性,一般不建议嵌入到具体方法中,最好的方法就是使用aop+注解的方式
4.注解
/** * 表单注解,放在需要验证表单的方法上,一般是controller上 */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface FormToken { }
5.AOP
@Aspect @Component public class ResubmitAspect { private static final String PARAM_TOKEN = "token"; private static final String PARAM_TOKEN_FLAG = "TokenFlag_"; /** * 执行切面拦截逻辑 */ @Around("@annotation(formToken)") public void execute(ProceedingJoinPoint joinPoint, FormToken formToken) throws Throwable { if (formToken != null) { //方法入参列表 Object[] args = joinPoint.getArgs(); //类名 String className = joinPoint.getTarget().getClass().getName(); for (Object arg : args) { //方法入参是否包含request if (arg != null && arg instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) arg; HttpSession session = request.getSession(true); if ("GET".equalsIgnoreCase(request.getMethod())) { /* GET 生成 token */ this.generate(joinPoint, request, session, PARAM_TOKEN_FLAG + className); } else { /* POST 验证 token */ this.validation(joinPoint, request, session, PARAM_TOKEN_FLAG + className); } } } } } /** * <p> * 生成表单 token * </p> */ public void generate(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpSession session, String tokenFlag) throws Throwable { String uuid = UUID.randomUUID().toString(); session.setAttribute(tokenFlag, uuid); request.setAttribute(PARAM_TOKEN, uuid); joinPoint.proceed(); }
/** * <p> * 验证表单 token * </p> * <p> * 验证结果一致,既为第一次提交,删除会话中存储的token,并继续执行方法。<br> * 否则不做任何处理。 * </p> */ public void validation(ProceedingJoinPoint joinPoint, HttpServletRequest request, HttpSession session, String tokenFlag) throws Throwable { Object sessionFlag = session.getAttribute(tokenFlag); Object requestFlag = request.getParameter(PARAM_TOKEN); if (sessionFlag != null && sessionFlag.equals(requestFlag)) { //删除已验证的token session.removeAttribute(tokenFlag); joinPoint.proceed(); } } }
6.配置
在spring配置文件中
<aop:aspectj-autoproxy />
<context:component-scan base-package="com.baomidou.framework.aop">
</context:component-scan>
7.html中使用
<input type="hidden" name="token" value="${token}" />
情出自愿,事过无悔;不负遇见,不谈亏欠。