当前位置 : 主页 > 编程语言 > java >

java(若依)防止表单重复提交

来源:互联网 收集:自由互联 发布时间:2023-09-03
RepeatSubmit——防止重复提交(若依) 一、创建 RepeatSubmit自定义注解 import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention

RepeatSubmit——防止重复提交(若依)

一、创建 RepeatSubmit 自定义注解

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
{
    /**
     * 间隔时间(ms),小于此时间视为重复提交
     */
    public int interval() default 5000;

    /**
     * 提示消息
     */
    public String message() default "不允许重复提交,请稍候再试";
}



二、防重复提交核心代码isRepeatSubmit方法

要注意在转换RepeatedlyRequestWrapper之前做类型判断,在开发中有同事没有做校验,请求在前面Filter处理后,直接强转会报错,或使用构造器的方式创建RepeatedlyRequestWrapper对象。


/**
 * 判断请求url和数据是否和上一次相同,
 * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
 * 第三步 具体的校验规则
 * 
 * @author ruoyi
 */
@Component
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
{
    public final String REPEAT_PARAMS = "repeatParams";

    public final String REPEAT_TIME = "repeatTime";

    // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    @Autowired
    private RedisCache redisCache;

    @SuppressWarnings("unchecked")
    @Override
    //此处为父类抽象方法的重写
    public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
    {
        String nowParams = "";
        
        if (request instanceof RepeatedlyRequestWrapper)
        {
            RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
            nowParams = HttpHelper.getBodyString(repeatedlyRequest);
        }

        // body参数为空,获取Parameter的数据
        if (StringUtils.isEmpty(nowParams))
        {
            nowParams = JSON.toJSONString(request.getParameterMap());
        }
        Map<String, Object> nowDataMap = new HashMap<String, Object>();
        nowDataMap.put(REPEAT_PARAMS, nowParams);
        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());

        // 请求地址(作为存放cache的key值)
        String url = request.getRequestURI();

        // 唯一值(没有消息头则使用请求地址)
        String submitKey = StringUtils.trimToEmpty(request.getHeader(header));

        // 唯一标识(指定key + url + 消息头)
        String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;

        Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
        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, annotation.interval()))
                {
                    return true;
                }
            }
        }
        Map<String, Object> cacheMap = new HashMap<String, Object>();
        cacheMap.put(url, nowDataMap);
        redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
        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, int interval)
    {
        long time1 = (Long) nowMap.get(REPEAT_TIME);
        long time2 = (Long) preMap.get(REPEAT_TIME);
        if ((time1 - time2) < interval)
        {
            return true;
        }
        return false;
    }
    ---------------------------------------------------------------------------------------------------
    import com.ruoyi.common.core.redis.RedisCache;
    
        /**	
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }
    -----------------------------------------------------------------------------------------------------
    import com.ruoyi.common.constant.CacheConstants;
     /**
     * 防重提交 redis key
     */
    public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";

    ------------------------------------------------------------------------------------------------
	import com.ruoyi.common.utils.StringUtils;
    
    public class StringUtils extends org.apache.commons.lang3.StringUtils
           public static String trimToEmpty(final String str) {
        return str == null ? EMPTY : str.trim();
    }
    ------------------------------------------------------------------------------------------------
	import com.ruoyi.common.utils.http.HttpHelper;
    
        /**
         * 通用http工具封装
         * 
         * @author ruoyi
         */
        public class HttpHelper
        {
            private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);

            public static String getBodyString(ServletRequest request)
            {
                StringBuilder sb = new StringBuilder();
                BufferedReader reader = null;
                try (InputStream inputStream = request.getInputStream())
                {
                    reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                    String line = "";
                    while ((line = reader.readLine()) != null)
                    {
                        sb.append(line);
                    }
                }
                catch (IOException e)
                {
                    LOGGER.warn("getBodyString出现问题!");
                }
                finally
                {
                    if (reader != null)
                    {
                        try
                        {
                            reader.close();
                        }
                        catch (IOException e)
                        {
                            LOGGER.error(ExceptionUtils.getMessage(e));
                        }
                    }
                }
                return sb.toString();
            }
        }

通过注解和拦截器的配合可以完成防止重复提交的校验,只需要在需要校验方法上标注该注解即可。

【本文由:阿里云代理 http://www.56aliyun.com欢迎留下您的宝贵建议】
上一篇:JAVA设计模式之中介模式
下一篇:没有了
网友评论