表单重复提交问题有多种方法控制,以下主要说明后台控制。
原理:通过唯一标识来判断,通常采用UUID来生成唯一标识。当表单提交时会传一个Token(唯一标识)参数,该参数是保存在后台服务器session中,通过传递的Token值与后台服务器session值作比较来解决该问题,代码如下:
一、声明一个自定义注解类Token
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Token {
/**
* 获取token值
* @return
*/
boolean token() default false;
/**
* 标识哪些方法需要验证重复提交
* @return
*/
boolean remove() default false;
}
二、声明一个拦截器
public class TokenInterceptor 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();
Token annotation = AnnotationUtils.findAnnotation(method, Token.class);
if(annotation != null) {
boolean isGetToken = annotation.token();
if(isGetToken) {
request.getSession(false).setAttribute("token", UUID.randomUUID().toString());
}
boolean isRemoveSession = annotation.remove();
if(isRemoveSession) {
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 clientToken = request.getParameter("token");
if(clientToken == null) {
return true;
}
if(!serverToken.equals(clientToken)) {
return true;
}
return false;
}
}
三、在保存的Controller方法加下@Token注解即可
1.获取UUID方法
@Token(token = true)
@RequestMapping(value = "getToken",method = RequestMethod.GET)
@ResponseBody
public String getToken(HttpServletRequest request, HttpServletResponse response) {
String token = request.getSession(false).getAttribute("token").toString();
JsonBean jb = new JsonBean(token, "");
return getJson(jb);
}
2.表单提交的方法(父类)
@Token(remove = true)
@RequestMapping(method = { RequestMethod.POST })
@ResponseBody
public String create(HttpServletRequest request, HttpServletResponse response, @RequestBody Entity model) {
throw new UnsupportedOperationException("not yet implement");
}
说下需要注意的地方:
这里是通过spring提供的AnnotationUtils类来获取方法上声明的注解类,非Token annotation = method.getAnnotation(Token.class);
因为我们要拦截的表单请求Controller的Token注解是写在父类上,如果使用method.getAnnotation(Token.class)会得不到该Token值,如果该注解不是写在父类上,则两种方式都没问题。
CSDN第一篇博客,写得不好的地方请见谅哈。