package com.ruoyi.framework.interceptor;

import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.json.JSON;
import com.ruoyi.common.utils.ServletUtils; /**
* 防止重复提交拦截器
*
* @author ruoyi
*/
@Component
public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
if (handler instanceof HandlerMethod)
{
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
if (annotation != null)
{
if (this.isRepeatSubmit(request))
{
AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
ServletUtils.renderString(response, JSON.marshal(ajaxResult));
return false;
}
}
return true;
}
else
{
return super.preHandle(request, response, handler);
}
} /**
* 验证是否重复提交由子类实现具体的防重复提交的规则
*
* @param httpServletRequest
* @return
* @throws Exception
*/
public abstract boolean isRepeatSubmit(HttpServletRequest request) throws Exception;
}
package com.ruoyi.framework.interceptor.impl;

import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Component;
import com.ruoyi.common.json.JSON;
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; /**
* 判断请求url和数据是否和上一次相同,
* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
*
* @author ruoyi
*/
@Component
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
{
public final String REPEAT_PARAMS = "repeatParams"; public final String REPEAT_TIME = "repeatTime"; public final String SESSION_REPEAT_KEY = "repeatData"; /**
* 间隔时间,单位:秒 默认10秒
*
* 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
*/
private int intervalTime = 10; public void setIntervalTime(int intervalTime)
{
this.intervalTime = intervalTime;
} @SuppressWarnings("unchecked")
@Override
public boolean isRepeatSubmit(HttpServletRequest request) throws Exception
{
// 本次参数及系统时间
String nowParams = JSON.marshal(request.getParameterMap());
Map<String, Object> nowDataMap = new HashMap<String, Object>();
nowDataMap.put(REPEAT_PARAMS, nowParams);
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis()); // 请求地址(作为存放session的key值)
String url = request.getRequestURI(); HttpSession session = request.getSession();
Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY);
if (sessionObj != null)
{
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
if (sessionMap.containsKey(url))
{
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
{
return true;
}
}
}
Map<String, Object> sessionMap = new HashMap<String, Object>();
sessionMap.put(url, nowDataMap);
session.setAttribute(SESSION_REPEAT_KEY, sessionMap);
return false;
} /**
* 判断参数是否相同
*/
private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
{
String nowParams = (String) nowMap.get(REPEAT_PARAMS);
String preParams = (String) preMap.get(REPEAT_PARAMS);
return nowParams.equals(preParams);
} /**
* 判断两次间隔时间
*/
private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
{
long time1 = (Long) nowMap.get(REPEAT_TIME);
long time2 = (Long) preMap.get(REPEAT_TIME);
if ((time1 - time2) < (this.intervalTime * 1000))
{
return true;
}
return false;
}
}
package com.ruoyi.common.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 自定义注解防止表单重复提交
*
* @author ruoyi
*
*/
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit
{ }
package com.ruoyi.common.core.domain;

import java.util.HashMap;
import com.ruoyi.common.utils.StringUtils; /**
* 操作消息提醒
*
* @author ruoyi
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L; /** 状态码 */
public static final String CODE_TAG = "code"; /** 返回内容 */
public static final String MSG_TAG = "msg"; /** 数据对象 */
public static final String DATA_TAG = "data"; /**
* 状态类型
*/
public enum Type
{
/** 成功 */
SUCCESS(0),
/** 警告 */
WARN(301),
/** 错误 */
ERROR(500);
private final int value; Type(int value)
{
this.value = value;
} public int value()
{
return this.value;
}
} /**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
} /**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
*/
public AjaxResult(Type type, String msg)
{
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
} /**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(Type type, String msg, Object data)
{
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
} /**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
} /**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data)
{
return AjaxResult.success("操作成功", data);
} /**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
return AjaxResult.success(msg, null);
} /**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
{
return new AjaxResult(Type.SUCCESS, msg, data);
} /**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult warn(String msg)
{
return AjaxResult.warn(msg, null);
} /**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data)
{
return new AjaxResult(Type.WARN, msg, data);
} /**
* 返回错误消息
*
* @return
*/
public static AjaxResult error()
{
return AjaxResult.error("操作失败");
} /**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult error(String msg)
{
return AjaxResult.error(msg, null);
} /**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult error(String msg, Object data)
{
return new AjaxResult(Type.ERROR, msg, data);
}
}
package com.ruoyi.framework.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.ruoyi.common.config.Global;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; /**
* 通用配置
*
* @author ruoyi
*/
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
/**
* 首页地址
*/
@Value("${shiro.user.indexUrl}")
private String indexUrl; @Autowired
private RepeatSubmitInterceptor repeatSubmitInterceptor; /**
* 默认首页的设置,当输入域名是可以自动跳转到默认指定的网页
*/
@Override
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/").setViewName("forward:" + indexUrl);
} @Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** 本地文件上传路径 */
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + Global.getProfile() + "/"); /** swagger配置 */
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
} /**
* 自定义拦截规则
*/
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
}
}

RepeatSubmitInterceptor extends HandlerInterceptorAdapter的更多相关文章

  1. Spring MVC 中 HandlerInterceptorAdapter的使用

    一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的,这种方式可以实现Bean预处理.后处理. Spring MVC的拦截器不仅可实现Filter的所有功能,还可以更精确的控制拦截精度. s ...

  2. Spring MVC 中 HandlerInterceptorAdapter的使用--转载

    原文地址:http://blog.csdn.net/liuwenbo0920/article/details/7283757 一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的,这种方式可 ...

  3. springMvc(三)session、HandlerInterceptorAdapter

    仅供参考 设置session值,根据自己的需求设置值 /** * 登入验证 * * @return */ @RequestMapping(value = "/loginCheck.htm&q ...

  4. SpringMVC拦截器(包括自定以拦截器--实现HandlerInterceptorAdapter)(资源和权限管理)

    一,springmvc的配置 <!-- 访问拦截 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping ...

  5. Spring中RequestContextHolder以及HandlerInterceptorAdapter的使用

    1 . RequestContextHolder 的使用 想要使用RequestContextHolder,要在web.xml中配置RequestContextListener的监听才能使用. //全 ...

  6. Springboot 拦截器(HandlerInterceptorAdapter)中注入无效

    1,传统filter和HandlerInterceptorAdapter的区别 springboot对传统Filter进行增强,添加更多细粒度的操作,分别实现预处理.后处理(调用了Service并返回 ...

  7. Spring Boot使用HandlerInterceptorAdapter和WebMvcConfigurerAdapter实现原始的登录验证

    HandlerInterceptorAdapter的介绍:http://www.cnblogs.com/EasonJim/p/7704740.html,相当于一个Filter拦截器,但是这个颗粒度更细 ...

  8. Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用

    一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的 而在Spring中,基于Filter这种方式可以实现Bean预处理.后处理. 比如注入FilterRegistrationBean,然后 ...

  9. SpringBoot之HandlerInterceptorAdapter

    SpringBoot之HandlerInterceptorAdapter   在SpringBoot中我们可以使用HandlerInterceptorAdapter这个适配器来实现自己的拦截器.这样就 ...

随机推荐

  1. oracle11g导出dmp文件时不能导出空表,导致缺表

    一.执行 select 'analyze table '||table_name||' compute statistics;' from user_tables; 将该查询语句查询到的结果粘贴到sq ...

  2. postman测试带有json数据格式的字段

    测试六个字段 普通字段: ModelCode 普通字段: MmodelCode 普通字段: ModelTagKey 普通字段: ModelTagValue 普通字段: ModelTagType jso ...

  3. html使用aes进行加密

    1.导入 aes.js 文件 !function(t,n){*t.length},toString:function(t){);o<r;o++){]>>>-o%*&;n ...

  4. 【STM32H7教程】第50章 STM32H7的LCD控制器LTDC基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第50章       STM32H7的LCD控制器LTDC基础 ...

  5. Python Learning Day8

    bp4解析库 pip3 install beautifulsoup4 # 安装bs4pip3 install lxml # 下载lxml解析器 html_doc = """ ...

  6. slf4j NoSuchMethodError 错误 ---- 版本冲突

    java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/Stri ...

  7. Jenkins-在Centos上配置自动化部署(Jenkins+Gitlab+Rancher)

    Jenkins-在Centos上配置自动化部署(Jenkins+Gitlab+Rancher) 环境:centos7 首先在服务器上安装好Jenkins和Gitlab和Rancher Gitlab安装 ...

  8. UVALive 4043 转化最佳完美匹配

    首先黑点和白点是组成一个二分图这毫无疑问 关键是题目中要求的所有黑白配的线不能交叉...一开始我也没想到这个怎么转化为二分图里面的算法. 后来看书才知道,如果两两交叉,则可以把两根线当四边形的对角线, ...

  9. POJ 1149 网络流 合并建图

    这个题目我敲了一个简单的EK,这不是难点 难点在于建图,按题目的要求 每个猪圈和顾客都建点的话,那也太多了...我看了Edelweiss里面的缩点方法才建好的图,哎,惭愧啊 实际那些猪圈根本不需要单独 ...

  10. IDEA控制台输出中文乱码日志文件正常

    控制台中文输出乱码但输出的日志文件正常 idea.exe.vmoptions与idea64.exe.vmoptions已经配置 -Dfile.encoding=UTF-8 logback.xml中也配 ...