此防止指正常提交时,多次点击,也可以通过前台按钮禁止来控制,主要思路就是,新进页面的时候在session中产生一个token,
把这个token放入session和request中,表单提交时,把request返回的token一块提交,在环绕通知中判断session的token和request中的token是否一致,如果一致则提交并变更session中的token
当表单提交后,未刷新页面,此时页面的token是上一次的token,在再提交表单会提交不上,从而达到防止重复提交的目的,如果提交表单的表单是个弹框,则需要刷新页面
//此注解加在跳转路由的方法上,进入此页面则在session和request中放入token
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface GenrateFormToken {
}
//拦截方法为一个后置通知
@Aspect
@Component
public class GenerateFormTokenAspectJ {
@After("@annotation(com.duia.common.annotation.GenrateFormToken)")
public void beforeMethod(JoinPoint point) throws Throwable {
SysContent.getSession().setAttribute("forbidResubmissionToken", UUID.randomUUID().toString());
SysContent.getRequest().setAttribute("formToken", SysContent.getSession().getAttribute("forbidResubmissionToken"));
}
}
//此注解加在表单提交的方法上,表示需要走表单token对比的aop方法
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ForbidResubmission {
}
//走拦截处理判断是否相等,return null这个可以抛出指定异常,如new FormReSubmissionException(),在统一的异常处理器中返回给前台,前台在根据返回类型提示用户请勿重复提交
@Aspect
@Component
public class ForbidResubmissionAspectJ {
@Around("@annotation(com.duia.common.annotation.ForbidResubmission)")
public Object around(ProceedingJoinPoint point) throws Throwable {
Object forbidResubmissionToken = SysContent.getSession().getAttribute("forbidResubmissionToken");
Objects.requireNonNull(forbidResubmissionToken);
Object[] args = point.getArgs();
String formToken = SysContent.getRequest().getParameter("formToken");
if (forbidResubmissionToken instanceof String ) {
String forbidResubmissionToken1 = (String) forbidResubmissionToken;
String formToken1 = (String) formToken;
if (forbidResubmissionToken1.equals(formToken1)) {
SysContent.getSession().setAttribute("forbidResubmissionToken", UUID.randomUUID().toString());
return point.proceed(args);
}
return null;
}
return null;
}
}
//工具类,通过过滤器中filter方法获取request和response,并保存到threadLocal中,主要参考自...妈的,找不到了,下次找到补上吧
public class GetContentFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
SysContent.setRequest((HttpServletRequest) arg0);
SysContent.setResponse((HttpServletResponse) arg1);
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
public class SysContent {
private static ThreadLocal<HttpServletRequest> requestLocal = new ThreadLocal<HttpServletRequest>();
private static ThreadLocal<HttpServletResponse> responseLocal = new ThreadLocal<HttpServletResponse>();
public static HttpServletRequest getRequest() {
return (HttpServletRequest) requestLocal.get();
}
public static void setRequest(HttpServletRequest request) {
requestLocal.set(request);
}
public static HttpServletResponse getResponse() {
return (HttpServletResponse) responseLocal.get();
}
public static void setResponse(HttpServletResponse response) {
responseLocal.set(response);
}
public static HttpSession getSession() {
return (HttpSession) ((HttpServletRequest) requestLocal.get()).getSession();
}
}
[实现思想主要参考自java web技术内幕,表单防重]