原理:
在Session中保存一个表单的唯一编号,将该编号放在一个隐藏域中,同其他数据一同提交。在提交表单后,通过拦截器或其他机制检查唯一编号,如果存在则说明表单是第一次提交,如果不存在则被重复提交(在第一次提交检查后就会从Session中移除该编号)。
PS:要是拦截不成功,可在拦截器上做出一些打印字符,看看控制台是否有出现打印字符,若没有,则可能是隐藏域没有赋值。
拦截器的执行顺序是:preHandle方法——true时,执行action,然后postHandle方法——最后afterCompletion方法;
——false时,就不执行下去。
根据执行顺序可以在返回false之前作出跳转处理,有以下三种方法:
//1,抛出异常,然后在配置文件中,作出异常处理
throw new Exception("duplicated");
//2.response跳转
response.sendRedirect("/WEB-INF/template/common/error.ftl");
//3.request跳转
request.getRequestDispatcher("/WEB-INF/template/common/error.ftl").forward(request, response);
以上三种方法建议第三种,读者也可根据自己的需要选择。
最后,因为这个是SpringMVC整合freemarker,可能有很多不足的地方没说到,希望读者勿喷,做此文只是为了交流。
在Session中保存一个表单的唯一编号,将该编号放在一个隐藏域中,同其他数据一同提交。在提交表单后,通过拦截器或其他机制检查唯一编号,如果存在则说明表单是第一次提交,如果不存在则被重复提交(在第一次提交检查后就会从Session中移除该编号)。
步骤:1,生成两个拦截器;2,在表单中加入隐藏域;3,在对应的action中加入把隐藏赋值的代码;4,配置文件中做出响应配置。
//拦截器1,作为在添加的时候的拦截
package com.tagsdata.tdshop.interceptor;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class ProductAddInteceptor implements HandlerInterceptor{
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
// TODO Auto-generated method stub
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String token = getUUID();
request.getSession().setAttribute("post_token", token);
System.out.println("放在session的token:"+token);
return true;
}
/**
* 随机获取UUID字符串(无中划线)
*
* @return UUID字符串
*/
public static String getUUID() {
String uuid = UUID.randomUUID().toString();
return uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24);
}
}
//拦截器2,作为校验表单隐藏域跟session的uuid是否相同
package com.tagsdata.tdshop.interceptor;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class ProductSaveInteceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
System.out.println("执行afterCompletion方法");
//arg1.sendRedirect("common/error");
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println("执行postHandle方法");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String session_token = (String) request.getSession().getAttribute("post_token");
String post_token =request.getParameter("post_token");
System.out.println("session跟form对比:"+session_token.equalsIgnoreCase(post_token));
if(session_token.equalsIgnoreCase(post_token)){
request.getSession().removeAttribute(post_token);
String token = getUUID();
request.getSession().setAttribute("post_token", token);
System.out.println("============cross interceptor========");
return true;
}
//throw new Exception("duplicated");
//response.sendRedirect("/WEB-INF/template/common/error.ftl");
request.getRequestDispatcher("/WEB-INF/template/common/error.ftl").forward(request, response);
return false;
}
/**
* 随机获取UUID字符串(无中划线)
*
* @return UUID字符串
*/
public static String getUUID() {
String uuid = UUID.randomUUID().toString();
return uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24);
}
}
在商品添加的表单中加入一个隐藏域,接收token数据 :<input type="hidden" name="post_token" value="${post_token!}" />
// 添加
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String add(HttpServletRequest request) {
//拿到拦截器放在session的内容,放在隐藏域中
String post_token = (String) request.getSession().getAttribute("post_token");
request.setAttribute("post_token", post_token);</span>
return VIEW_PATH + "product_Type_input";
}
//配置文件中,加入相应的拦截
<!-- 防止重复提交 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/product**/add/**"/>
<mvc:mapping path="/product**/edit/**"/>
<bean class="com.tagsdata.tdshop.interceptor.ProductAddInteceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/product**/save/**"/>
<mvc:mapping path="/product**/update/**"/>
<bean class="com.tagsdata.tdshop.interceptor.ProductSaveInteceptor"/>
</mvc:interceptor>
</mvc:interceptors>
PS:要是拦截不成功,可在拦截器上做出一些打印字符,看看控制台是否有出现打印字符,若没有,则可能是隐藏域没有赋值。
拦截器的执行顺序是:preHandle方法——true时,执行action,然后postHandle方法——最后afterCompletion方法;
——false时,就不执行下去。
根据执行顺序可以在返回false之前作出跳转处理,有以下三种方法:
//1,抛出异常,然后在配置文件中,作出异常处理
throw new Exception("duplicated");
//2.response跳转
response.sendRedirect("/WEB-INF/template/common/error.ftl");
//3.request跳转
request.getRequestDispatcher("/WEB-INF/template/common/error.ftl").forward(request, response);
以上三种方法建议第三种,读者也可根据自己的需要选择。
最后,因为这个是SpringMVC整合freemarker,可能有很多不足的地方没说到,希望读者勿喷,做此文只是为了交流。