防重提交-开发思路
情况:在我们插入数据以后,只要刷新页面,就会重新插入这条数据。
原因:在我们提交数据后,浏览器会保留上一次请求的数据!!在刷新页面的时候,会将上一次请求重新发送一次,导致了重提交问题的出现。
问题:如果解决重提交的问题呢?
答:解决思路是,在重提交的时候,让请求不要重新发送上一次的请求。那么我们需要实现防重提交的机制。实现防重提交的机制,是使用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