方法很多,先转载下,后面一个个实验,获得最优方案
原理:在新建页面中Session保存token随机码,当保存时验证,通过后删除,当再次点击保存时由于服务器端的Session中已经不存在了,所有无法验证通过。
1.新建注解:
- /**
- * <p>
- * 防止重复提交注解,用于方法上<br/>
- * 在新建页面方法上,设置needSaveToken()为true,此时拦截器会在Session中保存一个token,
- * 同时需要在新建的页面中添加
- * <input type="hidden" name="token" value="${token}">
- * <br/>
- * 保存方法需要验证重复提交的,设置needRemoveToken为true
- * 此时会在拦截器中验证是否重复提交
- * </p>
- * @author: chuanli
- * @date: 2013-6-27上午11:14:02
- *
- */
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface AvoidDuplicateSubmission {
- boolean needSaveToken() default false;
- boolean needRemoveToken() default false;
- }
2. 新建拦截器
- /**
- * <p>
- * 防止重复提交过滤器
- * </p>
- *
- * @author: chuanli
- * @date: 2013-6-27上午11:19:05
- */
- public class AvoidDuplicateSubmissionInterceptor extends HandlerInterceptorAdapter {
- private static final Logger LOG = Logger.getLogger(AvoidDuplicateSubmissionInterceptor.class);
- @Override
- public boolean preHandle(HttpServletRequest request,
- HttpServletResponse response, Object handler) throws Exception {
- User user = UserUtil.getUser();
- if (user != null) {
- HandlerMethod handlerMethod = (HandlerMethod) handler;
- Method method = handlerMethod.getMethod();
- AvoidDuplicateSubmission annotation = method.getAnnotation(AvoidDuplicateSubmission.class);
- if (annotation != null) {
- boolean needSaveSession = annotation.needSaveToken();
- if (needSaveSession) {
- request.getSession(false).setAttribute("token", TokenProcessor.getInstance().generateToken());
- }
- boolean needRemoveSession = annotation.needRemoveToken();
- if (needRemoveSession) {
- if (isRepeatSubmit(request)) {
- LOG.warn("please don't repeat submit,[user:" + user.getUsername() + ",url:"
- + request.getServletPath() + "]");
- return false;
- }
- request.getSession(false).removeAttribute("token");
- }
- }
- }
- return true;
- }
- private boolean isRepeatSubmit(HttpServletRequest request) {
- String serverToken = (String) request.getSession(false).getAttribute("token");
- if (serverToken == null) {
- return true;
- }
- String clinetToken = request.getParameter("token");
- if (clinetToken == null) {
- return true;
- }
- if (!serverToken.equals(clinetToken)) {
- return true;
- }
- return false;
- }
- }
3. 在Spring中配置
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
- <property name="interceptors">
- <list>
- <bean class="com.sohu.tv.crm.aop.UserLogInterceptor"/>
- <bean class="com.sohu.tv.crm.aop.AvoidDuplicateSubmissionInterceptor"/>
- </list>
- </property>
- </bean>
4. 在相关方法中加入注解:
- @RequestMapping("/save")
- @AvoidDuplicateSubmission(needRemoveToken = true)
- public synchronized ModelAndView save(ExecutionUnit unit, HttpServletRequest request, HttpServletResponse response)
- throws Exception {
- @RequestMapping("/edit")
- @AvoidDuplicateSubmission(needSaveToken = true)
- public ModelAndView edit(Integer id, HttpServletRequest request) throws Exception {
5.在新建页面中加入
<input type="hidden" name="token" value="${token}">