spring-mvc拦截器+注解 解决重复请求

在实际生产环境中,首次保存信息,点击一次保存按钮可服务器响应较慢,客户心急多次点击保存按钮,就会导致保存多分除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');就行了

 

 

 

 

 

至此,宝宝再也不担心重复提交了 


 

 

 

 

Spring MVC拦截器是一种强大的功能,它允许你在请求到达控制器方法之前或之后执行自定义逻辑。通过使用注解,你可以方便地配置拦截器行为。Spring提供了`@ControllerAdvice`和`@ModelAttribute`等注解来实现拦截器功能。 **@ControllerAdvice** 注解: - 当你需要对整个控制器层进行通用的错误处理或日志记录时,可以将该注解应用到一个类上。所有被@Controller修饰的类的方法(如`@ExceptionHandler`处理异常)会被拦截器捕获。 **@ModelAttribute** 注解: - 这个注解通常与`@InitBinder`一起使用,可以在模型绑定前进行数据校验或预处理。例如,检查参数是否符合特定格式,然后填充到视图模型中。 **创建自定义拦截器注解**: - 你可以定义一个自定义注解,如`@PreAuthorize`,然后编写一个对应的拦截器类,实现`HandlerInterceptor`接口,方法中执行你的逻辑。 例如: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface PreAuthorize { // 定义拦截器规则 } ``` 实现拦截器: ```java @Component public class MyAuthorizationInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在这里检查权限,如果满足条件则返回true继续执行,否则可以抛出异常或设置响应码 if (myAuthorizationRule(request)) { return true; } // 阻止请求并返回错误信息 return false; } // 其他HandlerInterceptor方法... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值