Commit ab992f4848d663b0ca5dc65883b05ad950eae778

Authored by RuoYi
1 parent baea48be

修复防重复提交注解无效问题

ruoyi/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java 0 → 100644
  1 +package com.ruoyi.common.filter;
  2 +
  3 +import java.io.IOException;
  4 +import javax.servlet.Filter;
  5 +import javax.servlet.FilterChain;
  6 +import javax.servlet.FilterConfig;
  7 +import javax.servlet.ServletException;
  8 +import javax.servlet.ServletRequest;
  9 +import javax.servlet.ServletResponse;
  10 +import javax.servlet.http.HttpServletRequest;
  11 +
  12 +import com.ruoyi.common.enums.HttpMethod;
  13 +
  14 +/**
  15 + * Repeatable 过滤器
  16 + *
  17 + * @author ruoyi
  18 + */
  19 +public class RepeatableFilter implements Filter
  20 +{
  21 + @Override
  22 + public void init(FilterConfig filterConfig) throws ServletException
  23 + {
  24 +
  25 + }
  26 +
  27 + @Override
  28 + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  29 + throws IOException, ServletException
  30 + {
  31 + HttpServletRequest req = (HttpServletRequest) request;
  32 + if (HttpMethod.PUT.name().equals(req.getMethod()) || HttpMethod.POST.name().equals(req.getMethod()))
  33 + {
  34 + RepeatedlyRequestWrapper repeatedlyRequest = new RepeatedlyRequestWrapper((HttpServletRequest) request);
  35 + chain.doFilter(repeatedlyRequest, response);
  36 + }
  37 + else
  38 + {
  39 + chain.doFilter(request, response);
  40 + }
  41 + }
  42 +
  43 + @Override
  44 + public void destroy()
  45 + {
  46 +
  47 + }
  48 +}
... ...
ruoyi/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java 0 → 100644
  1 +package com.ruoyi.common.filter;
  2 +
  3 +import java.io.BufferedReader;
  4 +import java.io.ByteArrayInputStream;
  5 +import java.io.IOException;
  6 +import java.io.InputStreamReader;
  7 +import java.nio.charset.Charset;
  8 +import javax.servlet.ReadListener;
  9 +import javax.servlet.ServletInputStream;
  10 +import javax.servlet.http.HttpServletRequest;
  11 +import javax.servlet.http.HttpServletRequestWrapper;
  12 +import com.ruoyi.common.utils.StringUtils;
  13 +
  14 +/**
  15 + * 构建可重复读取inputStream的request
  16 + *
  17 + * @author ruoyi
  18 + */
  19 +public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
  20 +{
  21 + private final byte[] body;
  22 +
  23 + public RepeatedlyRequestWrapper(HttpServletRequest request) throws IOException
  24 + {
  25 + super(request);
  26 + body = readBytes(request.getReader(), "utf-8");
  27 + }
  28 +
  29 + @Override
  30 + public BufferedReader getReader() throws IOException
  31 + {
  32 + return new BufferedReader(new InputStreamReader(getInputStream()));
  33 + }
  34 +
  35 + @Override
  36 + public ServletInputStream getInputStream() throws IOException
  37 + {
  38 + final ByteArrayInputStream bais = new ByteArrayInputStream(body);
  39 + return new ServletInputStream()
  40 + {
  41 +
  42 + @Override
  43 + public boolean isFinished()
  44 + {
  45 + return false;
  46 + }
  47 +
  48 + @Override
  49 + public boolean isReady()
  50 + {
  51 + return false;
  52 + }
  53 +
  54 + @Override
  55 + public void setReadListener(ReadListener listener)
  56 + {
  57 +
  58 + }
  59 +
  60 + @Override
  61 + public int read() throws IOException
  62 + {
  63 + return bais.read();
  64 + }
  65 + };
  66 + }
  67 +
  68 + /**
  69 + * 通过BufferedReader和字符编码集转换成byte数组
  70 + */
  71 + private byte[] readBytes(BufferedReader br, String encoding) throws IOException
  72 + {
  73 + String str = null, retStr = "";
  74 + while ((str = br.readLine()) != null)
  75 + {
  76 + retStr += str;
  77 + }
  78 + if (StringUtils.isNotBlank(retStr))
  79 + {
  80 + return retStr.getBytes(Charset.forName(encoding));
  81 + }
  82 + return null;
  83 + }
  84 +}
... ...
ruoyi/src/main/java/com/ruoyi/common/xss/XssFilter.java renamed to ruoyi/src/main/java/com/ruoyi/common/filter/XssFilter.java
1   -package com.ruoyi.common.xss;
  1 +package com.ruoyi.common.filter;
2 2  
3 3 import java.io.IOException;
4 4 import java.util.ArrayList;
... ...
ruoyi/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java renamed to ruoyi/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
1   -package com.ruoyi.common.xss;
  1 +package com.ruoyi.common.filter;
2 2  
3 3 import java.io.ByteArrayInputStream;
4 4 import java.io.IOException;
... ...
ruoyi/src/main/java/com/ruoyi/framework/config/FilterConfig.java
... ... @@ -7,8 +7,9 @@ import org.springframework.beans.factory.annotation.Value;
7 7 import org.springframework.boot.web.servlet.FilterRegistrationBean;
8 8 import org.springframework.context.annotation.Bean;
9 9 import org.springframework.context.annotation.Configuration;
  10 +import com.ruoyi.common.filter.RepeatableFilter;
  11 +import com.ruoyi.common.filter.XssFilter;
10 12 import com.ruoyi.common.utils.StringUtils;
11   -import com.ruoyi.common.xss.XssFilter;
12 13  
13 14 /**
14 15 * Filter配置
... ... @@ -36,11 +37,24 @@ public class FilterConfig
36 37 registration.setFilter(new XssFilter());
37 38 registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
38 39 registration.setName("xssFilter");
39   - registration.setOrder(Integer.MAX_VALUE);
  40 + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
40 41 Map<String, String> initParameters = new HashMap<String, String>();
41 42 initParameters.put("excludes", excludes);
42 43 initParameters.put("enabled", enabled);
43 44 registration.setInitParameters(initParameters);
44 45 return registration;
45 46 }
  47 +
  48 + @SuppressWarnings({ "rawtypes", "unchecked" })
  49 + @Bean
  50 + public FilterRegistrationBean someFilterRegistration()
  51 + {
  52 + FilterRegistrationBean registration = new FilterRegistrationBean();
  53 + registration.setFilter(new RepeatableFilter());
  54 + registration.addUrlPatterns("/*");
  55 + registration.setName("repeatableFilter");
  56 + registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
  57 + return registration;
  58 + }
  59 +
46 60 }
... ...
ruoyi/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
... ... @@ -2,14 +2,19 @@ package com.ruoyi.framework.interceptor.impl;
2 2  
3 3 import java.util.HashMap;
4 4 import java.util.Map;
  5 +import java.util.concurrent.TimeUnit;
5 6 import javax.servlet.http.HttpServletRequest;
6   -import javax.servlet.http.HttpSession;
  7 +import org.springframework.beans.factory.annotation.Autowired;
7 8 import org.springframework.stereotype.Component;
8 9 import com.alibaba.fastjson.JSONObject;
  10 +import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
  11 +import com.ruoyi.common.utils.StringUtils;
  12 +import com.ruoyi.common.utils.http.HttpHelper;
9 13 import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
  14 +import com.ruoyi.framework.redis.RedisCache;
10 15  
11 16 /**
12   - * 判断请求url和数据是否和上一次相同,
  17 + * 判断请求url和数据是否和上一次相同,
13 18 * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
14 19 *
15 20 * @author ruoyi
... ... @@ -23,6 +28,9 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
23 28  
24 29 public final String SESSION_REPEAT_KEY = "repeatData";
25 30  
  31 + @Autowired
  32 + private RedisCache redisCache;
  33 +
26 34 /**
27 35 * 间隔时间,单位:秒 默认10秒
28 36 *
... ... @@ -39,8 +47,14 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
39 47 @Override
40 48 public boolean isRepeatSubmit(HttpServletRequest request)
41 49 {
42   - // 本次参数及系统时间
43   - String nowParams = JSONObject.toJSONString(request.getParameterMap());
  50 + RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
  51 + String nowParams = HttpHelper.getBodyString(repeatedlyRequest);
  52 +
  53 + // body参数为空,获取Parameter的数据
  54 + if (StringUtils.isEmpty(nowParams))
  55 + {
  56 + nowParams = JSONObject.toJSONString(request.getParameterMap());
  57 + }
44 58 Map<String, Object> nowDataMap = new HashMap<String, Object>();
45 59 nowDataMap.put(REPEAT_PARAMS, nowParams);
46 60 nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
... ... @@ -48,8 +62,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
48 62 // 请求地址(作为存放session的key值)
49 63 String url = request.getRequestURI();
50 64  
51   - HttpSession session = request.getSession();
52   - Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY);
  65 + Object sessionObj = redisCache.getCacheObject(SESSION_REPEAT_KEY);
53 66 if (sessionObj != null)
54 67 {
55 68 Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
... ... @@ -62,9 +75,9 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
62 75 }
63 76 }
64 77 }
65   - Map<String, Object> sessionMap = new HashMap<String, Object>();
66   - sessionMap.put(url, nowDataMap);
67   - session.setAttribute(SESSION_REPEAT_KEY, sessionMap);
  78 + Map<String, Object> cacheMap = new HashMap<String, Object>();
  79 + cacheMap.put(url, nowDataMap);
  80 + redisCache.setCacheObject(SESSION_REPEAT_KEY, cacheMap, intervalTime, TimeUnit.SECONDS);
68 81 return false;
69 82 }
70 83  
... ...