广州建设网站方案,龙岩天宫山电话,现在建设网站挣钱吗,嘉定营销型 网站制作Java后台防止客户端重复请求、提交表单实现原理发布于 2021-1-8|复制链接摘记: 这篇文章主要介绍了Java后台防止客户端重复请求、提交表单实现原理,文中通过示例代码介绍的非常详细#xff0c;对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下前言在Web / Ap…Java后台防止客户端重复请求、提交表单实现原理发布于 2021-1-8|复制链接摘记: 这篇文章主要介绍了Java后台防止客户端重复请求、提交表单实现原理,文中通过示例代码介绍的非常详细对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下前言在Web / App项目中有一些请求或操作会对数据产生影响(比如新增、删除、修改)针对这类请求一般都需要做一些 ..这篇文章主要介绍了Java后台防止客户端重复请求、提交表单实现原理,文中通过示例代码介绍的非常详细对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下前言在Web / App项目中有一些请求或操作会对数据产生影响(比如新增、删除、修改)针对这类请求一般都需要做一些保护以防止用户有意或无意的重复发起这样的请求导致的数据错乱。常见处理方案1.客户端 例如表单提交后将提交按钮设为disable 等等方法...2.服务端 前端的限制仅能解决少部分问题且不够彻底后端自有的防重复处理措施必不可少义不容辞。 在此提供一个我在项目中用到的方案。简单来说就是判断请求url和数据是否和上一次相同。方法步骤1.主要逻辑 给所有的url加一个拦截器每次请求将url存入session下次请求验证url数据是否相同相同则拒绝访问。 当然我在此基础上做了一些优化比如 使用session有局限性用户量大了以后服务器会撑不住在此我使用了redis来替换。 加入了token令牌机制。2.实现步骤2.1自定义一个注解java/*** Title: SameUrlData* Description: 自定义注解防止表单重复提交* Auther: xhq* Version: 1.0* create 2019/3/26 10:43*/InheritedTarget(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)Documentedpublic interface SameUrlData {}2.2自定义拦截器类检查此接口调用的方法是否使用了SameUrlData注解若没有使用表示此接口不需要校验若使用了注解获取请求url参数并去除一直在变化的参数(比如时间戳timeStamp和签名sign)检查参数中是否有token参数(token代表不同的用户的唯一标识)没有直接放行有token参数将tokenurl作为redis的keyurl参数作为value存入redis并设定自动销毁时间再次访问进行验证是否重复请求javaimport com.alibaba.fastjson.JSONObject;import com.tuohang.hydra.framework.common.spring.SpringKit;import com.tuohang.hydra.toolkit.basis.string.StringKit;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.concurrent.TimeUnit;/*** Title: 防止用户重复提交数据拦截器* Description: 将用户访问的url和参数结合token存入redis每次访问进行验证是否重复请求接口* Auther: xhq* Version: 1.0* create 2019/3/26 10:35*/Componentpublic class SameUrlDataInterceptor extends HandlerInterceptorAdapter {private static Logger LOG LoggerFactory.getLogger(SameUrlDataInterceptor.class);/*** 是否阻止提交,fasle阻止,true放行* return*/Overridepublic 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 dont repeat submit,url: request.getServletPath());JSONObject result new JSONObject();result.put(statusCode,500);result.put(message,请勿重复请求);response.setCharacterEncoding(UTF-8);response.setContentType(application/json; charsetutf-8);response.getWriter().write(result.toString());response.getWriter().close();// 拦截之后跳转页面// String formRequest request.getRequestURI();// request.setAttribute(myurl, formRequest);// request.getRequestDispatcher(/WebRoot/common/error/jsp/error_message.jsp).forward(request, response);return false;}else {//如果不是重复相同数据return true;}}return true;} else {return super.preHandle(request, response, handler);}}/*** 验证同一个url数据是否相同提交,相同返回true* param httpServletRequest* return*/public boolean repeatDataValidator(HttpServletRequest httpServletRequest){//获取请求参数mapMap parameterMap httpServletRequest.getParameterMap();Iterator it parameterMap.entrySet().iterator();String token ;Map parameterMapNew new HashMap();while(it.hasNext()){Map.Entry entry it.next();if(!entry.getKey().equals(timeStamp) !entry.getKey().equals(sign)){//去除sign和timeStamp这两个参数因为这两个参数一直在变化parameterMapNew.put(entry.getKey(), entry.getValue());if(entry.getKey().equals(token)) {token entry.getValue()[0];}}}if (StringKit.isBlank(token)){//如果没有token直接放行return false;}//过滤过后的请求内容String params JSONObject.toJSONString(parameterMapNew);System.out.println(paramsparams);String url httpServletRequest.getRequestURI();Map map new HashMap();//key为接口value为参数map.put(url, params);String nowUrlParams map.toString();StringRedisTemplate smsRedisTemplate SpringKit.getBean(StringRedisTemplate.class);String redisKey token url;String preUrlParams smsRedisTemplate.opsForValue().get(redisKey);if(preUrlParams null){//如果上一个数据为null,表示还没有访问页面//存放并且设置有效期2秒smsRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 2, TimeUnit.SECONDS);return false;}else{//否则已经访问过页面if(preUrlParams.equals(nowUrlParams)){//如果上次url数据和本次url数据相同则表示重复添加数据return true;}else{//如果上次 url数据 和本次url加数据不同则不是重复提交smsRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 1, TimeUnit.SECONDS);return false;}}}}2.3注册拦截器javaConfigurationpublic class WebMvcConfigExt extends WebMvcConfig {/*** 防止重复提交拦截器*/Autowiredprivate SameUrlDataInterceptor sameUrlDataInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {// 避开静态资源List resourcePaths defineResourcePaths();registry.addInterceptor(sameUrlDataInterceptor).addPathPatterns(/**).excludePathPatterns(resourcePaths);// 重复请求}/*** 自定义静态资源路径** return*/Overridepublic List defineResourcePaths() {List patterns new ArrayList();patterns.add(/assets/**);patterns.add(/upload/**);patterns.add(/static/**);patterns.add(/common/**);patterns.add(/error);return patterns;}}在相应方法上加SameUrlData注解javaSameUrlDataResponseBodyRequestMapping(value /saveOrUpdate)public String saveOrUpdate(){}