情况:在我们插入数据以后,只要刷新页面,就会重新插入这条数据。
原因:在我们提交数据后,浏览器会保留上一次请求的数据!!在刷新页面的时候,会将上一次请求重新发送一次,导致了重提交问题的出现。
问题:如果解决重提交的问题呢?
答:解决思路是,在重提交的时候,让请求不要重新发送上一次的请求。那么我们需要实现防重提交的机制。实现防重提交的机制,是使用Token(令牌机制)实现的。
所以要解决这个问题,首先理解token机制的实现!!
实现一个拦截器。拦截多个请求。
第一步:新建一个拦截器
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.chu.annotation.TokenForm;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 防重提交
* @author ranger
*
*/
public class TokenInterceptor implements HandlerInterceptor {
@SuppressWarnings("unchecked")
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//第一步:如果是一个增加的请求,我们就创建一个Token
//问题:如何标志请求的方法是一个增加的方法呢?通过注解来标识
//HandlerMethod对象可以获得请求准备要调用的方法的方法信息
List<String> tokenPool=null;
HandlerMethod hm=(HandlerMethod) handler;
TokenForm tokenForm = hm.getMethodAnnotation(TokenForm.class);
if (tokenForm!=null) {
HttpSession session = request.getSession();
//问题:如果多个功能使用的SessionToken是同一个。会出现相互覆盖的情况
//解决方案,使用一个集合来存储sessionToken。将Token分为当前Token (用于返回到页面),Token池
if (session.getAttribute("tokenPool")==null) {
tokenPool=new ArrayList<>();
}else {
tokenPool=(List<String>) session.getAttribute("tokenPool");
}
//只要,进入或者提交都要出境一个新的Token放在Session里面
String sessionToken = UUID.randomUUID().toString();
//将创建的Token放在会话的tokenPool里面
tokenPool.add(sessionToken);
//将创建的Token放在会话方放在一个字段里面用于返回到页面
session.setAttribute("sessionToken", sessionToken);
session.setAttribute("tokenPool", tokenPool);
//remove为true,表示是一个提交增加的请求
if (tokenForm.remove()) {
//判断请求表单的token和会话里面的Token是否相同
String formToken = request.getParameter("formToken");
List<String> resultTokenPool = (List<String>) session.getAttribute("tokenPool");
boolean flag=false;
for (String token : resultTokenPool) {
if (token.equals(formToken)) {
//如果发现token池有对应的Token就移除
resultTokenPool.remove(token);
flag=true;
break;
}
}
//如果表单的Token在Token池里面没有。就跳转到指定的页面
if (flag==false) {
response.sendRedirect(request.getParameter("token.invoke"));
return false;
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
问题:如何标志请求的方法是一个增加的方法呢?通过注解来标识
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于防重提标志需要防重提交的方法
* @author ranger
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TokenForm {
//如果create为true,表示是一个跳转到增加页面的请求
boolean create() default false;
//如果是remove为true,表示是一个增加提交的请求
boolean remove() default false;
}
第二步:在controller在相应的方法加上注解
第三步:在springmvc配置文件或者配置类设置拦截器ok