防止servlet重复提交

Servlet 防止刷新重复提交 在java web工程中,当jsp向Servlet提交请求时,如何防止刷新提交(F5)? 第一种解决方法,参照老紫竹的思路: 可以使用的方法有,在jsp中定义一个变量值,这个变量值应该是唯一的,可以使用算法来保证生成数据的唯一性,例如hash算法,或者生成一个随机数(Random),并将这个数值保存到一个Set中,并将Set保存在session中,提交Servlet时将这个参数传递过去,在Servlet中的处理:接到参数和session中的set后,判断set中有没有传来的参数值,如果没有则页面是刷新造成的,并不是来自页面的提交,这时不做insert data的处理。 jsp 代码 : <% //生成一个formhash,算法可以自己定,不随便重复就可以了 Random ran = new Random(); String formhash = String.valueOf(ran.nextInt()); //读取当前session里面的hashCode集合,此处使用了Set,方便判断。 Set formhashSession = (Set ) session.getAttribute("formhashSession"); if (formhashSession == null) { formhashSession = new HashSet (); } // 检测重复问题 while (formhashSession.contains(formhash)) { formhash = String.valueOf(ran.nextInt()); } // 保存到session里面 formhashSession.add(formhash); // 保存 session.setAttribute("formhashSession", formhashSession); %>
中增加: Servlet代码: // 拿到表单的formhash String formhash = request.getParameter("formhash"); // 拿到session里面的集合 Set formhashSession = (Set ) session.getAttribute("formhashSession"); // 如果没有,则是重复提交,或者非法提交 if (formhashSession == null || !formhashSession.contains(formhash)) { System.out.println("重复提交!"); }else{ //正常的操作 } // 最后,如果操作成功,从session里面把这个formhash 删掉! formhashSession.remove(formhash); session.setAttribute("formhashSession", formhashSession); 参考文章:http://blog.csdn.net/java2000_net/archive/2008/02/25/2119298.aspx 第二种解决方法, 参考struts的token(令牌)机制: 在提交的时候在Servlet中根据用户的sessionid和当前时间的long值生成一个令牌(每次提交都会生成一个新令牌),将令牌保存在该用户的会话中,并将令牌的值以request属性形式传到前端页面,在前端页面的form中增加传递令牌的隐藏域 ,提交form的时候,也会将clientToken传入Servlet,如果session中保存的令牌值与传入的不同,则是重复提交,因为每次请求Servlet都会生成新的令牌,刷新时的令牌值是旧的令牌值,不是最新的令牌值。 jsp代码: <% String clientToken = (String)request.getAttribute("clientToken"); clientToken = clientToken==null?"":clientToken; %> 中增加 Servlet代码: String clientToken = request.getParameter("clientToken"); String sessionToken = (String) session.getAttribute("token"); if(sessionToken!=null&&!clientToken.equals(sessionToken)){ System.out.println("请不要重复提交!"); }else{ //正常的操作 } //生成新令牌 String token = generateToken(request); request.setAttribute("clientToken", token); //替换旧令牌 session.setAttribute("token", token);
### Java中防止重复提交的注解实现方式 在Java开发中,为了有效解决用户可能因网络延迟或其他原因造成的重复提交问题,可以通过自定义注解配合拦截器的方式来实现。这种方法不仅提高了代码的可维护性和复用性,还增强了系统的健壮性。 #### 自定义注解的设计 自定义注解的核心在于定义其元数据以及作用范围。以下是常见的设计模式: 1. **定义注解属性** 注解通常包含一些必要的配置参数,例如时间间隔和提示信息。这些参数允许开发者灵活调整行为[^2]。 ```java import java.lang.annotation.*; @Target(ElementType.METHOD) // 定义注解的作用目标为方法级别 @Retention(RetentionPolicy.RUNTIME) // 表示注解会在运行时可用 @Documented // 将注解放入生成的文档中 public @interface RepeatSubmit { /** * 时间间隔(毫秒),小于该时间则认为是重复提交 */ int interval() default 5000; /** * 错误提示信息,默认值为“不允许重复提交,请稍后再试” */ String message() default "不允许重复提交,请稍后再试"; } ``` 2. **拦截器的实现** 拦截器负责捕获带有`@RepeatSubmit`注解的方法调用,并验证当前请求是否属于重复提交。如果检测到重复,则抛出异常并返回错误响应[^3]。 ```java 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.util.concurrent.TimeUnit; @Component public class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { private final static String REQUEST_KEY = "REPEAT_SUBMIT_TOKEN"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod method = (HandlerMethod) handler; RepeatSubmit repeatSubmitAnnotation = method.getMethodAnnotation(RepeatSubmit.class); if (repeatSubmitAnnotation != null) { long currentTimeMillis = System.currentTimeMillis(); Long lastRequestTime = (Long) request.getSession().getAttribute(REQUEST_KEY); if (lastRequestTime != null && (currentTimeMillis - lastRequestTime < repeatSubmitAnnotation.interval())) { throw new RuntimeException(repeatSubmitAnnotation.message()); } request.getSession().setAttribute(REQUEST_KEY, currentTimeMillis); // 更新最后一次请求时间 } } return true; } } ``` 3. **注册拦截器** 在Spring框架下,需将拦截器注册至应用上下文中以便生效[^4]。 ```java 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; @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private RepeatSubmitInterceptor repeatSubmitInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/api/**"); } } ``` #### 最佳实践建议 - **合理设置时间间隔**:根据具体的业务需求设定合适的`interval()`值,过短可能导致用户体验不佳,而过长又会影响性能[^5]。 - **支持国际化**:对于提示信息字段`message()`,推荐采用占位符形式结合资源文件管理,便于后期扩展和支持多语言环境。 - **线程安全性考虑**:当涉及高并发场景时,应特别注意Session存储机制是否会引发竞争条件等问题。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值