在实际生产环境中,首次保存信息,点击一次保存按钮可服务器响应较慢,客户心急多次点击保存按钮,就会导致保存多分除ID外一模一样的信息,这是一个较为严重的bug
怎么解决?f不多说,这是我总结实现的代码
第一步:写一个拦截器, 验证请求内容是否完全相同
package com.thinkgem.jeesite.common.interceptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.thinkgem.jeesite.common.mapper.JsonMapper;
/**
16. * 一个用户 相同url 同时提交 相同数据 验证
17. * 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单
18. * @author Administrator
19. *
20. */
public class SameUrlDataInterceptor extends HandlerInterceptorAdapter{
private static final Logger LOG = Logger.getLogger(SameUrlData.class);
/**
* 是否阻止提交 ,fasle 阻止 ,true放行
* @param httpServletRequest
* @return
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
SameUrlData annotation = method.getAnnotation(SameUrlData.class);
if (annotation != null) {
if(repeatDataValidator(request)){
LOG.warn("please don't repeat submit,url:"+ request.getServletPath());
String id = request.getParameter("id");
if(id!=null&&!"".equals(id)){ //如果信息表ID已经存在则不是新加信息,而是修改信息,放行
return true;
}
String formRequest = request.getRequestURI();
request.setAttribute("myurl", formRequest);
request.getRequestDispatcher("/WEB-INF/views/modules/middle/middle.jsp").forward(request, response);//拦截之后页面跳转位置
return false;
}//如果重复相同数据
else {
return true;
}
}
return true;
} else {
return super.preHandle(request, response, handler);
}
}
/**
* 验证标识是否相同提交 ,相同返回true ,
*防止有人在提交时修改数据,
* @param httpServletRequest
* @return
*/
public boolean repeatDataValidator(HttpServletRequest httpServletRequest)
{
//String params=IdGen.generateShortUuid();
String params=JsonMapper.toJsonString(httpServletRequest.getParameterMap()); //获取全部请求内容
System.out.println("params==========="+params);
String url=httpServletRequest.getRequestURI();
Map<String,String> map=new HashMap<String,String>();
map.put(url, params);
String nowUrlParams=map.toString();//
Object preUrlParams=httpServletRequest.getSession().getAttribute("repeatData");
if(preUrlParams==null)//如果上一个数据为null,表示还没有访问页面
{
httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
return false;
}
else//否则,已经访问过页面
{
if(preUrlParams.toString().equals(nowUrlParams))
{ //如果上次url+数据和本次url+数据相同,则表示重复添加数据
return true;
}
else//如果上次 url+数据 和本次url加数据不同,则不是重复提交
{
httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
return false;
}
}
}
}
第二步:把拦截器写成注解
package com.thinkgem.jeesite.common.interceptor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
09. * 一个用户 相同url 同时提交 相同数据 验证
10. * @author Administrator
11. *
12. */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SameUrlData {
}
第三步:把拦截器路径写在spring-mvc的配置文件中
<!-- 配置拦截器,防止用户重复提交数据 -->
<!--拦截得路径 拦截所有得URL-->
<!--class文件路径改成你自己写得拦截器路径!!-->
<mvc:interceptor>
<mvc:mapping path="${adminPath}/wkst/worksheet/save"/>
<mvc:mapping path="${adminPath}/cust/customer/save"/>
<bean class="com.thinkgem.jeesite.common.interceptor.SameUrlDataInterceptor"/>
</mvc:interceptor>
第四步:把注解写在controller的最前面
@SameUrlData
@RequiresPermissions("cust:customer:edit")
@RequestMapping(value = "save")
public String save(Customer customer, Model model,HttpServletRequest request, RedirectAttributes redirectAttributes)
第5步:写拦截到重复请求页面跳转的位置
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'middle.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<script type="text/javascript">
function readyLoad(){
var url = "${myurl}";
if(url.indexOf('/wkst/worksheet/save')>=0){
setTimeout(function(){window.location.href = "${ctx}/wkst/worksheet/autosave";}, 2000 );
} else if(url.indexOf('/cust/customer/save')>=0){
setTimeout(function(){window.location.href = "${ctx}/cust/customer/list";}, 2000 );
}
}
</script>
</head>
<body onload="readyLoad()">
</body>
</html>
6,如果担心在提交时修改数据加上表单提交loading加载,禁止一切操作,这样就完全避免了重复保存记录
表单提交loading加载参考 https://blog.csdn.net/Denglishang/article/details/81283540
ajax用 $.jBox.tip("正在提交,请稍等...",'loading');就行了
至此,宝宝再也不担心重复提交了