转载请注明出处:https://blog.csdn.net/l1028386804/article/details/80440853
这篇博文介绍第一种方法:判断session或其他缓存中保存的token,这里以session为例,具体大家也可以自行扩展以其他的缓存实现。
这种方式比较麻烦,每次在提交表单时都必须传入上次的token。而且当一个页面使用ajax时,多个表单提交就会有问题。
注解的作用主要是用来标识哪些类需要被拦截,处理防重复提交的问题,具体代码如下:
package io.mykit.filter.spring.repeat.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 以Token注解形式方式重复提交内容
* @author liuyazhuang
*
*/
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FormToken {
boolean save() default false;
boolean remove() default false;
}
这个类主要是对标识了@FormToken的方法进行拦截,并且按照相应的规则进行处理,FormTokenInterceptor不进行具体的规则处理,具体规则交由子类实现。具体代码如下:
package io.mykit.filter.spring.repeat.interceptor;
import java.lang.reflect.Method;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import io.mykit.filter.spring.repeat.annotation.FormToken;
/**
* 基于Token形式的防重复提交拦截器
* @author liuyazhuang
*
*/
public abstract class FormTokenInterceptor 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();
FormToken annotation = method.getAnnotation(FormToken.class);
if (annotation != null) {
boolean needSaveSession = annotation.save();
if (needSaveSession) {
request.getSession(false).setAttribute("formToken", UUID.randomUUID().toString());
}
boolean needRemoveSession = annotation.remove();
if (needRemoveSession) {
if (isRepeatSubmit(request)) {
return false;
}
request.getSession(false).removeAttribute("formToken");
}
}
return true;
} else {
return super.preHandle(request, response, handler);
}
}
/**
* 具体规则交由子类实现
* @param request
* @return
*/
public abstract boolean isRepeatSubmit(HttpServletRequest request);
}
这个类继承FormTokenInterceptor类,实现isRepeatSubmit方法来提供具体的处理规则,这个类也是本例提供的处理方式,如果大家想用其他的处理方式,可自行定义处理类继承FormTokenInterceptor,实现isRepeatSubmit方法即可,这也体现了本实例的高可扩展性。具体代码如下:
package io.mykit.filter.spring.repeat.interceptor.impl;
import javax.servlet.http.HttpServletRequest;
import io.mykit.filter.spring.repeat.interceptor.FormTokenInterceptor;
/**
* 具体规则的实现,这种方式页面需要添加
*
* @author liuyazhuang
*
*/
public class MyFormTokenInterceptor extends FormTokenInterceptor {
@Override
public boolean isRepeatSubmit(HttpServletRequest request) {
String serverToken = (String) request.getSession(false).getAttribute("formToken");
if (serverToken == null) {
return true;
}
String clinetToken = request.getParameter("formToken");
if (clinetToken == null) {
return true;
}
if (!serverToken.equals(clinetToken)) {
return true;
}
return false;
}
}
在相关的web工程中的springmvc配置文件中引入springmvc-interceptor.xml文件
如下:
当你自己继承FormTokenInterceptor类实现了具体的拦截规则时,就不能在相关的web工程中的springmvc配置文件中引入springmvc-interceptor.xml文件了,需要添加如下配置
然后在接口的方法上加上注解即可。在需要生成token的controller上增加@FormToken(save=true),而在需要检查重复提交的controller上添加@FormToken(remove=true)就可以了。
另外,你需要在view里在form里增加下面代码:
注意在ajax提交时 要加上 formToken参数
UTF-8
javax.servlet
javax.servlet-api
3.0.1
cglib
cglib
3.2.6
com.alibaba
fastjson
1.2.47
org.springframework
spring-expression
${spring.version}
org.springframework
spring-messaging
${spring.version}
org.springframework
spring-jms
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-web
${spring.version}
org.aspectj
aspectjtools
1.9.1
org.springframework
spring-webmvc
${spring.version}