java(若依)防止表单重复提交
生活随笔
收集整理的這篇文章主要介紹了
java(若依)防止表单重复提交
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
RepeatSubmit——防止重復(fù)提交(若依)
一、創(chuàng)建 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;/*** 自定義注解防止表單重復(fù)提交* 第一步* * @author ruoyi**/ @Inherited @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RepeatSubmit {/*** 間隔時(shí)間(ms),小于此時(shí)間視為重復(fù)提交*/public int interval() default 5000;/*** 提示消息*/public String message() default "不允許重復(fù)提交,請(qǐng)稍候再試"; }二、實(shí)現(xiàn)HandlerInterceptor,創(chuàng)建RepeatSubmitInterceptor抽象方法
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.HandlerInterceptor; import com.alibaba.fastjson2.JSON; import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.ServletUtils;/*** 防止重復(fù)提交攔截器 * 第二步** @author ruoyi*/ @Component public abstract class RepeatSubmitInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{ //instanceof是Java的一個(gè)保留關(guān)鍵字,左邊是對(duì)象,右邊是類,返回類型是Boolean類型。//它的具體作用是測(cè)試左邊的對(duì)象是否是右邊類或者該類的子類創(chuàng)建的實(shí)例對(duì)象if (handler instanceof HandlerMethod){//處理器方法HandlerMethod handlerMethod = (HandlerMethod) handler;//獲取處理方法中的注冊(cè)方法Method method = handlerMethod.getMethod();//從注冊(cè)方法中獲取到自定義注解RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);//判斷注解是否存在if (annotation != null){ //調(diào)用抽象方法,判斷此注解是否以存在if (this.isRepeatSubmit(request, annotation)){//重復(fù)提交AjaxResult ajaxResult = AjaxResult.error(annotation.message());//將字符串渲染到客戶端ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));return false;}}return true;}else{return true;}}/*** 驗(yàn)證是否重復(fù)提交由子類實(shí)現(xiàn)具體的防重復(fù)提交的規(guī)則* @param request* @return* @throws Exception*/public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation); }----------------------------------------------------------------------------------------------------------- import com.ruoyi.common.utils.ServletUtils;/*** 將字符串渲染到客戶端* * @param response 渲染對(duì)象* @param string 待渲染的字符串*/public static void renderString(HttpServletResponse response, String string){try{response.setStatus(200);response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().print(string);}catch (IOException e){e.printStackTrace();}}----------------------------------------------------------------------------------------------------------------- import com.ruoyi.common.core.domain.AjaxResult;/*** 返回錯(cuò)誤消息* * @param msg 返回內(nèi)容* @return 警告消息*/public static AjaxResult error(String msg){return AjaxResult.error(msg, null);}三、繼承RepeatSubmitInterceptor抽象方法實(shí)現(xiàn),重寫isRepeatSubmit抽象方法,實(shí)現(xiàn)具體的校驗(yàn)規(guī)則。
import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.alibaba.fastjson2.JSON; import com.ruoyi.common.annotation.RepeatSubmit; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.filter.RepeatedlyRequestWrapper; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.http.HttpHelper; import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;/*** 判斷請(qǐng)求url和數(shù)據(jù)是否和上一次相同,* 如果和上次相同,則是重復(fù)提交表單。 有效時(shí)間為10秒內(nèi)。* 第三步 具體的校驗(yàn)規(guī)則* * @author ruoyi*/ @Component public class SameUrlDataInterceptor extends RepeatSubmitInterceptor {public final String REPEAT_PARAMS = "repeatParams";public final String REPEAT_TIME = "repeatTime";// 令牌自定義標(biāo)識(shí)@Value("${token.header}")private String header;@Autowiredprivate 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參數(shù)為空,獲取Parameter的數(shù)據(jù)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());// 請(qǐng)求地址(作為存放cache的key值)String url = request.getRequestURI();// 唯一值(沒有消息頭則使用請(qǐng)求地址)String submitKey = StringUtils.trimToEmpty(request.getHeader(header));// 唯一標(biāo)識(shí)(指定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;}/*** 判斷參數(shù)是否相同*/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);}/*** 判斷兩次間隔時(shí)間*/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;/** * 獲得緩存的基本對(duì)象。** @param key 緩存鍵值* @return 緩存鍵值對(duì)應(yīng)的數(shù)據(jù)*/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.StringUtilspublic 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出現(xiàn)問題!");}finally{if (reader != null){try{reader.close();}catch (IOException e){LOGGER.error(ExceptionUtils.getMessage(e));}}}return sb.toString();}}四、構(gòu)建可重復(fù)讀取inputStream的request
import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import com.ruoyi.common.utils.http.HttpHelper; import com.ruoyi.common.constant.Constants;/*** 構(gòu)建可重復(fù)讀取inputStream的request* * @author ruoyi*/ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {private final byte[] body;public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException{super(request);request.setCharacterEncoding(Constants.UTF8);response.setCharacterEncoding(Constants.UTF8);body = HttpHelper.getBodyString(request).getBytes(Constants.UTF8);}@Overridepublic BufferedReader getReader() throws IOException{return new BufferedReader(new InputStreamReader(getInputStream()));}@Overridepublic ServletInputStream getInputStream() throws IOException{final ByteArrayInputStream bais = new ByteArrayInputStream(body);return new ServletInputStream(){@Overridepublic int read() throws IOException{return bais.read();}@Overridepublic int available() throws IOException{return body.length;}@Overridepublic boolean isFinished(){return false;}@Overridepublic boolean isReady(){return false;}@Overridepublic void setReadListener(ReadListener readListener){}};} } --------------------------------------------------------------------------------------------------- import com.ruoyi.common.constant.Constants;/*** UTF-8 字符集*/public static final String UTF8 = "UTF-8";五、把已寫好的攔截器添加到mvc的攔截器組中
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;/*** 通用配置* * @author ruoyi*/ @Configuration public class ResourcesConfig implements WebMvcConfigurer {@Autowiredprivate RepeatSubmitInterceptor repeatSubmitInterceptor;/*** 自定義攔截規(guī)則**/@Overridepublic void addInterceptors(InterceptorRegistry registry){//將已經(jīng)寫好的重復(fù)提交攔截器添加到mvc的攔截器組中registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");}}總結(jié)
以上是生活随笔為你收集整理的java(若依)防止表单重复提交的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决固网 HU-1608n 更换主板后不
- 下一篇: 使用IDM从网站下载图片——从翻页网站下